{"version":3,"sources":["../../../node_modules/tsup/assets/cjs_shims.js","../src/auth.ts","../src/otel-grpc.ts","../src/otel.ts","../src/cli.ts","../src/banner.ts","../src/style.ts","../src/graph.ts","../src/extract.ts","../src/extract/index.ts","../src/ingest.ts","../src/durable-incident.ts","../src/policy.ts","../src/compat.ts","../compat.json","../src/events.ts","../src/traverse.ts","../src/extract/routes.ts","../src/extract/shared.ts","../src/extract/errors.ts","../src/extract/calls/shared.ts","../src/extract/gitignore.ts","../src/extract/imports.ts","../src/extract/go.ts","../src/extract/source-baseline.ts","../src/extract/infra/shared.ts","../src/columns.ts","../src/flags.ts","../src/latency-digest.ts","../src/stacktrace.ts","../src/extract/services.ts","../src/extract/python.ts","../src/extract/go-binaries.ts","../src/extract/ruby.ts","../src/extract/php.ts","../src/extract/csharp.ts","../src/extract/java.ts","../src/extract/kotlin.ts","../src/extract/rust.ts","../src/extract/cpp.ts","../src/extract/dockerfile-service.ts","../src/extract/owners.ts","../src/extract/aliases.ts","../src/extract/files.ts","../src/extract/symbols.ts","../src/extract/symbol-edges.ts","../src/extract/go-symbol-edges.ts","../src/extract/java-symbol-edges.ts","../src/extract/actions.ts","../src/extract/databases/index.ts","../src/extract/databases/db-config-yaml.ts","../src/extract/databases/dotenv.ts","../src/extract/databases/shared.ts","../src/extract/databases/prisma.ts","../src/extract/databases/drizzle.ts","../src/extract/databases/knex.ts","../src/extract/databases/ormconfig.ts","../src/extract/databases/typeorm.ts","../src/extract/databases/sequelize.ts","../src/extract/databases/csharp.ts","../src/extract/databases/spring.ts","../src/extract/databases/docker-compose.ts","../src/extract/configs.ts","../src/extract/flags.ts","../src/extract/flags-configmap.ts","../src/extract/java-routes.ts","../src/extract/tornado-routes.ts","../src/extract/java-gateway.ts","../src/extract/proto.ts","../src/extract/calls/index.ts","../src/extract/calls/http.ts","../src/extract/calls/route-match.ts","../src/extract/calls/kafka.ts","../src/extract/calls/redis.ts","../src/extract/calls/aws.ts","../src/extract/calls/grpc.ts","../src/extract/calls/supabase.ts","../src/extract/calls/firestore.ts","../src/extract/calls/mongoose.ts","../src/extract/calls/sqlalchemy.ts","../src/extract/calls/socket.ts","../src/extract/calls/django-orm.ts","../src/extract/calls/drizzle.ts","../src/extract/calls/prisma.ts","../src/extract/calls/activerecord.ts","../src/extract/calls/eloquent.ts","../src/extract/calls/go.ts","../src/extract/calls/gorm.ts","../src/extract/calls/efcore.ts","../src/extract/calls/mysql-js.ts","../src/extract/calls/dbapi-python.ts","../src/extract/calls/jpa.ts","../src/extract/java-calls.ts","../src/extract/table-edges.ts","../src/extract/infra/index.ts","../src/extract/infra/docker-compose.ts","../src/extract/infra/dockerfile.ts","../src/extract/infra/terraform.ts","../src/extract/infra/k8s.ts","../src/extract/infra/cloudflare.ts","../src/extract/infra/vercel.ts","../src/extract/infra/railway.ts","../src/extract/infra/supabase.ts","../src/extract/infra/nginx.ts","../src/extract/zod-shapes.ts","../src/extract/firestore-rules.ts","../src/extract/retire.ts","../src/divergences.ts","../src/persist.ts","../src/gitignore.ts","../src/summary.ts","../src/otlp-headers.ts","../src/watch.ts","../src/api.ts","../src/extend/index.ts","../src/installers/package-manager.ts","../src/logs-store.ts","../src/goodybag.ts","../src/incidents-render.ts","../src/ask.ts","../src/diff.ts","../src/projects.ts","../src/registry.ts","../src/streaming.ts","../src/pr-verdict.ts","../../action/src/graph.mjs","../src/connectors/hosted-repos.ts","../src/connectors-config.ts","../src/connectors/status.ts","../src/connectors/index.ts","../src/connectors/registry.ts","../src/connectors/gcp-auth.ts","../src/connectors/junction.ts","../src/connectors/supabase/index.ts","../src/connectors/supabase/client.ts","../src/connectors/supabase/map.ts","../src/connectors/supabase/types.ts","../src/connectors/supabase/postgres-client.ts","../src/connectors/supabase/resolve.ts","../src/connectors/railway/index.ts","../src/connectors/railway/client.ts","../src/connectors/firebase/index.ts","../src/connectors/firebase/logging-api.ts","../src/connectors/firebase/map.ts","../src/connectors/firebase/resolve.ts","../src/connectors/infer-service.ts","../src/connectors/cloudflare/index.ts","../src/connectors/cloudflare/connector.ts","../src/connectors/cloudflare/client.ts","../src/connectors/cloudflare/map.ts","../src/connectors/cloudflare/types.ts","../src/connectors/vercel/index.ts","../src/connectors/vercel/client.ts","../src/connectors/neon/index.ts","../src/connectors/neon/client.ts","../src/connectors/neon/map.ts","../src/connectors/neon/types.ts","../src/connectors/neon/resolve.ts","../src/connectors/cloud-run/index.ts","../src/connectors/cloud-run/client.ts","../src/connectors/cloud-run/map.ts","../src/connectors/cloud-run/types.ts","../src/connectors/cloud-run/resolve.ts","../src/connectors/gcp-lb/index.ts","../src/connectors/gcp-lb/client.ts","../src/connectors/gcp-lb/map.ts","../src/connectors/gcp-lb/types.ts","../src/connectors/gcp-lb/resolve.ts","../src/connectors/render/index.ts","../src/connectors/render/types.ts","../src/connectors/render/client.ts","../src/connectors/planetscale/index.ts","../src/connectors/planetscale/client.ts","../src/connectors/planetscale/types.ts","../src/connectors/planetscale/map.ts","../src/connectors/planetscale/resolve.ts","../src/connectors/eas/index.ts","../src/connectors/eas/client.ts","../src/connectors/eas/types.ts","../src/connectors/eas/map.ts","../src/connectors/eas/resolve.ts","../src/hang-sensor.ts","../src/connectors/kubernetes/index.ts","../src/connectors/kubernetes/client.ts","../src/connectors/kubernetes/kubeconfig.ts","../src/connectors/kubernetes/map.ts","../src/connectors/kubernetes/types.ts","../src/connectors/kubernetes/process-context.ts","../src/connectors/kubernetes/resolve.ts","../src/connectors/kubernetes/substrate.ts","../src/flag-stores/index.ts","../src/flag-stores/flagd-sync.ts","../src/daemon.ts","../src/connectors/hosted.ts","../src/connectors/railway/target-ref.ts","../src/unrouted.ts","../src/search.ts","../src/deploy/detect.ts","../src/installers/index.ts","../src/installers/javascript.ts","../src/installers/templates.ts","../src/installers/python.ts","../src/installers/go.ts","../src/installers/ruby.ts","../src/installers/php.ts","../src/installers/shared.ts","../src/orchestrator.ts","../src/connector-cli.ts","../src/hosted-connect-cli.ts","../src/login-sso.ts","../src/profiles.ts","../src/daemon-probe.ts","../src/login-connect.ts","../src/doctor-cli.ts","../src/cli-client.ts","../src/up-cli.ts","../src/login-cli.ts","../src/welcome.ts","../src/agent-directive.generated.ts","../src/hooks-cli.ts","../src/claude-cli.ts","../src/codex-cli.ts","../src/editors-cli.ts","../src/monitor.ts","../src/cli-verbs.ts"],"sourcesContent":["// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n  typeof document === \"undefined\" \n    ? new URL(`file:${__filename}`).href \n    : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n      ? document.currentScript.src \n      : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","/**\n * Delegated auth at the daemon boundary (ADR-073 §3 + §4).\n *\n * NEAT does not issue, rotate, or distribute the token — that is the deploy\n * platform's job. This module provides the two surfaces the daemon needs:\n *\n *   - `assertBindAuthority(host, token)` — fail-loud pre-bind check. When no\n *     token is set, the daemon refuses to bind on any non-loopback address.\n *     Loopback-only without a token stays unauthenticated (laptop dev path).\n *\n *   - `mountBearerAuth(app, opts)` — Fastify `preHandler` that requires\n *     `Authorization: Bearer <token>` on every request other than the\n *     unauthenticated health/readiness probes. Constant-time comparison.\n *\n * The same shape covers both the REST host and the OTLP receivers; the OTLP\n * side passes a different token (`NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN`) so the\n * two surfaces rotate independently.\n */\n\nimport { timingSafeEqual } from 'node:crypto'\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'\n\n// Hosts that count as loopback for the bind-authority gate. `0.0.0.0` is\n// explicitly not loopback — it binds on every interface, including any\n// public one the operator's box happens to have.\nconst LOOPBACK_HOSTS: ReadonlySet<string> = new Set([\n  '127.0.0.1',\n  'localhost',\n  '::1',\n  '::ffff:127.0.0.1',\n])\n\nexport function isLoopbackHost(host: string | undefined | null): boolean {\n  if (!host) return false\n  return LOOPBACK_HOSTS.has(host)\n}\n\nexport class BindAuthorityError extends Error {\n  constructor(host: string) {\n    super(\n      `NEAT refuses to bind on a public interface without \\`NEAT_AUTH_TOKEN\\` set (host=\"${host}\"). Set the token or bind to loopback only.`,\n    )\n    this.name = 'BindAuthorityError'\n  }\n}\n\nexport function assertBindAuthority(host: string, token: string | undefined): void {\n  if (token && token.length > 0) return\n  if (isLoopbackHost(host)) return\n  throw new BindAuthorityError(host)\n}\n\nexport interface AuthOptions {\n  // Bearer token required on every protected route. Undefined / empty → the\n  // middleware is not mounted and the route stays unauthenticated. The\n  // loopback-only gate above is what keeps that case from being public.\n  token?: string\n  // When `true`, trust an upstream reverse proxy and skip the request-side\n  // check. The fail-loud bind-authority gate still applies upstream. Wired\n  // to `NEAT_AUTH_PROXY=true` in production.\n  trustProxy?: boolean\n  // ADR-073 §3 amendment — public-read mode for reference deployments.\n  // When `true`, GET / HEAD / OPTIONS pass through without a bearer; every\n  // other verb still requires the token. OTLP ingest is excluded — that\n  // surface stays gated unconditionally (the receiver mounts its own\n  // middleware without this flag).\n  publicRead?: boolean\n  // Extra paths to leave unauthenticated, matched exactly (no suffix\n  // matching — see the note on DEFAULT_UNAUTH_PATHS below). Used by tests\n  // and by ad-hoc callers that mount their own probes.\n  extraUnauthenticatedSuffixes?: ReadonlyArray<string>\n  // Diagnostic hook fired whenever a request is rejected with 401 for a\n  // missing or invalid bearer. The REST host leaves this unset — a human\n  // running `curl` doesn't need a server-side line for their own 401. The\n  // OTLP receiver passes it so an app whose telemetry is being dropped for a\n  // bad token leaves a signal on the daemon side instead of failing silently.\n  // The hook does not change the response body or status; it only observes.\n  onReject?: () => void\n}\n\n// Verbs the public-read split treats as reads. Everything else is a write\n// and keeps the bearer requirement.\nconst PUBLIC_READ_METHODS: ReadonlySet<string> = new Set(['GET', 'HEAD', 'OPTIONS'])\n\n// Probes that always stay open. `/health` is dual-mounted under\n// `/projects/:project/` too (registerRoutes mounts it both unprefixed and\n// inside the `/projects/:project` plugin scope) — that's the one project-\n// scoped variant a real route relies on today. ADR-073 §3 names `/healthz`\n// and `/readyz` explicitly as reserved probe paths (no handler registers them\n// yet); `/health` is the existing endpoint the web shell and CI smoke already\n// lean on. `/api/config` is the public-read negotiation endpoint — the web\n// shell hits it before any authed call to learn which mode the daemon is\n// running in.\n//\n// Matching used to be `path === suffix || path.endsWith(suffix)`, which\n// exempts *any* path that merely ends with one of these strings — a future\n// protected route named e.g. `/admin/health` would slip through\n// unauthenticated by accident. Matching is now exact on the root path, plus\n// one explicit pattern for the `/projects/:project/<name>` shape. Nothing\n// else qualifies.\nconst DEFAULT_UNAUTH_PATHS: ReadonlyArray<string> = [\n  '/health',\n  '/healthz',\n  '/readyz',\n  '/api/config',\n]\n\n// `/projects/<one segment>/health` (or /healthz, /readyz, /api/config) —\n// exactly one path segment for the project name, nothing before `/projects`\n// and nothing after the probe name. Built from DEFAULT_UNAUTH_PATHS so the\n// two lists can't drift.\nconst PROJECT_SCOPED_UNAUTH_PATTERN = new RegExp(\n  `^/projects/[^/]+/(?:${DEFAULT_UNAUTH_PATHS.map((p) => p.slice(1)).join('|')})$`,\n)\n\n/** Route config marking a route as authenticated by its own handler. */\nexport const BEARER_DELEGATED = { bearerDelegated: true } as const\n\nfunction isBearerDelegated(req: FastifyRequest): boolean {\n  const config = req.routeOptions?.config as { bearerDelegated?: unknown } | undefined\n  return config?.bearerDelegated === true\n}\n\nexport function mountBearerAuth(app: FastifyInstance, opts: AuthOptions): void {\n  if (!opts.token || opts.token.length === 0) return\n  if (opts.trustProxy) return\n\n  const expected = Buffer.from(opts.token, 'utf8')\n  const exactUnauthPaths = new Set([\n    ...DEFAULT_UNAUTH_PATHS,\n    ...(opts.extraUnauthenticatedSuffixes ?? []),\n  ])\n  const publicRead = opts.publicRead === true\n\n  app.addHook('preHandler', (req: FastifyRequest, reply: FastifyReply, done: (err?: Error) => void) => {\n    const path = (req.url.split('?')[0] ?? '').replace(/\\/+$/, '')\n    if (exactUnauthPaths.has(path) || PROJECT_SCOPED_UNAUTH_PATTERN.test(path)) {\n      done()\n      return\n    }\n\n    // A route that checks a different bearer itself. The OTLP routes served on\n    // the REST listener are gated by the ingest token, not this one, so this\n    // hook stands aside and the receiver behind them decides (ADR-073 §4). The\n    // flag lives on the route, so no path string can claim it by resemblance.\n    if (isBearerDelegated(req)) {\n      done()\n      return\n    }\n\n    // Public-read split: GET / HEAD / OPTIONS pass through anonymously, every\n    // other verb keeps the bearer check. The token still authorizes writes,\n    // and the bind-authority gate above still demands a token for non-loopback\n    // binds — public-read enables anonymous reads on top of that, it doesn't\n    // replace either invariant.\n    if (publicRead && PUBLIC_READ_METHODS.has(req.method)) {\n      done()\n      return\n    }\n\n    const header = req.headers.authorization\n    if (typeof header !== 'string' || !header.startsWith('Bearer ')) {\n      opts.onReject?.()\n      void reply.code(401).send({ error: 'unauthorized' })\n      return\n    }\n    const provided = Buffer.from(header.slice('Bearer '.length).trim(), 'utf8')\n    if (provided.length !== expected.length || !timingSafeEqual(provided, expected)) {\n      opts.onReject?.()\n      void reply.code(401).send({ error: 'unauthorized' })\n      return\n    }\n    done()\n  })\n}\n\n// Read both tokens from the environment in one place so server.ts, daemon.ts,\n// and the OTel receivers all agree on precedence (ADR-073 §4). `publicRead`\n// rides the same shape so callers don't need a second env read.\nexport interface AuthEnv {\n  authToken: string | undefined\n  otelToken: string | undefined\n  trustProxy: boolean\n  publicRead: boolean\n}\n\nfunction parseBoolEnv(v: string | undefined): boolean {\n  if (!v) return false\n  return v === 'true' || v === '1'\n}\n\nexport function readAuthEnv(env: NodeJS.ProcessEnv = process.env): AuthEnv {\n  const t = env.NEAT_AUTH_TOKEN\n  const ot = env.NEAT_OTEL_TOKEN\n  return {\n    authToken: t && t.length > 0 ? t : undefined,\n    otelToken: ot && ot.length > 0 ? ot : t && t.length > 0 ? t : undefined,\n    trustProxy: env.NEAT_AUTH_PROXY === 'true',\n    publicRead: parseBoolEnv(env.NEAT_PUBLIC_READ),\n  }\n}\n","import { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport { timingSafeEqual } from 'node:crypto'\nimport * as grpc from '@grpc/grpc-js'\nimport * as protoLoader from '@grpc/proto-loader'\nimport {\n  parseOtlpRequest,\n  type OtlpTracesRequest,\n  type ParsedSpan,\n  type SpanHandler,\n} from './otel.js'\n\n// OTLP/gRPC receiver. Sits next to buildOtelReceiver (HTTP/JSON) in otel.ts;\n// shares the same parseOtlpRequest decoder so a span looks identical to the\n// downstream onSpan handler whether it came in over JSON or protobuf.\n//\n// Default OFF — opts.enabled (typically NEAT_OTLP_GRPC=true) decides whether\n// server.ts wires this up. We keep gRPC behind a flag so existing HTTP-only\n// deployments don't get a surprise port binding on upgrade.\n\nexport interface BuildOtelGrpcReceiverOptions {\n  onSpan: SpanHandler\n  // ADR-073 §4 — bearer required in the gRPC call's `authorization` metadata\n  // when set. Same precedence as the HTTP receiver: NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN.\n  authToken?: string\n  // Skip the request-side check when an upstream proxy already authenticated.\n  trustProxy?: boolean\n}\n\n// proto-loader output for the trace service has fields like resource_spans,\n// scope_spans, span_id, etc. (snake_case keys, since we leave keepCase: true\n// when loading). The HTTP path uses camelCase JSON, so we shape-shift the\n// gRPC payload onto the HTTP shape and let parseOtlpRequest do the rest.\n//\n// All `bytes` fields arrive as Buffers; the HTTP wire format encodes them as\n// hex strings, so we hex-encode for consistency.\n\ninterface GrpcAnyValue {\n  string_value?: string\n  bool_value?: boolean\n  int_value?: string | number\n  double_value?: number\n  array_value?: { values?: GrpcAnyValue[] }\n  // bytes/kvlist fields exist in the proto but the demo doesn't use them.\n}\n\ninterface GrpcKeyValue {\n  key?: string\n  value?: GrpcAnyValue\n}\n\ninterface GrpcStatus {\n  code?: number\n  message?: string\n}\n\ninterface GrpcEvent {\n  name?: string\n  time_unix_nano?: string | number\n  attributes?: GrpcKeyValue[]\n}\n\ninterface GrpcSpan {\n  trace_id?: Buffer | Uint8Array\n  span_id?: Buffer | Uint8Array\n  parent_span_id?: Buffer | Uint8Array\n  name?: string\n  kind?: number\n  start_time_unix_nano?: string | number\n  end_time_unix_nano?: string | number\n  attributes?: GrpcKeyValue[]\n  events?: GrpcEvent[]\n  status?: GrpcStatus\n}\n\ninterface GrpcScopeSpans {\n  spans?: GrpcSpan[]\n}\n\ninterface GrpcResourceSpans {\n  resource?: { attributes?: GrpcKeyValue[] }\n  scope_spans?: GrpcScopeSpans[]\n}\n\ninterface GrpcExportRequest {\n  resource_spans?: GrpcResourceSpans[]\n}\n\nfunction bytesToHex(buf: Buffer | Uint8Array | undefined): string {\n  if (!buf) return ''\n  if (Buffer.isBuffer(buf)) return buf.toString('hex')\n  // protobufjs hands back plain Uint8Arrays in environments where its Buffer\n  // detection misses; hex-encode those too rather than silently emptying the\n  // span's identity (#468 — empty traceId/spanId killed every protobuf span).\n  if (buf instanceof Uint8Array) return Buffer.from(buf).toString('hex')\n  return ''\n}\n\nfunction nanosToString(n: string | number | undefined): string {\n  if (n === undefined || n === null) return '0'\n  return typeof n === 'string' ? n : String(n)\n}\n\nfunction reshapeAttributes(\n  attrs: GrpcKeyValue[] | undefined,\n): OtlpTracesRequest['resourceSpans'] extends Array<infer R>\n  ? R extends { resource?: { attributes?: infer A } }\n    ? A\n    : never\n  : never {\n  // Map snake_case oneof fields to the camelCase the JSON path expects.\n  const out = (attrs ?? []).map((kv) => ({\n    key: kv.key ?? '',\n    value: kv.value\n      ? {\n          stringValue: kv.value.string_value,\n          boolValue: kv.value.bool_value,\n          intValue: kv.value.int_value,\n          doubleValue: kv.value.double_value,\n          arrayValue: kv.value.array_value\n            ? {\n                values: (kv.value.array_value.values ?? []).map((v) => ({\n                  stringValue: v.string_value,\n                  boolValue: v.bool_value,\n                  intValue: v.int_value,\n                  doubleValue: v.double_value,\n                })),\n              }\n            : undefined,\n        }\n      : undefined,\n  }))\n  return out as never\n}\n\nexport function reshapeGrpcRequest(req: GrpcExportRequest): OtlpTracesRequest {\n  return {\n    resourceSpans: (req.resource_spans ?? []).map((rs) => ({\n      resource: rs.resource ? { attributes: reshapeAttributes(rs.resource.attributes) } : undefined,\n      scopeSpans: (rs.scope_spans ?? []).map((ss) => ({\n        spans: (ss.spans ?? []).map((s) => ({\n          traceId: bytesToHex(s.trace_id),\n          spanId: bytesToHex(s.span_id),\n          parentSpanId: s.parent_span_id ? bytesToHex(s.parent_span_id) : undefined,\n          name: s.name,\n          kind: s.kind,\n          startTimeUnixNano: nanosToString(s.start_time_unix_nano),\n          endTimeUnixNano: nanosToString(s.end_time_unix_nano),\n          attributes: reshapeAttributes(s.attributes),\n          events: (s.events ?? []).map((e) => ({\n            name: e.name,\n            timeUnixNano: nanosToString(e.time_unix_nano),\n            attributes: reshapeAttributes(e.attributes),\n          })),\n          status: s.status ? { code: s.status.code, message: s.status.message } : undefined,\n        })),\n      })),\n    })),\n  }\n}\n\n// Find the bundled .proto tree at packages/core/proto/. The dev server runs\n// from the source tree (tsx); the built bundles run from dist/. tsup keeps\n// source layout, so __dirname-relative resolution works for both — we look two\n// levels up from this file.\nfunction resolveProtoRoot(): string {\n  // Built output (CJS) sets __dirname natively; ESM build is bundled by tsup\n  // and keeps a dirname injection. import.meta.url is the safe bet.\n  const here = path.dirname(fileURLToPath(import.meta.url))\n  // src/ → packages/core/proto/, dist/ → packages/core/proto/.\n  return path.resolve(here, '..', 'proto')\n}\n\nfunction loadTraceService(): grpc.ServiceDefinition {\n  const protoRoot = resolveProtoRoot()\n  const def = protoLoader.loadSync(\n    'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n    {\n      keepCase: true,\n      longs: String,\n      enums: Number,\n      defaults: true,\n      oneofs: true,\n      includeDirs: [protoRoot],\n    },\n  )\n  const pkg = grpc.loadPackageDefinition(def) as unknown as {\n    opentelemetry: {\n      proto: {\n        collector: {\n          trace: {\n            v1: {\n              TraceService: { service: grpc.ServiceDefinition }\n            }\n          }\n        }\n      }\n    }\n  }\n  return pkg.opentelemetry.proto.collector.trace.v1.TraceService.service\n}\n\nexport interface OtelGrpcReceiver {\n  // Bound address (host:port) once .start() has resolved. Useful for tests.\n  address: string\n  // Stop accepting new requests, shut down the server.\n  stop: () => Promise<void>\n}\n\nexport async function startOtelGrpcReceiver(\n  opts: BuildOtelGrpcReceiverOptions & { host?: string; port?: number },\n): Promise<OtelGrpcReceiver> {\n  const server = new grpc.Server()\n  const service = loadTraceService()\n\n  const requiresAuth = !opts.trustProxy && !!opts.authToken && opts.authToken.length > 0\n  const expectedHeader = requiresAuth ? `Bearer ${opts.authToken}` : ''\n\n  server.addService(service, {\n    Export: (\n      call: grpc.ServerUnaryCall<GrpcExportRequest, unknown>,\n      callback: grpc.sendUnaryData<{ partial_success: object }>,\n    ) => {\n      // ADR-073 §4 — same bearer shape as the HTTP receiver, carried in the\n      // `authorization` gRPC metadata header. Constant-time comparison.\n      if (requiresAuth) {\n        const meta = call.metadata.get('authorization')\n        const got = meta.length > 0 ? String(meta[0]) : ''\n        const a = Buffer.from(got, 'utf8')\n        const b = Buffer.from(expectedHeader, 'utf8')\n        const ok = a.length === b.length && timingSafeEqual(a, b)\n        if (!ok) {\n          callback({ code: grpc.status.UNAUTHENTICATED, message: 'unauthorized' })\n          return\n        }\n      }\n      void (async () => {\n        try {\n          const reshaped = reshapeGrpcRequest(call.request ?? {})\n          const spans: ParsedSpan[] = parseOtlpRequest(reshaped)\n          for (const span of spans) {\n            await opts.onSpan(span)\n          }\n          callback(null, { partial_success: {} })\n        } catch (err) {\n          callback({\n            code: grpc.status.INTERNAL,\n            message: err instanceof Error ? err.message : String(err),\n          })\n        }\n      })()\n    },\n  })\n\n  const host = opts.host ?? '0.0.0.0'\n  const port = opts.port ?? 4317\n\n  const boundPort = await new Promise<number>((resolve, reject) => {\n    server.bindAsync(`${host}:${port}`, grpc.ServerCredentials.createInsecure(), (err, p) => {\n      if (err) return reject(err)\n      resolve(p)\n    })\n  })\n\n  return {\n    address: `${host}:${boundPort}`,\n    stop: () =>\n      new Promise<void>((resolve) => {\n        server.tryShutdown(() => resolve())\n      }),\n  }\n}\n","import path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport zlib from 'node:zlib'\nimport type { Transform } from 'node:stream'\nimport Fastify, { type FastifyInstance } from 'fastify'\nimport protobuf from 'protobufjs'\nimport { mountBearerAuth } from './auth.js'\n\n// OTLP/HTTP receiver. Listens on /v1/traces and decodes the JSON wire format\n// (collector's `otlphttp` exporter with `encoding: json`). Each span is\n// flattened into a ParsedSpan and handed to the configured handler. The\n// handler is the seam #8 wires its edge mapper into; #7 itself stays decoupled\n// from graph mutation.\n\nexport interface ParsedSpan {\n  service: string\n  // True when the resource carried a `service.name` attribute. False (or\n  // omitted, for legacy producers) routes the span to `service:unidentified`\n  // in the resolved project and trips a once-per-session-per-project warning\n  // on the ingest side (issue #374). OTel spec requires SDKs to set\n  // `service.name`, but customised exporters can omit it — diagnostic\n  // visibility beats silent drop. Field is optional so test fixtures that\n  // hand-construct ParsedSpan with a known service.name don't need to set\n  // a flag they don't care about; the receiver always sets it.\n  // See docs/contracts/otlp-routing.md §Fallback when `resource.service.name`\n  // is missing.\n  resourceServiceNamePresent?: boolean\n  traceId: string\n  spanId: string\n  parentSpanId?: string\n  name: string\n  kind?: number\n  startTimeUnixNano: string\n  endTimeUnixNano: string\n  // ISO8601 derived from startTimeUnixNano. Production paths (lastObserved on\n  // OBSERVED edges) read this so the recorded time reflects when the span fired,\n  // not when the receiver received it. Undefined only when startTimeUnixNano is\n  // missing or unparseable — handler falls back to wall-clock in that case.\n  // See docs/contracts/otel-ingest.md §lastObserved-from-span-time.\n  startTimeIso?: string\n  // bigint so the 9-digit-nanos arithmetic doesn't lose precision on long traces.\n  durationNanos: bigint\n  // Deployment environment from `deployment.environment(.name)`. Span attrs\n  // win over resource attrs (per-span overrides a resource-wide declaration);\n  // the canonical `deployment.environment.name` (OTel SC v1.27+) wins over\n  // the compat form `deployment.environment`. Literal `'unknown'` is the\n  // honest fallback when no env signal is present anywhere on the span or\n  // its resource. See ADR-074 §2 / docs/contracts/env-dimension.md.\n  env: string\n  attributes: Record<string, AttributeValue>\n  // Convenience accessors for the attributes #8 cares about.\n  dbSystem?: string\n  dbName?: string\n  // The collection a `db.system: mongodb` span operated on (ADR-148). The\n  // mongodb / mongoose instrumentation sets `db.collection.name` in the stable\n  // convention, `db.mongodb.collection` in the older one — read the first, fall\n  // back to the second.\n  dbCollection?: string\n  // The table a SQL span operated on (ADR-152). The SQLAlchemy / dbapi\n  // instrumentation emits no table attribute — the table is only inside the\n  // `db.statement` SQL text — so this is parsed from it (`tableFromSqlStatement`),\n  // conservatively: a single FROM/INTO/UPDATE table, else undefined.\n  dbTable?: string\n  // The columns that same SQL span TOUCHED (ADR-157 §2), parsed from the\n  // `db.statement` alongside the table (`columnsFromSqlStatement`). Empty when\n  // the statement recovers no columns (a `SELECT *`, an aggregate, a JOIN /\n  // subquery degrade, or a shape the parser doesn't read). Merged onto the\n  // `sql-table` node as OBSERVED column attributes in handleSpan.\n  dbColumns?: string[]\n  // The served route + method off a SERVER span (#576). `http.route` is the\n  // templated path the router matched (`/users/{id}`); the method is the stable\n  // `http.request.method`, falling back to the legacy `http.method`. handleSpan\n  // matches these against the statically-extracted RouteNode to mint the OBSERVED\n  // twin of a declared route.\n  httpRoute?: string\n  httpMethod?: string\n  // Messaging semconv (OTel). `messaging.system` names the broker family\n  // (kafka, rabbitmq, redis, …); the destination is the topic/queue the span\n  // produced to or consumed from — the canonical `messaging.destination.name`\n  // (SC v1.24+) with the legacy `messaging.destination` as fallback. handleSpan\n  // reads these to mint a PUBLISHES_TO (PRODUCER) or CONSUMES_FROM (CONSUMER)\n  // OBSERVED edge to the destination node, fusing with the static extractor's\n  // topic node. See docs/contracts/otel-ingest.md §Queue producers and consumers.\n  messagingSystem?: string\n  messagingDestination?: string\n  // GraphQL semconv (OTel). `graphql.operation.name` is the client-supplied\n  // operation name the execution span resolved (`GetUser`); `graphql.operation.type`\n  // is the operation kind (`query` / `mutation` / `subscription`). handleSpan reads\n  // both to mint an OBSERVED `CONTAINS` edge from the serving service to a\n  // per-operation node, recovering the operation-level topology that HTTP grain\n  // collapses onto `POST /graphql`. See docs/contracts/otel-ingest.md §GraphQL\n  // operations.\n  graphqlOperationName?: string\n  graphqlOperationType?: string\n  // gRPC RPC semconv (OTel). `rpc.system` names the RPC framework (`grpc`);\n  // `rpc.service` is the fully-qualified proto service (`orders.OrderService`)\n  // and `rpc.method` the bare method (`GetOrder`). The serving (SERVER) and\n  // calling (CLIENT) sides both carry these. handleSpan reads them off the\n  // serving span to mint an OBSERVED `CONTAINS` edge from the serving service to\n  // a per-method node, recovering the method-level topology gRPC's service-grain\n  // edge collapses — and keyed so the static `.proto` definition fuses onto the\n  // same node. See docs/contracts/otel-ingest.md §gRPC methods.\n  rpcSystem?: string\n  rpcService?: string\n  rpcMethod?: string\n  // Opentracing / Jaeger datastore clients name the datastore in `peer.service` (the\n  // engine, e.g. `memcached`) and the host in `peer.hostname`, with no `db.system`\n  // (#1415). Set from those attributes so ingest can resolve the datastore the\n  // OTel-native db branch would miss.\n  peerService?: string\n  peerHostname?: string\n  // WebSocket channel (OTel HTTP semconv). A WebSocket connection opens with an\n  // HTTP upgrade handshake: a SERVER `GET` whose `Upgrade` request header names\n  // `websocket`. That single span is the only reliable OBSERVED signal a channel\n  // exists — the message frames afterwards ride the socket, not more spans. This\n  // field carries the channel path off that upgrade span (`http.route` when the\n  // router templated it, else `url.path` / `http.target`), and is set only when\n  // the upgrade header is present. handleSpan reads it to mint a\n  // WebSocketChannelNode and an OBSERVED `CONNECTS_TO` edge from the serving\n  // service to it. See docs/contracts/otel-ingest.md §WebSocket channels.\n  websocketChannel?: string\n  // 0 = UNSET, 1 = OK, 2 = ERROR per OTLP. We only care that 2 means error.\n  statusCode?: number\n  errorMessage?: string\n  // Pre-extracted from a span event with name=\"exception\". OTLP SDKs record\n  // exceptions this way (richer than status.message). handleSpan reads these\n  // first, falling back to status.message and span.name. See\n  // docs/contracts/otel-ingest.md §exception-data-from-span-events.\n  exception?: {\n    type?: string\n    message?: string\n    stacktrace?: string\n  }\n  // Feature-flag evaluations recorded on the span as `feature_flag.evaluation`\n  // events (OTel feature-flag semconv; ADR-242). Each is what one evaluation\n  // returned: the flag key, the variant, the provider, and the OpenFeature\n  // reason. The evaluation context is never read. handleSpan folds them onto the\n  // flag grain of the matching flag-store node.\n  flagEvaluations?: FlagEvaluation[]\n}\n\nexport interface FlagEvaluation {\n  key: string\n  variant?: string\n  provider?: string\n  reason?: string\n}\n\nexport type AttributeValue =\n  | string\n  | number\n  | boolean\n  | bigint\n  | string[]\n  | number[]\n  | boolean[]\n  | null\n\nexport type SpanHandler = (span: ParsedSpan) => void | Promise<void>\n// Variant that receives the project the URL already resolved to. Used by the\n// project-scoped route mounted at `/projects/:project/v1/traces` (issue #367):\n// the receiver hands the URL-path project to the daemon directly so the\n// daemon never has to guess via `service.name`-against-registry matching.\nexport type ProjectSpanHandler = (project: string, span: ParsedSpan) => void | Promise<void>\n\nexport interface BuildOtelReceiverOptions {\n  onSpan: SpanHandler\n  // Synchronous handler for spans with statusCode === 2. The receiver awaits\n  // it before replying, so a write failure can return 500 → OTel SDK retries.\n  // Optional — wiring is expected to plumb appendErrorEvent here when error\n  // durability matters; ad-hoc receivers leave it undefined.\n  // See docs/contracts/otel-ingest.md §Error events.\n  onErrorSpanSync?: (span: ParsedSpan) => Promise<void>\n  // Project-scoped variants — used by the `/projects/:project/v1/traces`\n  // route. When unset the route is still mounted but falls through to the\n  // legacy `onSpan` / `onErrorSpanSync` handlers (the project name is then\n  // available to the consumer via the `OTEL_PROJECT_OVERRIDE` attribute on\n  // each parsed span; ad-hoc receivers commonly leave both unset).\n  onProjectSpan?: ProjectSpanHandler\n  onProjectErrorSpanSync?: (project: string, span: ParsedSpan) => Promise<void>\n  // #881 — decides whether the `/projects/:project/v1/traces` route serves the\n  // named project. When it returns false the route replies 404 instead of a\n  // 200 + empty `partialSuccess` that silently drops the batch, so a\n  // misconfigured exporter (a wrong or wrong-cased project name in the URL)\n  // finds out. Optional: when unset the route accepts any name — the\n  // single-project `neat watch` receiver, where the URL name is advisory since\n  // there is only one project to land in.\n  isProjectRegistered?: (project: string) => boolean\n  // #881 — classifies a bare `/v1/traces` batch for routability before reply.\n  // The bare route replies 200 as soon as the body is parsed (§Non-blocking\n  // ingest) and only routes each span later, off the queue — so without this\n  // hook an unroutable span leaves on a 200 + empty `partialSuccess`, which an\n  // OTel exporter reads as \"everything accepted\" while the batch was dropped.\n  // The hook returns how many spans in the batch belong to no project this\n  // daemon hosts (and a human message); the receiver keeps the 200 but reports\n  // those as `partialSuccess.rejectedSpans` + `errorMessage` so a misconfigured\n  // exporter finds out. Pure and synchronous: it reads in-memory routing state,\n  // never mutates the graph or writes the unrouted ledger — the async `onSpan`\n  // path still owns the drop and the `errors.ndjson` record. Optional: an\n  // ad-hoc or single-consumer receiver leaves it unset and keeps the historical\n  // empty-`partialSuccess` reply for every batch.\n  classifyBareRoutability?: (spans: ParsedSpan[]) => { rejected: number; message?: string }\n  // Fastify body limit. OTLP batches can be large; default is 16 MB.\n  bodyLimit?: number\n  // ADR-073 §4 — bearer required on `/v1/traces`. Defaults to `NEAT_AUTH_TOKEN`\n  // when unset; `NEAT_OTEL_TOKEN` overrides at the call site so the REST and\n  // OTLP surfaces rotate on independent schedules.\n  authToken?: string\n  // Same shape as the REST middleware: skip the request-side check when an\n  // upstream reverse proxy already authenticated.\n  trustProxy?: boolean\n}\n\ninterface OtlpKeyValue {\n  key: string\n  value?: OtlpAnyValue\n}\n\ninterface OtlpAnyValue {\n  stringValue?: string\n  intValue?: string | number\n  doubleValue?: number\n  boolValue?: boolean\n  arrayValue?: { values?: OtlpAnyValue[] }\n  // kvlistValue / bytesValue are skipped — neither is on the demo path.\n}\n\ninterface OtlpStatus {\n  code?: number\n  message?: string\n}\n\ninterface OtlpEvent {\n  name?: string\n  timeUnixNano?: string\n  attributes?: OtlpKeyValue[]\n}\n\ninterface OtlpSpan {\n  traceId?: string\n  spanId?: string\n  parentSpanId?: string\n  name?: string\n  kind?: number\n  startTimeUnixNano?: string\n  endTimeUnixNano?: string\n  attributes?: OtlpKeyValue[]\n  events?: OtlpEvent[]\n  status?: OtlpStatus\n}\n\nfunction extractExceptionFromEvents(events: OtlpEvent[] | undefined): ParsedSpan['exception'] {\n  if (!events) return undefined\n  for (const ev of events) {\n    if (ev.name !== 'exception') continue\n    const attrs = attrsToRecord(ev.attributes)\n    const out: ParsedSpan['exception'] = {}\n    const t = attrs['exception.type']\n    const m = attrs['exception.message']\n    const s = attrs['exception.stacktrace']\n    if (typeof t === 'string') out.type = t\n    if (typeof m === 'string') out.message = m\n    if (typeof s === 'string') out.stacktrace = s\n    if (out.type || out.message || out.stacktrace) return out\n  }\n  return undefined\n}\n\n// Current semconv names first, then the legacy names OpenFeature's older\n// telemetry helpers still emit.\nfunction firstString(attrs: Record<string, AttributeValue>, names: string[]): string | undefined {\n  for (const n of names) {\n    const v = attrs[n]\n    if (typeof v === 'string' && v.length > 0) return v\n  }\n  return undefined\n}\n\nfunction extractFlagEvaluations(events: OtlpEvent[] | undefined): FlagEvaluation[] | undefined {\n  if (!events) return undefined\n  const out: FlagEvaluation[] = []\n  for (const ev of events) {\n    if (ev.name !== 'feature_flag.evaluation' && ev.name !== 'feature_flag') continue\n    const attrs = attrsToRecord(ev.attributes)\n    const key = firstString(attrs, ['feature_flag.key'])\n    if (!key) continue\n    const variant = firstString(attrs, ['feature_flag.result.variant', 'feature_flag.variant'])\n    const provider = firstString(attrs, ['feature_flag.provider.name', 'feature_flag.provider_name'])\n    const reason = firstString(attrs, ['feature_flag.result.reason', 'feature_flag.evaluation.reason'])\n    out.push({\n      key,\n      ...(variant ? { variant } : {}),\n      ...(provider ? { provider } : {}),\n      ...(reason ? { reason } : {}),\n    })\n  }\n  return out.length > 0 ? out : undefined\n}\n\ninterface OtlpScopeSpans {\n  spans?: OtlpSpan[]\n}\n\ninterface OtlpResourceSpans {\n  resource?: { attributes?: OtlpKeyValue[] }\n  scopeSpans?: OtlpScopeSpans[]\n}\n\nexport interface OtlpTracesRequest {\n  resourceSpans?: OtlpResourceSpans[]\n}\n\nfunction flattenAttribute(v: OtlpAnyValue | undefined): AttributeValue {\n  if (!v) return null\n  if (v.stringValue !== undefined) return v.stringValue\n  if (v.boolValue !== undefined) return v.boolValue\n  if (v.intValue !== undefined) {\n    return typeof v.intValue === 'string' ? Number(v.intValue) : v.intValue\n  }\n  if (v.doubleValue !== undefined) return v.doubleValue\n  if (v.arrayValue?.values) {\n    return v.arrayValue.values.map((x) => flattenAttribute(x)) as AttributeValue\n  }\n  return null\n}\n\nfunction attrsToRecord(attrs: OtlpKeyValue[] | undefined): Record<string, AttributeValue> {\n  const out: Record<string, AttributeValue> = {}\n  if (!attrs) return out\n  for (const kv of attrs) {\n    if (kv.key) out[kv.key] = flattenAttribute(kv.value)\n  }\n  return out\n}\n\nfunction durationNanos(start?: string, end?: string): bigint {\n  if (!start || !end) return 0n\n  try {\n    return BigInt(end) - BigInt(start)\n  } catch {\n    return 0n\n  }\n}\n\n// Convert OTLP's startTimeUnixNano (a base-10 string of nanoseconds since the\n// Unix epoch) to ISO8601. Returns undefined when the input is missing, zero,\n// or unparseable, so the caller can fall back to wall-clock without surfacing\n// a fake timestamp on the edge.\nexport function isoFromUnixNano(nanos: string | undefined): string | undefined {\n  if (!nanos || nanos === '0') return undefined\n  try {\n    const ms = Number(BigInt(nanos) / 1_000_000n)\n    if (!Number.isFinite(ms)) return undefined\n    return new Date(ms).toISOString()\n  } catch {\n    return undefined\n  }\n}\n\n// Resolve `deployment.environment` per ADR-074 §2. The four-step fallback\n// is: span-attr canonical form → span-attr compat form → resource-attr\n// canonical form → resource-attr compat form → literal `'unknown'`. The\n// literal `'unknown'` is the honest sentinel; defaulting to `'production'`\n// or `'development'` would bake an incorrect assumption into every span\n// from a workload that hasn't yet wired its env signal.\nconst ENV_ATTR_CANONICAL = 'deployment.environment.name'\nconst ENV_ATTR_COMPAT = 'deployment.environment'\nconst ENV_FALLBACK = 'unknown'\n\nfunction pickEnv(\n  spanAttrs: Record<string, AttributeValue>,\n  resourceAttrs: Record<string, AttributeValue>,\n): string {\n  for (const attrs of [spanAttrs, resourceAttrs]) {\n    for (const key of [ENV_ATTR_CANONICAL, ENV_ATTR_COMPAT]) {\n      const v = attrs[key]\n      if (typeof v === 'string' && v.length > 0) return v\n    }\n  }\n  return ENV_FALLBACK\n}\n\n// The datastore engine a `db.system` span names, normalized at the parse\n// boundary. The mongoose OTel instrumentation — the one that actually emits\n// per-operation collection spans on real apps — tags its spans\n// `db.system: 'mongoose'`, but mongoose is an ORM over mongodb: the datastore\n// IS mongodb, and `mongoose` on the span is an instrumentation detail. Rewrite\n// it to `mongodb` here so every downstream reader (the collection edge, the\n// database-node engine, ADR-141 fusion) sees one engine and none of them has to\n// know the ORM label. See ADR-150.\nfunction normalizeDbSystem(attrs: Record<string, AttributeValue>): string | undefined {\n  // `db.system` (semconv ≤ 1.10) or `db.system.name` (≥ 1.30) — read both so the\n  // mongodb guard and every dbSystem consumer see the system on the newer semconv.\n  const raw = attrs['db.system'] ?? attrs['db.system.name']\n  if (typeof raw !== 'string') return undefined\n  return raw === 'mongoose' ? 'mongodb' : raw\n}\n\n// The table a SQL statement targets, for the OBSERVED table-grain edge. The\n// SQLAlchemy / dbapi instrumentation emits no dedicated table attribute (verified\n// against a live app — ADR-152); the table lives only in the `db.statement` SQL.\n// Conservative by design: the single table after FROM / INTO / UPDATE, quote- and\n// schema-stripped. A joined or multi-`FROM` (subquery) statement degrades to\n// `null` — the database-grain edge stands, and the table is never guessed.\nexport function tableFromSqlStatement(sql: string): string | null {\n  if (typeof sql !== 'string' || sql.length === 0) return null\n  if (/\\bjoin\\b/i.test(sql)) return null\n  const froms = sql.match(/\\bfrom\\b/gi)\n  if (froms && froms.length > 1) return null // subquery / multi-table — degrade\n  const m = /\\b(?:from|into|update)\\s+(?:\"?[\\w$]+\"?\\s*\\.\\s*)?\"?([a-zA-Z_][\\w$]*)\"?/i.exec(sql)\n  return m ? m[1]! : null\n}\n\n// The columns a SQL statement TOUCHES, for the OBSERVED column-grain attributes\n// (ADR-157 §2) — the column sibling of `tableFromSqlStatement` above. Production\n// statements are parameterized (values redacted to `$1`), but the column NAMES\n// are still in the text: an INSERT names its column list, an UPDATE its SET\n// targets, a SELECT its projection, and each of those plus a DELETE names the\n// columns in its WHERE predicate. Real ORM SQL is quoted and schema-qualified,\n// and SQLAlchemy projects every column as `<table>.<col> AS <table>_<col>`, so\n// the parse strips quotes and the table/schema qualifier and drops the `AS`\n// alias to recover the REAL column name, never the alias (`orders.id AS\n// orders_id` → `id`). Aggregate / function / `*` projections yield no column.\n// It degrades to `[]` on the same JOIN / multi-`FROM` (subquery) shapes\n// `tableFromSqlStatement` degrades to `null` on — there the columns belong to\n// more than one table and can't be attributed honestly. Returned names are\n// lowercased and de-duplicated; an unparseable or empty statement yields `[]`.\n// Ported verbatim from the proven column-grain spike.\nexport function columnsFromSqlStatement(sql: string): string[] {\n  if (typeof sql !== 'string' || sql.length === 0) return []\n  const s = sql.replace(/\\s+/g, ' ').trim()\n  if (/\\bjoin\\b/i.test(s)) return []\n  if ((s.match(/\\bfrom\\b/gi) ?? []).length > 1) return [] // subquery / multi-table — degrade\n\n  // One projected/assigned term → its bare column name, or null to skip it (an\n  // aggregate / function / wildcard, or a token that isn't a plain identifier).\n  const bare = (raw: string): string | null => {\n    let t = raw.trim().replace(/\"/g, '')\n    if (/[()*]/.test(t)) return null // aggregate / func / wildcard — skip\n    t = t.split(/\\s+as\\s+/i)[0]!.trim() // drop \"AS alias\" — keep the real column\n    t = t.split('.').pop()! // drop table / schema qualifier\n    return /^[a-z_][\\w$]*$/i.test(t) ? t.toLowerCase() : null\n  }\n  const isCol = (c: string | null): c is string => c !== null\n  const cols = (list: string): string[] => [...new Set(list.split(',').map(bare).filter(isCol))]\n  const whereCols = (w: string | undefined): string[] =>\n    w\n      ? [\n          ...new Set(\n            [\n              ...w.matchAll(\n                /(?:\"?[\\w$]+\"?\\.)?\"?([a-z_][\\w$]*)\"?\\s*(?:=|<|>|<=|>=|<>|!=|\\bis\\b|\\bin\\b|\\blike\\b)/gi,\n              ),\n            ]\n              .map((match) => match[1]!.toLowerCase())\n              .filter((c) => !/^(and|or|not|null)$/i.test(c)),\n          ),\n        ]\n      : []\n\n  let m: RegExpExecArray | null\n  if ((m = /\\binsert\\s+into\\s+(?:\"?[\\w$]+\"?\\.)?\"?[\\w$]+\"?\\s*\\(([^)]*)\\)/i.exec(s))) {\n    return cols(m[1]!)\n  }\n  if ((m = /\\bupdate\\s+(?:\"?[\\w$]+\"?\\.)?\"?[\\w$]+\"?\\s+set\\s+(.+?)(?:\\bwhere\\b(.+))?$/i.exec(s))) {\n    const set = m[1]!\n      .split(',')\n      .map((p) => bare(p.split('=')[0]!))\n      .filter(isCol)\n    return [...new Set([...set, ...whereCols(m[2] ?? undefined)])]\n  }\n  if ((m = /\\bdelete\\s+from\\s+(?:\"?[\\w$]+\"?\\.)?\"?[\\w$]+\"?(?:\\s+where\\b(.+))?$/i.exec(s))) {\n    return whereCols(m[1] ?? undefined)\n  }\n  if ((m = /\\bselect\\s+(.+?)\\s+from\\s+(?:\"?[\\w$]+\"?\\.)?\"?[\\w$]+\"?(?:\\s+where\\b(.+))?$/i.exec(s))) {\n    if (m[1]!.trim() === '*') return [] // SELECT * — no column list to attribute\n    return [...new Set([...cols(m[1]!), ...whereCols(m[2] ?? undefined)])]\n  }\n  return []\n}\n\n// The messaging destination (topic / queue / stream) a producer or consumer\n// span names. `messaging.destination.name` is the canonical semconv key\n// (SC v1.24+); `messaging.destination` is the older form some instrumentations\n// still emit. Prefer the canonical one, fall back to the legacy, and treat an\n// empty string as absent so an anonymous destination never keys a node.\nfunction messagingDestinationOf(\n  attrs: Record<string, AttributeValue>,\n): string | undefined {\n  for (const key of ['messaging.destination.name', 'messaging.destination']) {\n    const v = attrs[key]\n    if (typeof v === 'string' && v.length > 0) return v\n  }\n  return undefined\n}\n\n// True when the span's `Upgrade` request header names `websocket`. OTel HTTP\n// instrumentation captures configured request headers as `http.request.header.<key>`\n// with the key lower-cased and the value an array of strings (one per header\n// occurrence); older SDKs may write a bare string. A WebSocket handshake carries\n// `Upgrade: websocket`, so any element equal to `websocket` (case-insensitive)\n// marks the upgrade. Returns false when the header is absent — a plain `GET`\n// route span never mints a channel.\nfunction hasWebsocketUpgradeHeader(attrs: Record<string, AttributeValue>): boolean {\n  const v = attrs['http.request.header.upgrade']\n  const matches = (s: unknown): boolean =>\n    typeof s === 'string' && s.trim().toLowerCase() === 'websocket'\n  if (Array.isArray(v)) return v.some(matches)\n  return matches(v)\n}\n\n// The channel path an upgrade span opens onto. Prefer the templated route\n// (`http.route`, e.g. `/ws/:room`) so high-cardinality connection paths collapse\n// onto one channel node; fall back to the concrete request path (`url.path`, the\n// SC v1.21+ name, or the legacy `http.target`) with any query string trimmed.\n// Returns undefined when nothing carries a path — the branch then falls through\n// rather than minting a channel keyed on an empty string.\nfunction websocketChannelPathOf(attrs: Record<string, AttributeValue>): string | undefined {\n  const route = attrs['http.route']\n  if (typeof route === 'string' && route.length > 0) return route\n  for (const key of ['url.path', 'http.target']) {\n    const v = attrs[key]\n    if (typeof v === 'string' && v.length > 0) {\n      const q = v.indexOf('?')\n      const path = q === -1 ? v : v.slice(0, q)\n      if (path.length > 0) return path\n    }\n  }\n  return undefined\n}\n\n// The WebSocket channel this span serves, or undefined. Set only on the HTTP\n// upgrade handshake span — a request carrying `Upgrade: websocket` — so a plain\n// HTTP route span is never mistaken for a channel. See docs/contracts/otel-ingest.md\n// §WebSocket channels.\nfunction websocketChannelOf(attrs: Record<string, AttributeValue>): string | undefined {\n  if (!hasWebsocketUpgradeHeader(attrs)) return undefined\n  return websocketChannelPathOf(attrs)\n}\n\n// Opentracing / Jaeger-converted gRPC spans carry the called method only in the\n// operation name (`/pkg.Service/Method`), not the `rpc.*` semconv attributes an\n// OTel-native gRPC span sets — the collector's jaeger receiver tags them with a\n// `component` of `gRPC` and nothing else (DeathStarBench hotelReservation, #1427).\n// Recover the method identity from the name so the gRPC method fusion — serving\n// `CONTAINS` (ADR-123 / #616) and calling `CALLS` (#1413) — reaches those spans too,\n// keyed the same way `grpcMethodId` and the `.proto` extractor key the node. Gated\n// tightly so it never misreads a non-gRPC span: only when no `rpc.*` attribute is\n// present (an OTel-native span keeps the attribute path), the `component` tag\n// lowercases to `grpc`, and the name is exactly `/<service>/<method>` — two non-empty,\n// slash-free segments.\nfunction grpcFromSpanName(\n  attrs: Record<string, AttributeValue>,\n  name: string | undefined,\n): { rpcService: string; rpcMethod: string } | undefined {\n  if (typeof attrs['rpc.service'] === 'string' || typeof attrs['rpc.method'] === 'string') {\n    return undefined\n  }\n  const component = attrs['component']\n  if (typeof component !== 'string' || component.toLowerCase() !== 'grpc') return undefined\n  if (typeof name !== 'string') return undefined\n  const m = /^\\/([^/\\s]+)\\/([^/\\s]+)$/.exec(name)\n  if (!m) return undefined\n  return { rpcService: m[1]!, rpcMethod: m[2]! }\n}\n\n// C# `Grpc.AspNetCore` records a *serving* gRPC call as an ASP.NET HTTP SERVER span,\n// not an rpc span: `http.route` is `/<package.Service>/<Method>` and no `rpc.service`\n// / `rpc.method` is set (the .NET server instrumentation is HTTP; the Grpc.Net.Client\n// *calling* side does carry rpc.*). So a C# service's own gRPC methods never fused —\n// the serving `CONTAINS` (ADR-123 / #616) keys on `rpc.service`. Recover the method\n// identity from that `http.route`, the same shape `grpcFromSpanName` recovers from a\n// Jaeger operation name (#1427), so the SERVER join reaches these spans too (#1460).\n// Gated tightly so a REST route is never misread as gRPC: no `rpc.*` attribute, a\n// SERVER span, and an `http.route` that is exactly\n// `/<lowercase.dotted.package>.<PascalCaseService>/<Method>` — the gRPC path shape a\n// REST template (`/api/users`, `/v1.0/orders`) does not match.\nconst GRPC_HTTP_ROUTE =\n  /^\\/([a-z0-9_]+(?:\\.[a-z0-9_]+)*\\.[A-Z][A-Za-z0-9_]*)\\/([A-Za-z_][A-Za-z0-9_]*)$/\n\nfunction grpcFromHttpRoute(\n  attrs: Record<string, AttributeValue>,\n  kind: number | undefined,\n): { rpcService: string; rpcMethod: string } | undefined {\n  if (typeof attrs['rpc.service'] === 'string' || typeof attrs['rpc.method'] === 'string') {\n    return undefined\n  }\n  // Serving side only — a SERVER span (wire kind 2). A .NET gRPC CLIENT call goes\n  // through Grpc.Net.Client, which emits rpc.* and never reaches here.\n  if (kind !== 2) return undefined\n  const route = attrs['http.route']\n  if (typeof route !== 'string') return undefined\n  const m = GRPC_HTTP_ROUTE.exec(route)\n  if (!m) return undefined\n  return { rpcService: m[1]!, rpcMethod: m[2]! }\n}\n\nexport function parseOtlpRequest(body: OtlpTracesRequest): ParsedSpan[] {\n  const out: ParsedSpan[] = []\n  for (const rs of body.resourceSpans ?? []) {\n    const resourceAttrs = attrsToRecord(rs.resource?.attributes)\n    // OTel spec requires SDKs to set `service.name`, but customised exporters\n    // can omit it. Missing `service.name` routes to `service:unidentified`\n    // in handleSpan + emits a once-per-session-per-project warning so the\n    // diagnostic stays visible (issue #374). Silent drop is not an option.\n    const rawServiceName = resourceAttrs['service.name']\n    const resourceServiceNamePresent =\n      typeof rawServiceName === 'string' && rawServiceName.length > 0\n    const service = resourceServiceNamePresent\n      ? (rawServiceName as string)\n      : 'unidentified'\n\n    for (const ss of rs.scopeSpans ?? []) {\n      for (const span of ss.spans ?? []) {\n        const attrs = attrsToRecord(span.attributes)\n        // Opentracing / Jaeger gRPC spans name the method in the operation name, not\n        // rpc.* — recover it so the gRPC method fusion reaches them (#1427).\n        const grpcFromName = grpcFromSpanName(attrs, span.name)\n        // C# Grpc.AspNetCore serving spans are HTTP-shaped (http.route), not rpc —\n        // recover the gRPC method from the route so the SERVER join reaches them (#1460).\n        const grpcDerived = grpcFromName ?? grpcFromHttpRoute(attrs, span.kind)\n        // SQL text is `db.statement` (semconv ≤ 1.10) or `db.query.text` (≥ 1.30,\n        // the rename the current GORM/pg OTel plugins emit) — read both so a span\n        // on the newer semconv still yields a table and columns.\n        const dbSqlText =\n          typeof attrs['db.statement'] === 'string'\n            ? (attrs['db.statement'] as string)\n            : typeof attrs['db.query.text'] === 'string'\n              ? (attrs['db.query.text'] as string)\n              : undefined\n        const dbSystemName = normalizeDbSystem(attrs)\n        // The ORM's own resolved table, emitted directly as `db.sql.table` (old\n        // semconv) or, for a relational system, `db.collection.name` (new semconv).\n        // Ground truth — no SELECT*/join/CTE parse degradation. mongodb keeps\n        // `db.collection.name` as its collection, never a table.\n        const directDbTable =\n          typeof attrs['db.sql.table'] === 'string'\n            ? (attrs['db.sql.table'] as string)\n            : dbSystemName !== 'mongodb' && typeof attrs['db.collection.name'] === 'string'\n              ? (attrs['db.collection.name'] as string)\n              : undefined\n        const parsed: ParsedSpan = {\n          service,\n          resourceServiceNamePresent,\n          traceId: span.traceId ?? '',\n          spanId: span.spanId ?? '',\n          parentSpanId: span.parentSpanId || undefined,\n          name: span.name ?? '',\n          kind: span.kind,\n          startTimeUnixNano: span.startTimeUnixNano ?? '0',\n          endTimeUnixNano: span.endTimeUnixNano ?? '0',\n          startTimeIso: isoFromUnixNano(span.startTimeUnixNano),\n          durationNanos: durationNanos(span.startTimeUnixNano, span.endTimeUnixNano),\n          env: pickEnv(attrs, resourceAttrs),\n          attributes: attrs,\n          dbSystem: dbSystemName,\n          dbName: typeof attrs['db.name'] === 'string' ? (attrs['db.name'] as string) : undefined,\n          dbCollection:\n            typeof attrs['db.collection.name'] === 'string'\n              ? (attrs['db.collection.name'] as string)\n              : typeof attrs['db.mongodb.collection'] === 'string'\n                ? (attrs['db.mongodb.collection'] as string)\n                : undefined,\n          dbTable: directDbTable ?? (dbSqlText ? (tableFromSqlStatement(dbSqlText) ?? undefined) : undefined),\n          dbColumns: dbSqlText ? columnsFromSqlStatement(dbSqlText) : undefined,\n          httpRoute:\n            typeof attrs['http.route'] === 'string' ? (attrs['http.route'] as string) : undefined,\n          httpMethod:\n            typeof attrs['http.request.method'] === 'string'\n              ? (attrs['http.request.method'] as string)\n              : typeof attrs['http.method'] === 'string'\n                ? (attrs['http.method'] as string)\n                : undefined,\n          messagingSystem:\n            typeof attrs['messaging.system'] === 'string'\n              ? (attrs['messaging.system'] as string)\n              : undefined,\n          messagingDestination: messagingDestinationOf(attrs),\n          graphqlOperationName:\n            typeof attrs['graphql.operation.name'] === 'string' &&\n            (attrs['graphql.operation.name'] as string).length > 0\n              ? (attrs['graphql.operation.name'] as string)\n              : undefined,\n          graphqlOperationType:\n            typeof attrs['graphql.operation.type'] === 'string' &&\n            (attrs['graphql.operation.type'] as string).length > 0\n              ? (attrs['graphql.operation.type'] as string)\n              : undefined,\n          rpcSystem:\n            typeof attrs['rpc.system'] === 'string' &&\n            (attrs['rpc.system'] as string).length > 0\n              ? (attrs['rpc.system'] as string)\n              : grpcDerived\n                ? 'grpc'\n                : undefined,\n          rpcService:\n            typeof attrs['rpc.service'] === 'string' &&\n            (attrs['rpc.service'] as string).length > 0\n              ? (attrs['rpc.service'] as string)\n              : grpcDerived?.rpcService,\n          rpcMethod:\n            typeof attrs['rpc.method'] === 'string' &&\n            (attrs['rpc.method'] as string).length > 0\n              ? (attrs['rpc.method'] as string)\n              : grpcDerived?.rpcMethod,\n          peerService:\n            typeof attrs['peer.service'] === 'string' &&\n            (attrs['peer.service'] as string).length > 0\n              ? (attrs['peer.service'] as string)\n              : undefined,\n          peerHostname:\n            typeof attrs['peer.hostname'] === 'string' &&\n            (attrs['peer.hostname'] as string).length > 0\n              ? (attrs['peer.hostname'] as string)\n              : undefined,\n          websocketChannel: websocketChannelOf(attrs),\n          statusCode: span.status?.code,\n          errorMessage: span.status?.message,\n          exception: extractExceptionFromEvents(span.events),\n          flagEvaluations: extractFlagEvaluations(span.events),\n        }\n        out.push(parsed)\n      }\n    }\n  }\n  return out\n}\n\nexport interface OtelReceiver {\n  app: FastifyInstance\n  // Resolves once every span enqueued so far has been handed to opts.onSpan.\n  // Test seam — production code never awaits this.\n  flushPending: () => Promise<void>\n}\n\n// Lazy-loaded protobuf decoder for ExportTraceServiceRequest. The bundled\n// .proto tree at packages/core/proto/ is shared with the gRPC receiver\n// (ADR-020). Cached after first load so successive receiver builds reuse it.\nlet exportTraceServiceRequestType: protobuf.Type | null = null\nlet exportTraceServiceResponseType: protobuf.Type | null = null\n\nfunction loadProtoRoot(): protobuf.Root {\n  const here = path.dirname(fileURLToPath(import.meta.url))\n  const protoRoot = path.resolve(here, '..', 'proto')\n  const root = new protobuf.Root()\n  root.resolvePath = (_origin, target) => path.resolve(protoRoot, target)\n  root.loadSync(\n    'opentelemetry/proto/collector/trace/v1/trace_service.proto',\n    { keepCase: true },\n  )\n  return root\n}\n\nfunction loadProtobufDecoder(): protobuf.Type {\n  if (exportTraceServiceRequestType) return exportTraceServiceRequestType\n  const root = loadProtoRoot()\n  exportTraceServiceRequestType = root.lookupType(\n    'opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest',\n  )\n  return exportTraceServiceRequestType\n}\n\nfunction loadProtobufResponseEncoder(): protobuf.Type {\n  if (exportTraceServiceResponseType) return exportTraceServiceResponseType\n  const root = loadProtoRoot()\n  exportTraceServiceResponseType = root.lookupType(\n    'opentelemetry.proto.collector.trace.v1.ExportTraceServiceResponse',\n  )\n  return exportTraceServiceResponseType\n}\n\n// Empty-partial-success response, encoded once and cached — the hot path where\n// every span was accepted. Caching the bytes avoids re-running the protobuf\n// encoder per request.\nlet cachedProtobufResponseBody: Buffer | null = null\n\n// `rejected` omitted / 0 → the cached empty `ExportTraceServiceResponse`\n// (\"everything accepted\"). A positive `rejected` (the #881 unrouted-batch path)\n// encodes a populated `partial_success` — not cached, since the count and\n// message vary per batch. The proto is loaded `keepCase`, so the field names\n// stay snake_case (`partial_success`, `rejected_spans`, `error_message`).\nfunction encodeProtobufResponseBody(rejected?: number, message?: string): Buffer {\n  const Type = loadProtobufResponseEncoder()\n  if (!rejected) {\n    if (cachedProtobufResponseBody) return cachedProtobufResponseBody\n    // `partial_success` left unset = empty submessage = \"everything accepted\".\n    const msg = Type.create({})\n    cachedProtobufResponseBody = Buffer.from(Type.encode(msg).finish())\n    return cachedProtobufResponseBody\n  }\n  const msg = Type.fromObject({\n    partial_success: { rejected_spans: rejected, error_message: message ?? '' },\n  })\n  return Buffer.from(Type.encode(msg).finish())\n}\n\nasync function decodeProtobufBody(buf: Buffer): Promise<OtlpTracesRequest> {\n  const Type = loadProtobufDecoder()\n  // Decode keeps the proto field names verbatim (keepCase: true), matching the\n  // GrpcExportRequest shape that reshapeGrpcRequest already understands.\n  // toObject() options mirror the gRPC receiver's proto-loader config\n  // (otel-grpc.ts: longs: String, enums: Number, bytes left as Buffers) so\n  // both protobuf paths hand reshapeGrpcRequest the identical shape. The old\n  // .toJSON() here rendered bytes as base64 strings (bytesToHex returned ''\n  // → empty trace/span IDs) and enums as name strings (\"SPAN_KIND_CLIENT\"\n  // never matches the numeric mint gate) — every http/protobuf span was\n  // accepted and then silently minted nothing (#468).\n  // Dynamic import sidesteps the circular module dep with otel-grpc.ts.\n  const decoded = Type.toObject(Type.decode(buf), {\n    longs: String,\n    enums: Number,\n  }) as Record<string, unknown>\n  const { reshapeGrpcRequest } = await import('./otel-grpc.js')\n  return reshapeGrpcRequest(decoded as never)\n}\n\n// The OTLP/HTTP spec allows a request body to be gzip-compressed, and the\n// standard OpenTelemetry Collector's OTLP exporter does so by default\n// (`Content-Encoding: gzip`). The receiver must undo that before the body ever\n// reaches the JSON parser or the protobuf decoder — otherwise a compressed\n// batch is unparseable garbage and every \"bring your own collector\" deployment\n// silently fails to ingest. Returns the zlib transform stream for a supported\n// encoding, or null for `identity` / absent / anything we don't decode (which\n// then flows through untouched, exactly as before). `deflate` rides alongside\n// gzip since it's the same one-liner; `x-gzip` is the legacy alias some proxies\n// still emit. gRPC needs nothing here — @grpc/grpc-js decompresses at the\n// transport layer before `call.request` is ever materialized.\nfunction decompressorForEncoding(encoding: string): Transform | null {\n  switch (encoding) {\n    case 'gzip':\n    case 'x-gzip':\n      return zlib.createGunzip()\n    case 'deflate':\n      return zlib.createInflate()\n    default:\n      return null\n  }\n}\n\nexport async function buildOtelReceiver(\n  opts: BuildOtelReceiverOptions,\n): Promise<FastifyInstance & { flushPending: () => Promise<void> }> {\n  const app = Fastify({\n    logger: false,\n    bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024,\n  })\n\n  // Decompress a `Content-Encoding: gzip` (or `deflate`) body before Fastify's\n  // content-type parser runs, so the JSON parser and the protobuf decoder both\n  // see plaintext and the rest of the receiver stays oblivious to compression.\n  // Streaming (not buffer-then-inflate) so the content-type parser's bodyLimit\n  // is enforced on the *decompressed* bytes — a decompression bomb is capped at\n  // the same 16 MB ceiling an uncompressed batch is. A truncated or garbage\n  // body makes the zlib stream emit `error`, which Fastify turns into a clean\n  // 400 (the same shape a bad protobuf body gets); it never throws past the\n  // receiver or back-pressures the sender. An uncompressed request carries no\n  // `Content-Encoding`, so the hook is a pure pass-through and that path is\n  // byte-for-byte unchanged.\n  app.addHook('preParsing', (req, _reply, payload, done) => {\n    const encoding = (req.headers['content-encoding'] ?? '')\n      .toString()\n      .trim()\n      .toLowerCase()\n    if (encoding === '' || encoding === 'identity') {\n      done(null, payload)\n      return\n    }\n    const decompressor = decompressorForEncoding(encoding)\n    if (!decompressor) {\n      // An encoding we don't decode (e.g. `br`). Leave the body untouched — the\n      // content-type parser fails it just as it did before, no new behavior.\n      done(null, payload)\n      return\n    }\n    // Fastify checks the bytes it reads off the body stream against the\n    // `Content-Length` header. After decompression that count is the *plaintext*\n    // length, which never matches the compressed `Content-Length` — so Fastify\n    // would reject every batch with FST_ERR_CTP_INVALID_CONTENT_LENGTH unless\n    // the transformed stream reports how many *encoded* (wire) bytes it\n    // consumed. Track the source's byte count and expose it as\n    // `receivedEncodedLength`, the property Fastify reads for that comparison\n    // (mirrors @fastify/compress).\n    const tracked = decompressor as Transform & { receivedEncodedLength?: number }\n    tracked.receivedEncodedLength = 0\n    payload.on('data', (chunk: Buffer) => {\n      tracked.receivedEncodedLength = (tracked.receivedEncodedLength ?? 0) + chunk.length\n    })\n    // Forward a source read error onto the decompressor so the failure travels\n    // the same path a decode error does, rather than surfacing as an unhandled\n    // stream error that could dark the daemon.\n    payload.on('error', (err) => decompressor.destroy(err))\n    payload.pipe(decompressor)\n    done(null, decompressor)\n  })\n\n  // ADR-073 §4 — bearer on `/v1/traces`. `/health` stays unauthenticated via\n  // the default suffix list (the CI smoke and supervisors lean on it for\n  // liveness probes).\n  //\n  // A rejected OTLP POST is a silent failure on the sender's side — the app\n  // gets a bare 401 and its telemetry vanishes, so the operator sees an empty\n  // OBSERVED layer with no clue why. Emit a server-side warning when that\n  // happens, rate-limited to one line per interval so a chatty misconfigured\n  // exporter (they retry hard) can't flood the log. The plain REST 401 path\n  // stays quiet — that surface leaves this hook unset.\n  const REJECT_WARN_INTERVAL_MS = 60_000\n  let lastRejectWarnAt = 0\n  const warnRejectedOtlp = (): void => {\n    const now = Date.now()\n    if (now - lastRejectWarnAt < REJECT_WARN_INTERVAL_MS) return\n    lastRejectWarnAt = now\n    console.warn(\n      '[neatd] rejecting OTLP spans on /v1/traces — missing or invalid bearer token (set NEAT_OTEL_TOKEN on the instrumented app)',\n    )\n  }\n  mountBearerAuth(app, {\n    token: opts.authToken,\n    trustProxy: opts.trustProxy,\n    onReject: warnRejectedOtlp,\n  })\n\n  // Non-blocking ingest (ADR-033). The receiver replies 200 OK as soon as the\n  // body is parsed; mutation runs through this queue, drained on the next tick.\n  // OTel SDK exporters retry on timeout, so blocking ingest produces observable\n  // backpressure on the system being observed — ambient observation requires no\n  // observable effect.\n  const queue: ParsedSpan[] = []\n  let draining = false\n  let drainPromise: Promise<void> = Promise.resolve()\n\n  const drain = async (): Promise<void> => {\n    if (draining) return\n    draining = true\n    try {\n      while (queue.length > 0) {\n        const span = queue.shift()!\n        try {\n          await opts.onSpan(span)\n        } catch (err) {\n          console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n        }\n      }\n    } finally {\n      draining = false\n    }\n  }\n\n  const enqueue = (spans: ParsedSpan[]): void => {\n    if (spans.length === 0) return\n    for (const s of spans) queue.push(s)\n    // Schedule on the next tick so the 200 response is on the wire before any\n    // mutation runs. Each call gets its own promise so flushPending() can wait\n    // on the latest drain cycle.\n    drainPromise = drainPromise.then(() => drain())\n  }\n\n  // Per-project queue is reusable across the project-scoped route — the\n  // project name rides in the URL, not on the span. Drain semantics mirror\n  // the global queue so flushPending() captures both.\n  const projectQueue: Array<{ project: string; span: ParsedSpan }> = []\n  let projectDraining = false\n  let projectDrainPromise: Promise<void> = Promise.resolve()\n  const drainProject = async (): Promise<void> => {\n    if (projectDraining) return\n    projectDraining = true\n    try {\n      while (projectQueue.length > 0) {\n        const { project, span } = projectQueue.shift()!\n        try {\n          if (opts.onProjectSpan) {\n            await opts.onProjectSpan(project, span)\n          } else {\n            await opts.onSpan(span)\n          }\n        } catch (err) {\n          console.warn(`[neat] otel handler error: ${(err as Error).message}`)\n        }\n      }\n    } finally {\n      projectDraining = false\n    }\n  }\n  const enqueueProject = (project: string, spans: ParsedSpan[]): void => {\n    if (spans.length === 0) return\n    for (const s of spans) projectQueue.push({ project, span: s })\n    projectDrainPromise = projectDrainPromise.then(() => drainProject())\n  }\n\n  // One-time-per-service-name deprecation warning for spans landing on the\n  // bare `/v1/traces` endpoint. Under one daemon per project (ADR-096) that\n  // route is the project's own ingest path and needs no migration, so the\n  // warning is gated on whether this receiver actually offers project-scoped\n  // routing: only a receiver wired with `onProjectSpan` (the multi-project\n  // daemon that mounts `/projects/<name>/v1/traces`) has somewhere to migrate\n  // an exporter to. A single-project receiver leaves the gate closed and never\n  // nags. Still once-per-name so a long-running daemon doesn't flood stderr\n  // while an operator migrates.\n  const offersProjectRouting = opts.onProjectSpan !== undefined\n  const legacyEndpointWarned = new Set<string>()\n  function warnLegacyEndpoint(serviceName: string): void {\n    if (!offersProjectRouting) return\n    if (legacyEndpointWarned.has(serviceName)) return\n    legacyEndpointWarned.add(serviceName)\n    console.warn(\n      `[neatd] received span on the global endpoint; migrate OTEL_EXPORTER_OTLP_TRACES_ENDPOINT to /projects/<name>/v1/traces (service.name=\"${serviceName}\").`,\n    )\n  }\n\n  // Shared body-decode + content-negotiation. Both `/v1/traces` and\n  // `/projects/:project/v1/traces` go through this so the protobuf/JSON\n  // dispatch stays in one place.\n  async function readOtlpBody(req: import('fastify').FastifyRequest): Promise<\n    | { ok: true; body: OtlpTracesRequest; flavor: 'json' | 'protobuf' }\n    | { ok: false; code: 400 | 415; error: string }\n  > {\n    const ct = (req.headers['content-type'] ?? '').toString().split(';')[0]!.trim().toLowerCase()\n    if (ct === 'application/x-protobuf') {\n      try {\n        const body = await decodeProtobufBody(req.body as Buffer)\n        return { ok: true, body, flavor: 'protobuf' }\n      } catch (err) {\n        return { ok: false, code: 400, error: `protobuf decode failed: ${(err as Error).message}` }\n      }\n    }\n    if (!ct || ct === 'application/json') {\n      return { ok: true, body: (req.body ?? {}) as OtlpTracesRequest, flavor: 'json' }\n    }\n    return { ok: false, code: 415, error: `unsupported content-type: ${ct}` }\n  }\n\n  function sendOtlpSuccess(reply: import('fastify').FastifyReply, flavor: 'json' | 'protobuf'): unknown {\n    if (flavor === 'protobuf') {\n      const buf = encodeProtobufResponseBody()\n      return reply\n        .code(200)\n        .header('content-type', 'application/x-protobuf')\n        .send(buf)\n    }\n    return reply\n      .code(200)\n      .header('content-type', 'application/json')\n      .send({ partialSuccess: {} })\n  }\n\n  // #881 — a 200 that honestly reports dropped spans. Still a 200 (the OTLP\n  // non-blocking discipline holds and the exporter isn't back-pressured), but\n  // `partialSuccess.rejectedSpans` + `errorMessage` are populated so an exporter\n  // aimed at a service this daemon can't place stops looking healthy. Encoding\n  // stays symmetric with the request: protobuf in → protobuf out, JSON in → JSON\n  // out (the OTLP spec requires it, per §HTTP receiver supports JSON and\n  // protobuf).\n  function sendOtlpPartial(\n    reply: import('fastify').FastifyReply,\n    flavor: 'json' | 'protobuf',\n    rejected: number,\n    message: string | undefined,\n  ): unknown {\n    if (flavor === 'protobuf') {\n      const buf = encodeProtobufResponseBody(rejected, message)\n      return reply\n        .code(200)\n        .header('content-type', 'application/x-protobuf')\n        .send(buf)\n    }\n    return reply\n      .code(200)\n      .header('content-type', 'application/json')\n      .send({ partialSuccess: { rejectedSpans: rejected, errorMessage: message } })\n  }\n\n  // Buffer application/x-protobuf bodies as raw bytes; the route handler\n  // decodes them via the bundled .proto tree (ADR-020).\n  app.addContentTypeParser(\n    'application/x-protobuf',\n    { parseAs: 'buffer', bodyLimit: opts.bodyLimit ?? 16 * 1024 * 1024 },\n    (_req, body, done) => {\n      done(null, body)\n    },\n  )\n\n  app.get('/health', async () => ({ ok: true }))\n\n  app.post('/v1/traces', async (req, reply) => {\n    // Legacy global endpoint. Spans land here when an OTel exporter hasn't\n    // migrated to the project-scoped URL yet (issue #367); the daemon still\n    // routes by `service.name` against the registry. Per-service-name\n    // deprecation warning fires once so an operator notices without their\n    // stderr flooding.\n    const result = await readOtlpBody(req)\n    if (!result.ok) {\n      return reply.code(result.code).send({ error: result.error })\n    }\n    const spans = parseOtlpRequest(result.body)\n    for (const s of spans) warnLegacyEndpoint(s.service)\n    if (opts.onErrorSpanSync) {\n      try {\n        for (const span of spans) {\n          if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n        }\n      } catch (err) {\n        return reply.code(500).send({\n          error: `error-event write failed: ${(err as Error).message}`,\n        })\n      }\n    }\n    enqueue(spans)\n    // #881 — the routing decision runs off the queue (above), so by reply time\n    // we don't yet know a span will be dropped. Ask the pure classifier now:\n    // if any span in the batch belongs to no project this daemon hosts, report\n    // it as `partialSuccess.rejectedSpans` rather than a bare \"all accepted\".\n    // The async `onSpan` path still drops those spans and writes the unrouted\n    // ledger; this only makes the reply honest. Spans stay enqueued regardless,\n    // so a routable span in a mixed batch still lands.\n    if (opts.classifyBareRoutability) {\n      const { rejected, message } = opts.classifyBareRoutability(spans)\n      if (rejected > 0) return sendOtlpPartial(reply, result.flavor, rejected, message)\n    }\n    return sendOtlpSuccess(reply, result.flavor)\n  })\n\n  // Project-scoped route (issue #367). The URL `:project` carries the routing\n  // key, sidestepping the `service.name`-against-registry heuristic the legacy\n  // path uses. Spans get dispatched into the named project's ingest path\n  // directly; `OTEL_SERVICE_NAME` regains its proper semantic role of naming\n  // the ServiceNode inside the one project the URL already picked.\n  app.post<{ Params: { project: string } }>('/projects/:project/v1/traces', async (req, reply) => {\n    const project = req.params.project\n    // #881 — an exporter aimed at a project this receiver doesn't serve gets an\n    // honest 404, not a 200 that drops the batch. The bare `/v1/traces` route\n    // stays lenient (it routes by service.name); the project-scoped URL is an\n    // explicit assertion, so a wrong name is a real error worth surfacing.\n    if (opts.isProjectRegistered && !opts.isProjectRegistered(project)) {\n      return reply.code(404).send({ error: 'project not found', project })\n    }\n    const result = await readOtlpBody(req)\n    if (!result.ok) {\n      return reply.code(result.code).send({ error: result.error })\n    }\n    const spans = parseOtlpRequest(result.body)\n    if (opts.onProjectErrorSpanSync) {\n      try {\n        for (const span of spans) {\n          if (span.statusCode === 2) await opts.onProjectErrorSpanSync(project, span)\n        }\n      } catch (err) {\n        return reply.code(500).send({\n          error: `error-event write failed: ${(err as Error).message}`,\n        })\n      }\n    } else if (opts.onErrorSpanSync) {\n      try {\n        for (const span of spans) {\n          if (span.statusCode === 2) await opts.onErrorSpanSync(span)\n        }\n      } catch (err) {\n        return reply.code(500).send({\n          error: `error-event write failed: ${(err as Error).message}`,\n        })\n      }\n    }\n    enqueueProject(project, spans)\n    return sendOtlpSuccess(reply, result.flavor)\n  })\n\n  // Attach flushPending so tests can wait for the queue without exporting a\n  // separate handle. The cast goes through `unknown` because Fastify's typing\n  // is parameterised over the raw server type and the simple intersection\n  // confuses TS's structural narrowing.\n  const decorated = app as unknown as FastifyInstance & { flushPending: () => Promise<void> }\n  decorated.flushPending = async () => {\n    // Settle both drain chains, then loop until both queues are fully empty\n    // (a span enqueued mid-flush would otherwise be missed).\n    while (queue.length > 0 || draining || projectQueue.length > 0 || projectDraining) {\n      await Promise.all([drainPromise, projectDrainPromise])\n    }\n  }\n  return decorated\n}\n\n// How far the OTLP receiver steps before giving up, and the stride between\n// candidate ports. Matches the orchestrator's triple allocator (8 attempts,\n// stride 1) so the daemon's own bind and the pre-spawn allocation reach the\n// same free port under the same contention.\nconst OTLP_STEP_ATTEMPTS = 8\nconst OTLP_STEP_STRIDE = 1\n\n// Bind an OTLP receiver, stepping to the next free port when the requested one\n// is held (daemon.md §Binding — a held OTLP port steps, it does not crash the\n// daemon; project-daemon §3). The REST port is the daemon's identity and stays\n// fatal on collision, but every OTLP consumer resolves the port dynamically\n// from `daemon.json` `ports.otlp`, so stepping the receiver and recording the\n// port it actually bound keeps the OBSERVED layer alive instead of darking the\n// whole daemon on a foreign collector holding `:4318`. Returns the bound\n// address (host:port); callers read the real port back from it. A requested\n// port of `0` means \"let the kernel pick a free one\" — no collision is\n// possible, so no stepping happens. Non-`EADDRINUSE` failures (permission\n// denied) and an exhausted step window propagate to the caller unchanged.\nexport async function listenSteppingOtlp(\n  app: FastifyInstance,\n  requestedPort: number,\n  host: string,\n): Promise<string> {\n  let port = requestedPort\n  for (let attempt = 0; ; attempt++) {\n    try {\n      return await app.listen({ port, host })\n    } catch (err) {\n      const code = (err as NodeJS.ErrnoException).code\n      const canStep =\n        requestedPort !== 0 && code === 'EADDRINUSE' && attempt < OTLP_STEP_ATTEMPTS - 1\n      if (!canStep) throw err\n      console.warn(\n        `otel: OTLP port ${port} is in use, stepping to ${port + OTLP_STEP_STRIDE}`,\n      )\n      port += OTLP_STEP_STRIDE\n    }\n  }\n}\n\nexport function logSpanHandler(span: ParsedSpan): void {\n  const parent = span.parentSpanId ? span.parentSpanId.slice(0, 8) : '<root>'\n  const status = span.statusCode === 2 ? 'ERROR' : 'OK'\n  const db = span.dbSystem ? ` db=${span.dbSystem}/${span.dbName ?? '?'}` : ''\n  console.log(\n    `otel: ${span.service} ${span.name} parent=${parent} status=${status}${db}`,\n  )\n}\n","#!/usr/bin/env node\n\nimport path from 'node:path'\nimport os from 'node:os'\nimport { promises as fs } from 'node:fs'\nimport {\n  printBanner,\n  readPackageVersion,\n  commandPrefix,\n  isNpxInvocation,\n} from './banner.js'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport {\n  formatExtractionBanner,\n  formatSkippedBanner,\n  formatPrecisionFloorBanner,\n  isStrictExtractionEnabled,\n} from './extract/errors.js'\nimport { discoverServices } from './extract/services.js'\nimport type { DiscoveredService } from './extract/shared.js'\nimport { computeDivergences } from './divergences.js'\nimport { readErrorEvents } from './ingest.js'\nimport { saveGraphToDisk } from './persist.js'\nimport { ensureNeatOutIgnored } from './gitignore.js'\nimport { renderValueForwardSummary } from './summary.js'\nimport { startWatch, type WatchHandle } from './watch.js'\nimport { runDeploy, renderOtelEnvBlock } from './deploy/detect.js'\nimport { pathsForProject } from './projects.js'\nimport {\n  addProject,\n  discoverDaemons,\n  findDaemonByProject,\n  findProjectByPath,\n  listMachineProjects,\n  ProjectNameCollisionError,\n  pruneRegistry,\n  RegistryError,\n  removeProject,\n  removeDaemonRecord,\n  setStatus,\n  signalDaemonStop,\n  type MachineProject,\n} from './registry.js'\nimport {\n  INSTALLERS,\n  isEmptyPlan,\n  pickInstaller,\n  renderPatch,\n  type InstallPlan,\n  type PatchSection,\n} from './installers/index.js'\nimport { runOrchestrator } from './orchestrator.js'\nimport { runConnectorCommand } from './connector-cli.js'\nimport { runConnectCommand } from './hosted-connect-cli.js'\nimport { runDoctorCommand } from './doctor-cli.js'\nimport { runUpCommand } from './up-cli.js'\nimport { runLoginCommand, runLogoutCommand } from './login-cli.js'\nimport { runWelcome, shouldShowWelcome } from './welcome.js'\nimport { runHooksCommand } from './hooks-cli.js'\nimport { runClaudeCommand } from './claude-cli.js'\nimport { runCodexCommand } from './codex-cli.js'\nimport { runEditorCommand, type EditorClientId } from './editors-cli.js'\nimport { runMonitor } from './monitor.js'\nimport * as style from './style.js'\nimport { runSync } from './cli-verbs.js'\nimport { DivergenceTypeSchema, type DivergenceType } from '@neat.is/types'\nimport {\n  createHttpClient,\n  exitCodeForError,\n  formatHuman,\n  formatJson,\n  HttpError,\n  type HttpClient,\n  resolveAuthToken,\n  runAsk,\n  runBlastRadius,\n  runDependencies,\n  runDiff,\n  runDivergences,\n  runIncidents,\n  runObservedDependencies,\n  runPolicies,\n  runRootCause,\n  runSearch,\n  runStaleEdges,\n  TransportError,\n  type VerbResult,\n} from './cli-client.js'\nimport { resolveProfile, getActiveProfile } from './profiles.js'\nimport { isLoopbackHost } from './auth.js'\n\nexport interface InitOptions {\n  scanPath: string\n  outPath: string\n  // The project's registry name. Defaults to the basename of the scan path\n  // when the user didn't pass `--project` (ADR-046 — project naming).\n  project: string\n  // Whether `project` was set explicitly via `--project`. The flag affects\n  // which in-memory graph slot we use: explicit names get isolated slots\n  // per ADR-026, the default basename keeps using DEFAULT_PROJECT for\n  // back-compat with `neat watch`.\n  projectExplicit: boolean\n  apply: boolean\n  dryRun: boolean\n  noInstall: boolean\n  // ADR-232 — plan source-edit injection instead of runtime attachment. Only\n  // an explicit `--source-edit` sets it.\n  sourceEdit?: boolean\n  // ADR-073 §5 — when true, append the per-type node/edge breakdown after\n  // the value-forward findings block. Default false.\n  verbose: boolean\n}\n\nexport interface InitResult {\n  // Process exit code. 0 on success, 1 on collision / runtime failure,\n  // 2 on misuse (handled before we get here, but documented for completeness).\n  exitCode: number\n  // Paths the run actually wrote to. Empty in `--dry-run` except for\n  // `neat.patch`. Useful for tests asserting \"init only wrote X\".\n  writtenFiles: string[]\n}\n\n// `isNpxInvocation` / `commandPrefix` moved to banner.ts so the orchestrator's\n// summary can render the same prefix without a cli ↔ orchestrator import cycle.\n// Re-exported below alongside the banner helpers.\n\nexport function usage(): void {\n  const neat = commandPrefix()\n  console.log('Installed via npx? Prefix commands with `npx neat.is`, or install once: `npm i -g neat.is`.')\n  console.log('')\n  console.log(`usage: ${neat} <command> [args] [--project <name>]`)\n  console.log('')\n  console.log(`Run \\`${neat}\\` with no command from inside your project to go zero-to-graph in one step.`)\n  console.log(`On your first run in a terminal, \\`${neat}\\` opens a short menu — log in to a hosted`)\n  console.log(`NEAT, or set up self-hosted here. Run \\`${neat} welcome\\` to open it again anytime.`)\n  console.log(`The run stays in your terminal — query the graph over MCP or the CLI. For a visual`)\n  console.log(`dashboard, log in to hosted NEAT.`)\n  console.log('')\n  console.log(style.heading('lifecycle commands:'))\n  console.log('  welcome        Open the first-run menu: log in to a hosted NEAT, or set up')\n  console.log('                 self-hosted (print an agent-setup prompt, then build the graph')\n  console.log('                 for the current directory).')\n  console.log('  init <path>    One-time install: discover, extract, register, plan SDK install.')\n  console.log('                 Snapshot lands in <path>/neat-out/graph.json by default')\n  console.log('                 (or <path>/neat-out/<project>.json for non-default).')\n  console.log('                 Flags:')\n  console.log('                   --apply       run the SDK install patch in place')\n  console.log('                   --dry-run     write only neat.patch; do not register or snapshot')\n  console.log('                   --no-install  skip SDK install planning entirely')\n  console.log('                   --source-edit inject the OTel init into entry points instead of')\n  console.log('                                 attaching it at process start (ADR-232)')\n  console.log('  watch <path>   Start neat-core, watch <path>, re-extract on changes.')\n  console.log('                 PORT (default 8080), OTEL_PORT (4318), HOST (0.0.0.0)')\n  console.log('                 control listeners. NEAT_OTLP_GRPC=true also opens 4317.')\n  console.log('  monitor        Stream live graph facts to stdout — one line per new')\n  console.log('                 fact — as the daemon learns them: fresh divergences')\n  console.log('                 (down to the drifting column), integrations that just')\n  console.log('                 went stale, new observed runtime dependencies, and')\n  console.log('                 freshly-tripped policy violations. Silent when nothing')\n  console.log('                 is new; exits clean with no output when no daemon is')\n  console.log('                 reachable.')\n  console.log('                 Flags:')\n  console.log('                   --project <name>   watch a registered project by name')\n  console.log('                   --json             emit one JSON object per line')\n  console.log('  list           Report the daemons running on this machine (alias: ps).')\n  console.log('                 Reads ~/.neat/daemons/ and folds in any registered')\n  console.log('                 project no daemon has self-described yet.')\n  console.log('  ps             Alias of list.')\n  console.log('  pause <name>   Stop a project\\'s daemon until it is started again.')\n  console.log('  resume <name>  Bring a paused project back; for a stopped daemon, re-run')\n  console.log('                 `neat <path>` to start it.')\n  console.log('  uninstall <name>')\n  console.log('                 Stop a project\\'s daemon and retire it. Does not touch')\n  console.log('                 neat-out/, policy.json, or any user file.')\n  console.log('  prune          Drop registry entries whose path is gone from disk.')\n  console.log('                 Flags: --json   emit the removed list as JSON')\n  console.log('  version        Print the installed @neat.is/core version and exit.')\n  console.log('                 Aliases: --version, -v.')\n  console.log('  skill          Install or print the Claude Code MCP drop-in.')\n  console.log('                 Flags:')\n  console.log('                   --print-config   print the JSON snippet to stdout')\n  console.log('                   --apply          merge mcpServers.neat into ~/.claude.json')\n  console.log('  hooks          Wire NEAT into your agent so it queries the graph before')\n  console.log('                 grepping. Installs a Claude Code search hook (nudge by default,')\n  console.log('                 or a hard gate) and agent-agnostic graph-first guidance.')\n  console.log('                 Flags:')\n  console.log('                   --apply          install the hook + guidance')\n  console.log('                   --gate           with --apply: DENY search until `neat ask`')\n  console.log('                                    has run this session (default: nudge-only)')\n  console.log('                   --print-hook     print the hook script')\n  console.log('                   --print-guide    print the graph-first guidance')\n  console.log('                   --print-settings print the settings.json block --apply adds')\n  console.log('  claude         Write the query-first directive into ./CLAUDE.md as a `## neat`')\n  console.log('                 section so an agent reaches for `neat ask` before Read/Grep/Bash.')\n  console.log('                 Subcommands:')\n  console.log('                   install     write (or refresh) the `## neat` section')\n  console.log('                   uninstall   remove the `## neat` section')\n  console.log('                   print       print the directive block to stdout')\n  console.log('  codex          Install NEAT into the OpenAI Codex CLI: add [mcp_servers.neat]')\n  console.log('                 to ~/.codex/config.toml and the graph-first block to ./AGENTS.md.')\n  console.log('                 Plan by default; --apply to write.')\n  console.log('                 Flags:')\n  console.log('                   --apply          add the MCP server + AGENTS.md block')\n  console.log('                   --print-config   print the config.toml table')\n  console.log('                   --print-guide    print the AGENTS.md block')\n  console.log('  cursor         Wire NEAT into Cursor: add the MCP server to ~/.cursor/mcp.json')\n  console.log('                 and the graph-first guidance to ./.cursorrules. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  devin          Wire NEAT into Devin Desktop (Cascade): add the MCP server to')\n  console.log('                 ~/.codeium/windsurf/mcp_config.json and the graph-first guidance')\n  console.log('                 to ./.windsurfrules. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  gemini         Wire NEAT into the Gemini CLI: add the MCP server to')\n  console.log('                 ~/.gemini/settings.json and the graph-first guidance to')\n  console.log('                 ./GEMINI.md. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  qwen           Wire NEAT into Qwen Code: add the MCP server to')\n  console.log('                 ~/.qwen/settings.json and the graph-first guidance to')\n  console.log('                 ./QWEN.md. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  amazonq        Wire NEAT into the Amazon Q Developer CLI: add the MCP server to')\n  console.log('                 ~/.aws/amazonq/mcp.json. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config (default: plan)')\n  console.log('  roocode        Wire NEAT into Roo Code: add the MCP server to the project\\'s')\n  console.log('                 ./.roo/mcp.json. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config (default: plan)')\n  console.log('  zed            Wire NEAT into Zed: add the MCP server under context_servers in')\n  console.log('                 ~/.config/zed/settings.json (comments preserved) and the')\n  console.log('                 graph-first guidance to ./.rules. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  opencode       Wire NEAT into OpenCode: add the MCP server under mcp in')\n  console.log('                 ~/.config/opencode/opencode.json and the graph-first guidance')\n  console.log('                 to ./AGENTS.md. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  crush          Wire NEAT into Crush: add the MCP server under mcp in')\n  console.log('                 ~/.config/crush/crush.json and the graph-first guidance')\n  console.log('                 to ./AGENTS.md. Plan by default.')\n  console.log('                 Flags:')\n  console.log('                   --apply   write the MCP config + rules file (default: plan)')\n  console.log('  deploy         Detect the deploy substrate, generate NEAT_AUTH_TOKEN,')\n  console.log('                 emit a docker-compose / systemd / docker run artifact, and')\n  console.log('                 print the OTel env-vars block to paste into your platform.')\n  console.log('  sync           Re-run discovery, extraction, and SDK apply against the')\n  console.log('                 registered project, then notify the running daemon.')\n  console.log('                 Flags:')\n  console.log('                   --project <name>   target a registered project by name')\n  console.log('                   --to <url>         push the snapshot to a remote daemon')\n  console.log('                   --token <token>    bearer token for --to (or $NEAT_REMOTE_TOKEN)')\n  console.log('                   --dry-run          run extraction in-memory; do not write')\n  console.log('                   --no-instrument    skip the SDK install apply step')\n  console.log('                   --source-edit      inject into entry points instead of attaching')\n  console.log('                   --json             emit the delta summary as JSON')\n  console.log('  connector      Configure OBSERVED connectors — pull (supabase, railway,')\n  console.log('                 firebase, cloudflare, neon, cloud-run) and push (vercel,')\n  console.log('                 via a trace Drain).')\n  console.log('                 Subcommands:')\n  console.log('                   add <provider>   add a connector; validates the credential')\n  console.log('                                    against the provider first (--skip-validate to skip)')\n  console.log('                                    flags: --project <name>, --credential/--token <$VAR|value>,')\n  console.log('                                    --id <id>, --<option> <value>, --plaintext, --skip-validate')\n  console.log('                   list             list configured connectors (credentials redacted)')\n  console.log('                   remove <id>      remove a connector by id')\n  console.log('                   test <id>        re-check an existing connector\\'s credential')\n  console.log('                 Credentials default to an env-var reference ($VAR) resolved at')\n  console.log('                 run time; the config file is written owner-only (0600).')\n  console.log('  up             Start this project\\'s daemon, or recover it if it died. Does')\n  console.log('                 nothing when it is already running. Flags: --project, --json.')\n  console.log('  doctor         Preflight this directory\\'s setup — Node version, project,')\n  console.log('                 and daemon reachability — and print a fix for anything down.')\n  console.log('                 Flags: --json. Exits 0 when all pass, 1 when a check fails.')\n  console.log('  login          Connect this machine to a hosted NEAT and make it the default')\n  console.log('                 for the CLI and the MCP server. Paste the daemon endpoint +')\n  console.log('                 token, or run interactively (the token is read without echo).')\n  console.log('                 Flags: --endpoint <url>, --token <token>, --name <name>, --json.')\n  console.log('  logout         Clear the active hosted profile (back to your local daemon);')\n  console.log('                 --name <name> removes that profile entirely.')\n  console.log('')\n  console.log(style.heading('query commands (mirror the MCP tools, ADR-050):'))\n  console.log('  ask <question>                   Plain-language door: resolves the question to')\n  console.log('                                   nodes and routes it to the right traversal, with')\n  console.log('                                   a compact provenance-tagged answer. Reach here first.')\n  console.log(`                                   example: ${neat} ask \"why is checkout failing?\"`)\n  console.log('  root-cause <node-id>             Walk inbound edges to find what broke first.')\n  console.log(`                                   example: ${neat} root-cause service:<name>`)\n  console.log('  blast-radius <node-id>           BFS inbound — the dependents that break if this dies.')\n  console.log(`                                   example: ${neat} blast-radius database:<host>`)\n  console.log('  dependencies <node-id>           Transitive outbound dependencies.')\n  console.log('                                   Flags: --depth N (default 3, max 10)')\n  console.log(`                                   example: ${neat} dependencies service:<name> --depth 2`)\n  console.log('  observed-dependencies <node-id>  OBSERVED-only outbound edges (runtime traffic).')\n  console.log(`                                   example: ${neat} observed-dependencies service:<name>`)\n  console.log('  incidents [<node-id>]            Recent error events; per-node when an id is given.')\n  console.log('                                   Flags: --limit N (default 20)')\n  console.log(`                                   example: ${neat} incidents service:<name> --limit 5`)\n  console.log('  search <query>                   Semantic (or substring) match on node names/ids.')\n  console.log(`                                   example: ${neat} search \"checkout\"`)\n  console.log('  diff --against <snapshot>        Compare the live graph to a saved snapshot.')\n  console.log(`                                   example: ${neat} diff --against ./snapshots/baseline.json`)\n  console.log('  stale-edges                      Recent OBSERVED → STALE transitions.')\n  console.log('                                   Flags: --limit N, --edge-type CALLS|CONNECTS_TO|...')\n  console.log(`                                   example: ${neat} stale-edges --edge-type CALLS`)\n  console.log('  policies                         Current policy violations.')\n  console.log('                                   Flags: --node <id>, --hypothetical-action <json>')\n  console.log(`                                   example: ${neat} policies --node service:<name> --json`)\n  console.log('  divergences                      Where code (EXTRACTED) and production (OBSERVED) disagree.')\n  console.log('                                   Flags: --type <list>, --min-confidence <0..1>, --node <id>')\n  console.log(`                                   example: ${neat} divergences --min-confidence 0.7`)\n  console.log('')\n  console.log('flags:')\n  console.log('  --project <name>   Name the project this command targets. Default: \"default\".')\n  console.log('  --json             Emit machine-readable JSON instead of human text. Query verbs only.')\n  console.log('')\n  console.log('exit codes:')\n  console.log('  0  success')\n  console.log('  1  server error (4xx/5xx body printed to stderr)')\n  console.log('  2  misuse (missing args, bad flags) — handled before any network call')\n  console.log('  3  environmental — daemon unreachable, or one of ports 8080 / 4318 / 6328')\n  console.log('     is held by another process when `neat <path>` tries to spawn the daemon')\n  console.log('')\n  console.log('environment:')\n  console.log('  NEAT_API_URL    base URL for the core REST API (default http://localhost:8080)')\n  console.log('                  alias: NEAT_CORE_URL (the name the MCP server reads)')\n  console.log('  NEAT_PROJECT    project name when --project isn\\'t passed')\n}\n\n// Tiny argv parser — pulls `--project <name>`, the v0.2.5 init flags, and\n// the v0.2.8 verb flags out of `rest`. Boolean / value flags are surfaced\n// unconditionally; per-command validation lives in `main`.\ninterface ParsedArgs {\n  project: string | null\n  profile: string | null\n  apply: boolean\n  dryRun: boolean\n  noInstall: boolean\n  noInstrument: boolean\n  sourceEdit: boolean\n  open: boolean\n  noOpen: boolean\n  yes: boolean\n  verbose: boolean\n  printConfig: boolean\n  json: boolean\n  depth: number | null\n  limit: number | null\n  edgeType: string | null\n  node: string | null\n  since: string | null\n  against: string | null\n  errorId: string | null\n  hypotheticalAction: string | null\n  type: string | null\n  minConfidence: number | null\n  // `neat sync` (ADR-074 §1) — remote daemon URL + bearer token.\n  to: string | null\n  token: string | null\n  positional: string[]\n}\n\n// String-valued flags supported across the verb surface. Each entry maps the\n// canonical `--flag` name (and its `--flag=` equivalent) to the parsed-args\n// field that receives it. Centralising the table keeps misuse diagnostics\n// (exit code 2) consistent across verbs.\nconst STRING_FLAGS = [\n  ['--project', 'project'],\n  ['--profile', 'profile'],\n  ['--depth', 'depth'],\n  ['--limit', 'limit'],\n  ['--edge-type', 'edgeType'],\n  ['--node', 'node'],\n  ['--since', 'since'],\n  ['--against', 'against'],\n  ['--error-id', 'errorId'],\n  ['--hypothetical-action', 'hypotheticalAction'],\n  ['--type', 'type'],\n  ['--min-confidence', 'minConfidence'],\n  ['--to', 'to'],\n  ['--token', 'token'],\n] as const\n\nfunction parseArgs(rest: string[]): ParsedArgs {\n  const positional: string[] = []\n  const out: ParsedArgs = {\n    project: null,\n    profile: null,\n    apply: false,\n    dryRun: false,\n    noInstall: false,\n    noInstrument: false,\n    sourceEdit: false,\n    open: false,\n    noOpen: false,\n    yes: false,\n    verbose: false,\n    printConfig: false,\n    json: false,\n    depth: null,\n    limit: null,\n    edgeType: null,\n    node: null,\n    since: null,\n    against: null,\n    errorId: null,\n    hypotheticalAction: null,\n    type: null,\n    minConfidence: null,\n    to: null,\n    token: null,\n    positional: [],\n  }\n  for (let i = 0; i < rest.length; i++) {\n    const arg = rest[i] as string\n\n    // Boolean flags first.\n    if (arg === '--apply') { out.apply = true; continue }\n    if (arg === '--dry-run') { out.dryRun = true; continue }\n    if (arg === '--no-install') { out.noInstall = true; continue }\n    if (arg === '--no-instrument') { out.noInstrument = true; continue }\n    if (arg === '--source-edit') { out.sourceEdit = true; continue }\n    if (arg === '--open') { out.open = true; continue }\n    if (arg === '--no-open') { out.noOpen = true; continue }\n    if (arg === '--yes' || arg === '-y') { out.yes = true; continue }\n    if (arg === '--verbose') { out.verbose = true; continue }\n    if (arg === '--print-config') { out.printConfig = true; continue }\n    if (arg === '--json') { out.json = true; continue }\n\n    // String/number flags via the shared table.\n    let matched = false\n    for (const [flag, field] of STRING_FLAGS) {\n      if (arg === flag) {\n        const next = rest[i + 1]\n        if (next === undefined) {\n          console.error(`neat: ${flag} requires a value`)\n          process.exit(2)\n        }\n        assignFlag(out, field, next)\n        i++\n        matched = true\n        break\n      }\n      if (arg.startsWith(`${flag}=`)) {\n        assignFlag(out, field, arg.slice(flag.length + 1))\n        matched = true\n        break\n      }\n    }\n    if (matched) continue\n    positional.push(arg)\n  }\n  out.positional = positional\n  return out\n}\n\nexport { parseArgs }\n\n// Number flags get parsed at assignment time so misuse (`--depth foo`)\n// surfaces with exit code 2 before any network call.\nfunction assignFlag(out: ParsedArgs, field: (typeof STRING_FLAGS)[number][1], value: string): void {\n  if (field === 'depth' || field === 'limit') {\n    const n = Number(value)\n    if (!Number.isFinite(n) || !Number.isInteger(n) || n < 1) {\n      console.error(`neat: --${field === 'depth' ? 'depth' : 'limit'} must be a positive integer`)\n      process.exit(2)\n    }\n    out[field] = n\n    return\n  }\n  if (field === 'minConfidence') {\n    const n = Number(value)\n    if (!Number.isFinite(n) || n < 0 || n > 1) {\n      console.error('neat: --min-confidence must be a number in [0, 1]')\n      process.exit(2)\n    }\n    out.minConfidence = n\n    return\n  }\n  // String fields.\n  ;(out as unknown as Record<string, unknown>)[field] = value\n}\n\n// Per-type node/edge counts + compat formatting moved into summary.ts as\n// part of the value-forward findings block (issue #305 / ADR-073 §5).\n\n// `readPackageVersion` + `printBanner` (and now `commandPrefix` /\n// `isNpxInvocation`) live in banner.ts so the orchestrator can print the same\n// artwork and command examples without pulling in the whole CLI dispatch (and\n// without a cli ↔ orchestrator import cycle). Re-exported here so existing\n// importers of `cli.js` (e.g. the banner test, MCP) keep resolving them.\nexport { printBanner, readPackageVersion, commandPrefix, isNpxInvocation }\n\nfunction printVersion(): void {\n  process.stdout.write(`${readPackageVersion()}\\n`)\n}\n\n// Color a daemon/registry state by what it means — running reads live (green),\n// paused waits (amber), stopped/registered recede (dim), broken alarms (red).\nfunction styleState(state: string): string {\n  switch (state) {\n    case 'running':\n    case 'active':\n      return style.ok(state)\n    case 'paused':\n      return style.warn(state)\n    case 'broken':\n      return style.error(state)\n    case 'stopped':\n    case 'registered':\n      return style.dim(state)\n    default:\n      return state\n  }\n}\n\n// The cells for one `neat list` / `neat ps` row, fed to the width-aware table so\n// the columns line up. A discovery-backed row reports the daemon's state and\n// ports; a legacy registry row (no daemon file yet) reports `registered` and the\n// registry status so the migration window stays legible.\nfunction machineProjectCells(r: MachineProject): string[] {\n  if (r.ports) {\n    const ports = style.dim(`rest=${r.ports.rest} otlp=${r.ports.otlp} web=${r.ports.web}`)\n    const where = r.pid !== undefined ? `${r.projectPath}  ${style.dim(`pid=${r.pid}`)}` : r.projectPath\n    return [r.project, styleState(r.state), ports, where]\n  }\n  const status = r.registryStatus\n    ? `${style.dim('(')}${styleState(r.registryStatus)}${style.dim(')')}`\n    : ''\n  return [r.project, styleState(r.state), status, r.projectPath]\n}\n\nfunction printDiscoveryReport(opts: InitOptions, services: DiscoveredService[]): void {\n  const languages = [...new Set(services.map((s) => s.node.language))].sort()\n  const mode = opts.dryRun ? 'dry-run' : opts.apply ? 'apply' : 'patch-only'\n  printBanner()\n  console.log(style.heading('neat init · discovery'))\n  console.log(`scan path: ${opts.scanPath}`)\n  console.log(`project:   ${opts.project}`)\n  console.log(`mode:      ${mode}`)\n  console.log(`services:  ${services.length}`)\n  for (const s of services) {\n    const where = s.node.repoPath && s.node.repoPath.length > 0 ? s.node.repoPath : '.'\n    console.log(`  - ${s.node.name} (${s.node.language}) — ${where}`)\n  }\n  console.log(`languages: ${languages.length > 0 ? languages.join(', ') : '(none)'}`)\n  if (opts.noInstall) {\n    console.log('install:   skipped (--no-install)')\n  } else if (opts.dryRun) {\n    console.log('install:   patch will be written to neat.patch; nothing else.')\n  } else if (opts.apply) {\n    console.log('install:   patch will be applied in place. Run `npm install` afterwards.')\n  } else {\n    console.log('install:   patch will be written to neat.patch for review.')\n  }\n  console.log('')\n}\n\nasync function buildPatchSections(\n  services: DiscoveredService[],\n  project: string,\n  sourceEdit?: boolean,\n): Promise<PatchSection[]> {\n  const sections: PatchSection[] = []\n  for (const svc of services) {\n    const installer = await pickInstaller(svc.dir)\n    if (!installer) continue\n    // v0.4.1 / refs #339 — pass the registered project name so the per-\n    // package `.env.neat` carries `OTEL_SERVICE_NAME=<project>`. The daemon\n    // routes spans by registered project name; matching keys end-to-end\n    // is what keeps OBSERVED edges landing.\n    const plan: InstallPlan = await installer.plan(svc.dir, { project, sourceEdit })\n    // Lib-only + runtime-kind-skipped packages keep a section so the dry-run\n    // patch documents the skip and the apply summary counts them (ADR-069 §2,\n    // v0.4.4 / #370). Empty plans without either flag are already-instrumented\n    // end-to-end and drop out.\n    if (isEmptyPlan(plan) && !plan.libOnly && plan.runtimeKind === undefined) continue\n    sections.push({ installer: installer.name, plan })\n  }\n  return sections\n}\n\nexport async function runInit(opts: InitOptions): Promise<InitResult> {\n  const written: string[] = []\n\n  // ── Step 1: validate path ────────────────────────────────────────────\n  const stat = await fs.stat(opts.scanPath).catch(() => null)\n  if (!stat || !stat.isDirectory()) {\n    console.error(`neat init: ${opts.scanPath} is not a directory`)\n    return { exitCode: 2, writtenFiles: written }\n  }\n\n  // ── Step 2: discovery (ADR-046 #2 — before any mutation) ─────────────\n  const services = await discoverServices(opts.scanPath)\n  printDiscoveryReport(opts, services)\n\n  // ── Step 3: plan SDK install (pure data, no fs writes) ───────────────\n  const sections = opts.noInstall ? [] : await buildPatchSections(services, opts.project, opts.sourceEdit)\n  const patch = renderPatch(sections)\n  const patchPath = path.join(opts.scanPath, 'neat.patch')\n\n  // ── Step 4: dry-run shortcut — only neat.patch is allowed to land ────\n  if (opts.dryRun) {\n    await fs.writeFile(patchPath, patch, 'utf8')\n    written.push(patchPath)\n    console.log(`dry-run: patch written to ${patchPath}`)\n    // ADR-073 §6 — list the planned `.gitignore` write alongside the other\n    // planned writes. No file mutation in dry-run; only the announcement.\n    const gitignorePath = path.join(opts.scanPath, '.gitignore')\n    const gitignoreExists = await fs.stat(gitignorePath).then(() => true).catch(() => false)\n    const verb = gitignoreExists ? 'append' : 'create'\n    console.log(`dry-run: would ${verb} ${gitignorePath} (add neat-out/)`)\n    console.log('rerun without --dry-run to register and snapshot.')\n    return { exitCode: 0, writtenFiles: written }\n  }\n\n  // ── Step 5: extraction + snapshot ────────────────────────────────────\n  // Use DEFAULT_PROJECT for the in-memory graph slot when --project wasn't\n  // explicitly passed; named projects get isolated slots per ADR-026.\n  const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT\n  resetGraph(graphKey)\n  const graph = getGraph(graphKey)\n  // ADR-065 — per-file extraction failures land alongside the snapshot in\n  // <projectDir>/neat-out/errors.ndjson. Same file as OTel error events\n  // (ADR-033) with a `source: 'extract'` discriminator.\n  const projectPaths = pathsForProject(\n    graphKey,\n    path.join(opts.scanPath, 'neat-out'),\n  )\n  const errorsPath = path.join(path.dirname(opts.outPath), path.basename(projectPaths.errorsPath))\n  const result = await extractFromDirectory(graph, opts.scanPath, { errorsPath })\n  await saveGraphToDisk(graph, opts.outPath)\n  written.push(opts.outPath)\n\n  // ADR-073 §6 — ensure `neat-out/` is git-ignored. Snapshot just landed on\n  // disk; an un-ignored neat-out/ would leak into git history on the next\n  // commit. Idempotent: the helper no-ops when the line is already present.\n  const gitignoreResult = await ensureNeatOutIgnored(opts.scanPath)\n  if (gitignoreResult.action !== 'unchanged') {\n    written.push(gitignoreResult.file)\n  }\n\n  // ── Step 6: register in the machine-level registry ───────────────────\n  // Idempotent re-init of the same path under the same name refreshes the\n  // entry; collision against a different path exits non-zero (ADR-046 #7).\n  const languages = [...new Set(services.map((s) => s.node.language))].sort()\n  try {\n    await addProject({\n      name: opts.project,\n      path: opts.scanPath,\n      languages,\n      status: 'active',\n    })\n  } catch (err) {\n    if (err instanceof ProjectNameCollisionError) {\n      console.error(`neat init: ${err.message}`)\n      console.error('pass --project <other-name> to register under a different name.')\n      return { exitCode: 1, writtenFiles: written }\n    }\n    throw err\n  }\n\n  // Registering leaves every other project as it was, the same as the bare\n  // run (ADR-231) — `neat init` and `neat <path>` agree on that.\n\n  // ── Step 7: write or apply patch ─────────────────────────────────────\n  if (!opts.noInstall) {\n    if (opts.apply) {\n      let instrumented = 0\n      let alreadyInstrumented = 0\n      let libOnly = 0\n      let browserBundle = 0\n      let reactNative = 0\n      for (const section of sections) {\n        const installer = INSTALLERS.find((i) => i.name === section.installer)\n        if (!installer) continue\n        const outcome = await installer.apply(section.plan)\n        if (outcome.outcome === 'instrumented') {\n          instrumented++\n          for (const f of outcome.writtenFiles) written.push(f)\n        } else if (outcome.outcome === 'already-instrumented') {\n          alreadyInstrumented++\n        } else if (outcome.outcome === 'lib-only') {\n          libOnly++\n        } else if (outcome.outcome === 'browser-bundle') {\n          browserBundle++\n          console.log(`skipping ${section.plan.serviceDir}: browser bundle; browser-OTel support lands in a future release.`)\n        } else if (outcome.outcome === 'react-native') {\n          reactNative++\n          console.log(`skipping ${section.plan.serviceDir}: React Native target; browser-OTel support lands in a future release.`)\n        }\n      }\n      if (sections.length > 0) {\n        console.log('')\n        const parts = [\n          `instrumented ${instrumented}`,\n          `already-instrumented ${alreadyInstrumented}`,\n          `lib-only ${libOnly}`,\n        ]\n        if (browserBundle > 0) parts.push(`browser-bundle ${browserBundle}`)\n        if (reactNative > 0) parts.push(`react-native ${reactNative}`)\n        console.log(`apply: ${parts.join(', ')}`)\n        console.log('Run `npm install` (or your language equivalent) to refresh lockfiles.')\n      }\n    } else {\n      await fs.writeFile(patchPath, patch, 'utf8')\n      written.push(patchPath)\n    }\n  }\n\n  // ── Step 8: summary + incompatibilities ──────────────────────────────\n  // ADR-073 §5 / issue #305 — findings-first: compat violations, top\n  // divergences, services without OBSERVED coverage, then the OTel env-vars\n  // block. Per-type counts ride behind `--verbose`.\n  console.log('')\n  console.log(`snapshot: ${opts.outPath}`)\n  console.log(`added: ${result.nodesAdded} nodes, ${result.edgesAdded} edges`)\n  console.log('')\n  // Fold in any recorded incidents from a prior daemon run in this neat-out so\n  // symbol/field-grain divergence (ADR-215) shows in the init summary too; the\n  // read is best-effort and empty for a fresh extract.\n  const summaryIncidents = await readErrorEvents(errorsPath)\n  const divergenceResult = computeDivergences(graph, { incidents: summaryIncidents })\n  console.log(\n    renderValueForwardSummary({\n      graph,\n      divergences: divergenceResult.divergences,\n      verbose: opts.verbose,\n    }),\n  )\n  // ADR-065 — loud failure mode banner. Unconditional; 0 is a positive\n  // signal. When errors > 0, also surface the sidecar path so the operator\n  // can read per-file detail.\n  console.log(formatExtractionBanner(result.extractionErrors))\n  if (result.extractionErrors > 0) {\n    console.log(`errors:   ${errorsPath}`)\n  }\n  // #1258 — minified files are read and deliberately not parsed. Silent on\n  // zero: a repo with no machine output has nothing to say about it.\n  const skippedBanner = formatSkippedBanner(result.skippedFiles)\n  if (skippedBanner) console.log(skippedBanner)\n  // ADR-066 — precision-floor drop banner. Always emitted; 0 is observable\n  // as a positive signal that no cross-service heuristic edges grew the\n  // graph this pass.\n  console.log(formatPrecisionFloorBanner(result.extractedDropped))\n\n  // ADR-065 — NEAT_STRICT_EXTRACTION=1 makes any per-file failure exit\n  // non-zero. Default is forgiving (banner only). Exit code 4 keeps\n  // misuse (2) and daemon-down (3) distinguishable per the CLI contract.\n  if (result.extractionErrors > 0 && isStrictExtractionEnabled()) {\n    return { exitCode: 4, writtenFiles: written }\n  }\n\n  return { exitCode: 0, writtenFiles: written }\n}\n\n// ── Claude Code skill (ADR-049 / v0.2.5 step 6) ────────────────────────\n//\n// The skill is a one-shot MCP-config drop-in. Source of truth for the\n// snippet lives here (the @neat.is/claude-skill package's\n// claude_code_config.json holds an identical copy for documentation; a\n// contract test keeps the two byte-aligned).\n//\n// The shipped snippet pins no daemon address. The MCP server resolves its own\n// daemon (ADR-241/259); a fixed `localhost:8080` here sent every non-default\n// daemon's agent nowhere (#1401).\nexport const CLAUDE_SKILL_CONFIG = {\n  mcpServers: {\n    neat: {\n      type: 'stdio' as const,\n      command: 'npx',\n      args: ['-y', '@neat.is/mcp'],\n    },\n  },\n}\n\n// The env block an installer writes into mcpServers.neat (ADR-259): the address\n// of this directory's daemon, resolved the way the CLI resolves it\n// (resolveClientTarget, sole running daemon included), and its bearer when one is\n// known at install time (an env pin's NEAT_AUTH_TOKEN, a profile's token). A\n// local daemon records no token, so one is written only when this shell carries\n// it. Nothing resolved → no env, and the MCP server resolves at start.\nexport async function resolvedMcpEnv(cwd: string = process.cwd()): Promise<Record<string, string>> {\n  let target: ClientTarget\n  try {\n    target = await resolveClientTarget({ project: await projectForCwd(cwd) })\n  } catch {\n    return {}\n  }\n  if (target.source === 'default') return {}\n  const token = target.authToken ?? resolveAuthToken()\n  return { NEAT_CORE_URL: target.endpoint, ...(token ? { NEAT_AUTH_TOKEN: token } : {}) }\n}\n\n// Merge mcpServers.neat into Claude Code's user config with the resolved env,\n// leaving every other server the user wired up untouched. Shared by `neat skill\n// --apply` and `neat claude install`.\nexport async function writeClaudeMcpEntry(cwd: string = process.cwd()): Promise<{ target: string; env: Record<string, string> }> {\n  const target = claudeConfigPath()\n  let existing: Record<string, unknown> = {}\n  try {\n    existing = JSON.parse(await fs.readFile(target, 'utf8'))\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n      throw new Error(`failed to read ${target} — ${(err as Error).message}`)\n    }\n  }\n  const env = await resolvedMcpEnv(cwd)\n  const entry = { ...CLAUDE_SKILL_CONFIG.mcpServers.neat, ...(Object.keys(env).length > 0 ? { env } : {}) }\n  const mcp = (existing as { mcpServers?: Record<string, unknown> }).mcpServers ?? {}\n  const merged = { ...existing, mcpServers: { ...mcp, neat: entry } }\n  await fs.mkdir(path.dirname(target), { recursive: true })\n  await fs.writeFile(target, JSON.stringify(merged, null, 2) + '\\n', 'utf8')\n  return { target, env }\n}\n\n// One line saying what the MCP entry was aimed at, never the token itself.\nexport function describeMcpEnv(env: Record<string, string>): string {\n  if (!env.NEAT_CORE_URL) {\n    return 'no daemon found from here, so the MCP server will find one when it starts (or set NEAT_CORE_URL in its env).'\n  }\n  return `aimed at ${env.NEAT_CORE_URL}${env.NEAT_AUTH_TOKEN ? ' with the NEAT_AUTH_TOKEN from this shell' : ''}.`\n}\n\nfunction claudeConfigPath(): string {\n  // ~/.claude.json is Claude Code's user-level MCP config. Tests override\n  // via NEAT_CLAUDE_CONFIG so they don't touch the real file.\n  const override = process.env.NEAT_CLAUDE_CONFIG\n  if (override && override.length > 0) return path.resolve(override)\n  const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n  return path.join(home, '.claude.json')\n}\n\nexport interface SkillOptions {\n  apply: boolean\n  printConfig: boolean\n}\n\nexport async function runSkill(opts: SkillOptions): Promise<{ exitCode: number }> {\n  const snippet = JSON.stringify(CLAUDE_SKILL_CONFIG, null, 2) + '\\n'\n\n  if (opts.printConfig) {\n    process.stdout.write(snippet)\n    return { exitCode: 0 }\n  }\n\n  if (opts.apply) {\n    let written: { target: string; env: Record<string, string> }\n    try {\n      written = await writeClaudeMcpEntry()\n    } catch (err) {\n      console.error(`neat skill: ${(err as Error).message}`)\n      return { exitCode: 1 }\n    }\n    console.log(`neat skill: wrote mcpServers.neat to ${written.target}, ${describeMcpEnv(written.env)}`)\n    console.log('restart Claude Code to pick up the new MCP server.')\n    console.log('')\n    console.log('Tip: run `neat hooks --apply` to also install the search-nudge hook, so')\n    console.log('your agent reaches for the graph before it grep-scans the repo.')\n    return { exitCode: 0 }\n  }\n\n  console.log('neat skill — Claude Code MCP drop-in for NEAT')\n  console.log('')\n  console.log('  --print-config   print the JSON snippet to stdout')\n  console.log('  --apply          merge mcpServers.neat into ~/.claude.json')\n  console.log('')\n  console.log('Manual install: copy mcpServers.neat from --print-config into ~/.claude.json,')\n  console.log('then restart Claude Code. See packages/claude-skill/SKILL.md for the tool list.')\n  console.log('')\n  console.log('--apply aims the server at this directory\\'s daemon (NEAT_CORE_URL in its env).')\n  console.log('Without it, the MCP server finds the daemon itself when it starts.')\n  console.log('')\n  console.log('See also `neat hooks --apply` — the search-nudge hook + graph-first guidance')\n  console.log('that steer an agent to query the graph before falling back to text search.')\n  return { exitCode: 0 }\n}\n\nexport async function main(): Promise<void> {\n  const argv = process.argv.slice(2)\n  // First token, for the help/version flag checks. The command dispatch below\n  // keys off the first *positional* (flag-stripped) instead, so a bare\n  // `npx neat.is --no-open` still reaches the orchestrator.\n  const cmd0 = argv[0]\n\n  // `-h` / `--help` print the usage screen and exit clean — after a verb as well as\n  // before one. `neat init --help` used to reach `init`'s positional handling and\n  // fail with \"<cwd>/--help is not a directory\", which is the verb a first-timer is\n  // most likely to try it on: the front door's agent prompt tells them to run\n  // `init . --apply`. `ask` is the one verb whose argument is free text, and asking\n  // NEAT the literal string \"--help\" is not a question anyone means.\n  if (argv.some((a) => a === '-h' || a === '--help')) {\n    usage()\n    process.exit(0)\n  }\n\n  // The dispatcher honors three spellings: --version, -v, version.\n  if (cmd0 === '--version' || cmd0 === '-v' || cmd0 === 'version') {\n    printVersion()\n    process.exit(0)\n  }\n\n  // `neat connector <add|list|remove|test>` — the ADR-130 connector on-ramp\n  // (docs/contracts/connector-config.md §3). A top-level config command family,\n  // not an eleventh query verb; it takes provider-specific flags, so it parses\n  // its own argv rather than routing through the shared query-flag table.\n  if (cmd0 === 'connector') {\n    const code = await runConnectorCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat connect <provider>` — connect a provider to your HOSTED project over OAuth: the console's\n  // \"Connect\" button, from the terminal. It asks the control plane for the provider's consent URL, opens\n  // the browser, and polls until the connection lands. Distinct from `neat connector add`, which configures\n  // a LOCAL/self-hosted daemon by credential — this talks to the control plane, not a daemon.\n  if (cmd0 === 'connect') {\n    const code = await runConnectCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat doctor` — a read-only preflight for setup problems (cli-surface.md\n  // §neat doctor). A diagnostic command, not a query verb, so it parses its own\n  // argv and keeps its own exit-code meaning: 0 all-clear, 1 a check failed, 2\n  // misuse. It never exits 3 — a down daemon is a finding it reports, not a\n  // fatal error — so the `!== 0` gate carries every code it returns intact.\n  if (cmd0 === 'doctor') {\n    const code = await runDoctorCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat up` — start or recover this project's daemon (cli-surface.md §neat up).\n  // The command a query verb's daemon-down message names. Config-style, off the\n  // query allowlist; it resolves its target the way the query verbs do so it can\n  // tell a local daemon from one that isn't this machine's to start.\n  if (cmd0 === 'up') {\n    const code = await runUpCommand(argv.slice(1), {\n      resolveTarget: async (opts) => {\n        const target = await resolveClientTarget(opts)\n        const named = opts.profile ?? process.env.NEAT_PROFILE\n        return {\n          endpoint: target.endpoint,\n          local: isLoopbackEndpoint(target.endpoint),\n          via:\n            target.source === 'profile'\n              ? `the \\`${named}\\` profile`\n              : target.source === 'active'\n                ? 'your active profile'\n                : 'your environment',\n        }\n      },\n    })\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat login` / `neat logout` — connect this machine to a hosted NEAT by\n  // writing a client profile and setting it active (client-profiles.md §3/§4),\n  // so the CLI and the MCP server both resolve there. A config command family,\n  // not a query verb; each parses its own argv and keeps its own exit codes.\n  if (cmd0 === 'login') {\n    const code = await runLoginCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n  if (cmd0 === 'logout') {\n    const code = await runLogoutCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat hooks <--apply|--print-*>` — the Claude Code affordances that make an\n  // agent reach for NEAT's graph before it grep-scans. A config command family\n  // alongside `neat skill`, not a query verb, so it parses its own argv.\n  if (cmd0 === 'hooks') {\n    const code = await runHooksCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat codex <--apply|--print-*>` — one-command install of NEAT into the\n  // OpenAI Codex CLI (ADR-163): an `[mcp_servers.neat]` table in\n  // ~/.codex/config.toml plus the graph-first block in ./AGENTS.md. Like\n  // `neat hooks`, a config command family, not a locked query verb, so it\n  // parses its own argv.\n  if (cmd0 === 'codex') {\n    const code = await runCodexCommand(argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat claude <install|uninstall|print>` — write the query-first directive\n  // into ./CLAUDE.md as a `## neat` section so an agent reaches for `neat ask`\n  // before Read/Grep/Bash (ADR-198). Always-on, no manual trigger. A config\n  // command family like `neat hooks` / `neat codex`, not a locked query verb, so\n  // it parses its own argv.\n  if (cmd0 === 'claude') {\n    // `install` also wires the MCP server the directive names (#1397, ADR-259).\n    const code = await runClaudeCommand(argv.slice(1), async () => {\n      const { target, env } = await writeClaudeMcpEntry()\n      return `wrote mcpServers.neat to ${target}, ${describeMcpEnv(env)}`\n    })\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // `neat cursor` / `neat devin` / `neat gemini` / `neat qwen` / `neat amazonq` /\n  // `neat roocode` / `neat zed` / `neat opencode` / `neat crush` — one-command\n  // install of NEAT's MCP server (plus graph-first guidance where a client has a\n  // single always-on rules file) into the stdio-MCP agent clients that each keep\n  // their own config (ADR-164, ADR-172, ADR-176). A config command family like\n  // `neat skill` / `neat hooks`, not a locked query verb, so each parses its own\n  // argv.\n  const EDITOR_VERBS: readonly EditorClientId[] = [\n    'cursor',\n    'devin',\n    'gemini',\n    'qwen',\n    'amazonq',\n    'roocode',\n    'zed',\n    'opencode',\n    'crush',\n  ]\n  if (typeof cmd0 === 'string' && (EDITOR_VERBS as readonly string[]).includes(cmd0)) {\n    const code = await runEditorCommand(cmd0 as EditorClientId, argv.slice(1))\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // No positional command — `npx neat.is` (optionally with flags like\n  // `--no-open`) run from inside a repo. This is the zero-to-graph path\n  // (issue #483): run the orchestrator on the current working directory, the\n  // same dispatch the explicit `neat <path>` form takes (project name =\n  // basename of cwd). We detect \"no command\" by the absence of any\n  // positional after flag-stripping, so a bare `npx neat.is --no-instrument`\n  // still lands here instead of treating the flag as a command.\n  const argvParsed = parseArgs(argv)\n  if (argvParsed.positional.length === 0) {\n    // First-run \"front door\": on a true first run in an interactive terminal,\n    // open the welcome menu instead of running the orchestrator blind. Every\n    // other case — non-interactive/piped/CI, or a returning user who already\n    // has profiles — keeps the exact behaviour below. `shouldShowWelcome` is\n    // conservative and never throws: anything uncertain falls through.\n    if (await shouldShowWelcome()) {\n      const welcomeCode = await runWelcomeFlow(argvParsed)\n      if (welcomeCode !== 0) process.exit(welcomeCode)\n      return\n    }\n    const orchestratorCode = await tryOrchestrator(process.cwd(), argvParsed)\n    // tryOrchestrator returns null only when its path isn't a directory,\n    // which can't happen for process.cwd(); the non-null branch always runs.\n    if (orchestratorCode !== null && orchestratorCode !== 0) process.exit(orchestratorCode)\n    return\n  }\n\n  // From here on, the first positional is the command. Reuse the already-\n  // parsed flags and drop the command token from the positional list, so each\n  // verb's `parsed.positional[0]` stays the verb's own first argument (e.g.\n  // the node-id for `root-cause`), unchanged from the pre-#483 dispatch.\n  const cmd = argvParsed.positional[0] as string\n  const parsed: ParsedArgs = { ...argvParsed, positional: argvParsed.positional.slice(1) }\n  const { positional, apply, dryRun, noInstall } = parsed\n  const project = parsed.project ?? DEFAULT_PROJECT\n\n  // `neat welcome` — re-open the first-run front door on demand. The same menu\n  // the bare-first-run path shows, always available so a returning user can get\n  // back to it (log in, or print the self-hosted setup prompt).\n  if (cmd === 'welcome') {\n    const code = await runWelcomeFlow(parsed)\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  if (cmd === 'init') {\n    const target = positional[0]\n    if (!target) {\n      console.error('neat init: missing <path>')\n      usage()\n      process.exit(2)\n    }\n    if (apply && dryRun) {\n      console.error('neat init: --apply and --dry-run are mutually exclusive')\n      process.exit(2)\n    }\n    const scanPath = path.resolve(target)\n    // ADR-046 — when --project isn't passed, the registry name defaults to\n    // the basename of the scan path. The in-memory graph slot stays on\n    // DEFAULT_PROJECT (back-compat with existing `neat watch` invocations).\n    const projectExplicit = parsed.project !== null\n    const projectName = projectExplicit ? project : path.basename(scanPath)\n    // Default project keeps writing to graph.json (ADR-026 back-compat);\n    // named projects use <project>.json under the same neat-out directory.\n    const projectKey = projectExplicit ? project : DEFAULT_PROJECT\n    const fallback = pathsForProject(projectKey, path.join(scanPath, 'neat-out')).snapshotPath\n    const outPath = path.resolve(process.env.NEAT_OUT_PATH ?? fallback)\n    const result = await runInit({\n      scanPath,\n      outPath,\n      project: projectName,\n      projectExplicit,\n      apply,\n      dryRun,\n      noInstall,\n      sourceEdit: parsed.sourceEdit,\n      verbose: parsed.verbose,\n    })\n    if (result.exitCode !== 0) process.exit(result.exitCode)\n    return\n  }\n\n  if (cmd === 'watch') {\n    const target = positional[0]\n    if (!target) {\n      console.error('neat watch: missing <path>')\n      usage()\n      process.exit(2)\n    }\n    const scanPath = path.resolve(target)\n    const stat = await fs.stat(scanPath).catch(() => null)\n    if (!stat || !stat.isDirectory()) {\n      console.error(`neat watch: ${scanPath} is not a directory`)\n      process.exit(2)\n    }\n    const projectPaths = pathsForProject(project, path.join(scanPath, 'neat-out'))\n    const outPath = path.resolve(process.env.NEAT_OUT_PATH ?? projectPaths.snapshotPath)\n    const errorsPath = path.resolve(\n      process.env.NEAT_ERRORS_PATH ??\n        path.join(path.dirname(outPath), path.basename(projectPaths.errorsPath)),\n    )\n    const staleEventsPath = path.resolve(\n      process.env.NEAT_STALE_EVENTS_PATH ??\n        path.join(path.dirname(outPath), path.basename(projectPaths.staleEventsPath)),\n    )\n\n    const embeddingsCachePath = process.env.NEAT_EMBEDDINGS_CACHE_PATH\n      ? path.resolve(process.env.NEAT_EMBEDDINGS_CACHE_PATH)\n      : undefined\n\n    const handle: WatchHandle = await startWatch(getGraph(project), {\n      scanPath,\n      outPath,\n      errorsPath,\n      staleEventsPath,\n      project,\n      // Resolve NEAT_HOME so a `neat watch` picks up connectors added to\n      // ~/.neat/connectors.json (#871). Same resolution the rest of the CLI uses.\n      neatHome: process.env.NEAT_HOME\n        ? path.resolve(process.env.NEAT_HOME)\n        : path.join(os.homedir(), '.neat'),\n      ...(embeddingsCachePath ? { embeddingsCachePath } : {}),\n      host: process.env.HOST ?? '0.0.0.0',\n      port: Number(process.env.PORT ?? 8080),\n      otelPort: Number(process.env.OTEL_PORT ?? 4318),\n      otelGrpc: process.env.NEAT_OTLP_GRPC === 'true',\n      otelGrpcPort: process.env.NEAT_OTLP_GRPC_PORT\n        ? Number(process.env.NEAT_OTLP_GRPC_PORT)\n        : undefined,\n    })\n\n    // startPersistLoop already wires SIGTERM/SIGINT to flush + exit. Hook in\n    // ahead of it so the watcher closes cleanly first; the persist handler's\n    // `process.exit(0)` will still run after our stop() resolves.\n    let shuttingDown = false\n    const shutdown = (signal: NodeJS.Signals): void => {\n      if (shuttingDown) return\n      shuttingDown = true\n      console.log(`neat watch: ${signal} received, stopping…`)\n      void handle.stop().catch((err) => {\n        console.error('neat watch: shutdown error', err)\n      })\n    }\n    process.on('SIGTERM', shutdown)\n    process.on('SIGINT', shutdown)\n    return\n  }\n\n  // `list` / `ps` both report the daemons discovered on the machine. ADR-096\n  // §6 — discovery reads the lock-free `~/.neat/daemons/` directory and folds\n  // in any legacy registry entries no daemon has self-described yet, so a\n  // pre-migration install still lists its projects.\n  if (cmd === 'list' || cmd === 'ps') {\n    const rows = await listMachineProjects()\n    if (rows.length === 0) {\n      console.log('no daemons running and no projects registered. run `neat init <path>` to register one.')\n      return\n    }\n    const header = ['project', 'state', 'ports', 'path'].map((h) => style.dim(h))\n    const body = rows.map(machineProjectCells)\n    for (const line of style.table([header, ...body])) console.log(line)\n    return\n  }\n\n  // `pause` stops a project's daemon. Under one-daemon-per-project (ADR-096)\n  // that is the per-daemon shutdown driven by the discovery record's pid. While\n  // a project still lives only in the legacy registry (the migration window\n  // before #508 lands), it falls back to flipping the registry status the\n  // multi-project daemon reads.\n  if (cmd === 'pause') {\n    const name = positional[0]\n    if (!name) {\n      console.error('neat pause: missing <name>')\n      usage()\n      process.exit(2)\n    }\n    const daemon = await findDaemonByProject(name)\n    if (daemon) {\n      if (daemon.live && signalDaemonStop(daemon.record.pid)) {\n        console.log(`paused: ${name} (${daemon.record.projectPath}) — stopped daemon pid ${daemon.record.pid}`)\n      } else {\n        console.log(`paused: ${name} (${daemon.record.projectPath}) — daemon was not running`)\n      }\n      return\n    }\n    try {\n      const entry = await setStatus(name, 'paused')\n      console.log(`paused: ${entry.name} (${entry.path})`)\n    } catch (err) {\n      console.error((err as Error).message)\n      process.exit(1)\n    }\n    return\n  }\n\n  // `resume` brings a paused project back. Spawning a per-project daemon is the\n  // orchestrator's job (`neat <path>`), so against a stopped daemon record we\n  // point the operator at it; against a legacy registry entry we flip the\n  // status the multi-project daemon reads, preserving the pre-migration shape.\n  if (cmd === 'resume') {\n    const name = positional[0]\n    if (!name) {\n      console.error('neat resume: missing <name>')\n      usage()\n      process.exit(2)\n    }\n    const daemon = await findDaemonByProject(name)\n    if (daemon) {\n      if (daemon.live) {\n        console.log(`resume: ${name} (${daemon.record.projectPath}) — daemon already running`)\n      } else {\n        console.log(`resume: ${name} (${daemon.record.projectPath}) — run \\`neat ${daemon.record.projectPath}\\` to start its daemon again`)\n      }\n      return\n    }\n    try {\n      const entry = await setStatus(name, 'active')\n      console.log(`resumed: ${entry.name} (${entry.path})`)\n    } catch (err) {\n      console.error((err as Error).message)\n      process.exit(1)\n    }\n    return\n  }\n\n  if (cmd === 'skill') {\n    const result = await runSkill({ apply: parsed.apply, printConfig: parsed.printConfig })\n    if (result.exitCode !== 0) process.exit(result.exitCode)\n    return\n  }\n\n  // `uninstall` retires a project. Under ADR-096 that means stopping its daemon\n  // (via the discovery record's pid) and clearing its discovery file, then\n  // dropping any legacy registry row. As before it never touches neat-out/,\n  // policy.json, or user files at the project path (ADR-048 #6).\n  if (cmd === 'uninstall') {\n    const name = positional[0]\n    if (!name) {\n      console.error('neat uninstall: missing <name>')\n      usage()\n      process.exit(2)\n    }\n    const daemon = await findDaemonByProject(name)\n    const removed = await removeProject(name)\n    if (!daemon && !removed) {\n      console.error(`neat uninstall: no project named \"${name}\"`)\n      process.exit(1)\n    }\n    const projectPath = daemon?.record.projectPath ?? removed?.path ?? '(unknown path)'\n    if (daemon) {\n      if (daemon.live && signalDaemonStop(daemon.record.pid)) {\n        console.log(`uninstall: ${name} — stopped daemon pid ${daemon.record.pid}`)\n      }\n      // Clear the discovery copy. A live daemon clears its own on graceful stop,\n      // but removing it here covers a daemon that crashed without cleanup and\n      // makes the verb idempotent against a stale record.\n      await removeDaemonRecord(daemon.source)\n    }\n    console.log(`unregistered: ${name} (${projectPath})`)\n    console.log('note: neat-out/, policy.json, and other files at the project path were left in place.')\n    return\n  }\n\n  if (cmd === 'prune') {\n    // #463 — one-shot cleanup of registry entries whose path is gone. Explicit\n    // user intent, so it drops any ENOENT entry immediately regardless of the\n    // auto-prune TTL. Only definite ENOENT entries go — a project whose path\n    // still exists, or one behind a transient stat error, is left alone.\n    const removed = await pruneRegistry({ ttlMs: 0 })\n    if (parsed.json) {\n      console.log(JSON.stringify(removed.map((p) => ({ name: p.name, path: p.path })), null, 2))\n      return\n    }\n    if (removed.length === 0) {\n      console.log('nothing to prune — every registered project path still exists.')\n      return\n    }\n    console.log(`pruned ${removed.length} project${removed.length === 1 ? '' : 's'}: ${removed.map((p) => p.name).join(', ')}`)\n    return\n  }\n\n  if (cmd === 'deploy') {\n    // ADR-073 §2 — detect substrate, generate token, emit artifact, print\n    // the OTel env-vars block. Token is the only secret printed to stdout;\n    // the artifact written to disk names the env-var by reference only.\n    const artifact = await runDeploy()\n    const block = renderOtelEnvBlock(artifact.token)\n\n    console.log()\n    console.log(`Substrate detected: ${artifact.substrate}`)\n    if (artifact.artifactPath) {\n      console.log(`Artifact written:   ${artifact.artifactPath}`)\n    } else {\n      console.log('No on-disk artifact — copy the snippet below into your substrate.')\n      console.log()\n      console.log(artifact.contents)\n    }\n    console.log()\n    console.log('NEAT_AUTH_TOKEN (store this — it will not be printed again):')\n    console.log(`  ${artifact.token}`)\n    console.log()\n    console.log(\"For your application's deploy platform, set these env vars:\")\n    console.log(block.split('\\n').map((l) => `  ${l}`).join('\\n'))\n    console.log()\n    console.log('Once NEAT is running, your dashboard will be at:')\n    console.log('  https://<host>:6328')\n    console.log()\n    console.log('To start NEAT, run:')\n    console.log(`  ${artifact.startCommand}`)\n    return\n  }\n\n  if (cmd === 'sync') {\n    // ADR-074 §1 — re-runs discovery + extract + SDK apply + daemon notify\n    // against the registered project. Skips registry registration, browser\n    // open, daemon spawn, and the first-run summary block.\n    // Resolve the daemon through the same precedence the query verbs use\n    // (client-profiles.md §3, including the sole-daemon shortcut #1381) rather\n    // than the bare NEAT_API_URL → loopback fallback sync carried on its own.\n    const syncTarget = await resolveClientTarget({\n      ...(parsed.project ? { project: parsed.project } : {}),\n      ...(parsed.profile ? { profile: parsed.profile } : {}),\n    })\n    const result = await runSync({\n      ...(parsed.project ? { project: parsed.project } : {}),\n      ...(parsed.to ? { to: parsed.to } : {}),\n      ...(parsed.token ? { token: parsed.token } : {}),\n      daemonUrl: syncTarget.endpoint,\n      dryRun: parsed.dryRun,\n      noInstrument: parsed.noInstrument,\n      sourceEdit: parsed.sourceEdit,\n      json: parsed.json,\n    })\n    if (result.exitCode !== 0) process.exit(result.exitCode)\n    return\n  }\n\n  // `neat monitor` — stream live graph facts to stdout (ADR-159). A\n  // lifecycle/config-style verb, not a locked query verb: it resolves the\n  // daemon exactly like the query verbs (env → daemon record → loopback) but\n  // holds a long-lived SSE connection instead of a one-shot read. Read-only.\n  if (cmd === 'monitor') {\n    const code = await runMonitorVerb(parsed)\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // ── Query verbs (ADR-050) ────────────────────────────────────────────\n  // The nine verbs mirror the MCP tool allowlist. Same multi-project\n  // routing, same three-part response shape (summary + block + footer),\n  // exit codes branch on misuse vs server error vs daemon-down.\n  if (QUERY_VERBS.has(cmd)) {\n    const code = await runQueryVerb(cmd, parsed)\n    if (code !== 0) process.exit(code)\n    return\n  }\n\n  // ── Bare-path orchestrator (ADR-073 §1) ──────────────────────────────\n  // `neat <path>` — when the first positional doesn't match any verb but\n  // resolves to a directory, hand the run off to the orchestrator. This is\n  // the `npx neat.is <path>` shape from ADR-073: one command, end-to-end.\n  const orchestratorCode = await tryOrchestrator(cmd, parsed)\n  if (orchestratorCode !== null) {\n    if (orchestratorCode !== 0) process.exit(orchestratorCode)\n    return\n  }\n\n  console.error(`neat: unknown command \"${cmd}\"`)\n  usage()\n  process.exit(1)\n}\n\n// Returns null when the first positional doesn't resolve to a directory\n// (so the caller can fall through to the unknown-command error). Returns\n// an exit code when the orchestrator ran.\nasync function tryOrchestrator(\n  cmd: string,\n  parsed: ParsedArgs,\n  overrides: { skipBanner?: boolean } = {},\n): Promise<number | null> {\n  const scanPath = path.resolve(cmd)\n  const stat = await fs.stat(scanPath).catch(() => null)\n  if (!stat || !stat.isDirectory()) return null\n\n  const projectExplicit = parsed.project !== null\n  const projectName = projectExplicit ? (parsed.project as string) : path.basename(scanPath)\n  const result = await runOrchestrator({\n    scanPath,\n    project: projectName,\n    projectExplicit,\n    noInstrument: parsed.noInstrument,\n    sourceEdit: parsed.sourceEdit,\n    open: parsed.open,\n    noOpen: parsed.noOpen,\n    yes: parsed.yes,\n    ...(overrides.skipBanner ? { skipBanner: true } : {}),\n  })\n  return result.exitCode\n}\n\n// Wire the injectable welcome menu to the real login + orchestrator paths. The\n// login option takes the browser method by default; the self-hosted option runs\n// the same `tryOrchestrator(process.cwd(), …)` path a bare `neat` uses, so any\n// flags the user passed (e.g. `--no-open`) still apply. tryOrchestrator returns\n// null only for a non-directory path, which process.cwd() never is, so `?? 0`\n// is just a total-function guard.\nasync function runWelcomeFlow(parsed: ParsedArgs): Promise<number> {\n  // One orchestrator, shared by the door's local path and by the post-login\n  // step's offer to build a graph before pushing it (#1272) — so the instrument\n  // question is asked once, through the same overrides seam, wherever the run\n  // is started from.\n  const runLocal = async (\n    cwd: string,\n    opts?: { project?: string; noInstrument?: boolean; yes?: boolean; headerShown?: boolean },\n  ): Promise<number> =>\n    (await tryOrchestrator(\n      cwd,\n      {\n        ...parsed,\n        // ADR-232 — the front-door / local-menu run never source-edits, even if\n        // `--source-edit` was on the command line. Source-edit stays an explicit\n        // choice on a deliberately-typed `neat <path> --source-edit`.\n        sourceEdit: false,\n        ...(opts?.project !== undefined ? { project: opts.project } : {}),\n        ...(opts?.noInstrument !== undefined ? { noInstrument: opts.noInstrument } : {}),\n        ...(opts?.yes !== undefined ? { yes: opts.yes } : {}),\n      },\n      { skipBanner: opts?.headerShown === true },\n    )) ?? 0\n\n  return runWelcome({\n    login: (loginArgv) => runLoginCommand(loginArgv, { connect: { orchestrator: runLocal } }),\n    // What the person chose at the door reaches the orchestrator as the flags they\n    // stand for: the name as `--project`, the instrument answer as `--no-instrument`\n    // or as `yes` (which keeps the orchestrator's own prompt quiet, since the door\n    // already asked). `headerShown` isn't a flag anyone can type — it says the\n    // door's wordmark already opened this run, so the orchestrator's banner is skipped.\n    orchestrator: runLocal,\n    // An explicit flag is an answer; don't ask again.\n    instrumentFlagGiven: parsed.noInstrument || parsed.dryRun,\n    dryRun: parsed.dryRun,\n  })\n}\n\n// ── Query verb dispatcher ──────────────────────────────────────────────\n\nexport const QUERY_VERBS: Set<string> = new Set([\n  'root-cause',\n  'blast-radius',\n  'dependencies',\n  'observed-dependencies',\n  'incidents',\n  'search',\n  'diff',\n  'stale-edges',\n  'policies',\n  // Tenth verb (ADR-060) — amends ADR-050's locked allowlist of nine.\n  'divergences',\n  // Twelfth verb (ADR-198) — the plain-language door over the whole tool\n  // surface. Amends ADR-050's locked allowlist the same way `divergences` did.\n  'ask',\n])\n\n// ADR-050 #2: --project flag → NEAT_PROJECT env → undefined (server's\n// `default` slot). undefined keeps legacy unprefixed routes; explicit names\n// route through /projects/:project/... Returns undefined when neither was set,\n// which is the signal to resolveProjectForVerb that it should look at the\n// registered projects and pick intelligently.\nfunction resolveProjectFlag(parsed: ParsedArgs): string | undefined {\n  if (parsed.project) return parsed.project\n  const env = process.env.NEAT_PROJECT\n  if (env && env.length > 0 && env !== DEFAULT_PROJECT) return env\n  return undefined\n}\n\n// Thrown when a bare query verb (no --project, no NEAT_PROJECT) can't pick a\n// project on its own — either nothing is registered, or several are and none\n// is named `default`. Carries an exit code so the dispatcher can surface a\n// helpful message instead of letting the request 404 on the `default` slot.\nexport class ProjectResolutionError extends Error {\n  constructor(\n    message: string,\n    public readonly exitCode: number = 2,\n  ) {\n    super(message)\n    this.name = 'ProjectResolutionError'\n  }\n}\n\n// What `GET /projects` hands back (registry.ts RegistryEntry passthrough). We\n// only read `name`, so keep the shape minimal.\ninterface RegistryProjectSummary {\n  name: string\n}\n\n// Decide which project a bare query verb should route to (issue #500). When the\n// user passed --project or set NEAT_PROJECT, that wins untouched. Otherwise we\n// ask the daemon which projects it has registered and pick:\n//\n//   • exactly one registered → use it (the one-command `npx neat.is` case, so\n//     `neat divergences` \"just works\" without --project)\n//   • a project literally named `default` exists → keep the legacy default\n//     routing (return undefined → unprefixed routes the server maps to default)\n//   • several registered, none `default` → don't guess; error and list them\n//   • none registered → error clearly rather than 404 on `default`\n//\n// A daemon that can't be reached lets the TransportError propagate, so the verb\n\n// True when an endpoint points at a daemon on this machine — the only case where\n// telling the user to start one is right. A bad or relative URL is treated as\n// not-loopback, so the hint stays off rather than being offered on a guess.\nexport function isLoopbackEndpoint(endpoint: string): boolean {\n  try {\n    // URL.hostname keeps the brackets on an IPv6 literal (`[::1]`), and the\n    // loopback set doesn't carry them — strip so a daemon on ::1 is recognised.\n    return isLoopbackHost(new URL(endpoint).hostname.replace(/^\\[|\\]$/g, ''))\n  } catch {\n    return false\n  }\n}\n// still exits 3 with the existing \"is the daemon running?\" message.\nexport async function resolveProjectForVerb(\n  client: HttpClient,\n  parsed: ParsedArgs,\n  cwdProject?: string,\n): Promise<string | undefined> {\n  const explicit = resolveProjectFlag(parsed)\n  if (explicit) return explicit\n  // The project the person is standing in (#1157). Known from the registry before any\n  // request is made, so there is nothing to ask the daemon — and asking was the bug:\n  // the bare verb went to whichever daemon owned the loopback default and took its\n  // sole project as the answer, which from a second repo is a different repo's graph.\n  if (cwdProject) return cwdProject\n\n  // Bare verb. Let TransportError out (exit 3); only HttpError/parse issues\n  // become a resolution error here.\n  const projects = await client.get<RegistryProjectSummary[]>('/projects')\n\n  if (projects.some((p) => p.name === DEFAULT_PROJECT)) {\n    // Back-compat: a real `default` project exists, so the legacy unprefixed\n    // routes resolve. Returning undefined keeps that path.\n    return undefined\n  }\n\n  if (projects.length === 1) {\n    return projects[0]!.name\n  }\n\n  if (projects.length === 0) {\n    throw new ProjectResolutionError(\n      'No projects are registered with the daemon yet. Run `npx neat.is` in a repo to build a graph first, then re-run this command.',\n    )\n  }\n\n  const names = projects\n    .map((p) => p.name)\n    .sort()\n    .map((n) => `  ${n}`)\n    .join('\\n')\n  throw new ProjectResolutionError(\n    `Several projects are registered and none is named \"default\", so I can't pick one for you.\\n` +\n      `Pass --project <name> to choose:\\n${names}`,\n  )\n}\n\n// The daemon URL the CLI verbs talk to. Resolution mirrors the client-profiles\n// precedence (§3): an explicit env pin wins, then the requested project's own\n// per-project daemon (ADR-096 — one daemon per project, each on its own port),\n// then the loopback default. `NEAT_API_URL` is the name the verbs have always\n// read, so it keeps precedence for existing users; `NEAT_CORE_URL` is honored\n// as an alias so a single env var works for both the CLI and the MCP server.\n//\n// The project step is issue #579: with `--project foo` (or NEAT_PROJECT=foo)\n// but no env pin, the verb used to hit the loopback 8080 and append\n// `/projects/foo/...`, which lands on whatever daemon happens to own 8080 — a\n// different project's daemon, so it 404s. Under one-daemon-per-project the\n// project's REST port lives in its discovery record at `~/.neat/daemons/<foo>.json`;\n// resolving it there points the verb at the right daemon. A project that has no\n// discovery record falls through to loopback, unchanged.\n// How `resolveClientTarget` picked its endpoint — for callers that want to\n// explain which precedence level won (client-profiles.md §3).\nexport type ClientTargetSource = 'profile' | 'env' | 'active' | 'daemon-record' | 'sole-daemon' | 'default'\n\nexport interface ClientTarget {\n  endpoint: string\n  authToken?: string\n  source: ClientTargetSource\n}\n\n// Thrown when `--profile` / NEAT_PROFILE names a profile the store doesn't have.\n// An explicit selection of a missing endpoint is reported, never silently\n// swapped for a different one (client-profiles.md §3 level 1, §5).\nexport class UnknownProfileError extends Error {\n  constructor(name: string) {\n    super(\n      `no profile named \"${name}\" in ~/.neat/profiles.json — run \\`neat login\\` first, or drop --profile / NEAT_PROFILE`,\n    )\n    this.name = 'UnknownProfileError'\n  }\n}\n\n// Resolve the daemon a read verb talks to *and* the bearer to reach it as one\n// decision, so a hosted profile's token always rides with its endpoint and no\n// read path can reach a secured daemon without it (client-profiles.md §3 + §6).\n// Precedence, falling through on each miss below level 1:\n//   1. --profile / NEAT_PROFILE — an explicitly named profile (error if absent)\n//   2. NEAT_CORE_URL / NEAT_API_URL (+ NEAT_AUTH_TOKEN) — the env pin CI/prod set\n//   3. the store's persisted `active` profile — the `neat login` default\n//   4. the requested project's own per-project daemon discovery record (#579)\n//   5. loopback\nexport async function resolveClientTarget(\n  opts: { project?: string; profile?: string } = {},\n): Promise<ClientTarget> {\n  // Level 1 — an explicitly named profile. The flag beats the env var; a name\n  // that resolves to nothing is a loud error, not a fall-through.\n  const named = opts.profile ?? process.env.NEAT_PROFILE\n  if (named && named.length > 0) {\n    const profile = await resolveProfile(named)\n    if (!profile) throw new UnknownProfileError(named)\n    return { endpoint: profile.endpoint, authToken: profile.authToken, source: 'profile' }\n  }\n\n  // Level 2 — the explicit env pin. NEAT_API_URL keeps precedence for the verbs\n  // that have always read it; NEAT_CORE_URL is honored as an alias.\n  const pin = process.env.NEAT_API_URL ?? process.env.NEAT_CORE_URL\n  if (pin) return { endpoint: pin, authToken: resolveAuthToken(), source: 'env' }\n\n  // Level 3 — the persisted login default. A malformed or absent store falls\n  // through rather than bricking a local read (§3 \"never throws below level 1\").\n  const active = await getActiveProfile().catch(() => undefined)\n  if (active) return { endpoint: active.endpoint, authToken: active.authToken, source: 'active' }\n\n  // Level 4 — the requested project's own daemon (#579).\n  if (opts.project) {\n    const daemon = await findDaemonByProject(opts.project)\n    if (daemon) {\n      return { endpoint: `http://localhost:${daemon.record.ports.rest}`, source: 'daemon-record' }\n    }\n  } else {\n    // Level 4b (#1381) — no project resolved from the cwd. If exactly one local\n    // daemon is running, resolve to it instead of blind loopback, so a verb run\n    // from a directory that is not a registered project still reaches the one\n    // daemon there is. Zero or several live daemons fall through to loopback,\n    // where the caller surfaces an actionable hint (loopbackResolutionHint).\n    const live = (await discoverDaemons()).filter((d) => d.live)\n    if (live.length === 1) {\n      return {\n        endpoint: `http://localhost:${live[0]!.record.ports.rest}`,\n        source: 'sole-daemon',\n      }\n    }\n  }\n\n  // Level 5 — loopback.\n  return { endpoint: 'http://localhost:8080', source: 'default' }\n}\n\n// A bare verb (no project, no env pin) that lands on the loopback default did so\n// because the sole-daemon shortcut (#1381) could not fire: there are zero or\n// several live daemons. Say which, and how to aim the verb, so the agent self-\n// corrects instead of silently querying whatever owns :8080.\nexport async function loopbackResolutionHint(): Promise<string | undefined> {\n  const live = (await discoverDaemons()).filter((d) => d.live)\n  if (live.length === 0) {\n    return 'No NEAT daemon is running. Start one with `npx neat.is` in your project (or `neat up`), then re-run — or set NEAT_API_URL to a daemon.'\n  }\n  if (live.length > 1) {\n    const list = live\n      .map((d) => `  ${d.record.project} → http://localhost:${d.record.ports.rest}`)\n      .join('\\n')\n    return (\n      'This directory is not a registered NEAT project and several daemons are running, ' +\n      'so NEAT cannot pick one. Run from the project directory, pass --project <name>, or set NEAT_API_URL:\\n' +\n      list\n    )\n  }\n  return undefined\n}\n\n// The registered project the working directory belongs to, for a verb that named none\n// (#1157). Same registry the bare run writes, read through registry.ts. Never throws —\n// an unreadable registry means the verb falls back to asking the daemon, as before.\nexport async function projectForCwd(cwd: string = process.cwd()): Promise<string | undefined> {\n  try {\n    return (await findProjectByPath(cwd))?.name\n  } catch {\n    return undefined\n  }\n}\n\n// A cwd-derived project names a LOCAL registration, so it only means something to a\n// local daemon: the project's own (level 4) or whatever answers on loopback (level 5).\n// A named profile, an env pin, or the active login points at a daemon with its own\n// project namespace — a hosted tenant knows nothing of this machine's registry — so\n// there the verb keeps resolving the way it always has.\nexport function cwdProjectApplies(source: ClientTargetSource): boolean {\n  return source === 'daemon-record' || source === 'sole-daemon' || source === 'default'\n}\n\n// The endpoint half of `resolveClientTarget`, kept for callers and tests that\n// only need the URL. Precedence lives in one place — this delegates.\nexport async function resolveDaemonUrl(project?: string, profile?: string): Promise<string> {\n  return (await resolveClientTarget({ project, profile })).endpoint\n}\n\nexport async function runQueryVerb(cmd: string, parsed: ParsedArgs): Promise<number> {\n  // Resolve the URL against the requested project up front (issue #579). When\n  // the project comes from --project / NEAT_PROJECT it's known synchronously, so\n  // the client points at that project's daemon before the first call. A bare\n  // verb (no project named) resolves nothing here and keeps the loopback default\n  // — its project is discovered from /projects below (issue #500).\n  const requestedProject = resolveProjectFlag(parsed)\n  // No project named → the one this directory is registered as (#1157), so the verb\n  // reaches that project's own daemon instead of whichever one owns loopback.\n  const cwdProject = requestedProject ? undefined : await projectForCwd()\n  // ADR-073 §3 + client-profiles.md §3/§6 — resolve endpoint and bearer as one\n  // decision so a hosted profile's token always rides with its endpoint and no\n  // verb path can reach a secured daemon without it.\n  let target: ClientTarget\n  try {\n    target = await resolveClientTarget({\n      project: requestedProject ?? cwdProject,\n      profile: parsed.profile ?? undefined,\n    })\n  } catch (err) {\n    if (err instanceof UnknownProfileError) {\n      process.stderr.write(`${err.message}\\n`)\n      return 2\n    }\n    throw err\n  }\n  // Landed on loopback with no project to go on (#1381): the sole-daemon shortcut\n  // couldn't fire, so tell the agent how to aim the verb rather than let it query\n  // whatever owns :8080.\n  if (target.source === 'default' && !requestedProject && !cwdProject) {\n    const hint = await loopbackResolutionHint()\n    if (hint) process.stderr.write(`${hint}\\n`)\n  }\n  const client = createHttpClient(target.endpoint, target.authToken)\n  const positional = parsed.positional\n\n  // Per-verb arg/flag validation runs first so misuse exits 2 before any\n  // network call (ADR-050 #4). Each case builds a thunk that takes the\n  // resolved project — we resolve the project (issue #500) only after the verb\n  // proves well-formed, since resolution itself hits the daemon's /projects.\n  let makeWork: (project: string | undefined) => Promise<VerbResult>\n  switch (cmd) {\n    case 'root-cause': {\n      const node = positional[0]\n      if (!node) {\n        console.error('neat root-cause: missing <node-id>')\n        return 2\n      }\n      makeWork = (project) => runRootCause(client, {\n        errorNode: node,\n        ...(parsed.errorId ? { errorId: parsed.errorId } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'blast-radius': {\n      const node = positional[0]\n      if (!node) {\n        console.error('neat blast-radius: missing <node-id>')\n        return 2\n      }\n      makeWork = (project) => runBlastRadius(client, {\n        nodeId: node,\n        ...(parsed.depth !== null ? { depth: parsed.depth } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'dependencies': {\n      const node = positional[0]\n      if (!node) {\n        console.error('neat dependencies: missing <node-id>')\n        return 2\n      }\n      makeWork = (project) => runDependencies(client, {\n        nodeId: node,\n        ...(parsed.depth !== null ? { depth: parsed.depth } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'observed-dependencies': {\n      const node = positional[0]\n      if (!node) {\n        console.error('neat observed-dependencies: missing <node-id>')\n        return 2\n      }\n      makeWork = (project) => runObservedDependencies(client, {\n        nodeId: node,\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'incidents': {\n      // node-id is optional — bare `neat incidents` returns the global log.\n      makeWork = (project) => runIncidents(client, {\n        ...(positional[0] ? { nodeId: positional[0] } : {}),\n        ...(parsed.limit !== null ? { limit: parsed.limit } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'search': {\n      const q = positional.join(' ').trim()\n      if (!q) {\n        console.error('neat search: missing <query>')\n        return 2\n      }\n      makeWork = (project) => runSearch(client, { query: q, ...(project ? { project } : {}) })\n      break\n    }\n    case 'ask': {\n      // Free-text question — quoted or not, so `neat ask why is checkout\n      // failing` and `neat ask \"why is checkout failing\"` both work.\n      const question = positional.join(' ').trim()\n      if (!question) {\n        console.error('neat ask: missing <question>')\n        return 2\n      }\n      makeWork = (project) => runAsk(client, { question, ...(project ? { project } : {}) })\n      break\n    }\n    case 'diff': {\n      // --against names a snapshot file the core can resolve via\n      // loadSnapshotForDiff. --since is reserved for a future date-range\n      // mode (the contract lists it as `[--since <date>]`); for MVP, the\n      // diff verb requires --against.\n      const against = parsed.against ?? parsed.since\n      if (!against) {\n        console.error('neat diff: --against <snapshot-path> is required')\n        return 2\n      }\n      makeWork = (project) => runDiff(client, {\n        againstSnapshot: against,\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'stale-edges': {\n      makeWork = (project) => runStaleEdges(client, {\n        ...(parsed.limit !== null ? { limit: parsed.limit } : {}),\n        ...(parsed.edgeType ? { edgeType: parsed.edgeType } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'policies': {\n      let hypothetical: ReturnType<typeof JSON.parse> | undefined\n      if (parsed.hypotheticalAction) {\n        try {\n          hypothetical = JSON.parse(parsed.hypotheticalAction)\n        } catch (err) {\n          console.error(\n            `neat policies: --hypothetical-action must be valid JSON: ${(err as Error).message}`,\n          )\n          return 2\n        }\n      }\n      makeWork = (project) => runPolicies(client, {\n        ...(parsed.node ? { nodeId: parsed.node } : {}),\n        ...(hypothetical ? { hypotheticalAction: hypothetical } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    case 'divergences': {\n      let typeFilter: DivergenceType[] | undefined\n      if (parsed.type) {\n        const parts = parsed.type\n          .split(',')\n          .map((s) => s.trim())\n          .filter((s) => s.length > 0)\n        const out: DivergenceType[] = []\n        for (const p of parts) {\n          const r = DivergenceTypeSchema.safeParse(p)\n          if (!r.success) {\n            console.error(\n              `neat divergences: unknown --type \"${p}\". allowed: ${DivergenceTypeSchema.options.join(', ')}`,\n            )\n            return 2\n          }\n          out.push(r.data)\n        }\n        typeFilter = out\n      }\n      makeWork = (project) => runDivergences(client, {\n        ...(typeFilter ? { type: typeFilter } : {}),\n        ...(parsed.minConfidence !== null ? { minConfidence: parsed.minConfidence } : {}),\n        ...(parsed.node ? { node: parsed.node } : {}),\n        ...(project ? { project } : {}),\n      })\n      break\n    }\n    default:\n      // Unreachable — QUERY_VERBS gates the dispatch.\n      console.error(`neat: unknown query verb \"${cmd}\"`)\n      return 2\n  }\n\n  try {\n    // Resolve which project to route to (issue #500). When --project /\n    // NEAT_PROJECT are set this is a no-op; otherwise it asks the daemon's\n    // /projects list and picks the single registered one (or keeps `default`).\n    // A TransportError from here means the daemon is down — same exit-3 path as\n    // any verb call.\n    const project = await resolveProjectForVerb(\n      client,\n      parsed,\n      cwdProjectApplies(target.source) ? cwdProject : undefined,\n    )\n    const result = await makeWork(project)\n    if (parsed.json) process.stdout.write(formatJson(result) + '\\n')\n    else process.stdout.write(formatHuman(result) + '\\n')\n    return 0\n  } catch (err) {\n    // Server / transport errors land on stderr per ADR-050 #3 (stderr for\n    // diagnostics, stdout for results — never mix). Exit code branches per\n    // ADR-050 #4: 1 for HttpError, 3 for TransportError.\n    if (err instanceof ProjectResolutionError) {\n      // Couldn't pick a project on the user's behalf (none registered, or\n      // several and none named `default`). The message already says what to do.\n      console.error(`neat ${cmd}: ${err.message}`)\n      return err.exitCode\n    }\n    if (err instanceof HttpError) {\n      const detail = err.responseBody.length > 0 ? err.responseBody : err.message\n      console.error(`neat ${cmd}: ${detail.trim()}`)\n    } else if (err instanceof TransportError) {\n      console.error(`neat ${cmd}: ${err.message}. Is the daemon running? (endpoint=${target.endpoint})`)\n      // \"Is the daemon running?\" is a question the user can't act on without\n      // knowing the command that starts one, which isn't guessable from here —\n      // a self-hoster whose daemon died mid-session reads this as a dead end\n      // (#1250). Naming the command changes nothing about the exit code or the\n      // reads: the verb still exits 3 and still starts nothing itself.\n      // Only for a loopback endpoint. A hosted or remote daemon isn't ours to\n      // start, and telling someone to `neat watch` would build a graph on the\n      // wrong machine.\n      if (isLoopbackEndpoint(target.endpoint)) {\n        // A project named on the command line may not be the one in this directory,\n        // so the recovery command carries the same name.\n        const upCommand = requestedProject ? `neat up --project ${requestedProject}` : 'neat up'\n        console.error(`neat ${cmd}: run \\`${upCommand}\\` to start it.`)\n      }\n    } else {\n      console.error(`neat ${cmd}: ${(err as Error).message}`)\n    }\n    return exitCodeForError(err)\n  }\n}\n\n// ── Monitor verb (ADR-159) ─────────────────────────────────────────────\n//\n// Resolves the daemon and project the same way a query verb does, then hands a\n// concrete baseUrl + project to runMonitor, which holds the SSE connection.\n// The monitor is a silent, ambient stream: a daemon that can't be reached, or a\n// bare invocation that can't pick a single project, exits clean (0) with no\n// stdout rather than erroring — Claude Code's `monitors/` mechanism reads\n// stdout, so nothing there means the agent hears nothing, which is correct.\nexport async function runMonitorVerb(parsed: ParsedArgs): Promise<number> {\n  const requestedProject = resolveProjectFlag(parsed)\n  const cwdProject = requestedProject ? undefined : await projectForCwd()\n  // The monitor is silent by contract: a bad --profile / NEAT_PROFILE is a\n  // config error, but surfacing it here would pollute the stream, so fall to a\n  // clean exit the same way an unreachable daemon does (below).\n  let target: ClientTarget\n  try {\n    target = await resolveClientTarget({\n      project: requestedProject ?? cwdProject,\n      profile: parsed.profile ?? undefined,\n    })\n  } catch (err) {\n    if (err instanceof UnknownProfileError) return 0\n    throw err\n  }\n  const client = createHttpClient(target.endpoint, target.authToken)\n\n  let project: string | undefined\n  try {\n    project = await resolveProjectForVerb(\n      client,\n      parsed,\n      cwdProjectApplies(target.source) ? cwdProject : undefined,\n    )\n  } catch (err) {\n    // Daemon down (TransportError) → clean, silent exit. Can't pick a project\n    // (several registered, none named default) → a one-line hint on stderr so a\n    // human isn't baffled, but stdout stays pristine so the plugin sees nothing.\n    if (err instanceof ProjectResolutionError) {\n      console.error(`neat monitor: ${err.message}`)\n    }\n    return 0\n  }\n\n  const controller = new AbortController()\n  const onSignal = (): void => controller.abort()\n  process.once('SIGINT', onSignal)\n  process.once('SIGTERM', onSignal)\n  try {\n    return await runMonitor({\n      baseUrl: target.endpoint,\n      project,\n      json: parsed.json,\n      authToken: target.authToken,\n      signal: controller.signal,\n    })\n  } finally {\n    process.off('SIGINT', onSignal)\n    process.off('SIGTERM', onSignal)\n  }\n}\n\n// The last stop for an error nothing else caught. A registry failure — the lock\n// held by a live process, a name that isn't registered — is a condition with a\n// message that already says what happened and what to do, so it prints as that\n// message and nothing else (#1241). Anything else is a bug, and keeps its stack.\nexport function reportFatal(err: unknown, log: (line: unknown) => void = console.error): number {\n  if (err instanceof RegistryError) {\n    log(`neat: ${err.message}`)\n    return 1\n  }\n  log(err)\n  return 1\n}\n\n// Only auto-run when invoked as the CLI entry point. Importing this module\n// from tests must not start the parser; otherwise vitest sees a stray\n// `process.exit` from `main()` running with no argv. The separator class\n// `[\\\\/]` matches Windows paths too — the bin shim lands as `…\\bin\\neat`, so a\n// forward-slash-only check would leave `main()` unfired and the CLI a no-op.\nconst entry = process.argv[1] ?? ''\nif (/[\\\\/](?:cli\\.(?:cjs|js)|cli|neat|neat\\.is)$/.test(entry)) {\n  main().catch((err) => {\n    process.exit(reportFatal(err))\n  })\n}\n","import path from 'node:path'\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport { wordmark } from './style.js'\n\n// The `neat --version` family reads its answer from the bundled package's\n// own package.json. Reading at run time keeps the published bin in lockstep\n// with whatever version `tsup` shipped without a build-time substitution.\n// `dist/cli.cjs` sits one level below the package root.\nexport function readPackageVersion(): string {\n  const here =\n    typeof __dirname !== 'undefined'\n      ? __dirname\n      : path.dirname(fileURLToPath(import.meta.url))\n  // dist/ → package root. tsup writes both cjs and mjs to dist/, so the\n  // parent-of-parent walk is the same in either format.\n  const candidates = [\n    path.resolve(here, '../package.json'),\n    path.resolve(here, '../../package.json'),\n  ]\n  for (const candidate of candidates) {\n    try {\n      const raw = readFileSync(candidate, 'utf8')\n      const parsed = JSON.parse(raw) as { name?: string; version?: string }\n      if (parsed.name === '@neat.is/core' && typeof parsed.version === 'string') {\n        return parsed.version\n      }\n    } catch {\n      // try the next candidate\n    }\n  }\n  return 'unknown'\n}\n\n// The wordmark. Shared between the CLI's `neat init` discovery report and the\n// one-command orchestrator (issue #483) so the brand lives in exactly one place.\n// A compact mark rather than a six-row block: the identity reads on every run\n// without a screen of glyphs each time. The version is single-sourced from the\n// package (readPackageVersion), and the printed line still carries `neat.is` +\n// `v<version>` so a release bump can't leave it stale.\nexport function printBanner(): void {\n  console.log('')\n  console.log(wordmark(readPackageVersion()))\n  console.log('')\n}\n\n// True when this run came in through `npx neat.is` rather than a global\n// `neat` binary on PATH. npx never puts `neat`/`neatd`/`neat-mcp` on PATH —\n// only `npm i -g neat.is` does — so an npx user who copies a bare `neat init`\n// example from the help screen hits `command not found`. We render every\n// example with the prefix that actually works for how they invoked us.\n//\n// Two robust signals: npm sets `npm_command` / `npm_execpath` for anything it\n// spawns (including `npx`), and an npx run resolves argv[1] under a temporary\n// `_npx` cache dir rather than a global bin dir. Either one is enough.\n//\n// Lives here (not in cli.ts) so the orchestrator's summary can render the same\n// prefix without a cli ↔ orchestrator import cycle — the same reason\n// `printBanner` / `readPackageVersion` live in this module.\nexport function isNpxInvocation(): boolean {\n  if (process.env.npm_command === 'exec') return true\n  const execpath = process.env.npm_execpath ?? ''\n  if (execpath.includes('npx')) return true\n  const entry = process.argv[1] ?? ''\n  if (entry.includes('/_npx/') || entry.includes('\\\\_npx\\\\')) return true\n  return false\n}\n\n// The command prefix every help example renders with. `npx neat.is` for an\n// npx run, plain `neat` for a global install.\nexport function commandPrefix(): string {\n  return isNpxInvocation() ? 'npx neat.is' : 'neat'\n}\n","// The CLI's presentation layer — one module owns every color and glyph the\n// human-facing CLI emits, so the palette stays coherent and turns off cleanly.\n//\n// It aligns the terminal to the product's visual identity (design-system.md):\n// monochrome by default, with the OBSERVED green reserved to mean \"observed /\n// live\". Provenance carries the color — OBSERVED reads green, STALE amber,\n// INFERRED cyan, EXTRACTED stays plain — so a fact's trust is legible at a\n// glance, the same signal the dashboard and canvas use.\n//\n// Zero runtime dependencies: the escapes are hand-rolled and gated on a real\n// interactive stdout, with NO_COLOR / FORCE_COLOR honored. Piped output, `--json`,\n// and CI all resolve to byte-plain text — the styling is additive over the exact\n// strings the CLI printed before, never a replacement for them. Every helper is a\n// pass-through when color is off, so a caller can wrap freely without branching.\n\nimport { Provenance } from '@neat.is/types'\n\nconst RESET = '\\x1b[0m'\n\n// Enablement, resolved once at load and overridable for tests. Precedence\n// follows the community conventions: FORCE_COLOR pins it on, NO_COLOR (any value,\n// https://no-color.org) pins it off, a `dumb` terminal is never styled, and the\n// default is \"on only when stdout is an interactive TTY\" — which is what keeps\n// pipes and CI plain without any caller opting out.\nfunction computeEnabled(env: NodeJS.ProcessEnv = process.env): boolean {\n  if (env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== '0' && env.FORCE_COLOR !== '') {\n    return true\n  }\n  if (env.NO_COLOR !== undefined) return false\n  if (env.TERM === 'dumb') return false\n  return Boolean(process.stdout && process.stdout.isTTY)\n}\n\nlet enabled = computeEnabled()\n\n// Test seam: force the enablement either way, or re-read the environment.\nexport function setColorEnabled(value: boolean): void {\n  enabled = value\n}\nexport function refreshColorEnabled(env?: NodeJS.ProcessEnv): void {\n  enabled = computeEnabled(env)\n}\nexport function colorEnabled(): boolean {\n  return enabled\n}\n\nfunction wrap(open: string, s: string): string {\n  return enabled ? `${open}${s}${RESET}` : s\n}\n\n// ── Weights ────────────────────────────────────────────────────────────────\nexport const bold = (s: string): string => wrap('\\x1b[1m', s)\nexport const dim = (s: string): string => wrap('\\x1b[2m', s)\nexport const italic = (s: string): string => wrap('\\x1b[3m', s)\nexport const underline = (s: string): string => wrap('\\x1b[4m', s)\n\n// ── Palette ──────────────────────────────────────────────────────────────────\n// Truecolor for the brand green (the design-system's #5fcf9e) and the two\n// diagnostic hues; a terminal without 24-bit support renders a near neighbour.\n// Kept deliberately small — one accent, plus the semantic warn/error/inferred.\nconst OBSERVED_GREEN = '\\x1b[38;2;95;207;158m' // #5fcf9e — observed / live / success\nconst STALE_AMBER = '\\x1b[38;2;214;164;92m' //          — stale / warning\nconst ERROR_RED = '\\x1b[38;2;224;108;108m' //           — failure\nconst INFERRED_CYAN = '\\x1b[38;2;122;162;247m' //       — inferred / stitched\n\nexport const green = (s: string): string => wrap(OBSERVED_GREEN, s)\nexport const amber = (s: string): string => wrap(STALE_AMBER, s)\nexport const red = (s: string): string => wrap(ERROR_RED, s)\nexport const cyan = (s: string): string => wrap(INFERRED_CYAN, s)\n\n// Semantic aliases — the names callers reach for, so intent (not hue) is what\n// reads at the call site.\nexport const accent = green // the one accent color\nexport const ok = green\nexport const warn = amber\nexport const error = red\n\n// ── Glyphs ───────────────────────────────────────────────────────────────────\n// A tight set, reused everywhere so the CLI's vocabulary stays consistent.\nexport const sym = {\n  ok: '✓',\n  fail: '✗',\n  warn: '⚠',\n  bullet: '•',\n  arrow: '→',\n  stale: '⋯',\n  add: '+',\n  dot: '●',\n  chevron: '▸',\n} as const\n\n// ── Structural helpers ───────────────────────────────────────────────────────\n\n// A section heading — bold in a color terminal, and (deliberately) the bare\n// label when color is off, so piped and NO_COLOR output stay exactly the plain\n// text they were rather than gaining decorative glyphs.\nexport function heading(label: string): string {\n  return bold(label)\n}\n\n// An aligned `label   value` line. The label is dimmed and padded to `width`\n// so a column of them lines up.\nexport function keyval(label: string, value: string, width: number): string {\n  return `${dim(label.padEnd(width))}  ${value}`\n}\n\n// Color a single provenance token by what it means. The heart of the scheme:\n// the same green/amber/cyan the graph uses, so a CLI reader learns provenance\n// the way a dashboard reader does. Unknown tokens pass through unstyled.\nexport function provenanceToken(token: string): string {\n  switch (token.trim().toUpperCase()) {\n    case Provenance.OBSERVED:\n      return green(token)\n    case Provenance.STALE:\n      return amber(token)\n    case Provenance.INFERRED:\n      return cyan(token)\n    case Provenance.EXTRACTED:\n      return dim(token)\n    default:\n      return token\n  }\n}\n\n// A composite provenance string (\"OBSERVED, EXTRACTED\") with each token colored\n// and the separators left plain, so the literal text is unchanged when color is\n// off.\nexport function provenance(value: string): string {\n  return value\n    .split(',')\n    .map((part, i) => (i === 0 ? provenanceToken(part) : ' ' + provenanceToken(part.replace(/^\\s+/, ''))))\n    .join(',')\n}\n\n// Width-aware table. Given rows of cells, pad every column to the widest cell in\n// it (last column is left unpadded so it can run long). Alignment is computed on\n// the plain text, so injected color codes never throw the columns off.\nconst ANSI = /\\x1b\\[[0-9;]*m/g\nfunction visibleWidth(s: string): number {\n  return s.replace(ANSI, '').length\n}\nexport function table(rows: string[][], gap = 2): string[] {\n  if (rows.length === 0) return []\n  const cols = Math.max(...rows.map((r) => r.length))\n  const widths: number[] = []\n  for (let c = 0; c < cols - 1; c++) {\n    widths[c] = Math.max(...rows.map((r) => (r[c] ? visibleWidth(r[c]) : 0)))\n  }\n  const pad = ' '.repeat(gap)\n  return rows.map((r) =>\n    r\n      .map((cell, c) => {\n        if (c === r.length - 1) return cell // last cell runs free\n        const extra = widths[c] - visibleWidth(cell)\n        return cell + ' '.repeat(Math.max(0, extra))\n      })\n      .join(pad),\n  )\n}\n\n// Color an already-assembled result block (the middle third of a query verb's\n// human output). Provenance tokens take their meaning-color wherever they appear;\n// the leading `•` bullets dim back so the fact text carries the line. Purely\n// additive — with color off every helper passes through, so the block is the\n// exact text it was before.\nexport function styleBlock(block: string): string {\n  return block\n    .split('\\n')\n    .map((line) => {\n      let out = line.replace(/\\b(OBSERVED|STALE|INFERRED|EXTRACTED)\\b/g, (m) => provenanceToken(m))\n      out = out.replace(/^(\\s*)•/, (_all, indent: string) => `${indent}${dim(sym.bullet)}`)\n      return out\n    })\n    .join('\\n')\n}\n\n// The verb footer — `confidence: X · provenance: Y` — with the labels dimmed and\n// the provenance colored by meaning. The literal words and spacing are untouched,\n// so the plain-text (color-off) footer is byte-identical to before.\nexport function footer(confidence: string, provenanceValue: string): string {\n  const prov = provenanceValue === 'n/a' ? dim(provenanceValue) : provenance(provenanceValue)\n  return `${dim('confidence:')} ${confidence} ${dim('·')} ${dim('provenance:')} ${prov}`\n}\n\n// The compact wordmark. Replaces the six-row block banner: one bold mark, the\n// version, and a one-line tagline — brand without shouting on every run. Keeps a\n// line carrying `neat.is` + `v<version>` (the single-sourced version string).\nexport function wordmark(version: string): string {\n  const mark = `${accent(sym.chevron)} ${bold('neat')}`\n  const expansion = dim('Network Environment Architecture Tools')\n  const meta = dim(`neat.is · v${version} · Apache 2.0`)\n  return `${mark}  ${expansion}\\n${meta}`\n}\n","import GraphDefault from 'graphology'\nimport type { MultiDirectedGraph as MDGType } from 'graphology'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\n\n// graphology ships as a CJS bundle that does `module.exports = Graph` with\n// the other constructors attached as properties (`Graph.MultiDirectedGraph =\n// ...`). cjs-module-lexer can't see through that attachment, so a named\n// import like `import { MultiDirectedGraph } from 'graphology'` fails under\n// strict Node ESM (Node 22+ via tsx in particular). Pull the constructor off\n// the default export instead — same shape under tsx and tsup-bundled output.\ntype MultiDirectedGraphCtor = typeof MDGType\nconst MultiDirectedGraph: MultiDirectedGraphCtor = (\n  GraphDefault as unknown as { MultiDirectedGraph: MultiDirectedGraphCtor }\n).MultiDirectedGraph\n\n// Multi because two nodes can have edges of different types simultaneously\n// (e.g. CALLS and DEPENDS_ON between the same pair of services).\nexport type NeatGraph = MDGType<GraphNode, GraphEdge>\n\nexport const DEFAULT_PROJECT = 'default'\n\n// One graph per project. The map is the source of truth; getGraph() with no\n// arg or with 'default' hits the legacy single-project path so existing\n// callers keep working byte-for-byte (ADR-026).\nconst graphs = new Map<string, NeatGraph>()\n\n// A graph that belongs to no project — scratch space for a one-off extraction\n// (pr-verdict.ts) that must never be reachable through getGraph().\nexport function makeGraph(): NeatGraph {\n  return new MultiDirectedGraph<GraphNode, GraphEdge>({ allowSelfLoops: false })\n}\n\nexport function getGraph(project: string = DEFAULT_PROJECT): NeatGraph {\n  let g = graphs.get(project)\n  if (!g) {\n    g = makeGraph()\n    graphs.set(project, g)\n  }\n  return g\n}\n\nexport function hasProject(project: string): boolean {\n  return graphs.has(project)\n}\n\nexport function listProjects(): string[] {\n  return [...graphs.keys()].sort()\n}\n\n// Reset a single project, or all of them when the arg is omitted. Tests use\n// the no-arg form between cases; runtime never calls it.\nexport function resetGraph(project?: string): void {\n  if (project === undefined) {\n    graphs.clear()\n    return\n  }\n  graphs.delete(project)\n}\n","export { extractFromDirectory, type ExtractResult } from './extract/index.js'\n","// Static-extraction pipeline. Phase order is load-bearing:\n//   services → aliases → databases (+ compat) → configs → routes → grpc → calls → infra → frontier promotion.\n//   Routes precede calls so the cross-service matcher (ADR-119) sees the full\n//   RouteNode table when it resolves client call sites to server routes. gRPC\n//   `.proto` extraction (ADR-123) mints the method nodes an OBSERVED span fuses onto.\n//\n// Contract anchors (see /docs/contracts.md):\n//   * Rule 1 — Every emitted edge carries Provenance.EXTRACTED from @neat.is/types.\n//   * Rule 2 — EXTRACTED edges use the plain `${type}:src->tgt` id pattern.\n//     Never write under the OBSERVED id pattern; that's ingest.ts's territory.\n//   * Rule 5 — Nodes/edges constructed against schemas in @neat.is/types; no\n//     local interface redefinitions in this tree.\n//   * Rule 8 — No demo-name hardcoding. Driver names come from package.json\n//     dependencies; engine names from compat.json via compatPairs().\n//   * Rule 14 — ConfigNodes record file existence only; never the contents.\nimport type { NeatGraph } from '../graph.js'\nimport { DEFAULT_PROJECT } from '../graph.js'\nimport { promoteFrontierNodes } from '../ingest.js'\nimport { ensureCompatLoaded } from '../compat.js'\nimport { emitNeatEvent } from '../events.js'\nimport { addServiceNodes, discoverServices } from './services.js'\nimport { addServiceAliases } from './aliases.js'\nimport { addFiles } from './files.js'\nimport { addSymbols } from './symbols.js'\nimport { addSymbolEdges } from './symbol-edges.js'\nimport { addGoSymbolEdges } from './go-symbol-edges.js'\nimport { addJavaSymbolEdges } from './java-symbol-edges.js'\nimport { addImports } from './imports.js'\nimport { addServerActions } from './actions.js'\nimport { addDatabasesAndCompat } from './databases/index.js'\nimport { addConfigNodes } from './configs.js'\nimport { addFlagStores } from './flags.js'\nimport { addRoutes } from './routes.js'\nimport { addJavaRoutes } from './java-routes.js'\nimport { addTornadoRoutes } from './tornado-routes.js'\nimport { addGatewayRoutes } from './java-gateway.js'\nimport { addGrpcMethods } from './proto.js'\nimport { addCallEdges } from './calls/index.js'\nimport { addJavaCallEdges } from './java-calls.js'\nimport { addTableEdges } from './table-edges.js'\nimport { addInfra } from './infra/index.js'\nimport { addZodShapes } from './zod-shapes.js'\nimport { addFirestoreRules } from './firestore-rules.js'\nimport {\n  drainExtractionErrors,\n  writeExtractionErrors,\n  writeExtractionHealth,\n  extractionHealthPathFor,\n  drainDroppedExtracted,\n  drainSkippedFiles,\n  type SkippedSourceFile,\n  isRejectedLogEnabled,\n  writeRejectedExtracted,\n  type ExtractionError,\n  type DroppedExtractedEdge,\n} from './errors.js'\nimport path from 'node:path'\nimport { retireExtractedEdgesByMissingFile } from './retire.js'\nimport { setExtractionSource } from './calls/shared.js'\nimport {\n  beginSourceExtraction,\n  finishSourceExtraction,\n  invalidateSourceBaseline,\n  type SourceCommit,\n} from './source-baseline.js'\n\nexport interface ExtractResult {\n  nodesAdded: number\n  edgesAdded: number\n  frontiersPromoted: number\n  // ADR-065 — per-file extraction failures collected during the pass.\n  // `extractionErrors` is the count; `errorEntries` is the drained list,\n  // available for callers that want to surface per-file context. Both are\n  // present on every pass (zero is observable as a positive signal).\n  extractionErrors: number\n  errorEntries: ExtractionError[]\n  // #140 — count of EXTRACTED edges retired this pass because their\n  // evidence.file no longer exists on disk. Zero on a clean pass; non-zero\n  // means the snapshot was carrying ghosts from deleted source.\n  ghostsRetired: number\n  // #1258 — files read but deliberately not parsed (minified machine output).\n  // Their FileNodes stand; nothing was extracted from them. Counted so the skip\n  // is visible rather than silent.\n  skippedFiles: number\n  skippedEntries: SkippedSourceFile[]\n  // ADR-066 — count of EXTRACTED candidates dropped at emit time because\n  // their graded confidence fell below NEAT_EXTRACTED_PRECISION_FLOOR.\n  // Always reported (zero is observable). Detail entries surface in\n  // `droppedEntries` and route to rejected.ndjson when\n  // NEAT_EXTRACTED_REJECTED_LOG=1.\n  extractedDropped: number\n  droppedEntries: DroppedExtractedEdge[]\n}\n\nexport interface ExtractOptions {\n  // Actual resolved Git HEAD of the hosted clone this pass reads. Evidence\n  // only when its repository is this pass's `source`. Never inferred from a\n  // branch name or restored from a snapshot.\n  sourceCommit?: SourceCommit\n  // Post-extract policy trigger (ADR-043). Awaited after frontier promotion\n  // so policies see the final post-pass graph state. Daemons wire this to\n  // evaluateAllPolicies + PolicyViolationsLog.append.\n  onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n  // Project tag for the extraction-complete event (ADR-051). Defaults to\n  // DEFAULT_PROJECT when omitted.\n  project?: string\n  // ADR-065 — when set, drained extraction errors are appended to this\n  // path as ndjson with `source: 'extract'`. Daemons / `neat init` /\n  // `neat watch` wire this to `<projectDir>/neat-out/errors.ndjson`. When\n  // omitted, errors are still drained and returned in the result, just\n  // not persisted.\n  errorsPath?: string\n  // What this pass is extracting FROM (ADR-233) — a token that outlives the\n  // directory being read: `owner/name` for a bound repo on a hosted daemon, the\n  // project name locally. The retire sweep uses it to stay inside its own\n  // source, so a project with two bound repos stops having each pass retire the\n  // other's files (#1294) and a boot pass over a source-less root stops\n  // retiring the restored layer (#1291).\n  //\n  // Omitted means no source is named, and every sweep behaves exactly as it did\n  // before — which is what keeps a single-source local daemon unchanged.\n  source?: string\n  // Emit the `extraction-complete` event (ADR-051). Default true. A pass into a\n  // scratch graph that belongs to no project (pr-verdict.ts) turns it off, so\n  // subscribers don't see a completed extraction for a project that didn't have one.\n  announce?: boolean\n}\n\n// Extraction passes run one at a time, process-wide. A pass's working state is\n// module-level, not per call: the error, dropped-edge and skipped-file sinks it\n// drains, and the source it stamps on every FileNode it mints (ADR-233). Two\n// passes interleaving would drain each other's errors into the wrong project's\n// log and stamp one pass's FileNodes with the other's source — or with none,\n// which puts them outside every sourced retire sweep for good. A hosted daemon\n// runs passes from more than one place (boot, repo-sync, the PR verdict), so\n// overlap is real, not theoretical. The cost is that passes queue.\nlet passQueue: Promise<unknown> = Promise.resolve()\n\nexport function extractFromDirectory(\n  graph: NeatGraph,\n  scanPath: string,\n  opts: ExtractOptions = {},\n): Promise<ExtractResult> {\n  // Old evidence stops counting the moment another pass is asked for. The pass\n  // itself begins only when its turn comes: one waiting in the queue overlaps\n  // nothing, so it must not leave the running pass's successor conflicted (#1331).\n  invalidateSourceBaseline(graph, opts.source, 'syncing')\n  const pass = passQueue.then(async () => {\n    const sourceGeneration = beginSourceExtraction(graph, opts.source, opts.sourceCommit)\n    let result: ExtractResult | undefined\n    try {\n      result = await runExtractionPass(graph, scanPath, opts)\n      return result\n    } finally {\n      finishSourceExtraction(graph, sourceGeneration, opts.source, opts.sourceCommit,\n        result ?? { extractionErrors: 1, skippedFiles: 0 })\n    }\n  })\n  passQueue = pass.catch(() => {})\n  return pass\n}\n\nasync function runExtractionPass(\n  graph: NeatGraph,\n  scanPath: string,\n  opts: ExtractOptions,\n): Promise<ExtractResult> {\n  await ensureCompatLoaded()\n  // Clear any stale entries from a prior pass (the producer-side sink is\n  // process-local). Per ADR-065, every pass collects its own errors; we drain\n  // again at the end to capture this pass's failures.\n  drainExtractionErrors()\n  drainSkippedFiles()\n  // Pass-scoped, like the error and skipped-file sinks above: every FileNode\n  // this pass mints is stamped with it, and it is cleared before returning so a\n  // later pass that names no source can't inherit this one's (ADR-233).\n  setExtractionSource(opts.source)\n\n  const services = await discoverServices(scanPath)\n\n  const phase1Nodes = addServiceNodes(graph, services)\n  await addServiceAliases(graph, scanPath, services)\n  const fileEnum = await addFiles(graph, services)\n  // Symbol nodes under files (ADR-158). Runs after addFiles so the FileNodes it\n  // hangs symbols off already exist; before calls so a future Phase-2 symbol→\n  // symbol CALLS producer has the symbol inventory to resolve against.\n  const symbolEnum = await addSymbols(graph, services)\n  const importGraph = await addImports(graph, services)\n  // Static symbol edges (ADR-158 §3). Runs after addSymbols (the inventory it\n  // resolves targets against) and after addImports (so the import graph is in\n  // place). Confident heritage + call edges only, symbol→symbol, never guessed.\n  const symbolEdges = await addSymbolEdges(graph, services)\n  // Go symbol→symbol CALLS (ADR-158 §3, the Go rung symbol-edges.ts names as a\n  // follow-on). A separate producer because Go's AST node types and its absent\n  // ES-import resolver don't ride the JS/TS walker; same precision discipline,\n  // same-file resolution only. Runs after addSymbols (the inventory it resolves against).\n  const goSymbolEdges = await addGoSymbolEdges(graph, services)\n  // Java symbol→symbol CALLS, the same rung for Java: same-file, unambiguous only.\n  const javaSymbolEdges = await addJavaSymbolEdges(graph, services)\n  // Next.js Server Actions (ADR-168). Runs after addImports so its client-stitch\n  // can resolve an imported action binding through the same import graph. Mints a\n  // ServerActionNode per exported `\"use server\"` function (owned by its file via\n  // CONTAINS) and a `file ──CALLS──▶ action` edge on any client reference. Gated\n  // on the `next` dependency; a no-op for every other service.\n  const actionPhase = await addServerActions(graph, services)\n  const phase2 = await addDatabasesAndCompat(graph, services, scanPath)\n  const phase3 = await addConfigNodes(graph, services, scanPath)\n  // Flag grain (ADR-242): the committed flag definitions and the code that reads\n  // each key, onto one flag-store node per provider.\n  const flagPhase = await addFlagStores(graph, services, scanPath)\n  // Route extraction (ADR-119) runs before calls so the RouteNodes exist when\n  // addCallEdges' cross-service matcher (route-match.ts) looks them up.\n  const routePhase = await addRoutes(graph, services)\n  // Spring MVC routes (Java), the same RouteNode shape from annotations; before\n  // calls for the same reason.\n  const javaRoutePhase = await addJavaRoutes(graph, services)\n  // Tornado's literal handler table (Python), same RouteNode shape.\n  const tornadoRoutePhase = await addTornadoRoutes(graph, services)\n  // Spring Cloud Gateway's routing table (config as a source): gateway routes and\n  // the config file's CALLS to each routed service.\n  const gatewayPhase = await addGatewayRoutes(graph, services)\n  // gRPC `.proto` service/method extraction (ADR-123). Independent of the call\n  // phase — it reads the proto contract surface, not JS/TS call sites — and mints\n  // the same method nodes an OBSERVED gRPC span lands on, so declared and observed\n  // methods fuse.\n  const grpcPhase = await addGrpcMethods(graph, services, scanPath)\n  const phase4 = await addCallEdges(graph, services)\n  // Java RestTemplate / WebClient calls, after routes so a call can land on the\n  // RouteNode it names.\n  const javaCallPhase = await addJavaCallEdges(graph, services)\n  // Foreign-key table→table edges (ADR-161). Runs after addCallEdges so the\n  // column/table read has already minted both endpoints' `infra:sql-table:<name>`\n  // InfraNodes; it mints the `child ──REFERENCES──▶ parent` edges the data-axis\n  // traversal walks. The data-axis sibling of symbol-edges (ADR-158 §3).\n  const tableEdges = await addTableEdges(graph, services)\n  const phase5 = await addInfra(graph, scanPath, services)\n  // Zod declared shapes (ADR-170). A standalone, self-contained phase (it reads\n  // its own files, gated per service on the `zod` dep) minting an\n  // `infra:zod-schema:<name>` InfraNode + EXTRACTED columns per top-level\n  // `z.object` / `z.enum` literal. Independent of the other phases — it neither\n  // reads nor mutates their nodes — so order is not load-bearing; it runs here,\n  // after infra, before the ghost-retire sweep so its file-relative edges are\n  // dropped like any other producer's when their source disappears.\n  const zodPhase = await addZodShapes(graph, services)\n  // firestore.rules guard sets (ADR-169). A standalone phase — not a calls\n  // producer — that reads each service's checked-in `firestore.rules` and folds\n  // `guardedFields` onto the `firestore-collection` InfraNodes the F1 recognizer\n  // (ADR-167) mints in the calls phase, so it must run after addCallEdges. It\n  // adds no nodes or edges (it only enriches existing nodes), and is inert until\n  // firestore-collection nodes exist.\n  const firestoreRulesPhase = await addFirestoreRules(graph, services)\n  // #140 — drop EXTRACTED edges whose evidence.file no longer exists on disk.\n  // Catches the deleted-file ghost case for the full-pass entry point\n  // (init / daemon bootstrap). The edited-file case is handled per-mtime by\n  // watch.ts's `retireEdgesByFile`. Service dirs are passed alongside scanPath\n  // because CALLS-family producers store service-dir-relative paths while\n  // configs / databases / infra store scanPath-relative.\n  //\n  // A pass that found no source retires nothing (#1291). The sweep reads a\n  // file's absence under this scan root as the file being gone, which only\n  // holds when the root is where the graph's source lives. A root with no\n  // service in it — a hosted tenant's data directory before its repos are\n  // synced, a checkout that isn't mounted yet — says nothing about the files a\n  // loaded snapshot describes, and sweeping against it would empty the graph's\n  // whole EXTRACTED layer.\n  const ghostsRetired =\n    services.length === 0\n      ? 0\n      : retireExtractedEdgesByMissingFile(\n          graph,\n          scanPath,\n          services.map((s) => s.dir),\n          opts.source,\n        )\n  const frontiersPromoted = promoteFrontierNodes(graph)\n\n  // Post-extract policy trigger (ADR-043). Fires after frontier promotion so\n  // policies see the post-pass graph (including any FRONTIER → OBSERVED edge\n  // upgrades that just landed).\n  if (opts.onPolicyTrigger) await opts.onPolicyTrigger(graph)\n\n  // ADR-065 — drain the per-file extraction errors collected during the pass.\n  // If a sidecar path was supplied, append the entries; otherwise return them\n  // for the caller to surface.\n  const errorEntries = drainExtractionErrors()\n  if (opts.errorsPath && errorEntries.length > 0) {\n    try {\n      await writeExtractionErrors(errorEntries, opts.errorsPath)\n    } catch (err) {\n      console.warn(\n        `[neat] failed to write extraction errors to ${opts.errorsPath}: ${(err as Error).message}`,\n      )\n    }\n  }\n  // #883 — overwrite the coverage sidecar every pass (even zero, to clear a\n  // prior gap) so a daemon can put this pass's skipped-file count on /health.\n  // errors.ndjson is append-only and can't answer \"is the current graph\n  // complete?\"; this can. Best-effort — a failed write never fails extraction.\n  if (opts.errorsPath) {\n    try {\n      await writeExtractionHealth(errorEntries, extractionHealthPathFor(opts.errorsPath))\n    } catch (err) {\n      console.warn(\n        `[neat] failed to write extraction health sidecar: ${(err as Error).message}`,\n      )\n    }\n  }\n\n  // ADR-066 — drain the precision-floor drops. Always returned; only\n  // persisted when NEAT_EXTRACTED_REJECTED_LOG=1 (opt-in to keep the\n  // default sidecar surface quiet).\n  const droppedEntries = drainDroppedExtracted()\n  const skippedEntries = drainSkippedFiles()\n  if (\n    isRejectedLogEnabled() &&\n    opts.errorsPath &&\n    droppedEntries.length > 0\n  ) {\n    // rejected.ndjson lives alongside errors.ndjson under neat-out/. Derive\n    // from errorsPath rather than re-plumbing a new option.\n    const rejectedPath = path.join(path.dirname(opts.errorsPath), 'rejected.ndjson')\n    try {\n      await writeRejectedExtracted(droppedEntries, rejectedPath)\n    } catch (err) {\n      console.warn(\n        `[neat] failed to write rejected extracted edges to ${rejectedPath}: ${(err as Error).message}`,\n      )\n    }\n  }\n\n  // Every producer and the sweep have run; nothing below mints a FileNode. A\n  // pass always sets this on entry, so a leak could never reach the next one —\n  // clearing it just keeps the module's state honest between passes (ADR-233).\n  setExtractionSource(undefined)\n\n  const result: ExtractResult = {\n    nodesAdded:\n      phase1Nodes +\n      fileEnum.nodesAdded +\n      symbolEnum.nodesAdded +\n      importGraph.nodesAdded +\n      symbolEdges.nodesAdded +\n      goSymbolEdges.nodesAdded +\n      javaSymbolEdges.nodesAdded +\n      actionPhase.nodesAdded +\n      phase2.nodesAdded +\n      phase3.nodesAdded +\n      flagPhase.nodesAdded +\n      routePhase.nodesAdded +\n      javaRoutePhase.nodesAdded +\n      tornadoRoutePhase.nodesAdded +\n      gatewayPhase.nodesAdded +\n      grpcPhase.nodesAdded +\n      phase4.nodesAdded +\n      javaCallPhase.nodesAdded +\n      tableEdges.nodesAdded +\n      phase5.nodesAdded +\n      zodPhase.nodesAdded +\n      firestoreRulesPhase.nodesAdded,\n    edgesAdded:\n      fileEnum.edgesAdded +\n      symbolEnum.edgesAdded +\n      importGraph.edgesAdded +\n      symbolEdges.edgesAdded +\n      goSymbolEdges.edgesAdded +\n      javaSymbolEdges.edgesAdded +\n      actionPhase.edgesAdded +\n      phase2.edgesAdded +\n      phase3.edgesAdded +\n      flagPhase.edgesAdded +\n      routePhase.edgesAdded +\n      javaRoutePhase.edgesAdded +\n      tornadoRoutePhase.edgesAdded +\n      gatewayPhase.edgesAdded +\n      grpcPhase.edgesAdded +\n      phase4.edgesAdded +\n      javaCallPhase.edgesAdded +\n      tableEdges.edgesAdded +\n      phase5.edgesAdded +\n      zodPhase.edgesAdded +\n      firestoreRulesPhase.edgesAdded,\n    frontiersPromoted,\n    extractionErrors: errorEntries.length,\n    errorEntries,\n    ghostsRetired,\n    extractedDropped: droppedEntries.length,\n    droppedEntries,\n    skippedFiles: skippedEntries.length,\n    skippedEntries,\n  }\n\n  // extraction-complete (ADR-051). fileCount is the number of services\n  // discovered — the closest proxy we have for \"how much source did this\n  // pass touch\" without a per-phase file accountant.\n  if (opts.announce !== false) emitNeatEvent({\n    type: 'extraction-complete',\n    project: opts.project ?? DEFAULT_PROJECT,\n    payload: {\n      project: opts.project ?? DEFAULT_PROJECT,\n      fileCount: services.length,\n      nodesAdded: result.nodesAdded,\n      edgesAdded: result.edgesAdded,\n    },\n  })\n\n  return result\n}\n","import { promises as fs, existsSync, readFileSync } from 'node:fs'\nimport path from 'node:path'\nimport { isIP } from 'node:net'\nimport { appendRuntimeIncident } from './durable-incident.js'\nimport * as sourceMapJs from 'source-map-js'\nimport type {\n  DatabaseNode,\n  ErrorEvent,\n  FileNode,\n  FrontierNode,\n  GraphEdge,\n  GraphNode,\n  GraphQLOperationNode,\n  GrpcMethodNode,\n  InfraNode,\n  Policy,\n  ServiceNode,\n  StaleEvent,\n  SymbolNode,\n  WebSocketChannelNode,\n} from '@neat.is/types'\nimport type { PersistedGraph } from './persist.js'\nimport type { EvaluationContext as PolicyEvaluationContext } from './policy.js'\nimport { canPromoteFrontier } from './policy.js'\nimport {\n  EdgeType,\n  GraphEdgeSchema,\n  GraphNodeSchema,\n  NodeType,\n  Provenance,\n  confidenceForObservedSignal,\n  databaseId,\n  localDatabaseId,\n  extractedEdgeId,\n  fileId,\n  frontierId,\n  graphqlOperationId,\n  grpcMethodId,\n  incidentKindOf,\n  inferredEdgeId,\n  infraId,\n  observedEdgeId,\n  frontierEdgeId,\n  serviceId,\n  symbolId,\n  websocketChannelId,\n  type EdgeErrorExemplar,\n  type EdgeTypeValue,\n  type FlagDefinition,\n  type ProvenanceValue,\n  type RouteNode,\n  type DeployContext,\n  type ObservedDeployContext,\n} from '@neat.is/types'\nimport { normalizePathTemplate } from './extract/routes.js'\nimport { invalidateSourceBaseline } from './extract/source-baseline.js'\nimport { knownDatastoreEngine } from './extract/infra/shared.js'\nimport { foldColumns, OBSERVED_COLUMN_CONFIDENCE } from './columns.js'\nimport { FLAG_STORE_KIND, foldObservedFlags, foldObservedVariant } from './flags.js'\nimport { recordLatency, latencyPercentiles } from './latency-digest.js'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport type { AttributeValue, FlagEvaluation, ParsedSpan } from './otel.js'\nimport { emitNeatEvent } from './events.js'\nimport { deepestApplicationFrame } from './stacktrace.js'\n\n// Maps OTel spans to graph signal:\n//   * Cross-service span → upsert CALLS edge.\n//   * Database span (db.system attr present) → upsert CONNECTS_TO edge to a\n//     DatabaseNode resolved by host, or a service-scoped local DatabaseNode when\n//     the span carries no peer host (an in-process / embedded DB, ADR-118).\n//   * Span with status.code === 2 → ErrorEvent appended to errors.ndjson.\n//\n// Contract anchors (see /docs/contracts.md):\n//   * Rule 1 — Provenance: every edge here carries Provenance.X from @neat.is/types.\n//   * Rule 2 — Coexistence: OBSERVED edges live alongside EXTRACTED ones with a\n//     distinct id pattern (`${type}:OBSERVED:src->tgt`). Never write OBSERVED\n//     under the EXTRACTED id; that erases the gap NEAT exists to surface.\n//   * Rule 4 — Per-edge-type staleness (ADR-024): STALE_THRESHOLDS_BY_EDGE_TYPE\n//     governs decay; never hardcode a flat 24h threshold.\n//   * Rule 8 — No demo names: derive driver/engine identifiers from node\n//     properties, not literals.\n\nexport interface IngestContext {\n  graph: NeatGraph\n  errorsPath: string\n  // Absolute scan root the daemon is watching for this project. When set, a\n  // runtime `code.filepath` is made service-root-relative against it before the\n  // FileNode is keyed (file-awareness.md §4) — the service's absolute root is\n  // `scanPath/<repoPath>`, which recovers `dist/foo.js` even for a single-\n  // package service whose `repoPath` is empty (issue #430). Omitted by ad-hoc\n  // callers and most tests, which rely on the repoPath-segment anchor instead.\n  scanPath?: string\n  // Project name for event-bus routing (ADR-051). Defaults to DEFAULT_PROJECT\n  // when omitted — keeps single-project tests / scripts wire-compatible.\n  project?: string\n  now?: () => number\n  // Set to false when the receiver already wrote the ErrorEvent synchronously\n  // (production daemons via watch.ts wire this). When true or omitted, handleSpan\n  // appends the ErrorEvent itself — the path used by ad-hoc scripts and tests\n  // that don't go through buildOtelReceiver. ADR-033 §Error events.\n  writeErrorEventInline?: boolean\n  // Post-mutation policy trigger (ADR-043). Fires after handleSpan finishes\n  // and the queue is drained. Daemons wire this to evaluateAllPolicies +\n  // PolicyViolationsLog.append. Ad-hoc callers leave it undefined; their tests\n  // don't need policy side effects.\n  onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n  // 4xx-burst coalescing state, keyed by `${source}->${peer}` (issue #481).\n  // Lazily created the first time handleSpan sees a 4xx CLIENT/PRODUCER span.\n  // Carried on the context so each project/daemon keeps its own bursts and a\n  // long-lived handler accumulates across spans; ad-hoc callers reuse one ctx\n  // across a batch and get the same coalescing.\n  burstState?: Map<string, BurstState>\n}\n\nconst HOUR_MS = 60 * 60 * 1000\nconst DAY_MS = 24 * HOUR_MS\n\n// Per-edge-type stale thresholds. HTTP CALLS at 24h is meaningless because\n// healthy traffic recurs in seconds; infra DEPENDS_ON is the opposite — a\n// docker-compose service can sit idle overnight without anything being wrong.\n// Override via NEAT_STALE_THRESHOLDS (JSON, ms-per-edge-type).\nconst DEFAULT_STALE_THRESHOLDS: Record<string, number> = {\n  CALLS: HOUR_MS,\n  CONNECTS_TO: 4 * HOUR_MS,\n  PUBLISHES_TO: 4 * HOUR_MS,\n  CONSUMES_FROM: 4 * HOUR_MS,\n  DEPENDS_ON: DAY_MS,\n  CONFIGURED_BY: DAY_MS,\n  RUNS_ON: DAY_MS,\n}\n// Fallback for any edge type not in the map (forward compat — adding a new\n// EdgeType shouldn't break staleness sweeps).\nconst FALLBACK_STALE_THRESHOLD_MS = DAY_MS\n\nfunction loadStaleThresholdsFromEnv(): Record<string, number> {\n  const raw = process.env.NEAT_STALE_THRESHOLDS\n  if (!raw) return DEFAULT_STALE_THRESHOLDS\n  try {\n    const overrides = JSON.parse(raw) as Record<string, unknown>\n    const merged = { ...DEFAULT_STALE_THRESHOLDS }\n    for (const [k, v] of Object.entries(overrides)) {\n      if (typeof v === 'number' && Number.isFinite(v) && v >= 0) merged[k] = v\n    }\n    return merged\n  } catch (err) {\n    console.warn(\n      `[neat] NEAT_STALE_THRESHOLDS could not be parsed (${(err as Error).message}); using defaults`,\n    )\n    return DEFAULT_STALE_THRESHOLDS\n  }\n}\n\nexport function thresholdForEdgeType(\n  edgeType: string,\n  overrides?: Record<string, number>,\n): number {\n  const map = overrides ?? loadStaleThresholdsFromEnv()\n  return map[edgeType] ?? FALLBACK_STALE_THRESHOLD_MS\n}\n\n// Failing-response incident tuning. A span that completes 5xx, carries an\n// ERROR status, or an exception event records an incident on its own — those\n// are unambiguous failures. A 4xx CLIENT/PRODUCER span doesn't: a single 404 is\n// often correct app behavior (auth probe, conditional fetch). 4xx becomes a\n// signal only when it repeats — N consecutive 4xx against the same (source,\n// peer) pair inside a window record ONE coalesced incident carrying the count\n// and the dominant status code, rather than N separate lines that would drown\n// the history. Mirrors the NEAT_STALE_THRESHOLDS override shape.\n//   threshold — how many consecutive 4xx against one peer trip the burst.\n//   windowMs  — the gap that ends a burst; a 4xx more than this after the\n//               previous one starts a fresh burst rather than extending it.\nconst DEFAULT_INCIDENT_THRESHOLDS = {\n  threshold: 5,\n  windowMs: 60_000,\n}\n\nfunction loadIncidentThresholdsFromEnv(): { threshold: number; windowMs: number } {\n  const raw = process.env.NEAT_INCIDENT_THRESHOLDS\n  if (!raw) return DEFAULT_INCIDENT_THRESHOLDS\n  try {\n    const overrides = JSON.parse(raw) as Record<string, unknown>\n    const merged = { ...DEFAULT_INCIDENT_THRESHOLDS }\n    if (\n      typeof overrides.threshold === 'number' &&\n      Number.isFinite(overrides.threshold) &&\n      overrides.threshold >= 1\n    ) {\n      merged.threshold = Math.floor(overrides.threshold)\n    }\n    if (\n      typeof overrides.windowMs === 'number' &&\n      Number.isFinite(overrides.windowMs) &&\n      overrides.windowMs >= 0\n    ) {\n      merged.windowMs = overrides.windowMs\n    }\n    return merged\n  } catch (err) {\n    console.warn(\n      `[neat] NEAT_INCIDENT_THRESHOLDS could not be parsed (${(err as Error).message}); using defaults`,\n    )\n    return DEFAULT_INCIDENT_THRESHOLDS\n  }\n}\n\n// ── Streaming / long-lived span guard for the latency digest (ADR-208) ────────\n// `latencyMs: { p50, p95 }` is a per-request measurement (ADR-190). A streaming\n// or otherwise long-lived span carries a duration equal to the whole stream's\n// lifetime — not a per-request latency — so folding it into the per-edge latency\n// histogram (latency-digest.ts) poisons p95 and false-fires the saturation\n// classifier (traverse.ts `SATURATION_P95_MS`, ADR-189): flagd's gRPC\n// server-stream `EventStream` ran ~10 minutes and read as a 606208ms inbound p95,\n// which steered `get_root_cause` to a phantom \"load-generator overloads\n// everything\" verdict. The guard withholds these spans from the latency feed\n// only — spanCount, errorCount, and lastObserved still record like any other\n// observation, and no other edge property is touched.\n//\n// Span-shape signals come first, because they name the stream directly:\n//   • WebSocket upgrade span — the upgrade span lives for the whole connection\n//     (otel-ingest.md §WebSocket channels); `websocketChannel` is already parsed.\n//   • Server-Sent Events — an SSE response streams for its whole lifetime and\n//     names itself `content-type: text/event-stream` on the response header,\n//     when the HTTP instrumentation captured response headers.\n// A duration ceiling is the documented fallback: the base gRPC semconv carries no\n// streaming marker NEAT parses — a bidi / server-streaming RPC looks like a unary\n// one on the wire but for its per-message span events — so a span longer than the\n// ceiling is treated as long-lived. This is what catches flagd's `EventStream`.\n// Override via NEAT_LATENCY_STREAM_CEILING_MS (a positive number of ms).\nconst DEFAULT_LATENCY_STREAM_CEILING_MS = 60_000\n\nfunction latencyStreamCeilingMs(): number {\n  const raw = process.env.NEAT_LATENCY_STREAM_CEILING_MS\n  if (!raw) return DEFAULT_LATENCY_STREAM_CEILING_MS\n  const n = Number(raw)\n  if (Number.isFinite(n) && n > 0) return n\n  console.warn(\n    `[neat] NEAT_LATENCY_STREAM_CEILING_MS could not be parsed (${raw}); using default`,\n  )\n  return DEFAULT_LATENCY_STREAM_CEILING_MS\n}\n\n// True when a captured response header names the SSE content type\n// (`text/event-stream`). OTel HTTP instrumentation records captured response\n// headers as `http.response.header.<name>`; SDKs differ on whether the header\n// name keeps its dash or normalises it to `_`, and the value can arrive as a\n// string or a single-element array — read both spellings and both shapes,\n// honestly absent otherwise.\nfunction spanServesEventStream(attrs: Record<string, AttributeValue>): boolean {\n  for (const key of [\n    'http.response.header.content-type',\n    'http.response.header.content_type',\n  ]) {\n    const v = attrs[key]\n    const values = Array.isArray(v) ? v : v !== undefined && v !== null ? [v] : []\n    for (const item of values) {\n      if (typeof item === 'string' && item.toLowerCase().includes('text/event-stream')) {\n        return true\n      }\n    }\n  }\n  return false\n}\n\n// A span whose duration is the whole stream's lifetime rather than a per-request\n// latency. Such a span is kept out of the latency digest only (ADR-208) — every\n// other part of its signal records normally.\nexport function spanIsStreaming(\n  span: ParsedSpan,\n  ceilingMs = latencyStreamCeilingMs(),\n): boolean {\n  if (span.websocketChannel !== undefined) return true\n  if (spanServesEventStream(span.attributes)) return true\n  // durationNanos is a bigint; compare in nanos so no float round-trip is needed.\n  return span.durationNanos > BigInt(Math.round(ceilingMs)) * 1_000_000n\n}\n\n// An attribute bag — either a live span's `attributes` or the passthrough set a\n// recorded ErrorEvent carries. The message helpers read from both, so the same\n// \"what failed here\" logic that names an incident at record time can re-derive\n// it at read time (dedupeIncidents).\ntype AttrBag = Record<string, unknown>\n\n// Read the HTTP response status off an attribute bag. OTel semconv renamed this\n// attribute — modern SDKs write `http.response.status_code`, older ones\n// `http.status_code`. Returns undefined when neither is present or parseable, so\n// a span with no response status is never misclassified as a failure.\nfunction httpResponseStatusFromAttrs(attrs: AttrBag): number | undefined {\n  for (const key of ['http.response.status_code', 'http.status_code']) {\n    const v = attrs[key]\n    if (typeof v === 'number' && Number.isFinite(v)) return v\n    if (typeof v === 'string') {\n      const n = Number(v)\n      if (Number.isFinite(n)) return n\n    }\n  }\n  return undefined\n}\n\nfunction httpResponseStatus(span: ParsedSpan): number | undefined {\n  return httpResponseStatusFromAttrs(span.attributes)\n}\n\n// A human incident line built from the HTTP context a server span carries even\n// when no exception event was recorded — an Express error handler that answers\n// 500 cleanly leaves `span.exception` empty but still carries the route and\n// status. \"500 on GET /users/:id\" reads better than the literal 'unknown\n// error'. Returns undefined when the bag has no usable HTTP context, so a\n// non-HTTP failure falls through to nonHttpFailureMessage / 'unknown error'.\n// Method/route follow the OTel semconv rename (modern `http.request.method` /\n// legacy `http.method`; `http.route` matched template, `http.target` / `url.path`\n// concrete-path fallback).\nfunction httpFailureMessageFromAttrs(attrs: AttrBag): string | undefined {\n  const status = httpResponseStatusFromAttrs(attrs)\n  const route = pickAttrFrom(attrs, 'http.route', 'http.target', 'url.path')\n  const method = pickAttrFrom(attrs, 'http.request.method', 'http.method')\n  const where = route ? `${method ? `${method} ` : ''}${route}` : undefined\n  if (status !== undefined && where) return `${status} on ${where}`\n  if (status !== undefined) return `HTTP ${status}`\n  if (where) return `error on ${where}`\n  return undefined\n}\n\n// Canonical gRPC status code → name (grpc/status.proto). Fixed protocol\n// constants shared by every gRPC implementation — not driver/engine data, so\n// they don't belong in compat.json (Rule 8 governs the latter, not a wire enum).\nconst GRPC_STATUS_NAMES: Record<number, string> = {\n  1: 'CANCELLED',\n  2: 'UNKNOWN',\n  3: 'INVALID_ARGUMENT',\n  4: 'DEADLINE_EXCEEDED',\n  5: 'NOT_FOUND',\n  6: 'ALREADY_EXISTS',\n  7: 'PERMISSION_DENIED',\n  8: 'RESOURCE_EXHAUSTED',\n  9: 'FAILED_PRECONDITION',\n  10: 'ABORTED',\n  11: 'OUT_OF_RANGE',\n  12: 'UNIMPLEMENTED',\n  13: 'INTERNAL',\n  14: 'UNAVAILABLE',\n  15: 'DATA_LOSS',\n  16: 'UNAUTHENTICATED',\n}\n\nfunction grpcStatusCodeFromAttrs(attrs: AttrBag): number | undefined {\n  const v = attrs['rpc.grpc.status_code']\n  if (typeof v === 'number' && Number.isFinite(v)) return v\n  if (typeof v === 'string') {\n    const n = Number(v)\n    if (Number.isFinite(n)) return n\n  }\n  return undefined\n}\n\n// What counts as an OBSERVED error on a span — the boolean that increments an\n// edge's `errorCount`, the signal get_root_cause roots its failing-CALLS chain\n// on (ADR-209). Span status ERROR is the explicit marker, but most gRPC and HTTP\n// microservice SDKs leave the span status UNSET and put the outcome in an\n// attribute instead (issue #1065): a non-OK gRPC status (`rpc.grpc.status_code`\n// != 0; 0 is OK) or an HTTP 5xx server response. Reading all three keeps a\n// gRPC-based stack's failures from being invisible to RCA — a status-only gate\n// recorded zero errors on an otel-demo `checkout` whose 3,349 failing spans were\n// all `rpc.grpc.status_code=13` with UNSET status, so RCA had nothing to root on.\n// HTTP 4xx is deliberately excluded here: a client error is not the callee\n// failing, and a 4xx run is coalesced into its own incident separately\n// (advance4xxBurst) rather than counted as an edge error.\nfunction spanRecordsError(span: ParsedSpan): boolean {\n  if (span.statusCode === 2) return true\n  const grpc = grpcStatusCodeFromAttrs(span.attributes)\n  if (grpc !== undefined && grpc !== 0) return true\n  const httpStatus = httpResponseStatusFromAttrs(span.attributes)\n  if (httpStatus !== undefined && httpStatus >= 500) return true\n  return false\n}\n\n// A non-HTTP failure still carries its cause in span attributes — a non-OK gRPC\n// status, or a transport-level connection error (ECONNREFUSED reaching a peer).\n// Reading them keeps the incident from degrading to the literal 'unknown error'\n// when the span has no exception event and no HTTP response code. Returns\n// undefined for a span carrying neither, so the 'unknown error' floor still\n// applies to a genuinely opaque failure (issue #624).\nfunction nonHttpFailureMessageFromAttrs(attrs: AttrBag): string | undefined {\n  const grpc = grpcStatusCodeFromAttrs(attrs)\n  if (grpc !== undefined && grpc !== 0) {\n    const name = GRPC_STATUS_NAMES[grpc] ?? `status ${grpc}`\n    const detail = pickAttrFrom(attrs, 'rpc.grpc.status_message')\n    return detail ? `gRPC ${name}: ${detail}` : `gRPC ${name}`\n  }\n  // Transport/connection failure — OTel's `error.type` carries the errno\n  // (ECONNREFUSED, ETIMEDOUT, …) or the exception class for a call that never\n  // got a response. Skip the HTTP status-class forms (\"500\", \"_OTHER\") that\n  // http semconv also writes there; the HTTP path above owns those.\n  const errType = pickAttrFrom(attrs, 'error.type')\n  if (errType && errType !== '_OTHER' && !/^\\d+$/.test(errType)) {\n    const peer = pickAttrFrom(attrs, 'server.address', 'net.peer.name', 'net.host.name')\n    return peer ? `${errType} connecting to ${peer}` : errType\n  }\n  return undefined\n}\n\n// The incident's human message: the recorded exception first, then the HTTP\n// context a server span still carries, then a non-HTTP (gRPC / connection)\n// failure read from attributes, and only then the 'unknown error' floor. Shared\n// by every incident write path so the fallback chain can't drift between the\n// receiver's synchronous write and handleSpan's inline write.\nfunction incidentMessage(span: ParsedSpan): string {\n  return (\n    span.exception?.message ??\n    httpFailureMessageFromAttrs(span.attributes) ??\n    nonHttpFailureMessageFromAttrs(span.attributes) ??\n    'unknown error'\n  )\n}\n\n// In-flight 4xx burst against one (source, peer) pair. Lives on IngestContext so\n// it survives across spans without leaking into module state shared by every\n// project. firstTs/lastTs are the span timestamps (ADR-033 — span time, not\n// wall clock); codes counts each 4xx by status so the dominant one can be named\n// when the burst flushes.\ninterface BurstState {\n  count: number\n  firstTs: string\n  lastTs: string\n  lastMs: number\n  codes: Map<number, number>\n}\n\nfunction nowIso(ctx: IngestContext): string {\n  return new Date(ctx.now ? ctx.now() : Date.now()).toISOString()\n}\n\n// One-time-per-session-per-project warning for spans whose resource omits\n// `service.name`. The OTel spec requires SDKs to set it; customised exporters\n// occasionally don't. Routing the span to `service:unidentified` keeps\n// diagnostic visibility intact (silent drop hides a real SDK misconfiguration);\n// the warning gives an operator one line of stderr per project to act on.\n// See docs/contracts/otlp-routing.md §Fallback when `resource.service.name`\n// is missing.\nconst unidentifiedWarnedProjects = new Set<string>()\nfunction warnUnidentifiedSpan(project: string): void {\n  if (unidentifiedWarnedProjects.has(project)) return\n  unidentifiedWarnedProjects.add(project)\n  console.warn(\n    `[neatd] span lacked service.name; routed to 'unidentified' in project ${project}; check your OTel SDK config.`,\n  )\n}\n\n// Test seam — production code never calls this. Tests that exercise the\n// once-per-session contract reset between cases so each assertion sees a\n// fresh warned-set.\nexport function resetUnidentifiedSpanWarnings(): void {\n  unidentifiedWarnedProjects.clear()\n}\n\n// One-time-per-session-per-service audit for a compiled `dist/...js` call site\n// that carried no adjacent source map (file-awareness.md §4 + §6). Without a\n// map, ingest can't reconcile the observed dist file to the static `src/...ts`\n// the extractor parsed — the dist path is the honest answer, never a fabricated\n// src path. The leak this surfaces (issue #430) was hiding behind an absolute\n// path prefix; once the path is service-root-relative the mismatch is legible,\n// and this line tells the operator how to close it.\nconst noSourceMapWarnedServices = new Set<string>()\nfunction warnNoSourceMaps(serviceName: string): void {\n  if (noSourceMapWarnedServices.has(serviceName)) return\n  noSourceMapWarnedServices.add(serviceName)\n  console.warn(\n    `[neat] ${serviceName}: no .map files found under dist/; observed file edges will land on dist paths, not src. Set sourceMap: true in tsconfig to enable file-level reconciliation.`,\n  )\n}\n\n// Test seam — mirrors resetUnidentifiedSpanWarnings for the once-per-service\n// audit above.\nexport function resetNoSourceMapWarnings(): void {\n  noSourceMapWarnedServices.clear()\n}\n\nfunction pickAttrFrom(attrs: AttrBag, ...keys: string[]): string | undefined {\n  for (const k of keys) {\n    const v = attrs[k]\n    if (typeof v === 'string' && v.length > 0) return v\n  }\n  return undefined\n}\n\nfunction pickAttr(span: ParsedSpan, ...keys: string[]): string | undefined {\n  return pickAttrFrom(span.attributes, ...keys)\n}\n\nfunction hostFromUrl(u: string | undefined): string | undefined {\n  if (!u) return undefined\n  try {\n    return new URL(u).hostname\n  } catch {\n    return undefined\n  }\n}\n\n// OTel HTTP/db semconv has gone through several names for \"the host on the\n// other end of this call.\" Try the modern ones first, fall back to the legacy\n// ones, then last resort parse out of a full URL.\nfunction pickAddress(span: ParsedSpan): string | undefined {\n  return (\n    pickAttr(span, 'server.address', 'net.peer.name', 'net.host.name') ??\n    hostFromUrl(pickAttr(span, 'url.full', 'http.url'))\n  )\n}\n\n// The callee host for the cross-service CALLS path (ADR-251, #1424). A span with no kind\n// (undefined / UNSPECIFIED, the OpenTracing and OpenCensus bridges) says nothing\n// about which side of the call it sits on, and its request URL names where the\n// request went: on the receiving side that is the span's own address (nginx's\n// request span carries `http.url` at its own ClusterIP). So for a kindless span\n// only an attribute that names the peer stands in as the callee, never the URL.\n// A kinded CLIENT/PRODUCER span is the caller, so its URL host is the callee.\nfunction calleeAddress(span: ParsedSpan): string | undefined {\n  if (span.kind === undefined || span.kind === 0) {\n    return pickAttr(span, 'server.address', 'net.peer.name')\n  }\n  return pickAddress(span)\n}\n\n// A loopback peer address is this host talking to itself, never a distinct\n// upstream service. Cross-service correlation on the callee's SERVER span (the\n// parent-span fallback, ADR-033) recovers the real peer, so a loopback address\n// on a CLIENT span must not mint a standalone frontier:localhost /\n// frontier:127.0.0.1 that duplicates that resolved edge (issues #590, #577).\n// Scoped to the cross-service CALLS path — a loopback database is a real local\n// dependency and keeps its CONNECTS_TO edge.\nfunction isLoopbackHost(host: string): boolean {\n  const h = host.toLowerCase()\n  return (\n    h === 'localhost' ||\n    h === 'ip6-localhost' ||\n    h === '::1' ||\n    h === '[::1]' ||\n    /^127(?:\\.\\d{1,3}){3}$/.test(h)\n  )\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Call-site capture (file-awareness.md §4)\n//\n// The call-site processor stamps the source location on CLIENT/PRODUCER spans.\n// OpenTelemetry stabilized the code attributes at semconv v1.33 —\n// `code.file.path` / `code.line.number` / `code.function.name` — renaming the\n// prior `code.filepath` / `code.lineno` / `code.function`. NEAT's own emit\n// templates (installers/templates.ts, and the Python processor, ADR-151) and any\n// third-party instrumentation may carry either generation, so the read accepts\n// BOTH, stable-name first. When present, an OBSERVED relationship originates from\n// the file rather than the service; a span with neither stays service-level, and\n// evidence is never fabricated (§6).\nconst CODE_FILE_PATH_ATTR = 'code.file.path' // semconv ≥1.33 (stable)\nconst CODE_FILEPATH_ATTR = 'code.filepath' // prior convention\nconst CODE_LINE_NUMBER_ATTR = 'code.line.number'\nconst CODE_LINENO_ATTR = 'code.lineno'\nconst CODE_FUNCTION_NAME_ATTR = 'code.function.name'\nconst CODE_FUNCTION_ATTR = 'code.function'\n\n// Read the source call site off an attribute bag, accepting the stable\n// (semconv ≥1.33) and prior attribute names. Exported so every code.* reader —\n// edge attribution here, incident localization in traverse.ts — shares one\n// definition and the names can't drift across sites.\nexport function codeFilepathOf(attrs: Record<string, AttributeValue>): string | undefined {\n  const stable = attrs[CODE_FILE_PATH_ATTR]\n  if (typeof stable === 'string' && stable.length > 0) return stable\n  const prior = attrs[CODE_FILEPATH_ATTR]\n  return typeof prior === 'string' && prior.length > 0 ? prior : undefined\n}\nexport function codeLinenoOf(attrs: Record<string, AttributeValue>): number | undefined {\n  const stable = attrs[CODE_LINE_NUMBER_ATTR]\n  if (typeof stable === 'number' && Number.isFinite(stable)) return stable\n  const prior = attrs[CODE_LINENO_ATTR]\n  return typeof prior === 'number' && Number.isFinite(prior) ? prior : undefined\n}\nexport function codeFunctionOf(attrs: Record<string, AttributeValue>): string | undefined {\n  const stable = attrs[CODE_FUNCTION_NAME_ATTR]\n  if (typeof stable === 'string' && stable.length > 0) return stable\n  const prior = attrs[CODE_FUNCTION_ATTR]\n  return typeof prior === 'string' && prior.length > 0 ? prior : undefined\n}\n\nfunction toPosix(p: string): string {\n  return p.split('\\\\').join('/')\n}\n\nfunction languageForExt(relPath: string): string | undefined {\n  const dot = relPath.lastIndexOf('.')\n  if (dot === -1) return undefined\n  switch (relPath.slice(dot).toLowerCase()) {\n    case '.py':\n      return 'python'\n    case '.go':\n      return 'go'\n    case '.ts':\n    case '.tsx':\n      return 'typescript'\n    case '.js':\n    case '.jsx':\n    case '.mjs':\n    case '.cjs':\n      return 'javascript'\n    default:\n      return undefined\n  }\n}\n\n// Join the runtime `code.filepath` against the service root so the OBSERVED\n// relPath lines up with the EXTRACTED service-relative path (file-awareness.md\n// §4 + §7). ServiceNode.repoPath is the scanPath-relative package dir; its\n// segments appear inside the absolute runtime path, so anchoring on it recovers\n// the package-relative tail. With no usable anchor, the real runtime path is\n// returned in a relative-looking form — honest, even if it doesn't align with a\n// static src path. Never fabricated.\nfunction relPathForRuntimeFile(\n  filepath: string,\n  serviceNode?: ServiceNode,\n  scanPath?: string,\n): string | null {\n  let p = toPosix(filepath).replace(/^file:\\/\\//, '')\n  // When ingest knows the absolute scan root, the service's absolute root is\n  // `scanPath/<repoPath>`. Stripping it directly recovers the service-relative\n  // tail (`dist/foo.js`) even for a single-package service whose `repoPath` is\n  // empty — the segment anchor below has nothing to grab in that case, so the\n  // absolute path used to leak into the FileNode key (issue #430).\n  if (scanPath && scanPath.length > 0) {\n    const absRoot = toPosix(path.resolve(scanPath, serviceNode?.repoPath ?? ''))\n    const anchor = absRoot.endsWith('/') ? absRoot : `${absRoot}/`\n    if (p.startsWith(anchor)) return p.slice(anchor.length)\n  }\n  const root = serviceNode?.repoPath\n  if (root && root !== '.' && root.length > 0) {\n    const rootPosix = toPosix(root)\n    const anchor = `/${rootPosix}/`\n    const idx = p.lastIndexOf(anchor)\n    if (idx !== -1) return p.slice(idx + anchor.length)\n    const base = rootPosix.split('/').filter(Boolean).pop()\n    if (base) {\n      const baseAnchor = `/${base}/`\n      const bidx = p.lastIndexOf(baseAnchor)\n      if (bidx !== -1) return p.slice(bidx + baseAnchor.length)\n    }\n  }\n  p = p.replace(/^[A-Za-z]:/, '').replace(/^\\/+/, '')\n  return p.length > 0 ? p : null\n}\n\n// Exported so the connectors plane (packages/core/src/connectors/index.ts,\n// docs/contracts/connectors.md) can build one from a signal's own callSite —\n// a connector's file:line comes from the provider's telemetry rather than an\n// OTel span's code.* attributes, but reconciles onto the same EXTRACTED\n// FileNode through the same primitives below.\nexport interface CallSite {\n  relPath: string\n  line?: number\n  fn?: string\n  // The service-relative dist path the call site was captured on, when ingest\n  // resolved it through a source map to a different (source) `relPath`\n  // (file-awareness.md §4). Surfaces as FileNode.originalPath. Absent when the\n  // captured frame was already source-grained.\n  originalRelPath?: string\n}\n\n// dist→src source-map resolution (file-awareness.md §4). A runtime call site in\n// a compiled `dist/...js` is resolved through a disk-adjacent `.map` to the\n// original `src/...ts`, so an OBSERVED edge lands on the source file an agent\n// can open. Same-host only — when the daemon's filesystem doesn't carry the map\n// (a service that ran on a different machine) the dist frame is kept, honestly,\n// never fabricated (§6). Each dist file is read from disk once: a present map\n// caches its consumer, an absent one caches `null`. Synchronous reads keep\n// callSiteFromSpan synchronous; the cost is amortised across a file's spans.\nconst sourceMapCache = new Map<\n  string,\n  { consumer: sourceMapJs.SourceMapConsumer; dir: string } | null\n>()\n\ninterface ResolvedSrc {\n  filepath: string\n  line?: number\n}\n\nfunction resolveDistToSrc(absFilepath: string, line?: number): ResolvedSrc | null {\n  if (!absFilepath.endsWith('.js')) return null\n  let entry = sourceMapCache.get(absFilepath)\n  if (entry === undefined) {\n    entry = null\n    const mapPath = `${absFilepath}.map`\n    try {\n      if (existsSync(mapPath)) {\n        const raw = JSON.parse(readFileSync(mapPath, 'utf8')) as unknown\n        const consumer = new sourceMapJs.SourceMapConsumer(raw as never)\n        entry = { consumer, dir: path.dirname(mapPath) }\n      }\n    } catch {\n      entry = null\n    }\n    sourceMapCache.set(absFilepath, entry)\n  }\n  if (!entry) return null\n  try {\n    const queryLine = line !== undefined && Number.isFinite(line) ? line : 1\n    // tsc anchors every mapping at the token's real (indented) column, so a\n    // column-0 lookup under the default GREATEST_LOWER_BOUND bias finds no\n    // mapping on any indented statement — which is exactly the call site an\n    // OBSERVED CLIENT span reports for compiled Nest/TS code (issue #915). The\n    // map is on disk and read fine; only the position lookup came back empty,\n    // so the whole dist frame used to fall through to the raw path. Retry the\n    // lookup biased to the LEAST_UPPER_BOUND — the first mapping at or after\n    // column 0 on that generated line — so the line resolves to its source.\n    let pos = entry.consumer.originalPositionFor({ line: queryLine, column: 0 })\n    if (!pos || !pos.source) {\n      pos = entry.consumer.originalPositionFor({\n        line: queryLine,\n        column: 0,\n        bias: sourceMapJs.SourceMapConsumer.LEAST_UPPER_BOUND,\n      })\n    }\n    if (!pos || !pos.source) return null\n    const root = entry.consumer.sourceRoot ?? ''\n    const resolved = path.resolve(entry.dir, root, pos.source)\n    return { filepath: resolved, ...(pos.line ? { line: pos.line } : {}) }\n  } catch {\n    return null\n  }\n}\n\n// Whether a disk-adjacent `.map` was found for a compiled `dist/...js` frame.\n// Reuses the module-level cache resolveDistToSrc already warmed — a non-null\n// entry means the map is present (resolution may still have missed a specific\n// line), a null entry means none was on disk. Lets the missing-map audit stay\n// honest: it must not claim \"no .map files found\" when a map exists but a lone\n// line failed to resolve (file-awareness.md §6, issue #915).\nfunction hasAdjacentSourceMap(absFilepath: string): boolean {\n  return sourceMapCache.get(absFilepath) != null\n}\n\n// Read the call-site attributes off a span. Returns null when the span carries\n// no `code.filepath` (SERVER spans, un-instrumented peers, callee side) so the\n// caller falls back to a service-level edge.\nfunction callSiteFromSpan(\n  span: ParsedSpan,\n  serviceNode?: ServiceNode,\n  scanPath?: string,\n): CallSite | null {\n  const filepath = codeFilepathOf(span.attributes)\n  if (filepath === undefined) return null\n  let line = codeLinenoOf(span.attributes)\n  // Resolve a compiled dist frame to its source before computing the service-\n  // relative path, so the FileNode lands on the original `src/...ts`.\n  const abs = toPosix(filepath).replace(/^file:\\/\\//, '')\n  const resolved = resolveDistToSrc(abs, line)\n  let effectivePath = filepath\n  let originalRelPath: string | undefined\n  if (resolved) {\n    originalRelPath = relPathForRuntimeFile(filepath, serviceNode, scanPath) ?? undefined\n    effectivePath = resolved.filepath\n    if (resolved.line !== undefined) line = resolved.line\n  }\n  const relPath = relPathForRuntimeFile(effectivePath, serviceNode, scanPath)\n  if (!relPath) return null\n  // A compiled `dist/...js` call site that didn't resolve through a map keeps\n  // the (honest) dist path. Surface the absence once per service so the\n  // operator can enable source maps and recover src-level reconciliation\n  // (file-awareness.md §4 + §6, issue #430). Only warn when no `.map` is\n  // actually on disk — a present-but-unresolved line must not masquerade as a\n  // missing map, the misdiagnosis issue #915 called out.\n  if (\n    !resolved &&\n    abs.endsWith('.js') &&\n    relPath.startsWith('dist/') &&\n    !hasAdjacentSourceMap(abs) &&\n    serviceNode?.name\n  ) {\n    warnNoSourceMaps(serviceNode.name)\n  }\n  const fn = codeFunctionOf(span.attributes)\n  return {\n    relPath,\n    ...(line !== undefined ? { line } : {}),\n    ...(fn ? { fn } : {}),\n    ...(originalRelPath && originalRelPath !== relPath ? { originalRelPath } : {}),\n  }\n}\n\n// Reconcile a runtime-derived relPath onto the service-relative path the\n// extractor already minted, so OBSERVED and EXTRACTED FileNodes for the same\n// source file fuse into ONE node instead of two disjoint subgraphs\n// (file-awareness.md §4 — ingest joins the runtime path against the service\n// root to land the edge on a FileNode).\n//\n// relPathForRuntimeFile anchors the absolute `code.filepath` against scanPath /\n// repoPath. When that anchor can't be found — no scanPath wired, or the span\n// was emitted from a service whose absolute root differs from the daemon's\n// checkout (a container image rooted at `/app`, a relocated clone) — the\n// leftover relPath still carries the unanchored leading segments\n// (`app/src/foo.ts`, `Users/me/repo/src/foo.ts`) and forks a parallel FileNode\n// keyed off the absolute path. That splits the graph: the OBSERVED layer never\n// lands on the EXTRACTED `src/foo.ts` node, and divergence/traversal see two\n// half-graphs for one file.\n//\n// The extractor's FileNode paths are ground truth for which service-relative\n// paths exist. Recover the right one by matching the longest EXTRACTED (non-\n// OTel) FileNode path that is a trailing segment-suffix of the runtime relPath.\n// A match means the runtime path is the same file the extractor parsed, just\n// carrying extra leading directories the anchor couldn't strip — reuse the\n// extractor's path so both layers key the same node. No match means the file is\n// genuinely OTel-only; the honest runtime path stands (never fabricated, §6).\nexport function reconcileObservedRelPath(\n  graph: NeatGraph,\n  serviceName: string,\n  relPath: string,\n): string {\n  // Already lands on a known node (the anchor resolved cleanly, or a prior span\n  // created this node) — fused, nothing to recover.\n  if (graph.hasNode(fileId(serviceName, relPath))) return relPath\n  let best: string | null = null\n  graph.forEachNode((_id, attrs) => {\n    const a = attrs as FileNode & { type?: string }\n    if (a.type !== NodeType.FileNode || a.service !== serviceName) return\n    // Only fuse onto a statically-known file. An existing OTel-only node would\n    // already have matched the hasNode short-circuit above.\n    if (a.discoveredVia === 'otel') return\n    const p = a.path\n    if (!p) return\n    if ((relPath === p || relPath.endsWith(`/${p}`)) && (!best || p.length > best.length)) {\n      best = p\n    }\n  })\n  return best ?? relPath\n}\n\n// Ensure the FileNode for an observed call site and the owning service's\n// OBSERVED `CONTAINS` edge both exist, returning the FileNode id so the caller\n// can originate the relationship from it (file-awareness.md §1–2 + §4). The\n// CONTAINS edge carries no `lastObserved` — structural ownership doesn't go\n// STALE when traffic quiets (markStaleEdges skips edges without lastObserved),\n// and divergence detection skips CONTAINS so an OTel-only file node doesn't\n// surface as a missing-extracted finding.\nexport function ensureObservedFileNode(\n  graph: NeatGraph,\n  serviceName: string,\n  serviceNodeId: string,\n  callSite: CallSite,\n): string {\n  // Key the file node on the service the span already FUSED onto, not the raw\n  // span service.name. ensureServiceNode resolves a differently-cased or\n  // env-tagged OTEL_SERVICE_NAME onto the extracted service (`proofrun` → the\n  // ServiceNode named `ProofRun`, #880). Keying the file on the raw name here\n  // forks a `file:proofrun:…` twin off the extracted `file:ProofRun:…` — the\n  // file-level sibling of #880. Reading the canonical name back off the fused\n  // service node also lets reconcileObservedRelPath recover the extractor's\n  // relative path from a runtime absolute path: its file scan filters by an\n  // exact-cased `service`, so the raw name skipped every extracted file before\n  // the suffix match could run. Both forks — case and absolute path — close here.\n  const svcAttrs = graph.hasNode(serviceNodeId) ? (graph.getNodeAttributes(serviceNodeId) as ServiceNode) : undefined\n  const canonicalService =\n    svcAttrs && svcAttrs.type === NodeType.ServiceNode && typeof svcAttrs.name === 'string'\n      ? svcAttrs.name\n      : serviceName\n  const relPath = reconcileObservedRelPath(graph, canonicalService, callSite.relPath)\n  const fileNodeId = fileId(canonicalService, relPath)\n  if (!graph.hasNode(fileNodeId)) {\n    const language = languageForExt(relPath)\n    const node: FileNode = {\n      id: fileNodeId,\n      type: NodeType.FileNode,\n      service: canonicalService,\n      path: relPath,\n      ...(language ? { language } : {}),\n      ...(callSite.originalRelPath ? { originalPath: callSite.originalRelPath } : {}),\n      discoveredVia: 'otel',\n    }\n    graph.addNode(fileNodeId, node)\n  }\n  const containsId = makeObservedEdgeId(EdgeType.CONTAINS, serviceNodeId, fileNodeId)\n  if (!graph.hasEdge(containsId)) {\n    const edge: GraphEdge = {\n      id: containsId,\n      source: serviceNodeId,\n      target: fileNodeId,\n      type: EdgeType.CONTAINS,\n      provenance: Provenance.OBSERVED,\n    }\n    graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge)\n  }\n  // Observed-first edges land one grain finer than the file when the call site\n  // falls inside a symbol's definition span (ADR-158, file-awareness.md §4).\n  return landObservedSymbol(graph, fileNodeId, canonicalService, relPath, callSite)\n}\n\n// The terminal name of a source-declared qualname (`OrderService.create` →\n// `create`) — what `code.function` carries on a span, and the tiebreaker that\n// picks the intended symbol when nested definition spans both contain the line.\nfunction terminalName(qualname: string): string {\n  const dot = qualname.lastIndexOf('.')\n  return dot === -1 ? qualname : qualname.slice(dot + 1)\n}\n\n// Given the symbols whose definition span contains the observed `code.line`,\n// pick the one the edge lands on. Line-in-span is primary (every candidate\n// already contains the line); `code.function` is the tiebreaker and drift check —\n// when it names one of the candidates, that symbol wins; otherwise the innermost\n// (smallest) span wins, since a call site inside nested definitions belongs to\n// the tightest one enclosing it (ADR-158 point 4).\nfunction pickContainingSymbol(\n  candidates: { id: string; symbol: SymbolNode }[],\n  fn: string | undefined,\n): string {\n  const bySpan = (a: { symbol: SymbolNode }, b: { symbol: SymbolNode }): number => {\n    const sizeA = a.symbol.span.endLine - a.symbol.span.startLine\n    const sizeB = b.symbol.span.endLine - b.symbol.span.startLine\n    if (sizeA !== sizeB) return sizeA - sizeB\n    // Deterministic tiebreak on an exact-size tie: the later-starting span is the\n    // more deeply nested one.\n    return b.symbol.span.startLine - a.symbol.span.startLine\n  }\n  if (fn) {\n    const named = candidates.filter((c) => terminalName(c.symbol.qualname) === fn)\n    if (named.length > 0) return [...named].sort(bySpan)[0]!.id\n  }\n  return [...candidates].sort(bySpan)[0]!.id\n}\n\n// Mint the OBSERVED symbol a runtime call landed on that static never produced —\n// the symbol-grain missing-extracted signal (ADR-158 point 5, lifecycle.md\n// auto-create-and-merge). `code.function` names it, so the symbol is honest, not\n// guessed; the span is the single observed line NEAT can vouch for, and static\n// fields override it on the next extract pass if the definition later resolves.\n// The file owns it through an OBSERVED `file ──CONTAINS──▶ symbol` edge.\nfunction ensureObservedSymbolNode(\n  graph: NeatGraph,\n  fileNodeId: string,\n  service: string,\n  relPath: string,\n  fn: string,\n  line: number,\n): string {\n  const sid = symbolId(service, relPath, fn)\n  if (!graph.hasNode(sid)) {\n    const node: SymbolNode = {\n      id: sid,\n      type: NodeType.SymbolNode,\n      kind: 'function',\n      qualname: fn,\n      span: { startLine: line, endLine: line },\n      service,\n      relPath,\n      discoveredVia: 'otel',\n    }\n    graph.addNode(sid, node)\n  }\n  const containsId = makeObservedEdgeId(EdgeType.CONTAINS, fileNodeId, sid)\n  if (!graph.hasEdge(containsId)) {\n    const edge: GraphEdge = {\n      id: containsId,\n      source: fileNodeId,\n      target: sid,\n      type: EdgeType.CONTAINS,\n      provenance: Provenance.OBSERVED,\n    }\n    graph.addEdgeWithKey(containsId, fileNodeId, sid, edge)\n  }\n  return sid\n}\n\n// Resolve the observed edge's origin to a symbol under the file when the call\n// site's line falls inside a symbol's definition span; otherwise land on the file\n// (ADR-158, file-awareness.md §4–§5). Boundary-grained, not a full call graph:\n// the returned node is what the edge originates from.\n//\n// Degrade to the file honestly when there is no line, or the line is inside no\n// symbol span and either the file was never symbol-extracted (no symbols to be\n// \"missing\" from) or the span carries no function name. When the file *was*\n// symbol-extracted, the line is in no static symbol, and `code.function` names\n// the executing function, mint an `otel` symbol — the missing-extracted signal at\n// symbol grain (point 5), never a degrade that hides the dynamic wiring.\nfunction landObservedSymbol(\n  graph: NeatGraph,\n  fileNodeId: string,\n  service: string,\n  relPath: string,\n  callSite: CallSite,\n  // Whether to MINT an observed-only symbol when the line is in no static symbol\n  // span (the missing-extracted-at-symbol-grain signal, ADR-158 §5). The edge\n  // mint path leaves it true; the incident resolver (ADR-191) passes false so it\n  // reads the containing static symbol without mutating — safe at the receiver,\n  // which runs before reply and off the mutation queue (otel-ingest §Non-blocking).\n  mint = true,\n): string {\n  const line = callSite.line\n  if (line === undefined) return fileNodeId\n\n  let sawSymbol = false\n  const candidates: { id: string; symbol: SymbolNode }[] = []\n  graph.forEachOutboundEdge(fileNodeId, (_edge, edgeAttrs, _source, target) => {\n    if (edgeAttrs.type !== EdgeType.CONTAINS) return\n    const t = graph.getNodeAttributes(target) as GraphNode\n    if (t.type !== NodeType.SymbolNode) return\n    sawSymbol = true\n    if (line >= t.span.startLine && line <= t.span.endLine) {\n      candidates.push({ id: target, symbol: t })\n    }\n  })\n\n  if (candidates.length > 0) return pickContainingSymbol(candidates, callSite.fn)\n\n  if (mint && sawSymbol && callSite.fn) {\n    return ensureObservedSymbolNode(graph, fileNodeId, service, relPath, callSite.fn, line)\n  }\n  return fileNodeId\n}\n\n// Edge id helpers live in @neat.is/types/identity.ts (ADR-029). The local\n// signatures below preserve the (type, source, target) argument order ingest.ts\n// has used historically while delegating to the canonical wire-format helpers.\nfunction makeObservedEdgeId(type: EdgeTypeValue, source: string, target: string): string {\n  return observedEdgeId(source, target, type)\n}\n\nfunction makeInferredEdgeId(type: EdgeTypeValue, source: string, target: string): string {\n  return inferredEdgeId(source, target, type)\n}\n\nconst INFERRED_CONFIDENCE = 0.6\nconst STITCH_MAX_DEPTH = 2\n\n// The trace stitcher only reasons about runtime *dependency* edges — the ones an\n// error actually propagates along (a service calling a service, connecting to a\n// datastore, a declared runtime dependency). Structural edges (CONTAINS a file,\n// IMPORTS a module, CONFIGURED_BY a ConfigNode, RUNS_ON a host) are static facts\n// learned by extraction; a 500 says nothing new about them. Minting an INFERRED\n// twin of a structural EXTRACTED edge would corrupt the trust signal — the twin\n// (conf 0.6) outranks the ground-truth EXTRACTED edge (0.85) under PROV_RANK, so\n// consumer queries would surface the inference in place of the hard fact\n// (docs/contracts/trace-stitcher.md — dependency-edge-type allowlist).\nconst STITCH_EDGE_TYPES = new Set<EdgeTypeValue>([\n  EdgeType.CALLS,\n  EdgeType.CONNECTS_TO,\n  EdgeType.DEPENDS_ON,\n])\n\n// OTLP-wire SpanKind values. The receiver decodes the raw wire integer onto\n// `ParsedSpan.kind` (otel.ts), and the wire enum is offset by one from the\n// `@opentelemetry/api` SpanKind the SDK uses in-process — UNSPECIFIED 0,\n// INTERNAL 1, SERVER 2, CLIENT 3, PRODUCER 4, CONSUMER 5. So we must NOT import\n// `@opentelemetry/api` here: its CLIENT is 2 (= wire SERVER) and PRODUCER is 3\n// (= wire CLIENT), which would gate the wrong kinds. Cross-referenced with the\n// wire fixtures in otel.test.ts (kind 2 = SERVER, kind 3 = CLIENT) and the\n// CLIENT call-site spans in ingest.test.ts (kind 3).\nconst WIRE_SPAN_KIND_CLIENT = 3\nconst WIRE_SPAN_KIND_PRODUCER = 4\nconst WIRE_SPAN_KIND_CONSUMER = 5\n\n// The caller-side gate for the CALLS / CONNECTS_TO paths. A CLIENT or PRODUCER\n// span is the caller/producer side of a service-to-service call or a datastore\n// read; INTERNAL / SERVER spans are not — a SERVER span is the callee, and its\n// edge is minted from its parent CLIENT via the parent-span fallback. Without\n// this gate every INTERNAL span that happens to carry a peer address — e.g. a\n// `tcp.connect` / `tls.connect` to an AWS endpoint — mints a spurious\n// service-level edge (issue #429), because no §4 capture layer stamps `code.*`\n// on INTERNAL spans.\n//\n// CONSUMER spans are handled by the messaging branch in handleSpan, not here:\n// a queue consumer isn't calling a service, it's reading a topic, so it mints a\n// CONSUMES_FROM edge to the destination node (spanMintsMessagingEdge below) —\n// the observed mirror of the static consumer→topic edge, the queue-side pair of\n// the PRODUCER→topic PUBLISHES_TO edge.\n//\n// A span that reports no kind (undefined) or UNSPECIFIED (0) carries no\n// caller/callee signal, so it falls back to the historical unconditional\n// behavior — hand-built and legacy producers keep minting. The leak this gates\n// is always an explicitly-kinded INTERNAL span.\nfunction spanMintsObservedEdge(kind: number | undefined): boolean {\n  if (kind === undefined || kind === 0) return true\n  return kind === WIRE_SPAN_KIND_CLIENT || kind === WIRE_SPAN_KIND_PRODUCER\n}\n\n// The messaging counterpart to the caller-side gate. A PRODUCER span publishes\n// to a destination; a CONSUMER span reads from one. Both sides mint an OBSERVED\n// edge to the topic/queue node — the PRODUCER a PUBLISHES_TO, the CONSUMER a\n// CONSUMES_FROM — so declared and observed queue topology fuse. Only spans that\n// actually carry a messaging destination reach this (handleSpan checks the\n// semconv attrs first), so a stray CONSUMER span with no destination stays inert.\nfunction spanMintsMessagingEdge(kind: number | undefined): boolean {\n  return kind === WIRE_SPAN_KIND_PRODUCER || kind === WIRE_SPAN_KIND_CONSUMER\n}\n\n// The GraphQL execution span is emitted by the service that RESOLVES the\n// operation — a SERVER or INTERNAL span (the instrumentation's `graphql.execute`),\n// never the CLIENT side that only ever sees an opaque `POST /graphql`. Gating out\n// the caller/producer/consumer kinds keeps a client-side operation span from\n// attributing the operation to the caller (client-side operation attribution is\n// deferred, ADR-122); an unkinded / UNSET span still mints, mirroring the\n// caller-side gate's legacy-producer fallback.\nfunction spanServesGraphqlOperation(kind: number | undefined): boolean {\n  return (\n    kind !== WIRE_SPAN_KIND_CLIENT &&\n    kind !== WIRE_SPAN_KIND_PRODUCER &&\n    kind !== WIRE_SPAN_KIND_CONSUMER\n  )\n}\n\n// A GraphQL operation node keyed on (service, operationType, operationName) via\n// graphqlOperationId (ADR-122). Minted observed-first from the execution span so\n// operation-level topology is legible even before any static GraphQL extractor\n// exists; a later static extractor fuses onto the same id. `operationType` is\n// stored lower-cased to match the id's normalisation, so a `query` observed and a\n// `Query` static resolver land on one node. Idempotent — a high-volume operation\n// upserts, never grows the node set.\nfunction ensureGraphqlOperationNode(\n  graph: NeatGraph,\n  serviceName: string,\n  operationType: string,\n  operationName: string,\n): string {\n  const id = graphqlOperationId(serviceName, operationType, operationName)\n  if (graph.hasNode(id)) return id\n  const node: GraphQLOperationNode = {\n    id,\n    type: NodeType.GraphQLOperationNode,\n    name: operationName,\n    service: serviceName,\n    operationType: operationType.toLowerCase(),\n    operationName,\n    discoveredVia: 'otel',\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// The gRPC execution span carrying `rpc.service` / `rpc.method` is emitted on\n// both sides of a call — the SERVER that resolves the method and the CLIENT that\n// invokes it. Only the serving side owns the method (ADR-123): gating out the\n// caller/producer/consumer kinds keeps a CLIENT gRPC span from attributing\n// ownership to the caller (that client span still falls through to the\n// cross-service resolver below, so the caller→callee edge is unaffected).\n// Client→method attribution is deferred. An unkinded / UNSET span still mints,\n// mirroring the graphql and caller-side gates' legacy fallbacks.\nfunction spanServesGrpcMethod(kind: number | undefined): boolean {\n  return (\n    kind !== WIRE_SPAN_KIND_CLIENT &&\n    kind !== WIRE_SPAN_KIND_PRODUCER &&\n    kind !== WIRE_SPAN_KIND_CONSUMER\n  )\n}\n\n// A gRPC method node keyed on (rpcService, rpcMethod) via grpcMethodId (ADR-123).\n// `rpcService` is the fully-qualified `rpc.service` the wire carries verbatim\n// (`orders.OrderService`), so an OBSERVED span and a static `.proto` definition\n// fuse onto one node rather than twinning. Idempotent — a high-volume method\n// upserts, never grows the node set.\nfunction ensureGrpcMethodNode(\n  graph: NeatGraph,\n  rpcService: string,\n  rpcMethod: string,\n): string {\n  const id = grpcMethodId(rpcService, rpcMethod)\n  if (graph.hasNode(id)) return id\n  const node: GrpcMethodNode = {\n    id,\n    type: NodeType.GrpcMethodNode,\n    name: `${rpcService}/${rpcMethod}`,\n    rpcService,\n    rpcMethod,\n    discoveredVia: 'otel',\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// The HTTP upgrade span that opens a WebSocket is emitted by the service that\n// SERVES the channel — a SERVER span (the framework's inbound `GET`), or an\n// unkinded / INTERNAL span from a hand-built handshake. The CLIENT that dials the\n// socket carries the same upgrade header, but the channel belongs to the server\n// (ADR-125), so gating out the caller/producer/consumer kinds keeps a client-side\n// upgrade span from attributing the channel to the caller. An unkinded / UNSET\n// span still mints, mirroring the graphql and gRPC serving-side gates.\nfunction spanServesWebsocketChannel(kind: number | undefined): boolean {\n  return (\n    kind !== WIRE_SPAN_KIND_CLIENT &&\n    kind !== WIRE_SPAN_KIND_PRODUCER &&\n    kind !== WIRE_SPAN_KIND_CONSUMER\n  )\n}\n\n// A WebSocket channel node keyed on (service, channel) via websocketChannelId\n// (ADR-125). Minted OBSERVED-only from the upgrade span — a WebSocket channel is\n// known from observation, never from static extraction, so there is no declared\n// twin to fuse with and no static producer to fill in `path` / `line` (those stay\n// absent, never fabricated — file-awareness.md §6). Idempotent — every reconnect\n// on the same channel upserts, never grows the node set.\nfunction ensureWebsocketChannelNode(\n  graph: NeatGraph,\n  serviceName: string,\n  channel: string,\n): string {\n  const id = websocketChannelId(serviceName, channel)\n  if (graph.hasNode(id)) return id\n  const node: WebSocketChannelNode = {\n    id,\n    type: NodeType.WebSocketChannelNode,\n    name: channel,\n    service: serviceName,\n    channel,\n    discoveredVia: 'otel',\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// A messaging destination node (Kafka topic, queue, stream) keyed exactly the\n// way the static extractor keys it, so the OBSERVED and EXTRACTED edges fuse\n// onto one node instead of twinning. The Kafka static side names its topic\n// `infra:kafka-topic:<topic>` (extract/calls/kafka.ts), so the kind is\n// `<messaging.system>-topic` — `kafka` → `kafka-topic` — and the same shape\n// generalises to every messaging system the semconv names. `provider: 'self'`\n// mirrors the static extractor's non-AWS provider so an observed-first node\n// merges cleanly when static analysis later reaches the same destination.\nfunction messagingDestinationKind(system: string): string {\n  return `${system}-topic`\n}\n\nfunction ensureMessagingDestinationNode(\n  graph: NeatGraph,\n  system: string,\n  destination: string,\n): string {\n  const id = infraId(messagingDestinationKind(system), destination)\n  if (graph.hasNode(id)) return id\n  const node: InfraNode = {\n    id,\n    type: NodeType.InfraNode,\n    name: destination,\n    provider: 'self',\n    kind: messagingDestinationKind(system),\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// Parent-span TTL cache (ADR-033). Address-based peer resolution (server.address /\n// net.peer.name / url.full) misses non-HTTP RPCs and any span with an opaque\n// peer. The cache stores each span's service keyed by `${traceId}:${spanId}` so\n// a child span whose address resolution fails can fall back to its parent's\n// service, identifying a cross-service CALLS edge from parent → current.\n//\n// Bounded size + TTL — out-of-order arrival (child before parent) drops the\n// child rather than buffering. We accept that loss because the cache is best-\n// effort: for every cross-service call, the CLIENT span on the caller side\n// covers the same edge via address-based resolution, so missing one direction\n// is recoverable.\nconst PARENT_SPAN_CACHE_SIZE = 10_000\nconst PARENT_SPAN_CACHE_TTL_MS = 5 * 60 * 1000\n\ninterface ParentSpanCacheEntry {\n  service: string\n  // Env discriminator from the parent span (ADR-074 §2). The parent-span\n  // fallback in handleSpan uses this so the auto-created parent ServiceNode\n  // lands on the same env-tagged id the OTel emitter advertised.\n  env: string\n  // The parent span's own `code.*` call site, when its SpanProcessor captured\n  // one (file-awareness.md §4). The parent-span fallback below originates its\n  // edge from the parent's FileNode instead of the bare parent ServiceNode when\n  // this is present, so the fallback edge anchors to file:line rather than\n  // pinning to a service node (issue #536). Undefined when the parent carried no\n  // call site — never fabricated (§6), so the service-level fallback stands.\n  callSite?: CallSite\n  expiresAt: number\n}\n\nconst parentSpanCache = new Map<string, ParentSpanCacheEntry>()\n\nfunction parentSpanKey(traceId: string, spanId: string): string {\n  return `${traceId}:${spanId}`\n}\n\nfunction cacheSpanService(span: ParsedSpan, now: number, callSite: CallSite | null): void {\n  if (!span.traceId || !span.spanId) return\n  const key = parentSpanKey(span.traceId, span.spanId)\n  // Map preserves insertion order, so deleting + re-inserting bumps an entry to\n  // the back. Eviction is \"drop oldest\" once size exceeds the cap.\n  parentSpanCache.delete(key)\n  parentSpanCache.set(key, {\n    service: span.service,\n    env: span.env ?? 'unknown',\n    ...(callSite ? { callSite } : {}),\n    expiresAt: now + PARENT_SPAN_CACHE_TTL_MS,\n  })\n  while (parentSpanCache.size > PARENT_SPAN_CACHE_SIZE) {\n    const oldest = parentSpanCache.keys().next().value\n    if (!oldest) break\n    parentSpanCache.delete(oldest)\n  }\n}\n\nfunction lookupParentSpan(\n  traceId: string,\n  parentSpanId: string,\n  now: number,\n): { service: string; env: string; callSite?: CallSite } | null {\n  const entry = parentSpanCache.get(parentSpanKey(traceId, parentSpanId))\n  if (!entry) return null\n  if (entry.expiresAt <= now) {\n    parentSpanCache.delete(parentSpanKey(traceId, parentSpanId))\n    return null\n  }\n  return {\n    service: entry.service,\n    env: entry.env,\n    ...(entry.callSite ? { callSite: entry.callSite } : {}),\n  }\n}\n\n// Test seam: lets unit tests start from a clean slate.\nexport function resetParentSpanCache(): void {\n  parentSpanCache.clear()\n}\n\n// Peer host → ServiceNode id resolution. With env-dimension (ADR-074 §2),\n// the same `name` may live across multiple ServiceNodes — one per env, plus\n// the env-less form from static extraction. When `env` is known (the source\n// span's env), prefer a same-env match; fall back to the env-less node so\n// EXTRACTED edges from static analysis remain reachable until OBSERVED\n// traffic from the same env promotes them.\n//\n// Match passes:\n//   1. Exact id lookup for `(host, env)` — `serviceId(host, env)`.\n//   2. Exact id lookup for env-less `serviceId(host)`.\n//   3. Name/alias scan across every ServiceNode, preferring same-env then\n//      env-less then any other env.\nfunction resolveServiceId(\n  graph: NeatGraph,\n  host: string,\n  env: string,\n): string | null {\n  const envTagged = serviceId(host, env)\n  if (graph.hasNode(envTagged)) return envTagged\n  const envLess = serviceId(host)\n  if (envLess !== envTagged && graph.hasNode(envLess)) return envLess\n\n  let sameEnv: string | null = null\n  let envLessMatch: string | null = null\n  let anyMatch: string | null = null\n  graph.forEachNode((id, attrs) => {\n    if (sameEnv) return\n    const a = attrs as ServiceNode & { type?: string }\n    if (a.type !== NodeType.ServiceNode) return\n    const matchesByName = a.name === host\n    const matchesByAlias = a.aliases ? a.aliases.includes(host) : false\n    if (!matchesByName && !matchesByAlias) return\n    const nodeEnv = a.env ?? 'unknown'\n    if (nodeEnv === env) {\n      sameEnv = id\n      return\n    }\n    if (nodeEnv === 'unknown' && !envLessMatch) envLessMatch = id\n    else if (!anyMatch) anyMatch = id\n  })\n  return sameEnv ?? envLessMatch ?? anyMatch\n}\n\n// The service a bare-IP peer address belongs to, read off the OBSERVED addresses\n// the k8s substrate stamped on ServiceNodes (ADR-248). A client span that dials a\n// Service by its ClusterIP names the callee only as that IP; this is the one\n// lookup ingest makes before it mints a frontier for it. A hostname never takes\n// this path, and an address on more than one service resolves to none.\nexport function serviceIdForObservedAddress(graph: NeatGraph, host: string): string | null {\n  if (isIP(host) === 0) return null\n  let found: string | null = null\n  let ambiguous = false\n  graph.forEachNode((id, attrs) => {\n    if (ambiguous) return\n    const a = attrs as ServiceNode & { type?: string }\n    if (a.type !== NodeType.ServiceNode || !a.observedAddresses?.includes(host)) return\n    if (found !== null && found !== id) ambiguous = true\n    else found = id\n  })\n  return ambiguous ? null : found\n}\n\nexport function frontierIdFor(host: string): string {\n  return frontierId(host)\n}\n\n// Auto-create a minimal ServiceNode for span.service when no such node exists.\n// Used at the top of handleSpan so subsequent edge upserts always have endpoints\n// — without it, OBSERVED edges silently drop for any service the static\n// extractor hasn't reached yet (and never reaches at all in OTel-only setups).\n// `language: 'unknown'` is the contract's specified placeholder (ADR-033). When\n// static extraction later produces a ServiceNode at the same id, addServiceNodes\n// merges and flips discoveredVia to 'merged' rather than overwriting.\n// Exported for the connectors plane (connectors/index.ts) — a connector\n// signal needs the same auto-vivified ServiceNode any OTel span gets before\n// an edge upsert, since a connector-sourced service may never have been\n// statically extracted or seen a span yet.\n// Pure, read-only resolution of an observed `service.name` + `env` onto the id\n// of the ServiceNode it fuses with. This is the #880 matching, factored out of\n// ensureServiceNode so the incident/error path can share it without mutating\n// the graph.\n//\n// Two things push the observed id away from the extracted `service:<name>`:\n// `deployment.environment` (standard OTel semconv, commonly set) tags it\n// `service:<name>:<env>`, and OTEL_SERVICE_NAME is routinely a differently-\n// cased form of the manifest name the extractor used (`casetest` vs the\n// registered `CaseTest`). Either one alone splits the fused graph in two. So:\n// first an exact `(name, env)` id lookup, then a case-insensitive `name` match\n// against a statically extracted (non-otel) ServiceNode, ignoring env — env is\n// a dimension, not identity.\n//\n// When neither matches, the raw `serviceId(name, env)` is returned and the\n// caller decides: ensureServiceNode mints a node at that id, the incident path\n// (incidentAffectedNode) just attributes against it — the honest fallback for\n// an OTel-only service the graph hasn't materialised yet.\n//\n// Exported (ADR-185) so an incident-emitting connector's `resolveTarget` can\n// share the exact fused-service lookup — landing a build-failure incident on\n// the same extracted ServiceNode a span would, never a connector twin.\nexport function resolveFusedServiceId(\n  graph: NeatGraph,\n  serviceName: string,\n  env: string,\n): string {\n  const id = serviceId(serviceName, env)\n  if (graph.hasNode(id)) return id\n  const wanted = serviceName.toLowerCase()\n  const extractedId = graph.findNode((_nid, attrs) => {\n    if (attrs.type !== NodeType.ServiceNode) return false\n    const svc = attrs as ServiceNode\n    // Skip observed twins (discoveredVia 'otel') — only fuse onto a statically\n    // extracted (or already-merged) service, never onto another observed node.\n    if (svc.discoveredVia === 'otel') return false\n    return typeof svc.name === 'string' && svc.name.toLowerCase() === wanted\n  })\n  return extractedId ?? id\n}\n\nexport function ensureServiceNode(\n  graph: NeatGraph,\n  serviceName: string,\n  env: string,\n): string {\n  // Fuse an observed span onto the service the static extractor already minted\n  // (#880), rather than forking a twin that never joins the extracted graph —\n  // without it `observed-dependencies` reports \"no traffic\" on the extracted\n  // node while the traffic sits on the twin, and every divergence doubles.\n  const resolved = resolveFusedServiceId(graph, serviceName, env)\n  if (graph.hasNode(resolved)) return resolved\n  // Nothing matched — `resolved` is the raw serviceId, so this is a genuinely\n  // new OTel-only service. Mint it (the env-tagged or differently-cased spans\n  // that DID match an extracted node already returned above).\n  const node: ServiceNode = {\n    id: resolved,\n    type: NodeType.ServiceNode,\n    name: serviceName,\n    language: 'unknown',\n    discoveredVia: 'otel',\n    ...(env !== 'unknown' ? { env } : {}),\n  }\n  graph.addNode(resolved, node)\n  return resolved\n}\n\n// Exported so a connector's generic pipeline (connectors/index.ts) can create\n// an honest placeholder InfraNode for a provider-named resource no static\n// extractor has (yet) declared — a provider module has no mutation authority\n// of its own (ADR-030), so `resolveTarget` declares this need instead of\n// creating the node itself (ADR-133 §4a, docs/contracts/connectors.md).\n// Idempotent, same shape as `ensureServiceNode`.\nexport function ensureInfraNode(\n  graph: NeatGraph,\n  kind: string,\n  name: string,\n  provider: string,\n): string {\n  const id = infraId(kind, name)\n  if (graph.hasNode(id)) return id\n  const node: InfraNode = {\n    id,\n    type: NodeType.InfraNode,\n    name,\n    provider,\n    kind,\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// InfraNode kinds that carry columns — a database table read at column grain\n// (ADR-157 §1). `sql-table` is the canonical table node the OTel `db.statement`\n// mint and the Neon connector both land on; `supabase-table` is the same table\n// grain on the Supabase pull path. A project-level or non-table InfraNode (a\n// `supabase` project node, a `mongodb-collection`, a queue/route node) carries no\n// columns, so a merge onto one is a no-op.\nconst COLUMN_BEARING_INFRA_KINDS = new Set(['sql-table', 'supabase-table'])\n\n// Fold columns onto a table InfraNode at the given provenance (ADR-157 §1-2).\n// Columns are provenanced attributes on the table node, never their own nodes. A\n// column records each side it has been seen with in its `provenances` set — a\n// declared column production also touches ends up `[EXTRACTED, OBSERVED]`, not one\n// side clobbering the other — so column drift (ADR-157 §4) can read the declared\n// set and the observed set off one node. A no-op for a non-table node or an empty\n// column set, so a wildcard / join / DDL statement (which recovers no columns)\n// grows nothing. Mutation lives here in ingest.ts per the lifecycle authority\n// (ADR-030); the pure fold is columns.ts so extract/* can call it without a cycle.\nfunction mergeColumnsAt(\n  graph: NeatGraph,\n  tableNodeId: string,\n  columns: readonly string[] | undefined,\n  provenance: ProvenanceValue,\n  confidence: number,\n): void {\n  if (!columns || columns.length === 0 || !graph.hasNode(tableNodeId)) return\n  const node = graph.getNodeAttributes(tableNodeId) as InfraNode\n  if (node.type !== NodeType.InfraNode || !node.kind || !COLUMN_BEARING_INFRA_KINDS.has(node.kind)) {\n    return\n  }\n  graph.replaceNodeAttributes(tableNodeId, {\n    ...node,\n    columns: foldColumns(node.columns, columns, provenance, confidence),\n  })\n}\n\n// Merge the columns a production statement touched onto a table InfraNode as\n// OBSERVED (ADR-157 §1-2). OTel ingest and the connector mint path both call in.\nexport function mergeObservedColumns(\n  graph: NeatGraph,\n  tableNodeId: string,\n  columns: readonly string[] | undefined,\n): void {\n  mergeColumnsAt(graph, tableNodeId, columns, Provenance.OBSERVED, OBSERVED_COLUMN_CONFIDENCE)\n}\n\n// Merge the observed k8s deploy state — the container image the cluster's pods\n// actually run and the count of ready replicas — onto a `service:<name>` node as\n// OBSERVED (ADR-225). The observed half of the k8s deployment substrate: the\n// manifest extractor stamps `declaredImage`/`declaredReplicas` on this same node,\n// and the compare between the two names a `deploy-mismatch` divergence — the stuck\n// rollout that mints no incident because the service is still up on the old image.\n// Node attributes carry provenance in the name (`observed*` vs `declared*`), so\n// this is a plain attribute merge, not an edge; it never clobbers the declared\n// side. A no-op when the service node isn't in the graph yet, the same honest\n// missing-target discipline the connector pipeline holds.\nexport function mergeObservedDeployState(\n  graph: NeatGraph,\n  serviceNodeId: string,\n  state: { image?: string; readyReplicas?: number; addresses?: string[] },\n): void {\n  if (!graph.hasNode(serviceNodeId)) return\n  const attrs: Record<string, unknown> = {}\n  if (typeof state.image === 'string' && state.image.length > 0) attrs['observedImage'] = state.image\n  if (typeof state.readyReplicas === 'number') attrs['observedReadyReplicas'] = state.readyReplicas\n  // Addresses are replaced whole by each read (ADR-248): a Service that went away\n  // takes its address with it. Absent means the substrate didn't read them this\n  // time, so the last read stands.\n  if (Array.isArray(state.addresses)) {\n    if (state.addresses.length > 0) attrs['observedAddresses'] = [...state.addresses].sort()\n    else if ((graph.getNodeAttributes(serviceNodeId) as { observedAddresses?: unknown }).observedAddresses !== undefined) {\n      graph.removeNodeAttribute(serviceNodeId, 'observedAddresses' as never)\n    }\n  }\n  if (Object.keys(attrs).length === 0) return\n  graph.mergeNodeAttributes(serviceNodeId, attrs)\n}\n\n// Fuse a faulted workload's deploy/process/config context onto its node as OBSERVED\n// (ADR-243, amending ADR-237/240). The one copy: the incident card, `neat incidents`\n// and MCP read it from here, never from the incident. Tagged with the incident it\n// was observed with, so a card shows it only for that incident; a newer fault on the\n// same workload replaces it. Already redacted and bounded upstream\n// (process-context.ts). A no-op when the node isn't in the graph.\nexport function mergeObservedDeployContext(\n  graph: NeatGraph,\n  nodeId: string,\n  incidentId: string,\n  observedAt: string,\n  context: DeployContext,\n): void {\n  if (!graph.hasNode(nodeId)) return\n  if (Object.keys(context).length === 0) return\n  const value: ObservedDeployContext = { ...context, incidentId, observedAt }\n  graph.mergeNodeAttributes(nodeId, { observedDeployContext: value })\n}\n\n// Merge what a flag store is serving onto its flag grain as OBSERVED (ADR-242).\n// The store's sync reader calls in each poll with the full served set. Only a flag\n// the code base declares takes the observed definition; a served flag with no\n// committed twin mints nothing and comes back in `undeclared` for the reader's\n// poll status. A no-op (everything undeclared) when the store node isn't in the\n// graph, because then nothing declares a flag yet.\nexport function mergeObservedFlags(\n  graph: NeatGraph,\n  provider: string,\n  served: ReadonlyMap<string, FlagDefinition>,\n  at: string,\n): { undeclared: string[] } {\n  const storeId = infraId(FLAG_STORE_KIND, provider)\n  if (!graph.hasNode(storeId)) return { undeclared: [...served.keys()].sort() }\n  const node = graph.getNodeAttributes(storeId) as InfraNode\n  const { flags, undeclared } = foldObservedFlags(node.flags, served, at)\n  graph.mergeNodeAttributes(storeId, { flags })\n  return { undeclared }\n}\n\n// The flag store an evaluation came from: the one its provider names, else the\n// only flag store in the graph. Null when neither picks exactly one.\nfunction flagStoreFor(graph: NeatGraph, provider: string | undefined): string | null {\n  if (provider) {\n    const id = infraId(FLAG_STORE_KIND, provider)\n    return graph.hasNode(id) ? id : null\n  }\n  const stores: string[] = []\n  graph.forEachNode((id, attrs) => {\n    const n = attrs as GraphNode\n    if (n.type === NodeType.InfraNode && n.kind === FLAG_STORE_KIND) stores.push(id)\n  })\n  return stores.length === 1 ? stores[0]! : null\n}\n\n// Fold one service-side flag evaluation (a `feature_flag.evaluation` span event)\n// onto the flag grain, and record that the evaluating code reads the store: an\n// OBSERVED CONNECTS_TO from the span's origin, the twin of the EXTRACTED edge the\n// literal join mints. Only a flag the code base declares is recorded. Returns\n// whether it landed.\nfunction recordFlagEvaluation(\n  graph: NeatGraph,\n  source: () => string,\n  ev: FlagEvaluation,\n  ts: string,\n  callSiteEvidence: { file: string; line?: number } | undefined,\n): boolean {\n  if (!ev.variant) return false\n  const storeId = flagStoreFor(graph, ev.provider)\n  if (!storeId) return false\n  const node = graph.getNodeAttributes(storeId) as InfraNode\n  const flags = foldObservedVariant(node.flags, ev.key, ev.variant, ev.reason, ts)\n  if (!flags) return false\n  graph.mergeNodeAttributes(storeId, { flags })\n  upsertObservedEdge(graph, EdgeType.CONNECTS_TO, source(), storeId, ts, false, callSiteEvidence)\n  return true\n}\n\n// Merge the columns a schema/ORM declares onto a table InfraNode as EXTRACTED\n// (ADR-157 §3). The declared side of column grain: the static extractor recovers\n// each column at database-name fidelity and calls in from extract/calls/*.\nexport function mergeDeclaredColumns(\n  graph: NeatGraph,\n  tableNodeId: string,\n  columns: readonly string[] | undefined,\n  confidence: number,\n): void {\n  mergeColumnsAt(graph, tableNodeId, columns, Provenance.EXTRACTED, confidence)\n}\n\n// Same shape for unseen db.system + host pairs. Engine comes off the OTel\n// attribute as a string per Rule 8 — no hardcoded engine list. compatibleDrivers\n// is empty until static extraction merges in the matrix-derived drivers.\nfunction ensureDatabaseNode(graph: NeatGraph, host: string, engine: string): string {\n  const id = databaseId(host)\n  if (graph.hasNode(id)) return id\n  const node: DatabaseNode = {\n    id,\n    type: NodeType.DatabaseNode,\n    name: host,\n    engine,\n    engineVersion: 'unknown',\n    compatibleDrivers: [],\n    host,\n    discoveredVia: 'otel',\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// An in-process / embedded database (SQLite, better-sqlite3, an in-memory\n// store) crosses no network boundary, so its span carries no peer host to key a\n// DatabaseNode on. Key it on a service-scoped local identity instead so two\n// services each reading their own `app.db` stay distinct nodes rather than\n// collapsing onto one (ADR-118). `name` is the logical database from the span\n// (db.name) when present, the engine string otherwise. `host` is intentionally\n// omitted — an embedded database has no network host, and evidence is never\n// fabricated (file-awareness.md §6); host-mismatch divergence skips a hostless\n// DatabaseNode. Returns the node id so the caller can point the CONNECTS_TO edge\n// at it. Idempotent — high-volume DB spans upsert, never grow the node set.\nfunction ensureLocalDatabaseNode(\n  graph: NeatGraph,\n  serviceName: string,\n  name: string,\n  engine: string,\n): string {\n  const id = localDatabaseId(serviceName, name)\n  if (graph.hasNode(id)) return id\n  const node: DatabaseNode = {\n    id,\n    type: NodeType.DatabaseNode,\n    name,\n    engine,\n    engineVersion: 'unknown',\n    compatibleDrivers: [],\n    discoveredVia: 'otel',\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// ADR-141 — an ORM such as Prisma emits a `db.system` span with no peer host\n// (its query engine backdates the span off the connection), so a host-less span\n// would mint a fresh service-local DatabaseNode and leave the service's\n// statically declared database — the one parsed from its connection string / ORM\n// schema — with no OBSERVED twin: a false `missing-observed` divergence for a DB\n// the service demonstrably hammers. Before minting a local node, fuse onto the\n// service's already-declared database of the same engine when there is exactly\n// one. Ambiguous (two-plus same-engine declared DBs) or none falls back to the\n// ADR-118 service-local node — the fusion never guesses which of several it is.\nfunction findDeclaredDatabaseForService(\n  graph: NeatGraph,\n  serviceNodeId: string,\n  engine: string,\n): string | null {\n  if (!graph.hasNode(serviceNodeId)) return null\n  // A declared database CONNECTS_TO is file-grained by design — it originates\n  // from the config file that named the connection (databases/index.ts,\n  // file-awareness §7), not the service node. So scan the service node and every\n  // file it CONTAINS for a same-engine EXTRACTED CONNECTS_TO target.\n  const sources = [serviceNodeId]\n  for (const edgeId of graph.outboundEdges(serviceNodeId)) {\n    const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (e.type === EdgeType.CONTAINS) sources.push(e.target)\n  }\n  const matches = new Set<string>()\n  for (const src of sources) {\n    if (!graph.hasNode(src)) continue\n    for (const edgeId of graph.outboundEdges(src)) {\n      const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (edge.type !== EdgeType.CONNECTS_TO || edge.provenance !== Provenance.EXTRACTED) continue\n      if (!graph.hasNode(edge.target)) continue\n      const target = graph.getNodeAttributes(edge.target) as DatabaseNode\n      if (target.type !== NodeType.DatabaseNode || target.engine !== engine) continue\n      matches.add(edge.target)\n    }\n  }\n  return matches.size === 1 ? [...matches][0]! : null\n}\n\nfunction ensureFrontierNode(graph: NeatGraph, host: string, ts: string): string {\n  const id = frontierIdFor(host)\n  if (graph.hasNode(id)) {\n    const existing = graph.getNodeAttributes(id) as FrontierNode\n    graph.replaceNodeAttributes(id, { ...existing, lastObserved: ts })\n    return id\n  }\n  const node: FrontierNode = {\n    id,\n    type: NodeType.FrontierNode,\n    name: host,\n    host,\n    firstObserved: ts,\n    lastObserved: ts,\n  }\n  graph.addNode(id, node)\n  return id\n}\n\n// Exported so the connectors plane (connectors/index.ts) mints edges through\n// the identical primitive OTel ingest uses — a connector-sourced edge and a\n// span-sourced edge are meant to be indistinguishable to traversal,\n// divergence, and staleness (docs/connectors/README.md).\nexport interface UpsertResult {\n  edge: GraphEdge\n  created: boolean\n}\n\n// Bounded ceiling for an edge exemplar's message (ADR-236). The full exception\n// text lives in the incident ledger; the edge carries only enough to name the\n// failure's nature, so a pathological stack-dump message never bloats the edge.\nexport const EDGE_ERROR_MESSAGE_MAX = 512\n\n// Build the bounded last-error exemplar written onto `signal.lastError`\n// (ADR-236). `at` is the span's own observation time (ts), mirroring\n// `lastObserved`. Only fields the caller actually resolved are set — a failure\n// may carry a type, a message, a status, or only some of these — and `message`\n// is trimmed defensively here too, so no caller can route an unbounded string\n// onto the edge.\nfunction buildEdgeErrorExemplar(\n  detail: { exceptionType?: string; message?: string; httpStatusCode?: number },\n  ts: string,\n): EdgeErrorExemplar {\n  return {\n    ...(detail.exceptionType !== undefined ? { exceptionType: detail.exceptionType } : {}),\n    ...(detail.message !== undefined\n      ? { message: detail.message.slice(0, EDGE_ERROR_MESSAGE_MAX) }\n      : {}),\n    ...(detail.httpStatusCode !== undefined ? { httpStatusCode: detail.httpStatusCode } : {}),\n    at: ts,\n  }\n}\n\n// The detail for a failing span's edge exemplar (ADR-236): the real span\n// exception type/message (the `exception` event, parsed in `otel.ts`) plus the\n// HTTP response status when the failure is an HTTP one (`httpResponseStatus`,\n// the same helper the incident path reads). Returns `undefined` when the span\n// carries none of these — a failure with no detail leaves any prior exemplar\n// untouched (`upsertObservedEdge`). A non-exception, non-HTTP failure (a bare\n// gRPC status with no exception event) resolves to no detail here and rides as a\n// plain error count, honestly — the exemplar never fabricates a reason.\nfunction edgeErrorDetailFromSpan(\n  span: ParsedSpan,\n): { exceptionType?: string; message?: string; httpStatusCode?: number } | undefined {\n  const exceptionType = span.exception?.type\n  const message = span.exception?.message\n  const httpStatusCode = httpResponseStatus(span)\n  if (exceptionType === undefined && message === undefined && httpStatusCode === undefined) {\n    return undefined\n  }\n  return {\n    ...(exceptionType !== undefined ? { exceptionType } : {}),\n    ...(message !== undefined ? { message } : {}),\n    ...(httpStatusCode !== undefined ? { httpStatusCode } : {}),\n  }\n}\n\nexport function upsertObservedEdge(\n  graph: NeatGraph,\n  type: EdgeTypeValue,\n  source: string,\n  target: string,\n  ts: string,\n  isError = false,\n  evidence?: { file: string; line?: number },\n  // Span duration in ms (ADR-190). Present on span-derived edges; absent on a\n  // connector edge with no provider latency, which then carries no latency.\n  durationMs?: number,\n  // The failing observation's exception detail (ADR-236). When `isError` and\n  // this is present, it is written/overwritten onto `signal.lastError` as a\n  // bounded exemplar (last-write-wins, no history) so the edge carries WHAT\n  // failed. A non-error call, or an error without detail, leaves any prior\n  // exemplar untouched — mirrors the latency \"absent leaves prior untouched\"\n  // rule above. The caller trims `message` before passing it.\n  errorDetail?: { exceptionType?: string; message?: string; httpStatusCode?: number },\n): UpsertResult | null {\n  if (!graph.hasNode(source) || !graph.hasNode(target)) return null\n\n  // ADR-142 — grain is a stored fact, not a re-derivation. A `file:` source means\n  // a call site was captured (observedSource / the connector's callSite path both\n  // mint a FileNode only when they have one), so the edge is file-grained;\n  // anything else (service:/infra:/frontier:) is the coarse service-grained\n  // fallback. Set on both the OTel and the connector path — they share this mint.\n  // A `symbol:` source is finer still (ADR-158) — the call site landed on the\n  // calling symbol under its file — and belongs in the same call-site-captured\n  // bucket as `file:`, never the coarse service fallback.\n  const grain: 'file' | 'service' =\n    source.startsWith('file:') || source.startsWith('symbol:') ? 'file' : 'service'\n\n  const id = makeObservedEdgeId(type, source, target)\n  if (graph.hasEdge(id)) {\n    const existing = graph.getEdgeAttributes(id) as GraphEdge\n    const newSpanCount = (existing.signal?.spanCount ?? existing.callCount ?? 0) + 1\n    const newErrorCount = (existing.signal?.errorCount ?? 0) + (isError ? 1 : 0)\n    // Fold this span's duration into the bounded per-edge latency histogram and\n    // re-derive p50/p95 (latency-digest.ts, ADR-190). A call with no duration\n    // (a connector signal) leaves the prior latency untouched, never clears it.\n    const latencyHist =\n      durationMs !== undefined\n        ? recordLatency({ ...(existing.signal?.latencyHist ?? {}) }, durationMs)\n        : existing.signal?.latencyHist\n    const latencyMs = latencyPercentiles(latencyHist) ?? existing.signal?.latencyMs\n    // Bounded last-error exemplar (ADR-236): a failing observation that carries\n    // detail overwrites it (last-write-wins, O(1)); a clean call or a failure\n    // without detail leaves the prior exemplar untouched, mirroring latency.\n    const lastError =\n      isError && errorDetail\n        ? buildEdgeErrorExemplar(errorDetail, ts)\n        : existing.signal?.lastError\n    const newSignal = {\n      spanCount: newSpanCount,\n      errorCount: newErrorCount,\n      lastObservedAgeMs: 0,\n      ...(latencyHist ? { latencyHist } : {}),\n      ...(latencyMs ? { latencyMs } : {}),\n      ...(existing.signal?.anomalous !== undefined\n        ? { anomalous: existing.signal.anomalous }\n        : {}),\n      ...(lastError ? { lastError } : {}),\n    }\n    // ADR-066 §2 — confidence grades from the signal block. PROV_RANK stays;\n    // the grade reflects volume + recency + error ratio within the OBSERVED\n    // tier.\n    const updated: GraphEdge = {\n      ...existing,\n      provenance: Provenance.OBSERVED,\n      lastObserved: ts,\n      callCount: newSpanCount,\n      signal: newSignal,\n      confidence: confidenceForObservedSignal(newSignal),\n      grain, // backfills legacy edges that predate ADR-142\n    }\n    graph.replaceEdgeAttributes(id, updated)\n    return { edge: updated, created: false }\n  }\n\n  const latencyHist = durationMs !== undefined ? recordLatency({}, durationMs) : undefined\n  const latencyMs = latencyHist ? latencyPercentiles(latencyHist) : undefined\n  const lastError = isError && errorDetail ? buildEdgeErrorExemplar(errorDetail, ts) : undefined\n  const signal = {\n    spanCount: 1,\n    errorCount: isError ? 1 : 0,\n    lastObservedAgeMs: 0,\n    ...(latencyHist ? { latencyHist } : {}),\n    ...(latencyMs ? { latencyMs } : {}),\n    ...(lastError ? { lastError } : {}),\n  }\n  const edge: GraphEdge = {\n    id,\n    source,\n    target,\n    type,\n    provenance: Provenance.OBSERVED,\n    confidence: confidenceForObservedSignal(signal),\n    lastObserved: ts,\n    callCount: 1,\n    signal,\n    grain,\n    // Call-site evidence from span code.* semconv (file-awareness.md §4 + §6).\n    // Only set when code.filepath was present on the span — never fabricated.\n    ...(evidence ? { evidence } : {}),\n  }\n  graph.addEdgeWithKey(id, source, target, edge)\n  return { edge, created: true }\n}\n\n// When a span errors, the system is exercising its dependencies right now even\n// if some of them aren't auto-instrumented (pg 7.4.0 in the demo, see ADR-014).\n// Walk EXTRACTED edges out from the erroring service for a couple of hops and\n// promote them to INFERRED twins so traversal can prefer them over the bare\n// static edges without claiming OBSERVED-grade certainty.\nfunction stitchTrace(graph: NeatGraph, sourceServiceId: string, ts: string): void {\n  if (!graph.hasNode(sourceServiceId)) return\n\n  const visited = new Set<string>([sourceServiceId])\n  const queue: { nodeId: string; depth: number }[] = [{ nodeId: sourceServiceId, depth: 0 }]\n\n  while (queue.length > 0) {\n    const { nodeId, depth } = queue.shift()!\n    if (depth >= STITCH_MAX_DEPTH) continue\n\n    const outbound = graph.outboundEdges(nodeId)\n    for (const edgeId of outbound) {\n      const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (edge.provenance !== Provenance.EXTRACTED) continue\n\n      // Only runtime dependency edges get stitched. Structural edges (CONTAINS /\n      // IMPORTS / CONFIGURED_BY / RUNS_ON) are never mirrored into INFERRED twins\n      // and the BFS does not recurse through them — an error propagates along\n      // dependencies, not static containment (trace-stitcher.md allowlist).\n      if (!STITCH_EDGE_TYPES.has(edge.type)) continue\n\n      // OBSERVED twin already covers this hop with ground truth — no inference\n      // needed (ADR-034). Stomping it with INFERRED erases the gap NEAT exists\n      // to surface; skipping it keeps the OBSERVED edge as the authoritative\n      // record and avoids cluttering the graph with a redundant INFERRED twin.\n      if (graph.hasEdge(observedEdgeId(edge.source, edge.target, edge.type))) continue\n\n      upsertInferredEdge(graph, edge.type, edge.source, edge.target, ts)\n\n      if (!visited.has(edge.target)) {\n        visited.add(edge.target)\n        queue.push({ nodeId: edge.target, depth: depth + 1 })\n      }\n    }\n  }\n}\n\nfunction upsertInferredEdge(\n  graph: NeatGraph,\n  type: EdgeTypeValue,\n  source: string,\n  target: string,\n  ts: string,\n): void {\n  const id = makeInferredEdgeId(type, source, target)\n  if (graph.hasEdge(id)) {\n    const existing = graph.getEdgeAttributes(id) as GraphEdge\n    const updated: GraphEdge = { ...existing, lastObserved: ts }\n    graph.replaceEdgeAttributes(id, updated)\n    return\n  }\n\n  const edge: GraphEdge = {\n    id,\n    source,\n    target,\n    type,\n    provenance: Provenance.INFERRED,\n    confidence: INFERRED_CONFIDENCE,\n    lastObserved: ts,\n  }\n  graph.addEdgeWithKey(id, source, target, edge)\n}\n\n// Announce a freshly-recorded incident on the event bus (ADR-221). A lean\n// trigger — the affected node, service, and kind — that wakes `neat monitor`;\n// the full incident card is a REST read (GET /graph/incident-card/:nodeId). The\n// monitor dedupes on the incident id, so a stray double-emit is harmless. Fired\n// from every incident write path that knows its project: the OTel paths (this\n// one, plus the receiver's synchronous writer for status-error spans) and\n// connector incidents (ADR-185) through appendConnectorIncident, which threads\n// the project from its poll caller.\nfunction emitIncidentEvent(project: string, ev: ErrorEvent): void {\n  emitNeatEvent({\n    type: 'incident',\n    project,\n    payload: {\n      incidentId: ev.id,\n      affectedNode: ev.affectedNode,\n      service: ev.service,\n      incidentKind: incidentKindOf(ev),\n      at: ev.timestamp,\n    },\n  })\n}\n\nasync function appendErrorEvent(ctx: IngestContext, ev: ErrorEvent): Promise<void> {\n  await appendRuntimeIncident(ctx.errorsPath, ctx.project ?? DEFAULT_PROJECT, ev)\n  emitIncidentEvent(ctx.project ?? DEFAULT_PROJECT, ev)\n}\n\n// The semantic fields an incident-emitting connector's failure carries, minus\n// the ErrorEvent bookkeeping this function fills in (ADR-185, connectors.md §10).\nexport interface ConnectorIncidentInput {\n  // Stable dedupe key for the one failure (e.g. `eas:build:<buildId>`).\n  id: string\n  // The failure's own event time (ISO8601).\n  timestamp: string\n  // The NEAT service the failure belongs to.\n  service: string\n  // Short stable classifier (e.g. 'eas-build-failure'), the connector analog of\n  // the 'http-failure' errorType the response-code incidents carry.\n  errorType: string\n  // The human-readable failure line the incident surface shows.\n  errorMessage: string\n  // Provider context passed through verbatim (phase, commit, capped logs, docs\n  // URL). Same JSON-safe shape ErrorEvent.attributes carries.\n  attributes?: ErrorEvent['attributes']\n  // The graph node the failure implicates — already resolved by the connector's\n  // resolveTarget through the fused-node lookup, so this lands on the extracted\n  // node get_incident_history / get_root_cause query, never a twin.\n  affectedNode: string\n}\n\n// Write one connector-sourced incident to the project's incident ledger\n// (`errors.ndjson`) — the SAME store OTLP-derived incidents use, so\n// get_incident_history / get_root_cause read it with no special-casing (ADR-185,\n// connectors.md §10). The connectors plane has no mutation authority (ADR-030),\n// so it calls this ingest.ts primitive rather than writing the ledger itself.\n//\n// A connector failure carries no OTel trace, but the ErrorEvent shape requires\n// traceId/spanId. They are derived deterministically from the stable `id` so a\n// re-poll of the same failure collapses on them the same way `dedupeIncidents`\n// collapses on `id`, and two distinct failures never share a (traceId,\n// affectedNode) group. errorType is always set, so the incident is never mistaken\n// for a synthesized-HTTP echo and dropped.\nexport async function appendConnectorIncident(\n  errorsPath: string,\n  input: ConnectorIncidentInput,\n  project?: string,\n): Promise<void> {\n  const ev: ErrorEvent = {\n    id: input.id,\n    timestamp: input.timestamp,\n    service: input.service,\n    traceId: input.id,\n    spanId: input.id,\n    errorType: input.errorType,\n    errorMessage: input.errorMessage,\n    ...(input.attributes && Object.keys(input.attributes).length > 0\n      ? { attributes: input.attributes }\n      : {}),\n    affectedNode: input.affectedNode,\n  }\n  await appendRuntimeIncident(errorsPath, project ?? DEFAULT_PROJECT, ev)\n  // Push it onto the bus (ADR-221) exactly as the OTLP paths do, so a\n  // connector-sourced failure reaches an agent's monitor too — same event, same\n  // lean payload. Only when the caller threaded a project; a programmatic caller\n  // that passes none still writes the ledger, it just doesn't push.\n  if (project) emitIncidentEvent(project, ev)\n}\n\n// The node an incident is attributed to, plus a code locus RECOVERED from the\n// stacktrace when the span carried no `code.*` attributes of its own. The\n// recovered locus is set only on the stacktrace-fallback path (ADR-216); the\n// incident builders synthesize it onto the record so `symbolLocus`, root-cause,\n// and the incidents surface all read the declaring file:line the same way a span\n// that stamped `code.*` already does.\ninterface IncidentLocus {\n  affectedNode: string\n  codeFilepath?: string\n  codeLineno?: number\n}\n\n// Land a resolved runtime call site on the finest code node the graph carries —\n// the SYMBOL the line falls inside, else its FileNode, else the honest raw\n// service-relative file id. `trusted` distinguishes the two entry paths: a\n// span's own `code.*` call site is authoritative and lands on the file id even\n// when the graph has no matching node yet (the file:line is real, unchanged\n// pre-ADR-216 behavior); a stacktrace-recovered frame is a heuristic join, so it\n// attributes to code ONLY when it resolves to a FileNode the graph already\n// holds, and otherwise recovers nothing (never fabricated). Returns null to mean\n// \"keep the service attribution\".\nfunction landIncidentCallSite(\n  span: ParsedSpan,\n  callSite: CallSite,\n  trusted: boolean,\n  graph?: NeatGraph,\n): IncidentLocus | null {\n  const relPath = graph\n    ? reconcileObservedRelPath(graph, span.service, callSite.relPath)\n    : callSite.relPath\n  // Descend one grain finer to the SYMBOL the failure surfaced in — the same\n  // span-containment resolution OBSERVED edges use (landObservedSymbol, ADR-158\n  // §4) — so an in-process throw attributes to the function, not just its file\n  // (ADR-191). Keyed on the fused service name so the symbol id matches the\n  // statically-extracted symbol it fuses onto. Read-only (mint=false): it lands\n  // on an existing static symbol whose span contains the line, and degrades to\n  // the file honestly when no static symbol contains the line.\n  const canonicalService = serviceNodeName(graph, span) ?? span.service\n  const recovered = !trusted\n  if (graph) {\n    const fusedFileId = fileId(canonicalService, relPath)\n    if (graph.hasNode(fusedFileId)) {\n      const node = landObservedSymbol(\n        graph,\n        fusedFileId,\n        canonicalService,\n        relPath,\n        { ...callSite, relPath },\n        false,\n      )\n      return {\n        affectedNode: node,\n        ...(recovered\n          ? {\n              codeFilepath: relPath,\n              ...(callSite.line !== undefined ? { codeLineno: callSite.line } : {}),\n            }\n          : {}),\n      }\n    }\n    // A recovered frame that joins to no graph node is not attributed to code —\n    // that would fabricate a locus the graph can't vouch for. The trusted\n    // `code.*` path keeps its honest file id.\n    if (recovered) return null\n  }\n  return { affectedNode: fileId(span.service, relPath) }\n}\n\n// The fused ServiceNode's canonical name, so a differently-cased or env-tagged\n// `service.name` keys the same node the extractor minted (#880 / #988).\nfunction serviceNodeName(graph: NeatGraph | undefined, span: ParsedSpan): string | undefined {\n  if (!graph) return undefined\n  const sid = resolveFusedServiceId(graph, span.service, span.env)\n  if (!graph.hasNode(sid)) return undefined\n  const node = graph.getNodeAttributes(sid) as ServiceNode\n  return typeof node.name === 'string' ? node.name : undefined\n}\n\n// Recover a call site from the exception stacktrace's deepest application frame\n// (ADR-216) — the fallback for a span that carries a stacktrace but no `code.*`\n// attributes, the dominant shape of Python (and other) auto-instrumented\n// exception spans. The frame's absolute deploy path runs through the same\n// runtime-path → service-relative join a `code.*` call site uses, so it lands on\n// the FileNode the extractor already minted. Returns null when the stacktrace\n// names no application frame.\nfunction stacktraceCallSite(\n  span: ParsedSpan,\n  serviceNode: ServiceNode | undefined,\n  scanPath?: string,\n): CallSite | null {\n  const frame = deepestApplicationFrame(span.exception?.stacktrace)\n  if (!frame) return null\n  const relPath = relPathForRuntimeFile(frame.file, serviceNode, scanPath)\n  if (!relPath) return null\n  return { relPath, line: frame.line, ...(frame.fn ? { fn: frame.fn } : {}) }\n}\n\n// Resolve the incident's affectedNode (and any recovered code locus). When the\n// span carries a `code.filepath` call site, the incident attributes to the\n// FileNode/SymbolNode the failure surfaced in — the same file grain OBSERVED\n// CALLS edges land on (file-awareness.md §4) — resolving a compiled `dist/…js`\n// frame through its disk-adjacent source map when one is present. When the span\n// carries no call site but does carry an exception stacktrace, the deepest\n// application frame is parsed and run through the same runtime-path → graph-node\n// join (ADR-216), so a stacktrace-only exception span (Python\n// auto-instrumentation, the prime case) is attributed to code instead of\n// degrading to the service. Without either, or when a recovered frame joins to\n// no graph node, it stays at the originating service, the honest fallback (§2).\n//\n// The runtime paths are deploy-absolute (`/usr/src/app/…` in a container image,\n// `/var/task/…` on Lambda) and need not match the daemon's checkout; when the\n// graph is available they're reconciled onto the service-relative path the\n// extractor already minted (reconcileObservedRelPath), so the incident lands on\n// the ONE fused FileNode instead of a phantom keyed off the absolute path — the\n// node root-cause actually walks.\nfunction incidentLocus(\n  span: ParsedSpan,\n  graph?: NeatGraph,\n  scanPath?: string,\n): IncidentLocus {\n  // Resolve onto the fused ServiceNode the same way handleSpan's edge upserts\n  // do (ensureServiceNode / resolveFusedServiceId) — a case-insensitive,\n  // env-ignoring match against the extracted node — so an errored span carrying\n  // `deployment.environment` (or a differently-cased service.name) and no call\n  // site attributes to the ONE `service:<name>` the graph holds, not a phantom\n  // `service:<name>:<env>` twin that's absent from it, which get_incident_history\n  // and get_root_cause then miss (#988). Without a graph (the ad-hoc receiver\n  // surface, no fusion target) the honest raw serviceId stands.\n  const sid = graph\n    ? resolveFusedServiceId(graph, span.service, span.env)\n    : serviceId(span.service, span.env)\n  const serviceNode =\n    graph && graph.hasNode(sid)\n      ? (graph.getNodeAttributes(sid) as ServiceNode)\n      : undefined\n\n  const callSite = callSiteFromSpan(span, serviceNode, scanPath)\n  if (callSite) {\n    const landed = landIncidentCallSite(span, callSite, true, graph)\n    if (landed) return landed\n  } else {\n    const recovered = stacktraceCallSite(span, serviceNode, scanPath)\n    if (recovered) {\n      const landed = landIncidentCallSite(span, recovered, false, graph)\n      if (landed) return landed\n    }\n  }\n  return { affectedNode: sid }\n}\n\nfunction incidentAffectedNode(\n  span: ParsedSpan,\n  graph?: NeatGraph,\n  scanPath?: string,\n): string {\n  return incidentLocus(span, graph, scanPath).affectedNode\n}\n\n// Merge a stacktrace-recovered code locus onto an incident's attributes so the\n// synthesized `code.filepath`/`code.lineno` ride the record the same way a\n// span's own `code.*` would — `symbolLocus` (divergences.ts), root-cause, and\n// the incidents surface all read them. A no-op when the span already carried\n// `code.*` (locus.codeFilepath unset): the real attributes stand untouched.\nfunction withRecoveredCodeAttrs(\n  attrs: ReturnType<typeof sanitizeAttributes>,\n  locus: IncidentLocus,\n): ReturnType<typeof sanitizeAttributes> {\n  if (locus.codeFilepath === undefined) return attrs\n  attrs[CODE_FILEPATH_ATTR] = locus.codeFilepath\n  if (locus.codeLineno !== undefined) attrs[CODE_LINENO_ATTR] = locus.codeLineno\n  return attrs\n}\n\n// Build the minimal ErrorEvent the receiver writes synchronously before\n// replying (ADR-033 §Error events, amended). affectedNode attributes to the\n// FileNode when the span carries a `code.filepath` call site, else to the\n// originating service (incidentAffectedNode above).\n//\n// errorMessage reads from the exception event's `exception.message` (OTel\n// semconv) so the incident surface shows the actual thrown error string.\n// When the span carries no exception event the field falls back to the HTTP\n// context the span still holds — \"500 on GET /users/:id\" (httpFailureMessage)\n// — and only then to the literal 'unknown error'. `span.name` is never in the\n// chain: OTel HTTP server instrumentation routinely populates it with the HTTP\n// method, which produces incidents that read 'GET' or 'POST' instead of the\n// underlying failure. `span.status.message` is intentionally out for the same\n// reason.\n// Header attributes that carry credentials. Some auto-instrumentation copies\n// request/response headers into span attributes wholesale — a `...req.headers`\n// spread — which would otherwise persist a caller's session cookie or bearer\n// token into the incident record at rest. NEAT's own instrumentation never\n// emits these; the exposure rides in from a target's over-broad SDK, and NEAT\n// is the store, so it drops them here (#1182).\nconst SENSITIVE_HEADER_NAMES = new Set([\n  'authorization',\n  'proxy-authorization',\n  'cookie',\n  'set-cookie',\n  'x-api-key',\n  'api-key',\n  'x-auth-token',\n  'x-amz-security-token',\n  'x-csrf-token',\n])\n\n// The header name an attribute key carries — the segment after `.header.` for the\n// OTel `http.request.header.<name>` / `http.response.header.<name>` forms, or the\n// bare key itself for an SDK that names the header without a prefix.\nfunction attrHeaderName(key: string): string {\n  const lower = key.toLowerCase()\n  const marker = '.header.'\n  const at = lower.lastIndexOf(marker)\n  return at >= 0 ? lower.slice(at + marker.length) : lower\n}\n\nfunction isSensitiveAttrKey(key: string): boolean {\n  return SENSITIVE_HEADER_NAMES.has(attrHeaderName(key))\n}\n\n// Span attributes pass through so consumers can read source attribution\n// (`code.filepath`, `code.lineno`, `code.function`) and other SDK-emitted\n// context without ingest enumerating every key it cares about — with one\n// exception: credential-bearing header attributes are dropped (see above), so\n// a span that arrived carrying a cookie or bearer token doesn't persist it.\n// Coerce the survivors to a JSON-safe shape — bigint values from the parsed\n// span (long ids, high-cardinality counters) become strings so the record can\n// be serialised to the ErrorEvent shape and round-tripped through\n// ErrorEventSchema. All other types pass through unchanged.\nfunction sanitizeAttributes(\n  attrs: ParsedSpan['attributes'],\n): Record<string, string | number | boolean | null | string[] | number[] | boolean[]> {\n  const out: Record<string, string | number | boolean | null | string[] | number[] | boolean[]> = {}\n  for (const [k, v] of Object.entries(attrs)) {\n    if (isSensitiveAttrKey(k)) continue\n    if (typeof v === 'bigint') out[k] = v.toString()\n    else out[k] = v as string | number | boolean | null | string[] | number[] | boolean[]\n  }\n  return out\n}\n\nexport function buildErrorEventForReceiver(\n  span: ParsedSpan,\n  graph?: NeatGraph,\n  scanPath?: string,\n): ErrorEvent | null {\n  if (span.statusCode !== 2) return null\n  const ts = span.startTimeIso ?? new Date().toISOString()\n  const locus = incidentLocus(span, graph, scanPath)\n  const attrs = withRecoveredCodeAttrs(sanitizeAttributes(span.attributes), locus)\n  // #1118 — an ERROR-status span can also carry an HTTP response status: an\n  // ingress/proxy (Envoy) returns a 504 with status=Error and the code in the\n  // old-semconv `http.status_code` (a string). httpResponseStatus reads both\n  // semconv keys and coerces the string, so surface it here — otherwise the 504\n  // is dropped and the incident reads as a generic exception. incidentKindOf\n  // reads httpStatusCode to classify a 5xx, and the #1114 boundary-timeout\n  // classifier reads it to recognise a gateway timeout. Deliberately NOT tagging\n  // errorType: the SERVER-5xx echo of a downstream failure is identified by an\n  // absent errorType (isSynthesizedHttpIncident) so the trace-dedupe (#624) can\n  // drop it — tagging it would defeat that collapse.\n  const httpStatus = httpResponseStatus(span)\n  return {\n    id: `${span.traceId}:${span.spanId}`,\n    timestamp: ts,\n    service: span.service,\n    traceId: span.traceId,\n    spanId: span.spanId,\n    errorMessage: incidentMessage(span),\n    ...(span.exception?.type ? { exceptionType: span.exception.type } : {}),\n    ...(span.exception?.stacktrace\n      ? { exceptionStacktrace: span.exception.stacktrace }\n      : {}),\n    ...(httpStatus !== undefined ? { httpStatusCode: httpStatus } : {}),\n    ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n    affectedNode: locus.affectedNode,\n  }\n}\n\n// Synchronous file-write helper bound to a receiver. The receiver awaits this\n// before replying, so a write failure surfaces as 500 → OTel SDK retries.\nexport function makeErrorSpanWriter(\n  errorsPath: string,\n  graph?: NeatGraph,\n  scanPath?: string,\n  project: string = DEFAULT_PROJECT,\n): (span: ParsedSpan) => Promise<void> {\n  return async (span) => {\n    const ev = buildErrorEventForReceiver(span, graph, scanPath)\n    if (!ev) return\n    await appendRuntimeIncident(errorsPath, project, ev)\n    emitIncidentEvent(project, ev)\n  }\n}\n\n// Write one failing-response incident (issue #481) to errors.ndjson. Used for\n// an unambiguous 5xx (count 1) and for a flushed 4xx burst (count N). The\n// dominant status code names the failure; `incidentCount` carries N so the\n// incident surface shows \"5× 404\" without the per-span flood. Span attributes\n// pass through verbatim, same as the statusCode === 2 path, so source\n// attribution (`code.*`) and the response code survive to the consumer.\nasync function recordFailingResponseIncident(\n  ctx: IngestContext,\n  span: ParsedSpan,\n  affectedNode: string,\n  timestamp: string,\n  statusCode: number,\n  count: number,\n  firstTimestamp?: string,\n): Promise<void> {\n  const attrs = sanitizeAttributes(span.attributes)\n  const first = firstTimestamp ?? timestamp\n  const peer = pickAddress(span)\n  const message =\n    count > 1\n      ? `${count} consecutive HTTP ${statusCode} responses` +\n        (peer ? ` to ${peer}` : '')\n      : `HTTP ${statusCode} response` + (peer ? ` from ${peer}` : '')\n  const ev: ErrorEvent = {\n    id: `${span.traceId}:${span.spanId}`,\n    timestamp,\n    service: span.service,\n    traceId: span.traceId,\n    spanId: span.spanId,\n    errorType: 'http-failure',\n    errorMessage: message,\n    ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n    affectedNode,\n    httpStatusCode: statusCode,\n    incidentCount: count,\n    firstTimestamp: first,\n    lastTimestamp: timestamp,\n  }\n  await appendErrorEvent(ctx, ev)\n}\n\n// Record one incident for a span that carries an exception event but no ERROR\n// status and no HTTP failure code — an async / queue / background worker\n// (bullmq, Redis Streams, a scheduled task) whose job threw (ADR-117). Incident\n// recording keys on the failure signal, not on HTTP context: the message\n// follows the shared incidentMessage chain and the record attributes to the\n// handler file:line when the span carries `code.filepath`, else to the\n// originating service (incidentAffectedNode). handleSpan owns this write — the\n// receiver's synchronous error-writer fires only for statusCode === 2, so an\n// exception-only worker span reaches durability here, the same way the\n// response-code incidents below do.\nasync function recordExceptionIncident(\n  ctx: IngestContext,\n  span: ParsedSpan,\n  ts: string,\n): Promise<void> {\n  const locus = incidentLocus(span, ctx.graph, ctx.scanPath)\n  const attrs = withRecoveredCodeAttrs(sanitizeAttributes(span.attributes), locus)\n  const ev: ErrorEvent = {\n    id: `${span.traceId}:${span.spanId}`,\n    timestamp: ts,\n    service: span.service,\n    traceId: span.traceId,\n    spanId: span.spanId,\n    errorMessage: incidentMessage(span),\n    ...(span.exception?.type ? { exceptionType: span.exception.type } : {}),\n    ...(span.exception?.stacktrace\n      ? { exceptionStacktrace: span.exception.stacktrace }\n      : {}),\n    ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n    affectedNode: locus.affectedNode,\n  }\n  await appendErrorEvent(ctx, ev)\n}\n\n// Record one incident for a non-OK gRPC span (issue #1065). OTel's gRPC\n// instrumentation leaves the span status UNSET and carries the outcome in\n// `rpc.grpc.status_code` (0 = OK), so both the ERROR-status path and the HTTP\n// response-code path above miss it — the dominant failure representation on a\n// gRPC microservice stack, and the reason get_incident_history read empty over a\n// service whose calls were all failing INTERNAL (13). Recorded immediately, the\n// same as an unambiguous 5xx: gRPC has no numeric 4xx/5xx split to coalesce on,\n// and the errorCount signal already counts every non-OK code, so the incident\n// ledger agrees with it. The message names the canonical gRPC status\n// (incidentMessage → nonHttpFailureMessage) and the raw `rpc.grpc.status_code`\n// rides along in the passed-through attributes; attribution matches the\n// exception path — the handler `file:line` when the span carries `code.filepath`,\n// the failing service otherwise (incidentAffectedNode).\nasync function recordGrpcFailureIncident(\n  ctx: IngestContext,\n  span: ParsedSpan,\n  ts: string,\n): Promise<void> {\n  const attrs = sanitizeAttributes(span.attributes)\n  const ev: ErrorEvent = {\n    id: `${span.traceId}:${span.spanId}`,\n    timestamp: ts,\n    service: span.service,\n    traceId: span.traceId,\n    spanId: span.spanId,\n    errorType: 'grpc-failure',\n    errorMessage: incidentMessage(span),\n    ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n    affectedNode: incidentAffectedNode(span, ctx.graph, ctx.scanPath),\n  }\n  await appendErrorEvent(ctx, ev)\n}\n\n// Advance the 4xx burst for this (source, peer) pair (issue #481). A burst\n// accumulates silently; only when it crosses the threshold inside the window\n// does it flush ONE coalesced incident. A 4xx that arrives more than windowMs\n// after the previous one resets the burst — a slow trickle of probes never\n// coalesces. The dominant code is the most frequent 4xx seen across the burst.\nasync function advance4xxBurst(\n  ctx: IngestContext,\n  span: ParsedSpan,\n  affectedNode: string,\n  ts: string,\n  nowMs: number,\n  status: number,\n): Promise<void> {\n  const { threshold, windowMs } = loadIncidentThresholdsFromEnv()\n  if (!ctx.burstState) ctx.burstState = new Map()\n  const peer = pickAddress(span) ?? span.spanId\n  const key = `${span.service}->${peer}`\n  const existing = ctx.burstState.get(key)\n  let state: BurstState\n  if (existing && nowMs - existing.lastMs <= windowMs) {\n    existing.count += 1\n    existing.lastTs = ts\n    existing.lastMs = nowMs\n    existing.codes.set(status, (existing.codes.get(status) ?? 0) + 1)\n    state = existing\n  } else {\n    state = {\n      count: 1,\n      firstTs: ts,\n      lastTs: ts,\n      lastMs: nowMs,\n      codes: new Map([[status, 1]]),\n    }\n    ctx.burstState.set(key, state)\n  }\n\n  if (state.count < threshold) return\n\n  // Threshold met — flush one incident carrying the count, the dominant code,\n  // and the burst's first/last timestamps, then clear the burst so the next\n  // run of failures records its own incident rather than re-flushing every span.\n  let dominant = status\n  let max = 0\n  for (const [code, n] of state.codes) {\n    if (n > max) {\n      max = n\n      dominant = code\n    }\n  }\n  await recordFailingResponseIncident(\n    ctx,\n    span,\n    affectedNode,\n    state.lastTs,\n    dominant,\n    state.count,\n    state.firstTs,\n  )\n  ctx.burstState.delete(key)\n}\n\n// Next.js API-route serving spans name the matched route in `next.span_name`\n// (mirrored on the span's own name), NOT in `http.route`: the Pages Router emits\n// `executing api route (pages) /api/products/[productId]` and the App Router\n// `executing api route (app) /api/products/[productId]`. That phrase carries the\n// *templated* route — `[productId]` brackets and all — which is what fuses onto a\n// declared RouteNode; the same request's `http.target` carries only the concrete\n// path (`/api/products/L9ECAV7KIM`), which no param template ever matches. Pull\n// the template out of that phrase so a Next route earns its OBSERVED twin the way\n// an Express `http.route` already does (ADR-204). Returns undefined for any span\n// without the phrase, so the caller falls back to `http.route` and every other\n// framework fuses exactly as before — the source is additive, never a swap.\nconst NEXT_API_ROUTE_SPAN_NAME = /^executing api route \\((?:pages|app)\\) (\\/\\S*)$/\n\nfunction nextApiRouteTemplate(span: ParsedSpan): string | undefined {\n  const raw = pickAttr(span, 'next.span_name') ?? span.name\n  const match = raw ? NEXT_API_ROUTE_SPAN_NAME.exec(raw) : null\n  return match ? match[1] : undefined\n}\n\n// Match a SERVER span's `http.route` to the RouteNode the static extractor\n// minted, by normalized (method, template) so param-syntax differences\n// (`{id}` vs `:id` vs `<int:id>`) don't block the fusion. Returns the node id or\n// undefined; an unmatched route mints nothing here — a route NEAT never extracted\n// has no declared twin to fuse, and the served-but-undeclared case is a follow-on.\nfunction findRouteNodeByHttpRoute(\n  graph: NeatGraph,\n  serviceName: string,\n  method: string | undefined,\n  httpRoute: string,\n): string | undefined {\n  const target = normalizePathTemplate(httpRoute)\n  const m = method?.toUpperCase()\n  let found: string | undefined\n  graph.forEachNode((id, attrs) => {\n    if (found) return\n    const a = attrs as RouteNode & { type?: string }\n    if (a.type !== NodeType.RouteNode || a.service !== serviceName) return\n    if (m && a.method !== 'ALL' && a.method !== m) return\n    if (normalizePathTemplate(a.pathTemplate) === target) found = id\n  })\n  return found\n}\n\n// The request path of a SERVER span that names no route template (ADR-253, #1420):\n// `url.path`, else `http.target`, else the path of `url.full` / `http.url`, with\n// the query and fragment dropped. Jaeger-era and OpenTracing HTTP instrumentation\n// records the concrete request and never the matched template.\nfunction serverRequestPath(span: ParsedSpan): string | undefined {\n  let raw = pickAttr(span, 'url.path', 'http.target')\n  if (!raw) {\n    const url = pickAttr(span, 'url.full', 'http.url')\n    if (!url) return undefined\n    try {\n      raw = new URL(url).pathname\n    } catch {\n      return undefined\n    }\n  }\n  const path = raw.split('?')[0]!.split('#')[0]!\n  return path.startsWith('/') ? path : undefined\n}\n\n// A declared template segment that names a parameter: `:id`, `{id}`, `<id>` /\n// `<int:id>`, `[id]`.\nfunction isTemplateParam(seg: string): boolean {\n  return seg.startsWith(':') || seg.startsWith('{') || seg.startsWith('<') || seg.startsWith('[')\n}\n\n// Match a SERVER span's concrete request path against the RouteNodes the static\n// extractor minted for its service. A param segment matches exactly one path\n// segment, a literal matches itself (case-insensitive), and the method must agree\n// when the span names one. Exactly one matching route joins; none or several join\n// nothing, so a request that two declared routes could serve is never guessed at.\n// RouteNodes only come from extraction, so a URL never mints one.\nfunction findRouteNodeByRequestPath(\n  graph: NeatGraph,\n  serviceName: string,\n  method: string | undefined,\n  requestPath: string,\n): string | undefined {\n  const segs = requestPath.split('/').filter((x) => x.length > 0)\n  const m = method?.toUpperCase()\n  const matches: string[] = []\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as RouteNode & { type?: string }\n    if (a.type !== NodeType.RouteNode || a.service !== serviceName) return\n    if (m && a.method !== 'ALL' && a.method !== m) return\n    const tpl = a.pathTemplate.split('?')[0]!.split('/').filter((x) => x.length > 0)\n    if (tpl.length !== segs.length) return\n    for (let i = 0; i < tpl.length; i++) {\n      if (isTemplateParam(tpl[i]!)) continue\n      if (tpl[i]!.toLowerCase() !== segs[i]!.toLowerCase()) return\n    }\n    matches.push(id)\n  })\n  return matches.length === 1 ? matches[0] : undefined\n}\n\nexport async function handleSpan(ctx: IngestContext, span: ParsedSpan): Promise<void> {\n  // lastObserved derives from the span's own startTime per ADR-033 — replayed\n  // traces and out-of-order spans get a timestamp that reflects when the call\n  // actually fired, not when the receiver received it. Wall-clock is only the\n  // fallback for spans whose startTimeUnixNano is missing or unparseable.\n  const ts = span.startTimeIso ?? nowIso(ctx)\n  const nowMs = ctx.now ? ctx.now() : Date.now()\n  // Env discriminator from `deployment.environment(.name)` (ADR-074 §2).\n  // Older ParsedSpan producers may omit it — fall back to the literal\n  // `'unknown'` so the env-less wire format is preserved on auto-creation.\n  const env = span.env ?? 'unknown'\n  // Issue #374 — spans whose resource omits `service.name` route to\n  // `service:unidentified` in the URL-resolved project (the parser already\n  // substitutes the fallback). One warning per project per session names\n  // the project so an operator can fix the SDK config without grepping.\n  if (span.resourceServiceNamePresent === false) {\n    warnUnidentifiedSpan(ctx.project ?? DEFAULT_PROJECT)\n  }\n  // Auto-create a minimal ServiceNode for unseen span.service so OBSERVED\n  // edges land instead of silently dropping. Static extraction merges richer\n  // fields when it later finds the same id (ADR-033). The node is env-tagged\n  // when the span carries an env signal.\n  const sourceId = ensureServiceNode(ctx.graph, span.service, env)\n  // Fires on the span's own ERROR status AND on the attribute forms most gRPC/HTTP\n  // SDKs actually use — a non-OK gRPC status or an HTTP 5xx left on an UNSET span\n  // (spanRecordsError, issue #1065). This is the sole feed for the edge's\n  // errorCount signal, so the failing-CALLS chain get_root_cause walks now sees a\n  // gRPC-based stack's failures instead of reading them as clean traffic.\n  const isError = spanRecordsError(span)\n  // Span duration in ms for the OBSERVED latency signal (ADR-190). Only a real,\n  // positive duration is recorded; a span with missing/degenerate times\n  // contributes no latency rather than a fabricated zero (file-awareness.md §6).\n  // A streaming / long-lived span (WebSocket, SSE, a gRPC stream past the\n  // duration ceiling) carries the stream's whole lifetime as its duration, not a\n  // per-request latency, so it is withheld from the latency feed — the digest\n  // stays a per-request p95 and the saturation classifier does not false-fire\n  // (ADR-208). Every other signal on the span still records; `undefined` here\n  // leaves any prior latency on the edge untouched, never cleared (upsertObservedEdge).\n  const durationMs =\n    span.durationNanos > 0n && !spanIsStreaming(span)\n      ? Number(span.durationNanos) / 1e6\n      : undefined\n  // The bounded last-error exemplar's detail (ADR-236). Resolved once from the\n  // span's exception event + HTTP status and passed into every OBSERVED edge\n  // minted on this span's error path, so a failing edge carries WHAT failed —\n  // the real span exception type/message — not just an error count. Only built\n  // on a failing span; a clean span passes `undefined` and never disturbs a\n  // prior exemplar. The ledger still records the full exception independently\n  // (§Error events); this is the edge-level complement, not a replacement.\n  const errorDetail = isError ? edgeErrorDetailFromSpan(span) : undefined\n\n  // File-first OBSERVED origin (file-awareness.md §4). When the injected\n  // SpanProcessor captured a call site on this outbound (CLIENT/PRODUCER) span,\n  // the relationship originates from the file; without one it stays\n  // service-level. `observedSource()` creates the FileNode + CONTAINS lazily so\n  // they only land when an edge actually does — and never for the inbound\n  // (SERVER) parent-fallback side, which carries no call site.\n  const sourceServiceNode = ctx.graph.getNodeAttributes(sourceId) as ServiceNode\n  const callSite = callSiteFromSpan(span, sourceServiceNode, ctx.scanPath)\n\n  // Stash this span in the parent-span cache so any later child whose address\n  // resolution misses can still resolve the cross-service edge via parentSpanId.\n  // The call site rides along so the fallback edge anchors to this span's\n  // file:line when this span turns out to be a parent (issue #536).\n  cacheSpanService(span, nowMs, callSite)\n  const observedSource = (): string =>\n    callSite ? ensureObservedFileNode(ctx.graph, span.service, sourceId, callSite) : sourceId\n  // Evidence for the OBSERVED edge — populated from the span's code.* semconv\n  // when the call site resolved (file-awareness.md §4 + §6). Never fabricated:\n  // absent call site → undefined evidence. The path is reconciled the same way\n  // the edge's origin node is (reconcileObservedRelPath), so evidence.file names\n  // the fused EXTRACTED path the edge lands on rather than the raw deployed\n  // absolute path — otherwise the edge node and its own evidence disagree.\n  const callSiteEvidence: { file: string; line?: number } | undefined = callSite\n    ? {\n        file: reconcileObservedRelPath(ctx.graph, span.service, callSite.relPath),\n        ...(callSite.line !== undefined ? { line: callSite.line } : {}),\n      }\n    : undefined\n\n  let affectedNode = sourceId\n\n  // Feature-flag evaluations on this span (ADR-242): the second OBSERVED source\n  // for the flag grain, beside the store's own sync reader.\n  for (const ev of span.flagEvaluations ?? []) {\n    recordFlagEvaluation(ctx.graph, observedSource, ev, ts, callSiteEvidence)\n  }\n\n  // Only the caller/producer side of a call mints an OBSERVED edge directly\n  // (issue #429). INTERNAL / SERVER / CONSUMER spans don't: a SERVER/CONSUMER\n  // span is the callee, and its edge is minted from its parent via the\n  // parent-span fallback below (left ungated). Gating here keeps INTERNAL\n  // connection spans (`tcp.connect` / `tls.connect` with a peer address) from\n  // minting spurious service-level edges.\n  const mintsFromCallerSide = spanMintsObservedEdge(span.kind)\n\n  if (span.dbSystem) {\n    // Database span. A networked database resolves its DatabaseNode by peer\n    // host; an in-process / embedded one (SQLite, better-sqlite3, an in-memory\n    // store) crosses no network boundary and carries no peer address, so it\n    // keys on a service-scoped local identity instead (ADR-118). Both mint the\n    // same file-grained service→database CONNECTS_TO OBSERVED edge — the edge\n    // that makes a leaf service's datastore reads legible (#576, #546).\n    if (mintsFromCallerSide) {\n      const host = pickAddress(span)\n      // Engine comes off the OTel attribute as a string per Rule 8 — no\n      // hardcoded engine list on either branch.\n      let targetId: string\n      if (host) {\n        ensureDatabaseNode(ctx.graph, host, span.dbSystem)\n        targetId = databaseId(host)\n      } else {\n        // No peer host. Prefer fusing onto the service's declared database of\n        // the same engine (ADR-141) so an ORM's host-less span confirms the\n        // static dependency instead of minting a divergent twin. Falls back to a\n        // service-local node (ADR-118) for a genuinely embedded DB (SQLite) or an\n        // ambiguous declaration. Name the local node by its logical database\n        // (db.name) when the span carries one, the engine otherwise.\n        const declared = findDeclaredDatabaseForService(ctx.graph, sourceId, span.dbSystem)\n        if (declared) {\n          targetId = declared\n        } else {\n          const localName = span.dbName ?? span.dbSystem\n          targetId = ensureLocalDatabaseNode(\n            ctx.graph,\n            span.service,\n            localName,\n            span.dbSystem,\n          )\n        }\n      }\n      const result = upsertObservedEdge(\n        ctx.graph,\n        EdgeType.CONNECTS_TO,\n        observedSource(),\n        targetId,\n        ts,\n        isError,\n        callSiteEvidence,\n        durationMs,\n        errorDetail,\n      )\n      if (result) affectedNode = targetId\n\n      // ADR-148 — a mongodb span also names the collection it operated on, one\n      // grain finer than the database node above. Mint an additive OBSERVED\n      // CALLS edge to `infra:mongodb-collection:<name>` — the same node id the\n      // mongoose extractor emits (ensureInfraNode + infraId match calls/index.ts\n      // exactly) — so the declared and observed collection edges fuse instead of\n      // twinning. The collection is read straight off the span (dbCollection:\n      // db.collection.name / db.mongodb.collection), so it is ground truth where\n      // the extractor's Mongoose-pluralized derivation is quirk-wrong. Additive:\n      // a mongodb span with no collection still mints only the db-grain edge\n      // above.\n      if (span.dbSystem === 'mongodb' && span.dbCollection) {\n        const collectionId = ensureInfraNode(ctx.graph, 'mongodb-collection', span.dbCollection, 'self')\n        upsertObservedEdge(\n          ctx.graph,\n          EdgeType.CALLS,\n          observedSource(),\n          collectionId,\n          ts,\n          isError,\n          callSiteEvidence,\n          durationMs,\n          errorDetail,\n        )\n      }\n      // A SQL span's table (ADR-152), recovered from `db.statement` because the\n      // SQLAlchemy / dbapi instrumentation carries no table attribute. It mints\n      // onto the same `infra:sql-table:<name>` node the SQLAlchemy extractor\n      // produces, so the declared and observed table access fuse rather than\n      // twin. `db.statement`-derived, so it is ground truth where the extractor's\n      // model→table derivation is unresolved; additive to the db-grain edge.\n      if (span.dbTable) {\n        const tableId = ensureInfraNode(ctx.graph, 'sql-table', span.dbTable, 'self')\n        upsertObservedEdge(\n          ctx.graph,\n          EdgeType.CALLS,\n          observedSource(),\n          tableId,\n          ts,\n          isError,\n          callSiteEvidence,\n          durationMs,\n          errorDetail,\n        )\n        // ADR-157 — the same `db.statement` that named the table also names the\n        // columns it touched. Merge them onto the table node as OBSERVED column\n        // attributes (parsed in `parseOtlpRequest` via `columnsFromSqlStatement`).\n        // A statement that recovers no columns (`SELECT *`, a join/subquery\n        // degrade) grows nothing.\n        mergeObservedColumns(ctx.graph, tableId, span.dbColumns)\n      }\n    }\n  } else if (\n    span.messagingSystem &&\n    span.messagingDestination &&\n    spanMintsMessagingEdge(span.kind)\n  ) {\n    // Messaging span. The semantic destination is the topic / queue / stream the\n    // code talks to — not the broker host, which is transport. A PRODUCER span\n    // publishes; a CONSUMER span consumes. Both mint an OBSERVED edge to the same\n    // destination node the static extractor names (extract/calls/kafka.ts), so\n    // the declared and observed queue edges fuse into one (→ divergence) instead\n    // of twinning. File-grained through the same call-site path as any other\n    // OBSERVED edge (file-awareness.md §4): when the span carries `code.*`, the\n    // edge originates from the caller's FileNode at the exact call site,\n    // reconciled onto the EXTRACTED service-relative path (`reconcileObservedRelPath`,\n    // ADR-118); without a call site it stays service-level, honestly. This is the\n    // consumer-side pair of the producer edge — the queue topology the OBSERVED\n    // layer used to leave dark on the consumer side (issue #614).\n    const targetId = ensureMessagingDestinationNode(\n      ctx.graph,\n      span.messagingSystem,\n      span.messagingDestination,\n    )\n    const edgeType =\n      span.kind === WIRE_SPAN_KIND_CONSUMER\n        ? EdgeType.CONSUMES_FROM\n        : EdgeType.PUBLISHES_TO\n    const result = upsertObservedEdge(\n      ctx.graph,\n      edgeType,\n      observedSource(),\n      targetId,\n      ts,\n      isError,\n      callSiteEvidence,\n      durationMs,\n      errorDetail,\n    )\n    if (result) affectedNode = targetId\n  } else if (\n    span.graphqlOperationName &&\n    span.graphqlOperationType &&\n    spanServesGraphqlOperation(span.kind)\n  ) {\n    // GraphQL execution span (issue #615). Every GraphQL request rides one HTTP\n    // endpoint (`POST /graphql`), so at HTTP grain the whole API collapses to a\n    // single edge and the operation-level topology is invisible. The execution\n    // span carries the operation the client actually named — `graphql.operation.name`\n    // with `graphql.operation.type` — so mint an OBSERVED `CONTAINS` edge from the\n    // serving service to a per-operation node, the same ownership shape a service\n    // has over a route (ADR-119) and a file (file-awareness.md §2). OBSERVED-only:\n    // the SDL / resolver map is not parsed statically in this cut; the node is\n    // minted observed-first and a future static GraphQL extractor fuses onto the\n    // same id (ADR-122). File-grained through the same call-site path as any other\n    // OBSERVED edge (file-awareness.md §4): when the span carries `code.*` (the\n    // resolver call site) the edge originates from that `FileNode` at the exact\n    // `file:line`, reconciled onto the EXTRACTED service-relative path; without a\n    // call site it stays service-level, honestly. Both operation name and type\n    // must be present to key a stable id — a nameless/typeless execution span\n    // falls through rather than minting a fabricated operation.\n    const targetId = ensureGraphqlOperationNode(\n      ctx.graph,\n      span.service,\n      span.graphqlOperationType,\n      span.graphqlOperationName,\n    )\n    const result = upsertObservedEdge(\n      ctx.graph,\n      EdgeType.CONTAINS,\n      observedSource(),\n      targetId,\n      ts,\n      isError,\n      callSiteEvidence,\n      durationMs,\n      errorDetail,\n    )\n    if (result) affectedNode = targetId\n  } else if (\n    span.rpcSystem === 'grpc' &&\n    span.rpcService &&\n    span.rpcMethod &&\n    spanServesGrpcMethod(span.kind)\n  ) {\n    // gRPC execution span (issue #616). gRPC used to engage only at service\n    // grain: every method collapsed onto one service→service edge, so the\n    // per-method topology was invisible and one-sided. The serving span carries\n    // the method the caller actually invoked — `rpc.service` (the fully-qualified\n    // `orders.OrderService`) with `rpc.method` (`GetOrder`) — so mint an OBSERVED\n    // `CONTAINS` edge from the serving service to a per-method node, the same\n    // ownership shape a service has over a route (ADR-119), a GraphQL operation\n    // (ADR-122), and a file (file-awareness.md §2). The node is keyed on the\n    // fully-qualified `rpc.service` — the wire contract both the span and the\n    // `.proto` carry verbatim — so the static `.proto` extractor's declared\n    // method fuses onto this same id into a two-sided divergence (ADR-123).\n    // File-grained through the same call-site path as any other OBSERVED edge\n    // (file-awareness.md §4): when the span carries `code.*` (the handler call\n    // site) the edge originates from that `FileNode` at the exact `file:line`,\n    // reconciled onto the EXTRACTED service-relative path; without a call site it\n    // stays service-level, honestly. The gate admits only the serving side —\n    // SERVER / INTERNAL / unkinded — so a CLIENT span mints no ownership\n    // (client→method attribution is deferred) and instead falls through to the\n    // cross-service resolver, leaving the caller→callee edge intact. Both service\n    // and method must be present to key a stable id.\n    const targetId = ensureGrpcMethodNode(ctx.graph, span.rpcService, span.rpcMethod)\n    const result = upsertObservedEdge(\n      ctx.graph,\n      EdgeType.CONTAINS,\n      observedSource(),\n      targetId,\n      ts,\n      isError,\n      callSiteEvidence,\n      durationMs,\n      errorDetail,\n    )\n    if (result) affectedNode = targetId\n  } else if (span.websocketChannel && spanServesWebsocketChannel(span.kind)) {\n    // WebSocket upgrade span (issue #617). A WebSocket app used to produce no\n    // OBSERVED topology at all: only message-handler errors surfaced, as\n    // incidents, and the channels themselves stayed invisible — the frames after\n    // the handshake ride the socket, not more spans. The one span that reliably\n    // marks a channel is the HTTP upgrade that opens it: a SERVER `GET` carrying\n    // `Upgrade: websocket` and the connection path. So mint an OBSERVED\n    // `CONNECTS_TO` edge from the serving service to a per-channel node —\n    // reusing the same connection edge a service has to a datastore (#576), not a\n    // new edge type. Unlike the structural `CONTAINS` a service has over a route /\n    // operation / method — durably declared artifacts whose edge never goes\n    // stale — a channel's whole meaning is liveness, so `CONNECTS_TO` is the right\n    // shape: it carries `lastObserved` and decays OBSERVED → STALE on\n    // CONNECTS_TO's own threshold when the channel goes quiet (the daemon\n    // staleness loop, #532). OBSERVED-only: a WebSocket channel is known from\n    // observation, never from static extraction, so the node has no declared twin\n    // and is excluded from `missing-extracted` (divergences.ts). File-grained\n    // through the same call-site path as any other OBSERVED edge\n    // (file-awareness.md §4): when the span carries `code.*` the edge originates\n    // from that `FileNode` at the exact `file:line`, reconciled onto the EXTRACTED\n    // service-relative path; without a call site it stays service-level, honestly.\n    // The gate admits only the serving side — SERVER / INTERNAL / unkinded — so a\n    // CLIENT upgrade span mints no channel (client→channel attribution is\n    // deferred, ADR-125).\n    const targetId = ensureWebsocketChannelNode(\n      ctx.graph,\n      span.service,\n      span.websocketChannel,\n    )\n    const result = upsertObservedEdge(\n      ctx.graph,\n      EdgeType.CONNECTS_TO,\n      observedSource(),\n      targetId,\n      ts,\n      isError,\n      callSiteEvidence,\n      durationMs,\n      errorDetail,\n    )\n    if (result) affectedNode = targetId\n  } else {\n    // Possibly a cross-service call. Resolve the peer; if it matches a known\n    // ServiceNode, record an OBSERVED CALLS edge to the typed target. If it\n    // matches nothing — pod IP, ingress hostname, AWS PrivateLink endpoint —\n    // create a FrontierNode placeholder and record an OBSERVED edge to that\n    // FrontierNode so the call carries the same provenance + signal-block +\n    // graded confidence as any other OBSERVED edge (ADR-068). The target ref\n    // identifies the node-type; provenance describes how the edge was learned.\n    // promoteFrontierNodes (run by the extract orchestrator) rewrites the\n    // target ref once a later round resolves the host; the edge's provenance\n    // stays OBSERVED across promotion.\n    // A loopback host (localhost / 127.0.0.0/8 / ::1) is skipped here: it never\n    // resolves to a distinct peer, and minting frontier:localhost would double\n    // the edge that the callee's parent-span fallback already records for this\n    // same call (issues #590, #577). Leaving resolvedViaAddress false hands the\n    // call to that fallback instead.\n    const host = calleeAddress(span)\n    let resolvedViaAddress = false\n\n    // An opentracing datastore client (#1415). A Jaeger-converted datastore span\n    // carries no `db.system` — it names the engine in `peer.service` and the host in\n    // `peer.hostname` (DeathStarBench `memcached_get_profile`: peer.service=memcached,\n    // peer.hostname=memcached-profile). The OTel-native db branch above never fires on\n    // it, so resolve it the same way that branch does — a DatabaseNode keyed on the\n    // host, engine from `peer.service`, `CONNECTS_TO` — fusing onto the datastore node\n    // an OTel-native span would land on. Gated on `peer.service` naming an engine NEAT\n    // already recognizes (`knownDatastoreEngine`, the one list `classifyImage` reads),\n    // so a `peer.service` that is a service name mints nothing rather than a bogus\n    // DatabaseNode; a genuine service-name peer tier stays an unclaimed slot\n    // (otel-ingest §peer). Caller-side only, matching the db branch.\n    const datastoreEngine = mintsFromCallerSide\n      ? knownDatastoreEngine(span.peerService)\n      : undefined\n    if (datastoreEngine && span.peerHostname) {\n      const datastoreId = ensureDatabaseNode(ctx.graph, span.peerHostname, datastoreEngine)\n      upsertObservedEdge(\n        ctx.graph,\n        EdgeType.CONNECTS_TO,\n        observedSource(),\n        datastoreId,\n        ts,\n        isError,\n        callSiteEvidence,\n        durationMs,\n        errorDetail,\n      )\n      affectedNode = datastoreId\n      resolvedViaAddress = true\n    }\n\n    // Callee resolution is additive across grains, the way the db branch above mints\n    // a mongodb-collection / sql-table CALLS alongside the datastore edge, not instead\n    // of it:\n    //   • gRPC method (#1413) — a CLIENT span names the method it invoked via\n    //     `rpc.service` (the fully-qualified FQN) + `rpc.method`, the same pair the\n    //     serving branch (#616) and the static `.proto` key their `grpc:<service>/<method>`\n    //     node on. Mint an OBSERVED `CALLS` onto it — the invocation dual of the serving\n    //     side's `CONTAINS` ownership — a method-grain callee finer than the peer service.\n    //   • peer host — `server.address` / `net.peer.name` / url → ServiceNode, else a\n    //     bare-host FrontierNode. [#1415 peer.service/peer.hostname and #1411 ClusterIP→\n    //     ServiceNode via the k8s connector extend this host tier.]\n    // Both edges are minted, so the service→service reachability the host tier records\n    // is preserved. The one interaction: when the method node already captured the\n    // callee, an in-cluster ClusterIP on `server.address` needs no FrontierNode — the\n    // method node (owned by the serving service through its #616 / `.proto` CONTAINS\n    // edge) is the better-resolved callee, so caller→method→owner reaches it where an IP\n    // placeholder never would.\n    let grpcMethodNodeId: string | undefined\n    if (\n      mintsFromCallerSide &&\n      span.rpcSystem === 'grpc' &&\n      span.rpcService &&\n      span.rpcMethod\n    ) {\n      grpcMethodNodeId = ensureGrpcMethodNode(ctx.graph, span.rpcService, span.rpcMethod)\n      upsertObservedEdge(\n        ctx.graph,\n        EdgeType.CALLS,\n        observedSource(),\n        grpcMethodNodeId,\n        ts,\n        isError,\n        callSiteEvidence,\n        durationMs,\n        errorDetail,\n      )\n      affectedNode = grpcMethodNodeId\n      resolvedViaAddress = true\n    }\n\n    if (mintsFromCallerSide && host && host !== span.service && !isLoopbackHost(host)) {\n      const targetId =\n        resolveServiceId(ctx.graph, host, env) ?? serviceIdForObservedAddress(ctx.graph, host)\n      if (targetId && targetId !== sourceId) {\n        upsertObservedEdge(\n          ctx.graph,\n          EdgeType.CALLS,\n          observedSource(),\n          targetId,\n          ts,\n          isError,\n          callSiteEvidence,\n          durationMs,\n          errorDetail,\n        )\n        affectedNode = targetId\n        resolvedViaAddress = true\n      } else if (!targetId && !grpcMethodNodeId) {\n        // No gRPC method node captured this callee, so a bare host (pod IP, ingress\n        // hostname, a ClusterIP) still mints a FrontierNode placeholder (ADR-068).\n        const frontierNodeId = ensureFrontierNode(ctx.graph, host, ts)\n        upsertObservedEdge(\n          ctx.graph,\n          EdgeType.CALLS,\n          observedSource(),\n          frontierNodeId,\n          ts,\n          isError,\n          callSiteEvidence,\n          durationMs,\n          errorDetail,\n        )\n        affectedNode = frontierNodeId\n        resolvedViaAddress = true\n      }\n    }\n\n    // Parent-span fallback (ADR-033): when address-based resolution didn't\n    // produce an edge and the span has a parentSpanId we've cached, the\n    // parent's service identifies the caller. The current span is the server\n    // side of the call, so the edge direction is parent.service → current.\n    // The cached entry carries the parent span's env, so the auto-created\n    // parent ServiceNode lands on the env-tagged id the parent advertised.\n    if (!resolvedViaAddress && span.parentSpanId) {\n      const parent = lookupParentSpan(span.traceId, span.parentSpanId, nowMs)\n      if (parent && parent.service !== span.service) {\n        const parentId = ensureServiceNode(ctx.graph, parent.service, parent.env)\n        // When the parent span carried a `code.*` call site, originate the edge\n        // from the parent's FileNode so it anchors to file:line instead of the\n        // bare parent ServiceNode (issue #536). Without a cached call site the\n        // edge stays service-coarse — never fabricated (file-awareness.md §6).\n        const fallbackSource = parent.callSite\n          ? ensureObservedFileNode(ctx.graph, parent.service, parentId, parent.callSite)\n          : parentId\n        const fallbackEvidence: { file: string; line?: number } | undefined =\n          parent.callSite\n            ? {\n                file: reconcileObservedRelPath(\n                  ctx.graph,\n                  parent.service,\n                  parent.callSite.relPath,\n                ),\n                ...(parent.callSite.line !== undefined\n                  ? { line: parent.callSite.line }\n                  : {}),\n              }\n            : undefined\n        upsertObservedEdge(\n          ctx.graph,\n          EdgeType.CALLS,\n          fallbackSource,\n          sourceId,\n          ts,\n          isError,\n          fallbackEvidence,\n          durationMs,\n          errorDetail,\n        )\n      }\n    }\n  }\n\n  // A SERVER span's route fuses onto the declared RouteNode, giving an inbound\n  // route its OBSERVED twin the way GraphQL/gRPC serving spans do (#576). Matched\n  // by normalized (method, template) so a route NEAT extracted gets its observed\n  // counterpart; an unmatched route mints nothing here, honestly. Next.js names\n  // the template in `next.span_name` rather than `http.route`, so prefer that\n  // templated form over the concrete path when it's present (ADR-204); a span\n  // carrying neither falls through with no edge, as before.\n  // With no template at all, the concrete request path joins a declared route only\n  // when exactly one route of this service matches it (ADR-253).\n  const fusionRoute = nextApiRouteTemplate(span) ?? span.httpRoute\n  const requestPath = fusionRoute ? undefined : serverRequestPath(span)\n  if (\n    (fusionRoute || requestPath) &&\n    (span.kind === 2 || span.kind === 1 || span.kind === 0 || span.kind === undefined)\n  ) {\n    const routeNodeId = fusionRoute\n      ? findRouteNodeByHttpRoute(ctx.graph, span.service, span.httpMethod, fusionRoute)\n      : findRouteNodeByRequestPath(ctx.graph, span.service, span.httpMethod, requestPath!)\n    if (routeNodeId) {\n      const routeSvc = (ctx.graph.getNodeAttributes(routeNodeId) as RouteNode).service\n      upsertObservedEdge(ctx.graph, EdgeType.CONTAINS, serviceId(routeSvc), routeNodeId, ts, isError, undefined, durationMs, errorDetail)\n    }\n  }\n\n  if (span.statusCode === 2) {\n    stitchTrace(ctx.graph, sourceId, ts)\n    // The durable ErrorEvent write moved to the receiver so the file write\n    // happens synchronously before the 200 reply (ADR-033 §Error events,\n    // amended). watch.ts wires makeErrorSpanWriter into onErrorSpanSync.\n    // handleSpan still runs the in-graph error effects (stitchTrace above);\n    // it just doesn't append to errors.ndjson anymore. ctx.errorsPath stays\n    // for the optional opt-in path below — daemon-less callers (CLI tests,\n    // ad-hoc scripts) that skip the receiver hook still get a write here.\n    if (ctx.writeErrorEventInline !== false) {\n      // Daemon-less callers (CLI tests, ad-hoc scripts) that skip the receiver\n      // hook get their write here — through the same builder the receiver uses\n      // (buildErrorEventForReceiver), so the incident shape is one source of\n      // truth: the source-based ADR-191/216 attribution and the #1118 HTTP-status\n      // enrichment live in one place, not two drifting copies.\n      const ev = buildErrorEventForReceiver(span, ctx.graph, ctx.scanPath)\n      if (ev) await appendErrorEvent(ctx, ev)\n    }\n  }\n\n  // Failing-response incidents (issue #481). OTel semconv leaves a CLIENT span's\n  // status UNSET on a 4xx/5xx response, so the status-only path above is blind\n  // to a service whose outbound calls are failing en masse — the exact gap a\n  // debugging session hits (80× HTTP 404 against one peer surfacing nothing).\n  // A response status is read from the span here regardless of statusCode:\n  //   * 5xx → record an incident immediately (unambiguous failure, even with\n  //     UNSET status). Skipped when statusCode === 2 already recorded above so\n  //     a 5xx that also carries ERROR status isn't double-counted.\n  //   * 4xx on a CLIENT/PRODUCER span → coalesce. The burst against this\n  //     (source, peer) pair advances; when it reaches the threshold inside the\n  //     window it records ONE incident carrying the count and dominant code.\n  //   * a lone 4xx, or any 2xx/3xx → no incident.\n  // Always written here (not gated on writeErrorEventInline): the daemon's\n  // receiver only fires its synchronous error-writer for statusCode === 2, so\n  // these spans never reach that durability handoff — handleSpan owns them.\n  if (span.statusCode !== 2) {\n    const status = httpResponseStatus(span)\n    const grpcStatus = grpcStatusCodeFromAttrs(span.attributes)\n    // ADR-117 — an exception event on a span that left its status UNSET is\n    // still an unambiguous failure: a bullmq / Redis-Streams / background\n    // worker whose job threw carries the exception and no HTTP response\n    // context, so the status-only and response-code paths both miss it. Record\n    // it independent of HTTP, attributed to the handler file:line (or the\n    // service) the same way the statusCode === 2 path is. Ordered first because\n    // the exception is the unambiguous signal; the response-code branches below\n    // carry the exception-less HTTP failures.\n    if (span.exception) {\n      await recordExceptionIncident(ctx, span, ts)\n    } else if (status !== undefined && status >= 500) {\n      // A failing-response incident is attributed to the SOURCE service — the\n      // caller whose outbound calls are failing is the node a debugger asks\n      // about (\"why is my service erroring\"). The peer it failed against is\n      // carried in the message and in attributes. This is deliberately not the\n      // edge target (frontier/peer) the OBSERVED edge above resolved to: the\n      // signal is \"this service's calls to X are failing\", not \"X failed\".\n      await recordFailingResponseIncident(ctx, span, sourceId, ts, status, 1)\n    } else if (grpcStatus !== undefined && grpcStatus !== 0) {\n      // A non-OK gRPC status with UNSET span status (issue #1065) — the case the\n      // HTTP branches above can't see. Record it immediately, mirroring the 5xx\n      // path. The branches are mutually exclusive in practice (a span is a gRPC\n      // call or an HTTP one, not both), and the else-if chain records at most one\n      // incident per span, so this never double-counts against the 4xx-burst path\n      // below (a pure gRPC span carries no HTTP status to reach it anyway).\n      await recordGrpcFailureIncident(ctx, span, ts)\n    } else if (\n      status !== undefined &&\n      status >= 400 &&\n      spanMintsObservedEdge(span.kind)\n    ) {\n      await advance4xxBurst(ctx, span, sourceId, ts, nowMs, status)\n    }\n  }\n  void affectedNode\n\n  // Post-ingest policy trigger (ADR-043). The hook is awaited so failures\n  // surface; daemons wrap it in a try/catch that logs without throwing.\n  if (ctx.onPolicyTrigger) await ctx.onPolicyTrigger(ctx.graph)\n}\n\nexport { stitchTrace }\n\n// Promote any frontier:<host> placeholder whose host matches an alias on a\n// real ServiceNode: re-link inbound/outbound edges to the service, then drop\n// the placeholder. Returns the count of nodes promoted, for tests + logs.\n//\n// Called at the end of every extraction round. Static rounds are when new\n// aliases land (compose names, k8s metadata.name, Dockerfile labels), so\n// running it there picks up the case the issue describes: ingest fills in a\n// frontier when traffic arrives for an unknown host, and the next extraction\n// round resolves it.\n// Optional gate for block-action policies (ADR-044). When `policies` is\n// non-empty, each candidate FrontierNode runs through `canPromoteFrontier`\n// before its incident edges are rewired. Block-action policies that fire on\n// the frontier veto the promotion — the FrontierNode persists; the next\n// extract pass tries again.\nexport interface PromoteFrontierOptions {\n  policies?: Policy[]\n  policyCtx?: PolicyEvaluationContext\n}\n\nexport function promoteFrontierNodes(\n  graph: NeatGraph,\n  opts: PromoteFrontierOptions = {},\n): number {\n  const aliasIndex = new Map<string, string>()\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as ServiceNode & { type?: string }\n    if (a.type !== NodeType.ServiceNode) return\n    aliasIndex.set(a.name, id)\n    if (a.aliases) {\n      for (const alias of a.aliases) aliasIndex.set(alias, id)\n    }\n  })\n  // A frontier minted for a ClusterIP before the k8s substrate read the Services\n  // (ADR-248) promotes to the service the address now names.\n  graph.forEachNode((_id, attrs) => {\n    const a = attrs as FrontierNode & { type?: string }\n    if (a.type !== NodeType.FrontierNode || aliasIndex.has(a.host)) return\n    const owner = serviceIdForObservedAddress(graph, a.host)\n    if (owner) aliasIndex.set(a.host, owner)\n  })\n\n  const toPromote: { frontierId: string; serviceId: string }[] = []\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as FrontierNode & { type?: string }\n    if (a.type !== NodeType.FrontierNode) return\n    const target = aliasIndex.get(a.host)\n    if (!target) return\n    if (target === id) return\n    toPromote.push({ frontierId: id, serviceId: target })\n  })\n\n  let promoted = 0\n  for (const { frontierId, serviceId } of toPromote) {\n    if (opts.policies && opts.policies.length > 0 && opts.policyCtx) {\n      const gate = canPromoteFrontier(graph, frontierId, opts.policies, opts.policyCtx)\n      if (!gate.allowed) {\n        // Block-action policy fired on this frontier — skip the rewire and\n        // leave the FrontierNode in place. Violations already surfaced via\n        // the policy log on the same evaluation pass.\n        continue\n      }\n    }\n    rewireFrontierEdges(graph, frontierId, serviceId)\n    graph.dropNode(frontierId)\n    promoted++\n  }\n  return promoted\n}\n\n// ADR-226 — a staged FRONTIER surface graduates to OBSERVED by PROMOTION when its\n// real twin arrives. An OBSERVED edge with the same (source, target, type) means\n// NEAT can now see the hop it had only reached toward — a hung service came back,\n// a proposed edge became real — so the placeholder is dropped and the settled\n// OBSERVED edge stands in its place. This is the edge-level twin of\n// promoteFrontierNodes (ADR-044): a placeholder replaced once the real thing\n// resolves. Never gated — a settled fact is not blockable (the gate is the future\n// face, ADR-093). Returns the number of surfaces graduated; runs in the same\n// reconciliation sweep as promoteFrontierNodes.\n// ADR-226 — stage a FRONTIER surface edge. The hang sensor (hang-sensor.ts) does\n// the detection and resolves the hop; the graph write belongs here per the\n// lifecycle authority (ADR-030). Returns false when the hop is already OBSERVED\n// (production can see it — not a hang), already staged, or an endpoint is missing;\n// true when a new surface was added.\nexport function stageFrontierEdge(\n  graph: NeatGraph,\n  source: string,\n  target: string,\n  type: EdgeTypeValue,\n): boolean {\n  if (!graph.hasNode(source) || !graph.hasNode(target)) return false\n  if (graph.hasEdge(observedEdgeId(source, target, type))) return false\n  const key = frontierEdgeId(source, target, type)\n  if (graph.hasEdge(key)) return false\n  graph.addEdgeWithKey(key, source, target, {\n    id: key,\n    source,\n    target,\n    type,\n    provenance: Provenance.FRONTIER,\n  } as GraphEdge)\n  return true\n}\n\nexport function promoteFrontierEdges(graph: NeatGraph): number {\n  const graduated: string[] = []\n  graph.forEachEdge((edgeId, attrs) => {\n    const e = attrs as GraphEdge\n    if (e.provenance !== Provenance.FRONTIER) return\n    if (graph.hasEdge(observedEdgeId(e.source, e.target, e.type))) {\n      graduated.push(edgeId)\n    }\n  })\n  for (const edgeId of graduated) graph.dropEdge(edgeId)\n  return graduated.length\n}\n\nfunction rewireFrontierEdges(graph: NeatGraph, frontierId: string, serviceId: string): void {\n  const inbound = [...graph.inboundEdges(frontierId)]\n  const outbound = [...graph.outboundEdges(frontierId)]\n\n  for (const edgeId of inbound) {\n    const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n    rebuildEdge(graph, edge, edge.source, serviceId, edgeId)\n  }\n  for (const edgeId of outbound) {\n    const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n    rebuildEdge(graph, edge, serviceId, edge.target, edgeId)\n  }\n}\n\nfunction rebuildEdge(\n  graph: NeatGraph,\n  edge: GraphEdge,\n  newSource: string,\n  newTarget: string,\n  oldEdgeId: string,\n): void {\n  graph.dropEdge(oldEdgeId)\n  // ADR-068 — promotion rewrites the target ref; provenance carries forward.\n  // An OBSERVED edge to a FrontierNode promotes to an OBSERVED edge to the\n  // matched typed node; an INFERRED edge stays INFERRED; etc.\n  const newId =\n    edge.provenance === Provenance.OBSERVED\n      ? observedEdgeId(newSource, newTarget, edge.type)\n      : edge.provenance === Provenance.INFERRED\n        ? inferredEdgeId(newSource, newTarget, edge.type)\n        : extractedEdgeId(newSource, newTarget, edge.type)\n\n  if (graph.hasEdge(newId)) {\n    const existing = graph.getEdgeAttributes(newId) as GraphEdge\n    const merged: GraphEdge = {\n      ...existing,\n      callCount: (existing.callCount ?? 0) + (edge.callCount ?? 0),\n      lastObserved: pickLater(existing.lastObserved, edge.lastObserved),\n    }\n    graph.replaceEdgeAttributes(newId, merged)\n    return\n  }\n\n  const rebuilt: GraphEdge = {\n    ...edge,\n    id: newId,\n    source: newSource,\n    target: newTarget,\n  }\n  graph.addEdgeWithKey(newId, newSource, newTarget, rebuilt)\n}\n\nfunction pickLater(a: string | undefined, b: string | undefined): string | undefined {\n  if (!a) return b\n  if (!b) return a\n  return new Date(a).getTime() >= new Date(b).getTime() ? a : b\n}\n\nexport function makeSpanHandler(ctx: IngestContext): (span: ParsedSpan) => Promise<void> {\n  return (span) => handleSpan(ctx, span)\n}\n\nexport type { StaleEvent }\n\nexport interface MarkStaleOptions {\n  // Per-edge-type override map. Defaults to DEFAULT_STALE_THRESHOLDS, merged\n  // with NEAT_STALE_THRESHOLDS if the env var is set.\n  thresholds?: Record<string, number>\n  now?: number\n  // ndjson path. When set, every OBSERVED → STALE transition appends one\n  // line. Skipped if undefined — tests and embedded use cases don't need a\n  // log.\n  staleEventsPath?: string\n  // Project tag for event-bus routing (ADR-051). Defaults to DEFAULT_PROJECT.\n  project?: string\n}\n\n// Demote OBSERVED edges that haven't been seen in a while. Per-edge-type\n// thresholds: HTTP CALLS go stale fast; infra DEPENDS_ON is patient. Returns\n// the count of demotions and the events appended to the log.\nexport async function markStaleEdges(\n  graph: NeatGraph,\n  options: MarkStaleOptions = {},\n): Promise<{ count: number; events: StaleEvent[] }> {\n  const thresholds = options.thresholds ?? loadStaleThresholdsFromEnv()\n  const now = options.now ?? Date.now()\n  const events: StaleEvent[] = []\n\n  const project = options.project ?? DEFAULT_PROJECT\n  graph.forEachEdge((id, attrs) => {\n    const e = attrs as GraphEdge\n    if (e.provenance !== Provenance.OBSERVED) return\n    if (!e.lastObserved) return\n    const threshold = thresholdForEdgeType(e.type, thresholds)\n    const age = now - new Date(e.lastObserved).getTime()\n    if (age > threshold) {\n      const updated: GraphEdge = { ...e, provenance: Provenance.STALE, confidence: 0.3 }\n      graph.replaceEdgeAttributes(id, updated)\n      events.push({\n        edgeId: id,\n        source: e.source,\n        target: e.target,\n        edgeType: e.type,\n        thresholdMs: threshold,\n        ageMs: age,\n        lastObserved: e.lastObserved,\n        transitionedAt: new Date(now).toISOString(),\n      })\n      // Stale-transition fires through the bus (ADR-051). The graph\n      // subscription in events.ts can't see the OBSERVED→STALE semantic on\n      // its own — a provenance flip is just an attribute update from\n      // graphology's view.\n      emitNeatEvent({\n        type: 'stale-transition',\n        project,\n        payload: {\n          edgeId: id,\n          from: Provenance.OBSERVED,\n          to: Provenance.STALE,\n        },\n      })\n    }\n  })\n\n  if (options.staleEventsPath && events.length > 0) {\n    await appendStaleEvents(options.staleEventsPath, events)\n  }\n\n  return { count: events.length, events }\n}\n\nasync function appendStaleEvents(staleEventsPath: string, events: StaleEvent[]): Promise<void> {\n  await fs.mkdir(path.dirname(staleEventsPath), { recursive: true })\n  const lines = events.map((e) => JSON.stringify(e)).join('\\n') + '\\n'\n  await fs.appendFile(staleEventsPath, lines, 'utf8')\n}\n\nexport async function readStaleEvents(staleEventsPath: string): Promise<StaleEvent[]> {\n  try {\n    const raw = await fs.readFile(staleEventsPath, 'utf8')\n    return raw\n      .split('\\n')\n      .filter((line) => line.length > 0)\n      .map((line) => JSON.parse(line) as StaleEvent)\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n    throw err\n  }\n}\n\nexport interface StalenessLoopOptions {\n  thresholds?: Record<string, number>\n  intervalMs?: number\n  staleEventsPath?: string\n  // Project tag for event-bus routing (ADR-051).\n  project?: string\n  // Post-stale-transition policy trigger (ADR-043). Fires after each tick of\n  // markStaleEdges so policies see the new STALE state. Daemons wire this to\n  // evaluateAllPolicies + PolicyViolationsLog.append.\n  onPolicyTrigger?: (graph: NeatGraph) => Promise<void> | void\n  // Post-ingest reconciliation (ADR-226). Fires after each tick, the periodic\n  // point where OBSERVED state has settled. Daemons wire this to graduate FRONTIER\n  // surfaces whose twin has arrived (promoteFrontierEdges) and stage new hang\n  // surfaces (the hang sensor). Kept as a callback so ingest.ts never imports the\n  // sensor/traverse (which would cycle) — the daemon owns those wires.\n  onReconcile?: (graph: NeatGraph) => Promise<void> | void\n}\n\nexport function startStalenessLoop(\n  graph: NeatGraph,\n  options: StalenessLoopOptions = {},\n): () => void {\n  let stopped = false\n  const intervalMs = options.intervalMs ?? 60_000\n  const tick = (): void => {\n    if (stopped) return\n    void (async () => {\n      try {\n        await markStaleEdges(graph, {\n          thresholds: options.thresholds,\n          staleEventsPath: options.staleEventsPath,\n          project: options.project,\n        })\n        if (options.onPolicyTrigger) await options.onPolicyTrigger(graph)\n        if (options.onReconcile) await options.onReconcile(graph)\n      } catch (err) {\n        console.error('staleness tick failed', err)\n      }\n    })()\n  }\n  const interval = setInterval(tick, intervalMs)\n  if (typeof interval.unref === 'function') interval.unref()\n  return () => {\n    stopped = true\n    clearInterval(interval)\n  }\n}\n\n// errors.ndjson is append-only and unbounded, so on a long-running daemon with\n// a busy erroring service it grows without limit. Reading the whole file into\n// one utf8 string then throws `RangeError: Invalid string length` once it crosses\n// V8's ~2^29-char ceiling, which took down every incident-backed query\n// (get_incident_history / get_root_cause / ask) with a 500 (#1083). Two bounds\n// keep the read safe regardless of store size: never pull more than this many\n// bytes into a string, and never return more than INCIDENT_READ_MAX_EVENTS\n// parsed incidents. The newest incidents sit at the tail of the append-only file\n// and are the ones every consumer wants, so when the file is larger than the\n// byte budget we tail-read the most recent slice instead of the whole thing.\nconst INCIDENT_READ_MAX_BYTES = 32 * 1024 * 1024\n\n// Hard ceiling on how many incidents a single read hands back. Bounds both memory\n// and the size of any response built from the result, well under the string ceiling\n// even with large per-incident stacktraces. A caller can ask for fewer via `limit`.\nexport const INCIDENT_READ_MAX_EVENTS = 5000\n\n// Read at most `maxBytes` from the end of the file. When the file is larger than\n// the budget the first line in the window is almost certainly a partial record\n// (we cut mid-line), so drop everything up to and including the first newline —\n// every remaining line is whole, and the writer always terminates records with a\n// newline so the tail never ends mid-record.\nasync function readErrorFileTail(errorsPath: string, maxBytes: number): Promise<string> {\n  const handle = await fs.open(errorsPath, 'r')\n  try {\n    const { size } = await handle.stat()\n    if (size <= maxBytes) {\n      return (await handle.readFile()).toString('utf8')\n    }\n    const buf = Buffer.alloc(maxBytes)\n    await handle.read(buf, 0, maxBytes, size - maxBytes)\n    const raw = buf.toString('utf8')\n    const firstNewline = raw.indexOf('\\n')\n    return firstNewline === -1 ? '' : raw.slice(firstNewline + 1)\n  } finally {\n    await handle.close()\n  }\n}\n\n// A record persisted before the write-path scrub (#1184) can still carry\n// credential headers in its `attributes` — the sidecar is append-only, so the\n// bytes on disk predate the fix. Apply the same scrub on load so every reader\n// (incident cards, get_divergences, the web) sees a clean record without\n// rewriting the file. Reuses `sanitizeAttributes`, the one scrub definition; a\n// destructive on-disk sweep for retained hosted data stays a separate item.\n// Returns the record untouched when nothing was dropped, so a clean sidecar\n// pays no allocation past the scrub check.\nfunction redactPersistedAttributes(ev: ErrorEvent): ErrorEvent {\n  if (!ev.attributes) return ev\n  const scrubbed = sanitizeAttributes(ev.attributes)\n  if (Object.keys(scrubbed).length === Object.keys(ev.attributes).length) return ev\n  if (Object.keys(scrubbed).length > 0) return { ...ev, attributes: scrubbed }\n  const { attributes: _dropped, ...rest } = ev\n  return rest\n}\n\nexport async function readErrorEvents(\n  errorsPath: string,\n  opts?: { limit?: number },\n): Promise<ErrorEvent[]> {\n  let raw: string\n  try {\n    raw = await readErrorFileTail(errorsPath, INCIDENT_READ_MAX_BYTES)\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n    throw err\n  }\n  const events = raw\n    .split('\\n')\n    .filter((line) => line.length > 0)\n    .map((line) => redactPersistedAttributes(JSON.parse(line) as ErrorEvent))\n  const deduped = dedupeIncidents(events)\n  const cap =\n    opts?.limit !== undefined && opts.limit > 0\n      ? Math.min(opts.limit, INCIDENT_READ_MAX_EVENTS)\n      : INCIDENT_READ_MAX_EVENTS\n  // Keep the most-recent `cap`. dedupeIncidents preserves append order, so the\n  // tail is newest.\n  return deduped.length > cap ? deduped.slice(deduped.length - cap) : deduped\n}\n\n/** Resolve a pinned incident without the 5000-event list cap. Hosted replay can\n * name an older event, while ordinary incident reads remain bounded to the\n * newest window. The byte bound still prevents an unbounded ledger read.\n */\nexport async function readErrorEventById(errorsPath: string, id: string): Promise<ErrorEvent | undefined> {\n  let raw: string\n  try {\n    raw = await readErrorFileTail(errorsPath, INCIDENT_READ_MAX_BYTES)\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n    throw err\n  }\n  const lines = raw.split('\\n')\n  for (let i = lines.length - 1; i >= 0; i--) {\n    const line = lines[i]\n    if (!line) continue\n    const event = JSON.parse(line) as ErrorEvent\n    if (event.id === id) return redactPersistedAttributes(event)\n  }\n  return undefined\n}\n\n// A synthesized HTTP-status incident carries no failure of its own — it's the\n// \"500 on GET /users/:id\" line handleSpan mints for a server span that answered\n// 5xx with no exception event of its own (httpFailureMessage). When the real\n// failure surfaced deeper in the same trace (a DB driver threw, a downstream\n// gRPC returned UNAVAILABLE), that exception is recorded as its own incident on\n// the same node, and the server's HTTP echo is a duplicate of it. A record is\n// \"synthesized HTTP\" when it carries no exception data, no explicit errorType\n// (the coalesced http-failure incidents set one and carry their own count), and\n// its message is exactly the HTTP line re-derived from its own attributes.\nfunction isSynthesizedHttpIncident(ev: ErrorEvent): boolean {\n  if (ev.exceptionType || ev.exceptionStacktrace) return false\n  if (ev.errorType) return false\n  if (!ev.attributes) return false\n  const synth = httpFailureMessageFromAttrs(ev.attributes)\n  return synth !== undefined && synth === ev.errorMessage\n}\n\n// Make the incident surface idempotent per failure. Two passes:\n//\n// Pass 1 — collapse exact `(traceId, spanId)` re-deliveries. The ndjson sidecar\n// is append-only (persistence contract), so a re-delivered span — OTel\n// BatchSpanProcessor retries, or a receiver + handler both writing one POST —\n// leaves duplicate lines on disk. The deterministic incident `id` already\n// encodes the pair (`${traceId}:${spanId}`); we dedupe on it directly, falling\n// back to the raw pair for any record that predates the id. Records that carry\n// neither (extract parse-failure rows, `source: 'extract'`) pass through\n// untouched — they aren't span incidents. First write wins so the original\n// timestamp is preserved.\n//\n// Pass 2 — collapse one failure recorded from two spans of the same trace. A\n// failing request lands one incident from the span that actually threw (the DB\n// child's exception, a downstream gRPC error) and a second, synthesized one from\n// the HTTP server span that echoed it as a 5xx. Both key to the same\n// `(traceId, affectedNode)`; the exact-id pass can't see it because the spanIds\n// differ. When a real failure shares a trace and node with a synthesized HTTP\n// echo, drop the echo so the request counts once (issue #624). A cross-service\n// failure keeps both sides: the caller's failing-response incident and the\n// callee's exception land on different `affectedNode`s (separate ledgers per the\n// otel-ingest contract), so they never share a group.\nfunction dedupeIncidents(events: ErrorEvent[]): ErrorEvent[] {\n  const seen = new Set<string>()\n  const once: ErrorEvent[] = []\n  for (const ev of events) {\n    const key =\n      ev.id ??\n      (ev.traceId && ev.spanId ? `${ev.traceId}:${ev.spanId}` : undefined)\n    if (key === undefined) {\n      once.push(ev)\n      continue\n    }\n    if (seen.has(key)) continue\n    seen.add(key)\n    once.push(ev)\n  }\n\n  const groupKey = (ev: ErrorEvent): string => `${ev.traceId}\\u0000${ev.affectedNode}`\n  const hasRealFailure = new Set<string>()\n  for (const ev of once) {\n    if (ev.traceId && !isSynthesizedHttpIncident(ev)) hasRealFailure.add(groupKey(ev))\n  }\n  return once.filter((ev) => {\n    if (!ev.traceId || !isSynthesizedHttpIncident(ev)) return true\n    return !hasRealFailure.has(groupKey(ev))\n  })\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Snapshot merge (ADR-074 §1)\n//\n// `neat sync` (local) and `neat sync --to <url>` (remote) feed snapshots into\n// a live graph through this helper. It lives in ingest.ts because mutation\n// authority sits with ingest + extract per the lifecycle contract (ADR-030);\n// the merge is ingestion of an external snapshot, no different in shape from\n// the way handleSpan ingests an OTel span.\n//\n// The merge preserves EXTRACTED + OBSERVED coexistence per Rule 2 — each\n// provenance variant has its own edge id, so the incoming EXTRACTED edges\n// can't stomp the daemon's accumulated OBSERVED edges and vice versa. Rule of\n// thumb: incoming wins for nodes/edges the live graph hasn't seen yet;\n// everything already present keeps its current attributes.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface MergeSnapshotResult {\n  nodesAdded: number\n  edgesAdded: number\n}\n\n// A pushed snapshot is untrusted input — it can arrive from `neat sync --to`\n// against a daemon the operator doesn't fully control, or from anything else\n// that can reach the `/snapshot` route. Before #693, every entry's\n// `attributes` went straight from `JSON.parse` to `graph.addNode` /\n// `graph.addEdgeWithKey` with only a schemaVersion check upstream in api.ts —\n// a malformed or hostile payload (wrong `type` literal, missing required\n// field, wrong field type) landed on the live graph as-is. This error\n// collects every entry that fails `GraphNodeSchema` / `GraphEdgeSchema` — the\n// same canonical shapes the rest of the API validates responses against\n// (packages/types) — so the caller gets back exactly what was wrong instead\n// of a generic parse failure or, worse, a silently corrupted graph.\nexport class SnapshotValidationError extends Error {\n  constructor(public readonly issues: string[]) {\n    super(`snapshot failed validation (${issues.length} invalid ${issues.length === 1 ? 'entry' : 'entries'})`)\n    this.name = 'SnapshotValidationError'\n  }\n}\n\nfunction describeZodIssues(error: { issues: Array<{ path: PropertyKey[]; message: string }> }): string {\n  return error.issues\n    .map((issue) => (issue.path.length > 0 ? `${issue.path.join('.')}: ${issue.message}` : issue.message))\n    .join('; ')\n}\n\nexport function mergeSnapshot(\n  graph: NeatGraph,\n  snapshot: PersistedGraph,\n): MergeSnapshotResult {\n  invalidateSourceBaseline(graph)\n  const exported = snapshot.graph as {\n    nodes?: Array<{ key: string; attributes?: unknown }>\n    edges?: Array<{ key?: string; source: string; target: string; attributes?: unknown }>\n  }\n  const incomingNodes = Array.isArray(exported.nodes) ? exported.nodes : []\n  const incomingEdges = Array.isArray(exported.edges) ? exported.edges : []\n\n  // Validate everything up front and merge nothing until every entry checks\n  // out — a snapshot that's partly hostile or partly corrupt is rejected\n  // whole rather than landing its valid entries and silently dropping the\n  // rest (matching how the schemaVersion check upstream already treats a\n  // bad snapshot as all-or-nothing).\n  const issues: string[] = []\n  const validNodes: Array<{ key: string; attributes: GraphNode }> = []\n  const validEdges: Array<{ key: string; source: string; target: string; attributes: GraphEdge }> = []\n\n  for (const node of incomingNodes) {\n    // No attributes at all is a no-op skip, not a malformed entry — mirrors\n    // the pre-#693 behaviour for this specific (empty) shape.\n    if (node.attributes === undefined) continue\n    const parsed = GraphNodeSchema.safeParse(node.attributes)\n    if (!parsed.success) {\n      issues.push(`node \"${node.key}\": ${describeZodIssues(parsed.error)}`)\n      continue\n    }\n    validNodes.push({ key: node.key, attributes: parsed.data })\n  }\n\n  for (const edge of incomingEdges) {\n    if (edge.attributes === undefined) continue\n    const parsed = GraphEdgeSchema.safeParse(edge.attributes)\n    if (!parsed.success) {\n      const label = edge.key ?? `${edge.source}->${edge.target}`\n      issues.push(`edge \"${label}\": ${describeZodIssues(parsed.error)}`)\n      continue\n    }\n    const id = edge.key ?? parsed.data.id\n    validEdges.push({ key: id, source: edge.source, target: edge.target, attributes: parsed.data })\n  }\n\n  if (issues.length > 0) {\n    throw new SnapshotValidationError(issues)\n  }\n\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const node of validNodes) {\n    if (graph.hasNode(node.key)) continue\n    graph.addNode(node.key, node.attributes)\n    nodesAdded++\n  }\n\n  for (const edge of validEdges) {\n    if (graph.hasEdge(edge.key)) continue\n    // Skip when either endpoint is missing — can happen if the snapshot\n    // names a node the live graph already evicted and the incoming nodes\n    // array didn't include.\n    if (!graph.hasNode(edge.source) || !graph.hasNode(edge.target)) continue\n    graph.addEdgeWithKey(edge.key, edge.source, edge.target, edge.attributes)\n    edgesAdded++\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ErrorEvent } from '@neat.is/types'\n\n/**\n * Hosted runtime incidents are committed to the local sidecar's encrypted GCS\n * archive before the producer can acknowledge or publish the trigger. The\n * sidecar then appends the same record to the daemon's local ledger. Non-hosted\n * callers keep the existing append-only filesystem path.\n */\nexport async function appendRuntimeIncident(\n  errorsPath: string,\n  project: string,\n  event: ErrorEvent,\n  options: { token?: string; fetchImpl?: typeof fetch } = {},\n): Promise<void> {\n  const token = options.token ?? process.env.NEAT_INCIDENT_DURABLE_TOKEN\n  if (token !== undefined) {\n    if (Buffer.byteLength(token, 'utf8') < 32) throw new Error('durable incident sink unavailable')\n    const response = await (options.fetchImpl ?? fetch)('http://127.0.0.1:8081/incident-append', {\n      method: 'POST',\n      headers: { authorization: `Bearer ${token}`, 'content-type': 'application/json' },\n      body: JSON.stringify({ project, event }),\n      signal: AbortSignal.timeout(30_000),\n    })\n    if (response.status !== 204) throw new Error('durable incident sink unavailable')\n    return\n  }\n  await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n  await fs.appendFile(errorsPath, JSON.stringify(event) + '\\n', 'utf8')\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n  ApplicablePolicy,\n  GraphEdge,\n  GraphNode,\n  Policy,\n  PolicyAction,\n  PolicyFile,\n  PolicyRule,\n  PolicySeverity,\n  PolicyViolation,\n  ServiceNode,\n} from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  PolicyFileSchema,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport {\n  checkCompatibility,\n  checkDeprecatedApi,\n  checkNodeEngineConstraint,\n  checkPackageConflict,\n  compatPairs,\n  deprecatedApis,\n  nodeEngineConstraints,\n  packageConflicts,\n} from './compat.js'\nimport { emitNeatEvent } from './events.js'\nimport { getBlastRadius } from './traverse.js'\n\n// Policy evaluation engine (ADR-043). The entry point evaluateAllPolicies is\n// pure: same graph + same policies → same violations. Per-rule-type dispatch\n// via the policyEvaluators table. Adding a new rule type means one new\n// evaluator entry plus the schema entry in @neat.is/types/policy.ts.\n//\n// Deterministic violation ids per ADR-043: ${policy.id}:${context}. The\n// context is shape-specific (nodeId, edgeId, or composite). The\n// policy-violations.ndjson writer skips on duplicate ids.\n\nexport interface EvaluationContext {\n  // Wall-clock provider. Tests pin this; production uses Date.now.\n  now: () => number\n}\n\ninterface RuleEvaluatorArgs<T extends PolicyRule = PolicyRule> {\n  graph: NeatGraph\n  policy: Policy\n  rule: T\n  ctx: EvaluationContext\n}\n\ntype RuleEvaluator<T extends PolicyRule = PolicyRule> = (\n  args: RuleEvaluatorArgs<T>,\n) => PolicyViolation[]\n\n// Severity-driven default action per ADR-044.\nconst DEFAULT_ACTION_BY_SEVERITY: Record<PolicySeverity, PolicyAction> = {\n  info: 'log',\n  warning: 'alert',\n  error: 'alert',\n  critical: 'block',\n}\n\nexport function resolveOnViolation(policy: Policy): PolicyAction {\n  return policy.onViolation ?? DEFAULT_ACTION_BY_SEVERITY[policy.severity]\n}\n\nfunction makeViolation(\n  policy: Policy,\n  rule: PolicyRule,\n  contextSuffix: string,\n  message: string,\n  subject: PolicyViolation['subject'],\n  ctx: EvaluationContext,\n): PolicyViolation {\n  return {\n    id: `${policy.id}:${contextSuffix}`,\n    policyId: policy.id,\n    policyName: policy.name,\n    severity: policy.severity,\n    onViolation: resolveOnViolation(policy),\n    ruleType: rule.type,\n    subject,\n    message,\n    observedAt: new Date(ctx.now()).toISOString(),\n  }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Per-rule-type evaluators\n// ──────────────────────────────────────────────────────────────────────────\n\nconst evaluateStructural: RuleEvaluator<Extract<PolicyRule, { type: 'structural' }>> = ({\n  graph,\n  policy,\n  rule,\n  ctx,\n}) => {\n  const violations: PolicyViolation[] = []\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as GraphNode\n    if (a.type !== rule.fromNodeType) return\n    let satisfied = false\n    for (const edgeId of graph.outboundEdges(id)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type !== rule.edgeType) continue\n      const target = graph.getNodeAttributes(e.target) as GraphNode\n      // FrontierNodes are unresolved peers (ADR-068) — skip; the rule\n      // counts edges that resolve to a real typed node only.\n      if (target.type === NodeType.FrontierNode) continue\n      if (target.type === rule.toNodeType) {\n        satisfied = true\n        break\n      }\n    }\n    if (!satisfied) {\n      violations.push(\n        makeViolation(\n          policy,\n          rule,\n          id,\n          `${rule.fromNodeType} ${id} has no ${rule.edgeType} edge to a ${rule.toNodeType}`,\n          { nodeId: id },\n          ctx,\n        ),\n      )\n    }\n  })\n  return violations\n}\n\nconst evaluateOwnership: RuleEvaluator<Extract<PolicyRule, { type: 'ownership' }>> = ({\n  graph,\n  policy,\n  rule,\n  ctx,\n}) => {\n  const violations: PolicyViolation[] = []\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as GraphNode & Record<string, unknown>\n    if (a.type !== rule.nodeType) return\n    const value = a[rule.field]\n    if (typeof value !== 'string' || value.length === 0) {\n      violations.push(\n        makeViolation(\n          policy,\n          rule,\n          id,\n          `${rule.nodeType} ${id} is missing required field \"${rule.field}\"`,\n          { nodeId: id },\n          ctx,\n        ),\n      )\n    }\n  })\n  return violations\n}\n\nconst evaluateProvenance: RuleEvaluator<Extract<PolicyRule, { type: 'provenance' }>> = ({\n  graph,\n  policy,\n  rule,\n  ctx,\n}) => {\n  const required = Array.isArray(rule.required) ? new Set(rule.required) : new Set([rule.required])\n  const violations: PolicyViolation[] = []\n  graph.forEachEdge((edgeId, attrs) => {\n    const e = attrs as GraphEdge\n    if (e.type !== rule.edgeType) return\n    if (rule.targetNodeId && e.target !== rule.targetNodeId) return\n    if (!required.has(e.provenance)) {\n      const requiredList = [...required].join(' | ')\n      violations.push(\n        makeViolation(\n          policy,\n          rule,\n          edgeId,\n          `${rule.edgeType} edge ${edgeId} has provenance ${e.provenance}; required ${requiredList}`,\n          { edgeId },\n          ctx,\n        ),\n      )\n    }\n  })\n  return violations\n}\n\nconst evaluateBlastRadius: RuleEvaluator<Extract<PolicyRule, { type: 'blast-radius' }>> = ({\n  graph,\n  policy,\n  rule,\n  ctx,\n}) => {\n  const violations: PolicyViolation[] = []\n  const depth = rule.depth\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as GraphNode\n    if (a.type !== rule.nodeType) return\n    const result = depth !== undefined ? getBlastRadius(graph, id, depth) : getBlastRadius(graph, id)\n    if (result.totalAffected > rule.maxAffected) {\n      violations.push(\n        makeViolation(\n          policy,\n          rule,\n          id,\n          `${rule.nodeType} ${id} has blast radius ${result.totalAffected} > ${rule.maxAffected}`,\n          { nodeId: id, path: [id] },\n          ctx,\n        ),\n      )\n    }\n  })\n  return violations\n}\n\nconst evaluateCompatibility: RuleEvaluator<Extract<PolicyRule, { type: 'compatibility' }>> = ({\n  graph,\n  policy,\n  rule,\n  ctx,\n}) => {\n  const violations: PolicyViolation[] = []\n  // Iterate every ServiceNode and re-run the compat shapes the static\n  // extractor runs at extract time. Catches OBSERVED-vs-EXTRACTED divergence:\n  // a service whose dep manifest changed since the last extract gets re-flagged\n  // here on every evaluation cycle.\n  const wantsKind = (kind: NonNullable<typeof rule.kind>): boolean =>\n    rule.kind === undefined || rule.kind === kind\n\n  graph.forEachNode((svcId, attrs) => {\n    const a = attrs as GraphNode\n    if (a.type !== NodeType.ServiceNode) return\n    const svc = a as ServiceNode\n    const deps = svc.dependencies ?? {}\n\n    if (wantsKind('driver-engine')) {\n      // Walk every CONNECTS_TO edge from this service to a DatabaseNode,\n      // then run the driver-engine compat for each (driver, declared, engine,\n      // engineVersion) tuple.\n      for (const edgeId of graph.outboundEdges(svcId)) {\n        const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n        if (e.type !== EdgeType.CONNECTS_TO) continue\n        const dbAttrs = graph.getNodeAttributes(e.target) as GraphNode\n        // FrontierNodes are unresolved peers (ADR-068) — skip; compat\n        // checking needs a typed DatabaseNode.\n        if (dbAttrs.type === NodeType.FrontierNode) continue\n        if (dbAttrs.type !== NodeType.DatabaseNode) continue\n        const db = dbAttrs as { engine: string; engineVersion: string }\n        for (const pair of compatPairs()) {\n          if (pair.engine !== db.engine) continue\n          const declared = deps[pair.driver]\n          if (!declared) continue\n          const result = checkCompatibility(pair.driver, declared, db.engine, db.engineVersion)\n          if (!result.compatible && result.reason) {\n            violations.push(\n              makeViolation(\n                policy,\n                rule,\n                `${svcId}:driver-engine:${pair.driver}@${declared}:${db.engine}@${db.engineVersion}`,\n                result.reason,\n                { nodeId: svcId, edgeId },\n                ctx,\n              ),\n            )\n          }\n        }\n      }\n    }\n\n    if (wantsKind('node-engine')) {\n      const serviceNodeRange = svc.nodeEngine\n      for (const constraint of nodeEngineConstraints()) {\n        const declared = deps[constraint.package]\n        if (!declared) continue\n        const result = checkNodeEngineConstraint(constraint, declared, serviceNodeRange)\n        if (!result.compatible && result.reason) {\n          violations.push(\n            makeViolation(\n              policy,\n              rule,\n              `${svcId}:node-engine:${constraint.package}@${declared}`,\n              result.reason,\n              { nodeId: svcId },\n              ctx,\n            ),\n          )\n        }\n      }\n    }\n\n    if (wantsKind('package-conflict')) {\n      for (const conflict of packageConflicts()) {\n        const declared = deps[conflict.package]\n        if (!declared) continue\n        const requiredDeclared = deps[conflict.requires.name]\n        const result = checkPackageConflict(conflict, declared, requiredDeclared)\n        if (!result.compatible && result.reason) {\n          violations.push(\n            makeViolation(\n              policy,\n              rule,\n              `${svcId}:package-conflict:${conflict.package}@${declared}`,\n              result.reason,\n              { nodeId: svcId },\n              ctx,\n            ),\n          )\n        }\n      }\n    }\n\n    if (wantsKind('deprecated-api')) {\n      for (const dep of deprecatedApis()) {\n        const declared = deps[dep.package]\n        if (!declared) continue\n        const result = checkDeprecatedApi(dep, declared)\n        if (!result.compatible && result.reason) {\n          violations.push(\n            makeViolation(\n              policy,\n              rule,\n              `${svcId}:deprecated-api:${dep.package}@${declared}`,\n              result.reason,\n              { nodeId: svcId },\n              ctx,\n            ),\n          )\n        }\n      }\n    }\n  })\n\n  return violations\n}\n\n// ADR-169 — the generic declared-set-subset rule. For every node of the rule's\n// type (optionally narrowed to an InfraNode `kind`), every member of set A (the\n// named `subjectSet`) must appear in set B (the node's `guardSet` string[]\n// attribute). A member of A absent from B is one violation. A node whose\n// `guardSet` attribute is absent (or not an array) is INDETERMINATE — skipped,\n// never a false positive; this is what keeps condition-based / unparseable\n// firestore.rules silent. The Firestore instance's set A is client-written\n// columns, whose `sdkWrites` tag is F1's (ADR-167) declared interface — read\n// defensively (absent ⇒ set A empty ⇒ no violation).\nconst evaluateFieldGuard: RuleEvaluator<Extract<PolicyRule, { type: 'field-guard' }>> = ({\n  graph,\n  policy,\n  rule,\n  ctx,\n}) => {\n  const violations: PolicyViolation[] = []\n  graph.forEachNode((id, attrs) => {\n    const a = attrs as GraphNode & Record<string, unknown>\n    if (a.type !== rule.nodeType) return\n    if (rule.nodeKind !== undefined && a.kind !== rule.nodeKind) return\n    // Set B — the covering guard set. Absent / non-array ⇒ indeterminate ⇒ silent.\n    const guardRaw = a[rule.guardSet]\n    if (!Array.isArray(guardRaw)) return\n    const covering = new Set(guardRaw.map((g) => String(g)))\n    // Set A — resolved from the named selector.\n    for (const field of resolveFieldGuardSubject(rule.subjectSet, a)) {\n      if (!covering.has(field)) {\n        violations.push(\n          makeViolation(\n            policy,\n            rule,\n            `${id}:${field}`,\n            `${a.type}${rule.nodeKind !== undefined ? ` (${rule.nodeKind})` : ''} ${id} writes \"${field}\" but it is absent from ${rule.guardSet}`,\n            { nodeId: id },\n            ctx,\n          ),\n        )\n      }\n    }\n  })\n  return violations\n}\n\n// Resolves a `field-guard` rule's set A off a node. A new named selector is a new\n// case here (ADR-043 growth) — the RuleEvaluator interface is untouched.\nfunction resolveFieldGuardSubject(\n  selector: Extract<PolicyRule, { type: 'field-guard' }>['subjectSet'],\n  node: Record<string, unknown>,\n): string[] {\n  switch (selector) {\n    case 'client-written-columns': {\n      const columns = node.columns\n      if (!Array.isArray(columns)) return []\n      const out: string[] = []\n      for (const col of columns) {\n        // F1's ColumnAttr.sdkWrites (ADR-167). Read defensively so this compiles\n        // and behaves before F1 lands: absent ⇒ not a client write ⇒ the column\n        // is not in set A ⇒ no false positive. Admin-only writes bypass the\n        // rules and are excluded.\n        const sdkWrites = (col as { sdkWrites?: unknown }).sdkWrites\n        const name = (col as { name?: unknown }).name\n        if (Array.isArray(sdkWrites) && sdkWrites.includes('client') && typeof name === 'string') {\n          out.push(name)\n        }\n      }\n      return out\n    }\n  }\n}\n\nconst policyEvaluators: { [K in PolicyRule['type']]: RuleEvaluator<Extract<PolicyRule, { type: K }>> } = {\n  structural: evaluateStructural,\n  ownership: evaluateOwnership,\n  provenance: evaluateProvenance,\n  'blast-radius': evaluateBlastRadius,\n  compatibility: evaluateCompatibility,\n  'field-guard': evaluateFieldGuard,\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Public entry point\n// ──────────────────────────────────────────────────────────────────────────\n\n// Block-action gating for FrontierNode promotion (ADR-044 §block, MVP scope).\n// Runs the policy evaluator and returns the subset of block-action violations\n// that mention the candidate FrontierNode. Callers (ingest.ts\n// promoteFrontierNodes) check `allowed` before rewiring; when false, the\n// promotion is skipped and the violations surface through the standard\n// policy-violations.ndjson channel.\n//\n// Block scope is tightly bounded per the contract: FrontierNode promotion\n// only. Other gating points (deploy, codemod, OTel auto-create) need their\n// own ADRs before this function expands.\nexport function canPromoteFrontier(\n  graph: NeatGraph,\n  frontierId: string,\n  policies: Policy[],\n  ctx: EvaluationContext,\n): { allowed: boolean; violations: PolicyViolation[] } {\n  if (policies.length === 0) return { allowed: true, violations: [] }\n  const all = evaluateAllPolicies(graph, policies, ctx)\n  const blocking = all.filter((v) => {\n    if (v.onViolation !== 'block') return false\n    return (\n      v.subject.nodeId === frontierId ||\n      v.subject.path?.includes(frontierId) === true\n    )\n  })\n  return { allowed: blocking.length === 0, violations: blocking }\n}\n\nexport function evaluateAllPolicies(\n  graph: NeatGraph,\n  policies: Policy[],\n  ctx: EvaluationContext,\n): PolicyViolation[] {\n  const out: PolicyViolation[] = []\n  for (const policy of policies) {\n    const evaluator = policyEvaluators[policy.rule.type] as RuleEvaluator\n    const violations = evaluator({ graph, policy, rule: policy.rule, ctx })\n    for (const v of violations) out.push(v)\n  }\n  return out\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Soft guardrail — applicable-policy selection (ADR-108)\n// ──────────────────────────────────────────────────────────────────────────\n\n// The launch form of \"every agent stays inside the lines\": policies INFORM,\n// they never block. selectApplicablePolicies answers \"which policies govern the\n// node I'm about to edit?\" so the rules can ride into the agent's context.\n//\n// Matching is a subject/region match:\n//   - subject — the node's type is the rule's declared subject (the rule\n//     governs every node of that type).\n//   - region — for most rule types, the node sits one hop inside the rule's\n//     region: the target end of a structural edge, the database a compat rule\n//     reaches across a CONNECTS_TO, or a node sitting on an edge a provenance\n//     rule governs. For blast-radius rules the region is the subject's real\n//     blast radius — its dependents: we walk getBlastRadius (to the rule's\n//     declared depth) and surface the rule on every dependent it reaches, so a\n//     far-away node that breaks when the subject changes still sees the\n//     invariant that governs it.\n//\n// The general scope×distance injection over the policy overlay (ADR-105 §5),\n// which would carry this reachability behaviour to every rule type rather than\n// just blast-radius, is still unbuilt; the gap is written up in\n// docs/quirks/policies-soft-guardrail.md. selectApplicablePolicies never\n// evaluates a violation and never returns a verdict — surfacing a policy is not\n// gating it.\nexport function selectApplicablePolicies(\n  graph: NeatGraph,\n  policies: Policy[],\n  nodeId: string,\n): ApplicablePolicy[] {\n  // Without the node in the graph there's no type to match against, so we\n  // can't decide applicability. A not-yet-created node (a brand-new edit) is\n  // exactly the case the unbuilt overlay would handle; here we return empty\n  // rather than guess.\n  if (!graph.hasNode(nodeId)) return []\n  const node = graph.getNodeAttributes(nodeId) as GraphNode\n  const out: ApplicablePolicy[] = []\n  for (const policy of policies) {\n    const m = matchPolicyToNode(graph, policy, nodeId, node)\n    if (!m) continue\n    out.push({\n      policyId: policy.id,\n      policyName: policy.name,\n      ...(policy.description !== undefined ? { description: policy.description } : {}),\n      severity: policy.severity,\n      onViolation: resolveOnViolation(policy),\n      ruleType: policy.rule.type,\n      match: m.match,\n      reason: m.reason,\n    })\n  }\n  return out\n}\n\ninterface PolicyMatch {\n  match: ApplicablePolicy['match']\n  reason: string\n}\n\nfunction requiredProvenanceList(required: string | readonly string[]): string {\n  // required is ProvenanceRule['required'] — a single value or a non-empty\n  // array. Normalize to a readable \"A | B\" string.\n  if (Array.isArray(required)) return required.join(' | ')\n  return String(required)\n}\n\nfunction nodeTouchesEdgeType(\n  graph: NeatGraph,\n  nodeId: string,\n  edgeType: string,\n  requiredOtherEnd?: string,\n): boolean {\n  const incident = [...graph.outboundEdges(nodeId), ...graph.inboundEdges(nodeId)]\n  for (const edgeId of incident) {\n    const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (e.type !== edgeType) continue\n    // A provenance rule with a targetNodeId only governs edges that touch that\n    // target. Without one, any edge of the type counts.\n    if (requiredOtherEnd === undefined) return true\n    if (e.source === requiredOtherEnd || e.target === requiredOtherEnd) return true\n  }\n  return false\n}\n\n// Reverse-reachability for blast-radius rules. Returns the id of a subject-type\n// node whose blast radius (its dependents, to the rule's declared depth)\n// contains nodeId, or null if none does. This is what lets a blast-radius rule\n// surface on the dependents it actually governs, not only on its subject.\nfunction blastRadiusSubjectReaching(\n  graph: NeatGraph,\n  rule: Extract<PolicyRule, { type: 'blast-radius' }>,\n  nodeId: string,\n): string | null {\n  let found: string | null = null\n  graph.forEachNode((subjId, attrs) => {\n    if (found !== null) return\n    if (subjId === nodeId) return\n    if ((attrs as GraphNode).type !== rule.nodeType) return\n    const radius =\n      rule.depth !== undefined\n        ? getBlastRadius(graph, subjId, rule.depth)\n        : getBlastRadius(graph, subjId)\n    if (radius.affectedNodes.some((n) => n.nodeId === nodeId)) found = subjId\n  })\n  return found\n}\n\nfunction matchPolicyToNode(\n  graph: NeatGraph,\n  policy: Policy,\n  nodeId: string,\n  node: GraphNode,\n): PolicyMatch | null {\n  const rule = policy.rule\n  switch (rule.type) {\n    case 'structural': {\n      if (node.type === rule.fromNodeType) {\n        return {\n          match: 'subject',\n          reason: `every ${rule.fromNodeType} must have a ${rule.edgeType} edge to a ${rule.toNodeType}`,\n        }\n      }\n      // The target end is one hop inside the rule's region — editing it can\n      // make a sibling fromNodeType pass or fail the rule.\n      if (node.type === rule.toNodeType) {\n        return {\n          match: 'region',\n          reason: `${rule.fromNodeType} nodes must reach a ${rule.toNodeType} like this one via a ${rule.edgeType} edge`,\n        }\n      }\n      return null\n    }\n    case 'ownership': {\n      if (node.type === rule.nodeType) {\n        return {\n          match: 'subject',\n          reason: `every ${rule.nodeType} must declare a non-empty \"${rule.field}\" field`,\n        }\n      }\n      return null\n    }\n    case 'blast-radius': {\n      const depthLabel = rule.depth !== undefined ? ` at depth ${rule.depth}` : ''\n      if (node.type === rule.nodeType) {\n        return {\n          match: 'subject',\n          reason: `no ${rule.nodeType} may exceed a blast radius of ${rule.maxAffected}${depthLabel}`,\n        }\n      }\n      // Dependent surfacing. The whole point of a blast-radius rule is \"this\n      // subject has too many things depending on it\" — so the agent who most\n      // needs the warning is the one editing one of those dependents, the nodes\n      // that break if the subject changes. We compute the subject's actual\n      // blast radius with getBlastRadius (to the rule's own declared depth) and\n      // surface the rule on any dependent inside it. This is the buildable slice\n      // of ADR-105 §5's scope×distance injection: a real reverse-reachability\n      // walk, not the general overlay, so a far-away node still surfaces the\n      // invariant.\n      const subject = blastRadiusSubjectReaching(graph, rule, nodeId)\n      if (subject) {\n        return {\n          match: 'region',\n          reason: `this node is in the blast radius of ${subject} (a ${rule.nodeType} held to a blast radius of ${rule.maxAffected}${depthLabel}) — it breaks if that ${rule.nodeType} changes`,\n        }\n      }\n      return null\n    }\n    case 'compatibility': {\n      const kindLabel = rule.kind ?? 'all compat shapes'\n      // The evaluator iterates every ServiceNode, so a ServiceNode is the\n      // direct subject.\n      if (node.type === NodeType.ServiceNode) {\n        return {\n          match: 'subject',\n          reason: `this service's dependencies are compatibility-checked (${kindLabel})`,\n        }\n      }\n      // A DatabaseNode one CONNECTS_TO hop from a service is in the region of\n      // the driver-engine shape — its engine version feeds that check.\n      const reachesDriverEngine = rule.kind === undefined || rule.kind === 'driver-engine'\n      if (\n        reachesDriverEngine &&\n        node.type === NodeType.DatabaseNode &&\n        nodeTouchesEdgeType(graph, nodeId, EdgeType.CONNECTS_TO)\n      ) {\n        return {\n          match: 'region',\n          reason: 'services connecting to this database have their driver/engine compatibility checked against it',\n        }\n      }\n      return null\n    }\n    case 'provenance': {\n      const requiredList = requiredProvenanceList(rule.required)\n      // The named target is the direct subject — every governed edge points at\n      // it.\n      if (rule.targetNodeId !== undefined && nodeId === rule.targetNodeId) {\n        return {\n          match: 'subject',\n          reason: `every ${rule.edgeType} edge into ${rule.targetNodeId} must carry ${requiredList} provenance`,\n        }\n      }\n      // Otherwise the node is in the region if it sits on a governed edge.\n      if (nodeTouchesEdgeType(graph, nodeId, rule.edgeType, rule.targetNodeId)) {\n        return {\n          match: 'region',\n          reason:\n            rule.targetNodeId !== undefined\n              ? `this node sits on a ${rule.edgeType} edge to ${rule.targetNodeId}, which must carry ${requiredList} provenance`\n              : `this node sits on a ${rule.edgeType} edge, which must carry ${requiredList} provenance`,\n        }\n      }\n      return null\n    }\n    case 'field-guard': {\n      // The governed node is the rule's direct subject — its type (and, when\n      // narrowed, its `kind`) is what the rule checks. The rule reads two attribute\n      // sets on the one node, so there is no region hop to surface.\n      const kindLabel = rule.nodeKind !== undefined ? ` (kind ${rule.nodeKind})` : ''\n      if (\n        node.type === rule.nodeType &&\n        (rule.nodeKind === undefined || (node as { kind?: string }).kind === rule.nodeKind)\n      ) {\n        return {\n          match: 'subject',\n          reason: `every ${rule.subjectSet} on this ${rule.nodeType}${kindLabel} must appear in ${rule.guardSet}`,\n        }\n      }\n      return null\n    }\n  }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Loader\n// ──────────────────────────────────────────────────────────────────────────\n\n// Reads <projectRoot>/policy.json. Returns [] when the file doesn't exist —\n// a project without policies is a perfectly fine state. Failures to parse\n// throw with the Zod error so the daemon surfaces malformed files loudly\n// instead of silently dropping rules.\nexport async function loadPolicyFile(policyPath: string): Promise<Policy[]> {\n  let raw: string\n  try {\n    raw = await fs.readFile(policyPath, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n    throw err\n  }\n  const json = JSON.parse(raw) as unknown\n  const file: PolicyFile = PolicyFileSchema.parse(json)\n  return file.policies\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Append-only ndjson writer with id-based dedup\n// ──────────────────────────────────────────────────────────────────────────\n\n// Keeps an in-memory Set of seen violation ids so re-evaluation cycles don't\n// produce duplicate ndjson lines. The set hydrates from disk on first append\n// — startups that load an existing log don't lose dedup state.\nexport class PolicyViolationsLog {\n  private readonly path: string\n  private readonly project: string\n  private seen: Set<string> | null = null\n\n  constructor(logPath: string, project: string = DEFAULT_PROJECT) {\n    this.path = logPath\n    this.project = project\n  }\n\n  async append(v: PolicyViolation): Promise<boolean> {\n    if (!this.seen) await this.hydrate()\n    if (this.seen!.has(v.id)) return false\n    this.seen!.add(v.id)\n    await fs.mkdir(path.dirname(this.path), { recursive: true })\n    await fs.appendFile(this.path, JSON.stringify(v) + '\\n', 'utf8')\n    // Emit policy-violation only on first sighting (post-dedup) so SSE\n    // consumers don't see the same violation again on every evaluation\n    // cycle (ADR-051 #2).\n    emitNeatEvent({\n      type: 'policy-violation',\n      project: this.project,\n      payload: { violation: v },\n    })\n    return true\n  }\n\n  async readAll(): Promise<PolicyViolation[]> {\n    try {\n      const raw = await fs.readFile(this.path, 'utf8')\n      return raw\n        .split('\\n')\n        .filter(Boolean)\n        .map((line) => JSON.parse(line) as PolicyViolation)\n    } catch (err) {\n      if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n      throw err\n    }\n  }\n\n  private async hydrate(): Promise<void> {\n    this.seen = new Set()\n    const existing = await this.readAll()\n    for (const v of existing) this.seen.add(v.id)\n  }\n}\n","import { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport semver from 'semver'\nimport compatData from '../compat.json' with { type: 'json' }\n\nexport interface CompatibilityResult {\n  compatible: boolean\n  reason?: string\n  minDriverVersion?: string\n}\n\nexport interface CompatPair {\n  kind?: 'driver-engine'\n  driver: string\n  engine: string\n  minDriverVersion: string\n  // The driver constraint only kicks in once the engine is at this major or higher.\n  // Older engines (e.g. PostgreSQL 13) accept the older driver fine.\n  minEngineVersion?: string\n  reason: string\n}\n\nexport interface NodeEngineConstraint {\n  kind?: 'node-engine'\n  package: string\n  packageMinVersion?: string\n  minNodeVersion: string\n  reason: string\n}\n\nexport interface PackageConflict {\n  kind?: 'package-conflict'\n  package: string\n  packageMinVersion?: string\n  requires: { name: string; minVersion: string }\n  reason: string\n}\n\nexport interface DeprecatedApi {\n  kind?: 'deprecated-api'\n  package: string\n  packageMaxVersion?: string\n  reason: string\n}\n\n// A feature-flag store provider (ADR-242). The flag grain is provider-neutral; a\n// provider's name is data, read here, and never a branch in the reasoning core.\n// `schemaPattern` is the substring of a flag file's `$schema` that names it.\nexport interface FlagStoreProvider {\n  provider: string\n  schemaPattern: string\n  reason?: string\n}\n\nexport interface CompatMatrix {\n  pairs: CompatPair[]\n  nodeEngineConstraints?: NodeEngineConstraint[]\n  packageConflicts?: PackageConflict[]\n  deprecatedApis?: DeprecatedApi[]\n  flagStores?: FlagStoreProvider[]\n}\n\nconst bundledMatrix = compatData as CompatMatrix\nlet mergedMatrix: CompatMatrix | null = null\nlet remoteLoadAttempted = false\n\nconst REMOTE_CACHE_DIR = path.join(os.homedir(), '.neat')\nconst REMOTE_CACHE_PATH = path.join(REMOTE_CACHE_DIR, 'compat-cache.json')\nconst REMOTE_TTL_MS = 24 * 60 * 60 * 1000\n\ninterface RemoteCacheFile {\n  fetchedAt: string\n  url: string\n  matrix: CompatMatrix\n}\n\n// Engines like Postgres/MySQL only carry a major in the version field, so semver\n// won't always parse them cleanly. Compare as integers when both sides look like\n// majors; otherwise fall back to semver.coerce.\nfunction engineMeetsThreshold(engineVersion: string, threshold: string): boolean {\n  const e = parseInt(engineVersion, 10)\n  const t = parseInt(threshold, 10)\n  if (Number.isFinite(e) && Number.isFinite(t)) return e >= t\n\n  const ec = semver.coerce(engineVersion)\n  const tc = semver.coerce(threshold)\n  if (ec && tc) return semver.gte(ec, tc)\n\n  return false\n}\n\nexport function checkCompatibility(\n  driver: string,\n  driverVersion: string,\n  engine: string,\n  engineVersion: string,\n): CompatibilityResult {\n  const matrix = currentMatrix()\n  const pair = matrix.pairs.find((p) => p.driver === driver && p.engine === engine)\n  if (!pair) return { compatible: true }\n\n  if (pair.minEngineVersion && !engineMeetsThreshold(engineVersion, pair.minEngineVersion)) {\n    return { compatible: true }\n  }\n\n  const driverCoerced = semver.coerce(driverVersion)\n  if (!driverCoerced) return { compatible: true }\n\n  if (semver.lt(driverCoerced, pair.minDriverVersion)) {\n    return {\n      compatible: false,\n      reason: pair.reason,\n      minDriverVersion: pair.minDriverVersion,\n    }\n  }\n\n  return { compatible: true }\n}\n\nexport interface NodeEngineCheck {\n  compatible: boolean\n  reason?: string\n  requiredNodeVersion?: string\n}\n\n// True when `serviceNodeRange` (a service's `engines.node`) is guaranteed to\n// admit `requiredNodeVersion`. We use a permissive semver compare via `coerce`\n// — exact ranges like \">=20\" parse fine, exotic ones like \"^20 || ^22\" pass as\n// long as semver can resolve them. If the range can't be parsed at all, we\n// don't claim a conflict — under-flag rather than over-flag.\nfunction rangeAdmitsVersion(serviceNodeRange: string, requiredNodeVersion: string): boolean {\n  try {\n    const required = semver.coerce(requiredNodeVersion)\n    if (!required) return true\n    // Is every version that satisfies the service's range >= required? If yes,\n    // the service guarantees the requirement; if not, there's at least one\n    // admissible Node version that won't satisfy the dep — that's the\n    // conflict.\n    return semver.subset(serviceNodeRange, `>=${required.version}`, {\n      includePrerelease: false,\n    })\n  } catch {\n    return true\n  }\n}\n\nexport function checkNodeEngineConstraint(\n  constraint: NodeEngineConstraint,\n  declaredPackageVersion: string | undefined,\n  serviceNodeRange: string | undefined,\n): NodeEngineCheck {\n  if (constraint.packageMinVersion && declaredPackageVersion) {\n    const v = semver.coerce(declaredPackageVersion)\n    if (v && semver.lt(v, constraint.packageMinVersion)) {\n      return { compatible: true }\n    }\n  }\n  if (!serviceNodeRange) {\n    return { compatible: true }\n  }\n  if (rangeAdmitsVersion(serviceNodeRange, constraint.minNodeVersion)) {\n    return { compatible: true }\n  }\n  return {\n    compatible: false,\n    reason: constraint.reason,\n    requiredNodeVersion: constraint.minNodeVersion,\n  }\n}\n\nexport interface PackageConflictCheck {\n  compatible: boolean\n  reason?: string\n  requires?: { name: string; minVersion: string }\n  foundVersion?: string\n}\n\nexport function checkPackageConflict(\n  conflict: PackageConflict,\n  declaredPackageVersion: string | undefined,\n  declaredRequiredVersion: string | undefined,\n): PackageConflictCheck {\n  if (!declaredPackageVersion) return { compatible: true }\n  if (conflict.packageMinVersion) {\n    const v = semver.coerce(declaredPackageVersion)\n    if (v && semver.lt(v, conflict.packageMinVersion)) {\n      return { compatible: true }\n    }\n  }\n  if (!declaredRequiredVersion) {\n    return {\n      compatible: false,\n      reason: conflict.reason,\n      requires: conflict.requires,\n    }\n  }\n  const requiredCoerced = semver.coerce(declaredRequiredVersion)\n  if (!requiredCoerced) return { compatible: true }\n  if (semver.lt(requiredCoerced, conflict.requires.minVersion)) {\n    return {\n      compatible: false,\n      reason: conflict.reason,\n      requires: conflict.requires,\n      foundVersion: declaredRequiredVersion,\n    }\n  }\n  return { compatible: true }\n}\n\nexport function checkDeprecatedApi(\n  rule: DeprecatedApi,\n  declaredVersion: string | undefined,\n): { compatible: boolean; reason?: string } {\n  if (declaredVersion === undefined) return { compatible: true }\n  if (rule.packageMaxVersion) {\n    const v = semver.coerce(declaredVersion)\n    const max = semver.coerce(rule.packageMaxVersion)\n    if (v && max && semver.gt(v, max)) return { compatible: true }\n  }\n  return { compatible: false, reason: rule.reason }\n}\n\nfunction currentMatrix(): CompatMatrix {\n  return mergedMatrix ?? bundledMatrix\n}\n\nfunction mergeMatrices(a: CompatMatrix, b: CompatMatrix): CompatMatrix {\n  return {\n    pairs: [...a.pairs, ...(b.pairs ?? [])],\n    nodeEngineConstraints: [\n      ...(a.nodeEngineConstraints ?? []),\n      ...(b.nodeEngineConstraints ?? []),\n    ],\n    packageConflicts: [...(a.packageConflicts ?? []), ...(b.packageConflicts ?? [])],\n    deprecatedApis: [...(a.deprecatedApis ?? []), ...(b.deprecatedApis ?? [])],\n    flagStores: [...(a.flagStores ?? []), ...(b.flagStores ?? [])],\n  }\n}\n\nasync function readRemoteCache(url: string): Promise<CompatMatrix | null> {\n  try {\n    const raw = await fs.readFile(REMOTE_CACHE_PATH, 'utf8')\n    const parsed = JSON.parse(raw) as RemoteCacheFile\n    if (parsed.url !== url) return null\n    const age = Date.now() - new Date(parsed.fetchedAt).getTime()\n    if (age > REMOTE_TTL_MS) return null\n    return parsed.matrix\n  } catch {\n    return null\n  }\n}\n\nasync function writeRemoteCache(url: string, matrix: CompatMatrix): Promise<void> {\n  const file: RemoteCacheFile = {\n    fetchedAt: new Date().toISOString(),\n    url,\n    matrix,\n  }\n  try {\n    await fs.mkdir(REMOTE_CACHE_DIR, { recursive: true })\n    await fs.writeFile(REMOTE_CACHE_PATH, JSON.stringify(file), 'utf8')\n  } catch (err) {\n    console.warn(`[neat] failed to cache compat matrix: ${(err as Error).message}`)\n  }\n}\n\n// Loads the bundled matrix and, if `NEAT_COMPAT_URL` is set, merges in a\n// remote extension. Falls back to a fresh fetch when the on-disk cache is\n// stale (24h TTL) or missing. Returns the merged matrix; subsequent calls are\n// memoised.\n//\n// Async because the fetch happens lazily on first use. Extract phase 2 awaits\n// this before iterating pairs; everything else goes through the sync\n// `currentMatrix()` view, which is fine because by the time CLI / traversal\n// runs, extraction has already loaded.\nexport async function ensureCompatLoaded(): Promise<CompatMatrix> {\n  if (mergedMatrix) return mergedMatrix\n  if (remoteLoadAttempted) {\n    mergedMatrix = bundledMatrix\n    return mergedMatrix\n  }\n  remoteLoadAttempted = true\n\n  const url = process.env.NEAT_COMPAT_URL\n  if (!url) {\n    mergedMatrix = bundledMatrix\n    return mergedMatrix\n  }\n\n  const cached = await readRemoteCache(url)\n  if (cached) {\n    mergedMatrix = mergeMatrices(bundledMatrix, cached)\n    return mergedMatrix\n  }\n\n  try {\n    const res = await fetch(url)\n    if (!res.ok) throw new Error(`${res.status} ${res.statusText}`)\n    const remote = (await res.json()) as CompatMatrix\n    await writeRemoteCache(url, remote)\n    mergedMatrix = mergeMatrices(bundledMatrix, remote)\n    return mergedMatrix\n  } catch (err) {\n    console.warn(\n      `[neat] NEAT_COMPAT_URL fetch failed (${(err as Error).message}); using bundled matrix only`,\n    )\n    mergedMatrix = bundledMatrix\n    return mergedMatrix\n  }\n}\n\n// Reset the merged-matrix memo. Intended for tests so each test starts with a\n// freshly loaded matrix.\nexport function resetCompatMatrix(): void {\n  mergedMatrix = null\n  remoteLoadAttempted = false\n}\n\nexport function compatPairs(): readonly CompatPair[] {\n  return currentMatrix().pairs\n}\n\nexport function nodeEngineConstraints(): readonly NodeEngineConstraint[] {\n  return currentMatrix().nodeEngineConstraints ?? []\n}\n\nexport function packageConflicts(): readonly PackageConflict[] {\n  return currentMatrix().packageConflicts ?? []\n}\n\nexport function deprecatedApis(): readonly DeprecatedApi[] {\n  return currentMatrix().deprecatedApis ?? []\n}\n\nexport function flagStoreProviders(): readonly FlagStoreProvider[] {\n  return currentMatrix().flagStores ?? []\n}\n","{\n  \"pairs\": [\n    {\n      \"kind\": \"driver-engine\",\n      \"driver\": \"pg\",\n      \"engine\": \"postgresql\",\n      \"minDriverVersion\": \"8.0.0\",\n      \"minEngineVersion\": \"14\",\n      \"reason\": \"PostgreSQL 14+ requires scram-sha-256 auth by default; pg < 8.0.0 only speaks md5.\"\n    },\n    {\n      \"kind\": \"driver-engine\",\n      \"driver\": \"mysql2\",\n      \"engine\": \"mysql\",\n      \"minDriverVersion\": \"3.0.0\",\n      \"minEngineVersion\": \"8\",\n      \"reason\": \"MySQL 8 defaults to caching_sha2_password; mysql2 < 3.0.0 doesn't negotiate it.\"\n    },\n    {\n      \"kind\": \"driver-engine\",\n      \"driver\": \"mongoose\",\n      \"engine\": \"mongodb\",\n      \"minDriverVersion\": \"7.0.0\",\n      \"minEngineVersion\": \"7\",\n      \"reason\": \"MongoDB 7 drops legacy wire-protocol opcodes that mongoose < 7.0.0 still emits.\"\n    },\n    {\n      \"kind\": \"driver-engine\",\n      \"driver\": \"psycopg2\",\n      \"engine\": \"postgresql\",\n      \"minDriverVersion\": \"2.9.0\",\n      \"minEngineVersion\": \"14\",\n      \"reason\": \"PostgreSQL 14+ requires scram-sha-256 auth by default; psycopg2 < 2.9.0 only speaks md5.\"\n    },\n    {\n      \"kind\": \"driver-engine\",\n      \"driver\": \"pymongo\",\n      \"engine\": \"mongodb\",\n      \"minDriverVersion\": \"4.0.0\",\n      \"minEngineVersion\": \"7\",\n      \"reason\": \"MongoDB 7 drops legacy wire-protocol opcodes that pymongo < 4.0.0 still emits.\"\n    },\n    {\n      \"kind\": \"driver-engine\",\n      \"driver\": \"mysql-connector-python\",\n      \"engine\": \"mysql\",\n      \"minDriverVersion\": \"8.0.0\",\n      \"minEngineVersion\": \"8\",\n      \"reason\": \"MySQL 8 defaults to caching_sha2_password; mysql-connector-python < 8.0.0 doesn't negotiate it.\"\n    }\n  ],\n  \"nodeEngineConstraints\": [\n    {\n      \"kind\": \"node-engine\",\n      \"package\": \"vitest\",\n      \"packageMinVersion\": \"2.0.0\",\n      \"minNodeVersion\": \"18.0.0\",\n      \"reason\": \"vitest >= 2.0 drops Node 16 support; requires Node 18+.\"\n    },\n    {\n      \"kind\": \"node-engine\",\n      \"package\": \"next\",\n      \"packageMinVersion\": \"14.0.0\",\n      \"minNodeVersion\": \"18.17.0\",\n      \"reason\": \"Next 14+ requires Node 18.17+ (uses APIs introduced in that minor).\"\n    },\n    {\n      \"kind\": \"node-engine\",\n      \"package\": \"@modelcontextprotocol/sdk\",\n      \"packageMinVersion\": \"1.0.0\",\n      \"minNodeVersion\": \"18.0.0\",\n      \"reason\": \"@modelcontextprotocol/sdk >= 1 requires Node 18+ (web-streams polyfill removed).\"\n    }\n  ],\n  \"packageConflicts\": [\n    {\n      \"kind\": \"package-conflict\",\n      \"package\": \"@tanstack/react-query\",\n      \"packageMinVersion\": \"5.0.0\",\n      \"requires\": {\n        \"name\": \"react\",\n        \"minVersion\": \"18.0.0\"\n      },\n      \"reason\": \"@tanstack/react-query 5+ uses useSyncExternalStore — only available in React 18+.\"\n    },\n    {\n      \"kind\": \"package-conflict\",\n      \"package\": \"react-router-dom\",\n      \"packageMinVersion\": \"7.0.0\",\n      \"requires\": {\n        \"name\": \"react\",\n        \"minVersion\": \"18.0.0\"\n      },\n      \"reason\": \"react-router-dom 7+ requires React 18+.\"\n    },\n    {\n      \"kind\": \"package-conflict\",\n      \"package\": \"next\",\n      \"packageMinVersion\": \"14.0.0\",\n      \"requires\": {\n        \"name\": \"react\",\n        \"minVersion\": \"18.2.0\"\n      },\n      \"reason\": \"Next.js 14+ requires React 18.2+.\"\n    }\n  ],\n  \"deprecatedApis\": [\n    {\n      \"kind\": \"deprecated-api\",\n      \"package\": \"request\",\n      \"packageMaxVersion\": \"2.88.2\",\n      \"reason\": \"request is deprecated; use undici, node-fetch, or axios instead.\"\n    },\n    {\n      \"kind\": \"deprecated-api\",\n      \"package\": \"node-uuid\",\n      \"reason\": \"node-uuid is deprecated; use the `uuid` package.\"\n    }\n  ],\n  \"flagStores\": [\n    {\n      \"provider\": \"flagd\",\n      \"schemaPattern\": \"flagd.dev/schema\",\n      \"reason\": \"flagd flag definition files name flagd's JSON schema in `$schema`; flagd serves the live definitions on its sync service (FlagSyncService/FetchAllFlags).\"\n    }\n  ]\n}\n","// Frontend-facing event bus (ADR-051). The single in-process EventEmitter\n// every producer (ingest / extract / watch / policy) emits through and the\n// only thing the SSE handler in streaming.ts subscribes to.\n//\n// Direct producer-to-handler coupling is a contract violation — every event\n// goes through `eventBus.emit('event', envelope)` so the SSE layer is the\n// only consumer that has to know the wire taxonomy.\n//\n// The taxonomy was locked at eight types (ADR-051 #2) and grew by one —\n// `incident` — under ADR-221, on the principle that only an append-only,\n// non-reconstructable fact earns a type (a re-derivable query like divergence\n// stays off the bus). A tenth type requires a further successor ADR.\n\nimport { EventEmitter } from 'node:events'\nimport type {\n  GraphEdge,\n  GraphNode,\n  IncidentEventPayload,\n  PolicyViolation,\n  Provenance,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Locked event taxonomy. Nine values. Tests assert the array shape\n// directly, so adding here without updating the contract is a regression.\nexport const NEAT_EVENT_TYPES = [\n  'node-added',\n  'node-updated',\n  'node-removed',\n  'edge-added',\n  'edge-removed',\n  'extraction-complete',\n  'policy-violation',\n  'stale-transition',\n  'incident',\n] as const\n\nexport type NeatEventType = (typeof NEAT_EVENT_TYPES)[number]\n\n// Per-type payload shapes. The wire layer (SSE) writes the payload as the\n// `data` field; producers use `emit*` helpers below for type safety.\nexport interface NodeAddedPayload {\n  node: GraphNode\n}\nexport interface NodeUpdatedPayload {\n  id: string\n  changes: Partial<GraphNode>\n}\nexport interface NodeRemovedPayload {\n  id: string\n}\nexport interface EdgeAddedPayload {\n  edge: GraphEdge\n}\nexport interface EdgeRemovedPayload {\n  id: string\n}\nexport interface ExtractionCompletePayload {\n  project: string\n  fileCount: number\n  nodesAdded: number\n  edgesAdded: number\n}\nexport interface PolicyViolationPayload {\n  violation: PolicyViolation\n}\nexport interface StaleTransitionPayload {\n  edgeId: string\n  from: typeof Provenance.OBSERVED\n  to: typeof Provenance.STALE\n}\n\nexport type NeatEventPayload = {\n  'node-added': NodeAddedPayload\n  'node-updated': NodeUpdatedPayload\n  'node-removed': NodeRemovedPayload\n  'edge-added': EdgeAddedPayload\n  'edge-removed': EdgeRemovedPayload\n  'extraction-complete': ExtractionCompletePayload\n  'policy-violation': PolicyViolationPayload\n  'stale-transition': StaleTransitionPayload\n  // A lean trigger (ADR-221) — the full incident card is a REST read. Emitted\n  // directly by ingest.ts when an ErrorEvent is appended, not via the\n  // graph-mutation re-emitter.\n  incident: IncidentEventPayload\n}\n\n// What the bus carries internally. Project is metadata used by the SSE\n// handler to route between /events and /projects/:project/events; it never\n// lands in the wire payload.\nexport interface NeatEventEnvelope<T extends NeatEventType = NeatEventType> {\n  type: T\n  project: string\n  payload: NeatEventPayload[T]\n}\n\n// Single event channel — listeners filter by `envelope.type` and\n// `envelope.project`. Using one channel keeps the contract surface narrow\n// and matches the SSE handler's needs (one subscription, fan out).\nexport const EVENT_BUS_CHANNEL = 'event'\n\nclass NeatEventBus extends EventEmitter {}\n\n// Singleton. Process-wide so producers in ingest / extract / watch / policy\n// can emit without threading a bus instance through every call site.\nexport const eventBus: NeatEventBus = new NeatEventBus()\n\n// EventEmitter defaults to 10 listeners; SSE clients add up quickly under a\n// browser refresh storm, so lift the cap.\neventBus.setMaxListeners(0)\n\nexport function emitNeatEvent<T extends NeatEventType>(envelope: NeatEventEnvelope<T>): void {\n  eventBus.emit(EVENT_BUS_CHANNEL, envelope)\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Graph subscription — one place to wire graphology mutation events into\n// the bus so producers don't have to instrument every addNode/addEdge.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface AttachOptions {\n  project: string\n}\n\n// Subscribes to a NeatGraph and re-emits node/edge add/remove + node/edge\n// attribute updates as bus envelopes scoped to `project`. Returns a detach\n// fn that removes every listener it installed.\n//\n// Stale-transition is NOT routed through here — a provenance flip is just an\n// attribute update from graphology's view, and we'd lose the OBSERVED→STALE\n// semantic. ingest.ts emits stale-transition itself.\nexport function attachGraphToEventBus(graph: NeatGraph, opts: AttachOptions): () => void {\n  const { project } = opts\n\n  const onNodeAdded = (payload: { key: string; attributes: GraphNode }): void => {\n    emitNeatEvent({\n      type: 'node-added',\n      project,\n      payload: { node: payload.attributes },\n    })\n  }\n  const onNodeDropped = (payload: { key: string }): void => {\n    emitNeatEvent({\n      type: 'node-removed',\n      project,\n      payload: { id: payload.key },\n    })\n  }\n  const onEdgeAdded = (payload: { key: string; attributes: GraphEdge }): void => {\n    emitNeatEvent({\n      type: 'edge-added',\n      project,\n      payload: { edge: payload.attributes },\n    })\n  }\n  const onEdgeDropped = (payload: { key: string }): void => {\n    emitNeatEvent({\n      type: 'edge-removed',\n      project,\n      payload: { id: payload.key },\n    })\n  }\n  const onNodeAttrsUpdated = (payload: { key: string; attributes: GraphNode }): void => {\n    emitNeatEvent({\n      type: 'node-updated',\n      project,\n      payload: { id: payload.key, changes: payload.attributes },\n    })\n  }\n\n  graph.on('nodeAdded', onNodeAdded)\n  graph.on('nodeDropped', onNodeDropped)\n  graph.on('edgeAdded', onEdgeAdded)\n  graph.on('edgeDropped', onEdgeDropped)\n  graph.on('nodeAttributesUpdated', onNodeAttrsUpdated)\n\n  return () => {\n    graph.off('nodeAdded', onNodeAdded)\n    graph.off('nodeDropped', onNodeDropped)\n    graph.off('edgeAdded', onEdgeAdded)\n    graph.off('edgeDropped', onEdgeDropped)\n    graph.off('nodeAttributesUpdated', onNodeAttrsUpdated)\n  }\n}\n","import type {\n  BlastRadiusAffectedNode,\n  BlastRadiusResult,\n  DatabaseNode,\n  DeployContext,\n  ErrorEvent,\n  ExpandNeighbour,\n  ExpandResult,\n  GraphEdge,\n  GraphNode,\n  NodeClassification,\n  NodeContext,\n  ObservedDependenciesResult,\n  RelatePath,\n  RelateResult,\n  RootCauseCandidate,\n  RootCauseResult,\n  ServiceNode,\n  TransitiveDependenciesResult,\n  TransitiveDependency,\n} from '@neat.is/types'\nimport { codeFilepathOf, codeLinenoOf } from './ingest.js'\nimport {\n  BlastRadiusResultSchema,\n  EdgeType,\n  ExpandResultSchema,\n  NodeType,\n  ObservedDependenciesResultSchema,\n  ObservedDeployContextSchema,\n  PROV_RANK,\n  Provenance,\n  RelateResultSchema,\n  RootCauseResultSchema,\n  TransitiveDependenciesResultSchema,\n  fileId,\n  frontierEdgeId,\n  parseSymbolId,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport {\n  checkCompatibility,\n  checkNodeEngineConstraint,\n  checkPackageConflict,\n  compatPairs,\n  nodeEngineConstraints,\n  packageConflicts,\n} from './compat.js'\n\n// Contract anchors (see /docs/contracts.md + docs/contracts/provenance.md):\n//   * Rule 2 — Coexistence: walk by provenance priority, never collapse edges.\n//   * Rule 3 — FrontierNodes terminate traversal — edges to/from FrontierNodes\n//     are skipped, not merely deprioritized. If a node's only neighbour is a\n//     FrontierNode, traversal stops there. ADR-068 makes node-type the gating\n//     property, independent of edge provenance.\n//   * Rule 5 — Validate results against RootCauseResultSchema /\n//     BlastRadiusResultSchema before returning.\n//   * Rule 8 — No demo-name hardcoding: driver/engine identifiers come from\n//     node properties + compatPairs(), never literals.\n//   * ADR-029 — PROV_RANK is the canonical provenance ranking, imported\n//     from @neat.is/types so consumers (traversal, MCP, policies) all agree.\n\nconst ROOT_CAUSE_MAX_DEPTH = 5\nconst BLAST_RADIUS_DEFAULT_DEPTH = 10\n\nfunction isFrontierNode(graph: NeatGraph, nodeId: string): boolean {\n  if (!graph.hasNode(nodeId)) return false\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  return attrs.type === NodeType.FrontierNode\n}\n\n// Resolve a node on the walk path to the ServiceNode that carries the compat\n// evidence (declared dependencies + node engine). A ServiceNode resolves to\n// itself; a FileNode resolves to its owning service via the inbound\n// `service ──CONTAINS──▶ file` edge (file-awareness.md §2); a SymbolNode\n// resolves one containment level deeper, up the inbound CONTAINS chain\n// `symbol ◀─CONTAINS─ file ◀─CONTAINS─ service` (file-awareness.md §3, ADR-158\n// §7). In a file-first, symbol-deep graph the caller on the path is a File- or\n// SymbolNode, but the dependency declaration lives on the service that owns it —\n// the file or symbol stays on the traversal path, the service is only named as\n// the compat carrier. Anything else has no service to resolve to. Returns the\n// resolved ServiceNode's id + attributes, or null.\nfunction resolveOwningService(\n  graph: NeatGraph,\n  nodeId: string,\n): { id: string; svc: ServiceNode } | null {\n  if (!graph.hasNode(nodeId)) return null\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  if (attrs.type === NodeType.ServiceNode) {\n    return { id: nodeId, svc: attrs as ServiceNode }\n  }\n  // A FileNode is owned by its service directly; a SymbolNode is owned by its\n  // file, which is in turn owned by the service. Walk the inbound CONTAINS edge\n  // either way — the owner is a ServiceNode for a file (return it), or a FileNode\n  // for a symbol (resolve that file the same way, one hop further).\n  if (attrs.type === NodeType.FileNode || attrs.type === NodeType.SymbolNode) {\n    for (const edgeId of graph.inboundEdges(nodeId)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type !== EdgeType.CONTAINS) continue\n      const owner = graph.getNodeAttributes(e.source) as GraphNode\n      if (owner.type === NodeType.ServiceNode) {\n        return { id: e.source, svc: owner as ServiceNode }\n      }\n      if (owner.type === NodeType.FileNode) {\n        return resolveOwningService(graph, e.source)\n      }\n    }\n  }\n  return null\n}\n\n// A FRONTIER edge is a staged surface (ADR-226), not part of the settled graph:\n// it is never ranked (PROV_RANK has no FRONTIER entry) and never traversed — the\n// edge-level twin of the node-level \"stop at FrontierNodes\" gating (Rule 3). Every\n// ranking / traversal site skips it, so a proposal never contests a settled edge.\nfunction isFrontierEdge(e: GraphEdge): boolean {\n  return e.provenance === Provenance.FRONTIER\n}\n\n// FRONTIER is excluded from PROV_RANK (ADR-226): a staged surface never contests a\n// settled edge, and every ranking site skips it via `isFrontierEdge`. This keeps\n// the floor honest for the type system and as defence-in-depth — an unranked\n// provenance sorts below STALE (PROVENANCE.md's `STALE ≥ FRONTIER`), so even a\n// stray FRONTIER edge that slips a skip can never be picked as the best edge.\nfunction rankOf(p: GraphEdge['provenance']): number {\n  return p === Provenance.FRONTIER ? -1 : PROV_RANK[p]\n}\n\n// Multiple edges between the same pair coexist by provenance (EXTRACTED next to\n// OBSERVED next to INFERRED). Traversal walks the system as the graph \"sees it\n// best\", so for any neighbour pair we pick the highest-provenance edge.\n// Edges connecting to FrontierNodes are skipped at the node level (ADR-068):\n// FrontierNodes are unresolved peers, traversal terminates at them rather than\n// pretending the path continues into unknown territory. FRONTIER-provenance edges\n// are skipped at the edge level (ADR-226): a staged surface is not settled graph.\nfunction bestEdgeBySource(graph: NeatGraph, edgeIds: string[]): Map<string, GraphEdge> {\n  const best = new Map<string, GraphEdge>()\n  for (const id of edgeIds) {\n    const e = graph.getEdgeAttributes(id) as GraphEdge\n    if (isFrontierNode(graph, e.source) || isFrontierEdge(e)) continue\n    const cur = best.get(e.source)\n    if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {\n      best.set(e.source, e)\n    }\n  }\n  return best\n}\n\nfunction bestEdgeByTarget(graph: NeatGraph, edgeIds: string[]): Map<string, GraphEdge> {\n  const best = new Map<string, GraphEdge>()\n  for (const id of edgeIds) {\n    const e = graph.getEdgeAttributes(id) as GraphEdge\n    if (isFrontierNode(graph, e.target) || isFrontierEdge(e)) continue\n    const cur = best.get(e.target)\n    if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {\n      best.set(e.target, e)\n    }\n  }\n  return best\n}\n\n// Per-edge confidence is provenance × volume × recency × cleanliness.\n//   * provenance gives a ceiling: OBSERVED 1.0, INFERRED 0.7, EXTRACTED 0.5,\n//     STALE 0.3.\n//   * volume: log-scaled span count, saturating quickly so 1 span ≈ 0.55 and\n//     ~1k spans ≈ 1.0.\n//   * recency: 1.0 within an hour; decays toward 0.5 by 24h, toward 0.3 past.\n//   * cleanliness: error rate above ~10% pulls the score down — a flapping\n//     edge with thousands of spans shouldn't outrank a clean low-traffic one.\n// Bounded to [0, 1]. Walks of multiple edges multiply per-edge confidences.\nconst PROVENANCE_CEILING: Record<string, number> = {\n  OBSERVED: 1.0,\n  INFERRED: 0.7,\n  EXTRACTED: 0.5,\n  STALE: 0.3,\n  // A FRONTIER surface (ADR-226) is a proposal about a cause NEAT could not observe\n  // — the least-trusted claim it makes, below STALE (which was at least once seen).\n  FRONTIER: 0.2,\n}\n\nfunction volumeWeight(spanCount: number | undefined): number {\n  if (!spanCount || spanCount <= 0) return 0.5\n  // log10 saturating around ~1000 spans → ~1.0.\n  const w = 0.5 + Math.log10(spanCount + 1) / 3\n  return Math.min(1, w)\n}\n\nfunction recencyWeight(ageMs: number | undefined): number {\n  if (ageMs === undefined) return 0.8\n  const hour = 60 * 60 * 1000\n  if (ageMs <= hour) return 1.0\n  if (ageMs <= 24 * hour) {\n    const t = (ageMs - hour) / (23 * hour)\n    return 1.0 - 0.5 * t\n  }\n  return 0.3\n}\n\nfunction cleanlinessWeight(spanCount: number | undefined, errorCount: number | undefined): number {\n  if (!spanCount || spanCount <= 0) return 1\n  const rate = (errorCount ?? 0) / spanCount\n  if (rate <= 0.01) return 1\n  if (rate >= 0.5) return 0.3\n  return 1 - rate * 1.4\n}\n\nexport function confidenceForEdge(edge: GraphEdge, now = Date.now()): number {\n  const ceiling = PROVENANCE_CEILING[edge.provenance] ?? 0.5\n\n  // No runtime signal yet → the provenance ceiling is all we have. This keeps\n  // EXTRACTED-only graphs returning the same coarse 0.3/0.5/0.7/1.0 ladder\n  // they always have, while letting OBSERVED edges with real OTel data move\n  // off the ceiling once ingest starts populating signal counters.\n  const spanCount = edge.signal?.spanCount ?? edge.callCount\n  const ageMs = edge.signal?.lastObservedAgeMs ?? lastObservedAge(edge, now)\n  if (spanCount === undefined && ageMs === undefined && edge.signal === undefined) {\n    return ceiling\n  }\n\n  const v = volumeWeight(spanCount)\n  const r = recencyWeight(ageMs)\n  const c = cleanlinessWeight(spanCount, edge.signal?.errorCount)\n  return Math.max(0, Math.min(1, ceiling * v * r * c))\n}\n\nfunction lastObservedAge(edge: GraphEdge, now: number): number | undefined {\n  if (!edge.lastObserved) return undefined\n  const t = Date.parse(edge.lastObserved)\n  if (!Number.isFinite(t)) return undefined\n  return Math.max(0, now - t)\n}\n\n// Path-level confidence is the *product* of per-edge confidences (ADR-036).\n// Each hop is independent evidence and uncertainty compounds — a 3-hop path\n// of edges at confidence 0.8 each gives 0.512, not 0.8. Multiplying punishes\n// long walks accordingly, which is the contract's intent: traversal should\n// surface the cumulative trust the graph actually has, not the weakest link\n// alone.\nfunction confidenceFromMix(edges: GraphEdge[], now = Date.now()): number {\n  if (edges.length === 0) return 1.0\n  let product = 1\n  for (const e of edges) {\n    product *= confidenceForEdge(e, now)\n  }\n  return Math.max(0, Math.min(1, product))\n}\n\ninterface Walk {\n  path: string[]\n  edges: GraphEdge[]\n}\n\n// DFS along incoming edges from start, depth-bounded. Returns the longest path\n// reachable, picking best-provenance edges per neighbour pair so the walk\n// reflects the system as the graph knows it most reliably.\nfunction longestIncomingWalk(graph: NeatGraph, start: string, maxDepth: number): Walk {\n  let best: Walk = { path: [start], edges: [] }\n  const visited = new Set<string>([start])\n\n  function step(node: string, path: string[], edges: GraphEdge[]): void {\n    if (path.length > best.path.length) {\n      best = { path: [...path], edges: [...edges] }\n    }\n    if (path.length - 1 >= maxDepth) return\n\n    const incoming = bestEdgeBySource(graph, graph.inboundEdges(node))\n    for (const [srcId, edge] of incoming) {\n      if (visited.has(srcId)) continue\n      visited.add(srcId)\n      path.push(srcId)\n      edges.push(edge)\n      step(srcId, path, edges)\n      path.pop()\n      edges.pop()\n      visited.delete(srcId)\n    }\n  }\n\n  step(start, [start], [])\n  return best\n}\n\n// Per-shape match result. Each shape walks the same incoming `walk.path` but\n// looks for a different class of incompatibility. Adding a new shape (e.g. a\n// future ConfigNode \"missing required env var\" rule) is one entry in\n// `rootCauseShapes` plus its match function — no restructure to getRootCause.\ninterface RootCauseMatch {\n  rootCauseNode: string\n  rootCauseReason: string\n  fixRecommendation?: string\n}\n\ntype RootCauseShape = (\n  graph: NeatGraph,\n  origin: GraphNode,\n  walk: Walk,\n) => RootCauseMatch | null\n\n// DatabaseNode origin → driver/engine compat (the original v0.1.x behavior,\n// preserved verbatim). The walk ignores non-ServiceNodes; the first upstream\n// service whose declared driver fails compat against the origin DB's\n// (engine, engineVersion) wins.\nfunction databaseRootCauseShape(\n  graph: NeatGraph,\n  origin: GraphNode,\n  walk: Walk,\n): RootCauseMatch | null {\n  const targetDb = origin as DatabaseNode\n  // Pairs that could possibly hit on this engine — narrowed once outside the\n  // walk so we don't re-scan the matrix for every service we visit.\n  const candidatePairs = compatPairs().filter((p) => p.engine === targetDb.engine)\n  if (candidatePairs.length === 0) return null\n\n  for (const id of walk.path) {\n    // The compat carrier is a service: a ServiceNode resolves to itself, a\n    // FileNode on the path resolves to its owning service via CONTAINS\n    // (file-awareness.md §2). In a file-first graph the caller on the walk is\n    // the FileNode that holds the CALLS edge, but the declared driver lives on\n    // the service that owns it.\n    const owner = resolveOwningService(graph, id)\n    if (!owner) continue\n    const { id: serviceId, svc } = owner\n    const deps = svc.dependencies ?? {}\n    for (const pair of candidatePairs) {\n      const declared = deps[pair.driver]\n      if (!declared) continue\n      const result = checkCompatibility(\n        pair.driver,\n        declared,\n        targetDb.engine,\n        targetDb.engineVersion,\n      )\n      if (!result.compatible) {\n        return {\n          rootCauseNode: serviceId,\n          rootCauseReason: result.reason ?? 'incompatible driver',\n          ...(result.minDriverVersion\n            ? {\n                fixRecommendation: `Upgrade ${svc.name} ${pair.driver} driver to >= ${result.minDriverVersion}`,\n              }\n            : {}),\n        }\n      }\n    }\n  }\n  return null\n}\n\n// ServiceNode origin → node-engine + package-conflict shapes from compat.ts.\n// The check is over each ServiceNode along the incoming walk (the origin\n// itself + any upstream callers): a node-engine constraint failing against\n// the service's `engines.node`, or a package-conflict where a declared dep\n// requires a peer at a higher version than the service has.\nfunction serviceRootCauseShape(\n  graph: NeatGraph,\n  _origin: GraphNode,\n  walk: Walk,\n): RootCauseMatch | null {\n  for (const id of walk.path) {\n    // ServiceNode → itself; FileNode → owning service via CONTAINS\n    // (file-awareness.md §2). The compat evidence (declared deps, node engine)\n    // lives on the service, even when the caller on the walk is a file.\n    const owner = resolveOwningService(graph, id)\n    if (!owner) continue\n    const { id: serviceId, svc } = owner\n    const deps = svc.dependencies ?? {}\n    const serviceNodeEngine = svc.nodeEngine\n\n    for (const constraint of nodeEngineConstraints()) {\n      const declared = deps[constraint.package]\n      if (!declared) continue\n      const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine)\n      if (!result.compatible && result.reason) {\n        return {\n          rootCauseNode: serviceId,\n          rootCauseReason: result.reason,\n          ...(result.requiredNodeVersion\n            ? {\n                fixRecommendation: `Bump ${svc.name}'s engines.node to >= ${result.requiredNodeVersion}`,\n              }\n            : {}),\n        }\n      }\n    }\n\n    for (const conflict of packageConflicts()) {\n      const declared = deps[conflict.package]\n      if (!declared) continue\n      const requiredDeclared = deps[conflict.requires.name]\n      const result = checkPackageConflict(conflict, declared, requiredDeclared)\n      if (!result.compatible && result.reason) {\n        return {\n          rootCauseNode: serviceId,\n          rootCauseReason: result.reason,\n          fixRecommendation: `Upgrade ${svc.name}'s ${conflict.requires.name} to >= ${conflict.requires.minVersion}`,\n        }\n      }\n    }\n  }\n  return null\n}\n\n// FileNode origin → resolve the file to its owning service (file-awareness.md\n// §2) and run the service shape. In a file-first graph an error can land on a\n// FileNode (the file that holds the failing CALLS edge); the incompatibility,\n// if any, is still a property of the service that owns the file's declared\n// dependencies. The owning service is folded into the origin's position so the\n// service shape scans it alongside the upstream walk.\nfunction fileRootCauseShape(\n  graph: NeatGraph,\n  origin: GraphNode,\n  walk: Walk,\n): RootCauseMatch | null {\n  const owner = resolveOwningService(graph, origin.id)\n  if (!owner) return null\n  return serviceRootCauseShape(graph, owner.svc, walk)\n}\n\n// SymbolNode origin → resolve the symbol to its owning service through the\n// inbound CONTAINS chain (symbol ◀─CONTAINS─ file ◀─CONTAINS─ service,\n// file-awareness.md §3 / ADR-158 §7) and run the service shape — one grain finer\n// than the FileNode case. A failure can land on a SymbolNode (the function that\n// holds the failing edge); the incompatibility, if any, is still a property of\n// the service that owns the symbol's declared dependencies. The symbol stays the\n// origin on the traversal path; the service is only the resolved carrier.\nfunction symbolRootCauseShape(\n  graph: NeatGraph,\n  origin: GraphNode,\n  walk: Walk,\n): RootCauseMatch | null {\n  const owner = resolveOwningService(graph, origin.id)\n  if (!owner) return null\n  return serviceRootCauseShape(graph, owner.svc, walk)\n}\n\n// Dispatch by origin node type per ADR-037. Origin types not present here\n// (InfraNode, ConfigNode, FrontierNode) cleanly return null — getRootCause\n// needs an explicit shape to know what an \"incompatibility\" looks like for\n// that origin, and those types don't have one yet. Adding the SymbolNode shape\n// (ADR-158 §7) is one entry: symbols ride the same service-carrier resolution\n// files do, one containment level deeper.\nconst rootCauseShapes: Partial<Record<GraphNode['type'], RootCauseShape>> = {\n  [NodeType.DatabaseNode]: databaseRootCauseShape,\n  [NodeType.ServiceNode]: serviceRootCauseShape,\n  [NodeType.FileNode]: fileRootCauseShape,\n  [NodeType.SymbolNode]: symbolRootCauseShape,\n}\n\n// Which branch of the single-verdict walk produced a seed. The navigation reads\n// this so it never second-guesses an edge- or compat-backed cause (ADR-209): only\n// an `incident` seed — the failure localized to the queried node itself, no causal\n// edge walked — is a candidate for the STALE-chain fallback.\ntype LegacyCauseSource = 'compat' | 'cross-service' | 'incident'\ninterface TaggedRootCause {\n  result: RootCauseResult\n  source: LegacyCauseSource\n}\n\n// The single-verdict root cause (ADR-037 / ADR-114): the compat shape, the\n// cross-service failing-CALLS chain, then the incident store. This is the seed\n// the navigation classifies and, when the seed is a saturated/stale victim,\n// overrides. Retained verbatim so the deprecation escape hatch (ADR-189,\n// NEAT_RCA_NAVIGATION=0) returns exactly the pre-navigation result; the `source`\n// tag rides alongside and is dropped for that escape hatch.\nfunction legacyRootCause(\n  graph: NeatGraph,\n  errorNodeId: string,\n  errorEvent?: ErrorEvent,\n  incidents?: ErrorEvent[],\n): TaggedRootCause | null {\n  if (!graph.hasNode(errorNodeId)) return null\n  const origin = graph.getNodeAttributes(errorNodeId) as GraphNode\n  const shape = rootCauseShapes[origin.type]\n\n  if (shape) {\n    const walk = longestIncomingWalk(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH)\n    const match = shape(graph, origin, walk)\n    if (match) {\n      const reason = errorEvent\n        ? `${match.rootCauseReason} (observed error: ${errorEvent.errorMessage})`\n        : match.rootCauseReason\n\n      // Schema-validate before return (ADR-036, #139). A drift in the result\n      // shape becomes a runtime throw at the call site rather than a silently\n      // malformed payload reaching MCP / REST consumers.\n      return {\n        source: 'compat',\n        result: RootCauseResultSchema.parse({\n          rootCauseNode: match.rootCauseNode,\n          rootCauseReason: reason,\n          traversalPath: walk.path,\n          edgeProvenances: walk.edges.map((e) => e.provenance),\n          confidence: confidenceFromMix(walk.edges),\n          fixRecommendation: match.fixRecommendation,\n        }),\n      }\n    }\n  }\n\n  // A service surfacing a failure may be the entry point of a cross-service\n  // 500 that actually originates downstream. Nothing calls the entry service,\n  // so the incoming walk above is empty — but its own OBSERVED CALLS edge to\n  // the callee carries the failure. Follow that outbound failing CALLS chain to\n  // the real culprit's handler before self-attributing the caller's mislabelled\n  // CLIENT span (#589). Only null-returns here when no downstream call is\n  // failing, i.e. the failure is in process at the origin.\n  if (origin.type === NodeType.ServiceNode) {\n    const crossService = crossServiceRootCause(graph, errorNodeId, incidents, errorEvent)\n    if (crossService) return { result: crossService, source: 'cross-service' }\n  }\n\n  // No graph edge carried an incompatibility and no downstream call is failing —\n  // but a service can fail in process (a 500 thrown inside its own handler)\n  // without that failure ever crossing an edge, so the walk above sees a\n  // healthy-looking node. The recorded incident store is the OBSERVED evidence\n  // the graph can't carry: it localizes the failure to the file:line / route the\n  // failing span captured. Consulting it here keeps root-cause useful for the\n  // in-process case instead of reporting \"healthy\" over a pile of 500s (#584).\n  const incident = rootCauseFromIncidents(errorNodeId, incidents, errorEvent)\n  return incident ? { result: incident, source: 'incident' } : null\n}\n\n// OBSERVED-grade confidence for an incident-localized cause. The incident is a\n// real captured runtime fact (where the failure surfaced), but it names the\n// surface, not a proven upstream incompatibility — so it sits below an\n// edge-walked compat result yet well above an EXTRACTED guess.\nconst INCIDENT_ROOT_CAUSE_CONFIDENCE = 0.6\n\n// Match an incident to the queried node the same way the REST incident-history\n// read does (api.ts): an exact affectedNode hit, or a service match when the\n// node is the service the incident was recorded against. A file-grained\n// affectedNode (file:<svc>:<path>) still matches the owning service this way.\nfunction incidentMatchesNode(ev: ErrorEvent, nodeId: string): boolean {\n  if (ev.affectedNode === nodeId) return true\n  if (ev.service === nodeId.replace(/^service:/, '')) return true\n  // A symbol-grained incident (ADR-191) also matches its owning FILE, so a\n  // file-grained query still surfaces a failure the finer node localized —\n  // querying the function returns the function, querying its file still hits.\n  const sym = parseSymbolId(ev.affectedNode)\n  if (sym && fileId(sym.service, sym.relPath) === nodeId) return true\n  return false\n}\n\n// A failure localized to a node through the incident store: which node carries\n// the cause, the human reason, the file the failure surfaced in (when the\n// incident captured a `code.*` call site), and the derived fix.\ninterface IncidentLocalization {\n  rootCauseNode: string\n  rootCauseReason: string\n  // The finer node the failure surfaced in — a FileNode, or one grain deeper the\n  // SymbolNode `code.function` named (ADR-191) — present only when the incident\n  // localized below the queried node. Callers walk node → finer node as a single\n  // OBSERVED hop when this is set.\n  fileNode?: string\n  fixRecommendation?: string\n}\n\n// Pick the most recent incident affecting `nodeId` and localize the failure to\n// the file:line / route it captured. Returns null when no incident touches the\n// node. Shared by the in-process fallback and the cross-service chain (#589) so\n// both describe a culprit's handler the same way.\nfunction localizeFromIncidents(\n  nodeId: string,\n  incidents: ErrorEvent[] | undefined,\n  errorEvent: ErrorEvent | undefined,\n): IncidentLocalization | null {\n  const pool = incidents && incidents.length > 0 ? incidents : errorEvent ? [errorEvent] : []\n  const relevant = pool.filter((ev) => incidentMatchesNode(ev, nodeId))\n  if (relevant.length === 0) return null\n\n  // Most recent incident is the representative; ISO timestamps sort lexically.\n  const latest = [...relevant].sort((a, b) => b.timestamp.localeCompare(a.timestamp))[0]!\n  const attrs = latest.attributes ?? {}\n  // Read the call site through the shared dual-name helper (semconv ≥1.33 stable\n  // names + the prior ones), so incident localization survives either generation.\n  const filepath = codeFilepathOf(attrs)\n  const lineno = codeLinenoOf(attrs)\n  const route = typeof attrs['http.route'] === 'string' ? attrs['http.route'] : undefined\n  const location = filepath ? `${filepath}${lineno !== undefined ? `:${lineno}` : ''}` : undefined\n\n  // Count the incidents of *this* failure mode, not every incident on the node.\n  // The reason names one message (`latest.errorMessage`); pairing it with the\n  // node's total incident count reads as though that one error happened N times\n  // when the node may be failing several different ways. Scope the count to the\n  // records sharing this message so \"3 recorded incidents\" means three of the\n  // failure the reason actually describes (issue #624).\n  const sameMode = relevant.filter((ev) => ev.errorMessage === latest.errorMessage)\n  const count = sameMode.length\n  const tail = count > 1 ? ` (${count} recorded incidents)` : ' (1 recorded incident)'\n  const reasonParts = [`${latest.service}: ${latest.errorMessage}`]\n  if (location) reasonParts.push(`surfaced at ${location}`)\n  const rootCauseReason = `${reasonParts.join(' — ')}${tail}`\n\n  // When the incident localized to a finer node — a file, or one grain deeper the\n  // SYMBOL the failing span named via `code.function` (ADR-191) — name that node\n  // as the root cause, so a query at any grain descends to the exact function the\n  // failure surfaced in. OBSERVED is honest: the node came from a real `code.*` on\n  // the failing span. Otherwise the cause sits on the queried node itself.\n  const localizesFiner =\n    latest.affectedNode !== nodeId &&\n    (latest.affectedNode.startsWith('file:') || latest.affectedNode.startsWith('symbol:'))\n  const fileNode = localizesFiner ? latest.affectedNode : undefined\n\n  const fixRecommendation = location\n    ? `Inspect ${location}${route ? ` handling ${route}` : ''}`\n    : route\n      ? `Inspect ${latest.service}'s handler for ${route}`\n      : undefined\n\n  return {\n    rootCauseNode: fileNode ?? nodeId,\n    rootCauseReason,\n    ...(fileNode ? { fileNode } : {}),\n    ...(fixRecommendation ? { fixRecommendation } : {}),\n  }\n}\n\n// Build a root-cause result from the recorded incident store when the graph\n// walk found nothing. Localizes the failure to the queried node itself (or the\n// file it surfaced in). Returns null when no incident touches the node — the\n// honest \"nothing to say\" answer.\nfunction rootCauseFromIncidents(\n  nodeId: string,\n  incidents: ErrorEvent[] | undefined,\n  errorEvent: ErrorEvent | undefined,\n): RootCauseResult | null {\n  const loc = localizeFromIncidents(nodeId, incidents, errorEvent)\n  if (!loc) return null\n\n  const traversalPath = loc.fileNode ? [nodeId, loc.fileNode] : [nodeId]\n  const edgeProvenances = loc.fileNode ? [Provenance.OBSERVED] : []\n\n  return RootCauseResultSchema.parse({\n    rootCauseNode: loc.rootCauseNode,\n    rootCauseReason: loc.rootCauseReason,\n    traversalPath,\n    edgeProvenances,\n    confidence: INCIDENT_ROOT_CAUSE_CONFIDENCE,\n    ...(loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}),\n  })\n}\n\n// A CALLS edge counts as failing when its OBSERVED signal recorded at least one\n// error. This is the signal the cross-service chain follows: the caller's call\n// to the callee returned a 5xx (#589).\nfunction isFailingCallEdge(e: GraphEdge): boolean {\n  return e.type === EdgeType.CALLS && !isFrontierEdge(e) && (e.signal?.errorCount ?? 0) > 0\n}\n\n// Every node id that can originate an outbound CALLS edge on a service's behalf:\n// the service itself, each FileNode it CONTAINS, and each SymbolNode those files\n// CONTAIN. A file-first graph anchors the caller's CALLS edge on the call-site\n// file (file-awareness.md §4); one grain finer, an OBSERVED CALLS edge lands on\n// the calling SymbolNode (ADR-158 §4), so an entry service's failing call may\n// hang off a file it owns or a symbol that file owns, not the bare service node.\n// Descending the two CONTAINS levels keeps the cross-service chain symbol-aware\n// without the reasoning ever branching on grain.\nfunction callSourcesForService(graph: NeatGraph, serviceId: string): string[] {\n  const ids = [serviceId]\n  for (const edgeId of graph.outboundEdges(serviceId)) {\n    const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (e.type !== EdgeType.CONTAINS) continue\n    const tgt = graph.getNodeAttributes(e.target) as GraphNode\n    if (tgt.type !== NodeType.FileNode) continue\n    ids.push(e.target)\n    for (const symEdgeId of graph.outboundEdges(e.target)) {\n      const se = graph.getEdgeAttributes(symEdgeId) as GraphEdge\n      if (se.type !== EdgeType.CONTAINS) continue\n      const sym = graph.getNodeAttributes(se.target) as GraphNode\n      if (sym.type === NodeType.SymbolNode) ids.push(se.target)\n    }\n  }\n  return ids\n}\n\n// Did edge `e` to service `id` beat the current best failing call? Most recorded\n// errors win; ties break on PROV_RANK, then target id — deterministic.\nfunction failingCallDominates(\n  e: GraphEdge,\n  id: string,\n  curEdge: GraphEdge,\n  curId: string,\n): boolean {\n  const ec = e.signal?.errorCount ?? 0\n  const cc = curEdge.signal?.errorCount ?? 0\n  if (ec !== cc) return ec > cc\n  if (rankOf(e.provenance) !== rankOf(curEdge.provenance)) {\n    return rankOf(e.provenance) > rankOf(curEdge.provenance)\n  }\n  return id < curId\n}\n\n// The dominant failing outbound CALLS from a service: among the service's own\n// edges and those of the files it owns, the failing CALLS edge to another\n// service with the most recorded errors. Returns the next-hop service id and the\n// edge, or null when no downstream call is failing — meaning the failure is in\n// process here, not relayed from deeper.\nfunction dominantFailingCall(\n  graph: NeatGraph,\n  serviceId: string,\n  visited: Set<string>,\n): { nextService: string; edge: GraphEdge } | null {\n  let best: { nextService: string; edge: GraphEdge } | null = null\n  for (const src of callSourcesForService(graph, serviceId)) {\n    for (const edgeId of graph.outboundEdges(src)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (!isFailingCallEdge(e)) continue\n      if (isFrontierNode(graph, e.target)) continue\n      const owner = resolveOwningService(graph, e.target)\n      if (!owner || visited.has(owner.id)) continue\n      if (!best || failingCallDominates(e, owner.id, best.edge, best.nextService)) {\n        best = { nextService: owner.id, edge: e }\n      }\n    }\n  }\n  return best\n}\n\n// Walk the failing CALLS chain outbound from an entry service to the deepest\n// still-failing callee — the service whose own downstream calls are clean and\n// whose handler therefore threw (#589). Returns the path of service ids, the\n// failing edges along it, and the culprit, or null when nothing downstream is\n// failing.\nfunction followFailingCallChain(\n  graph: NeatGraph,\n  originServiceId: string,\n  maxDepth: number,\n): { path: string[]; edges: GraphEdge[]; culprit: string } | null {\n  const path = [originServiceId]\n  const edges: GraphEdge[] = []\n  const visited = new Set<string>([originServiceId])\n  let current = originServiceId\n\n  for (let depth = 0; depth < maxDepth; depth++) {\n    const hop = dominantFailingCall(graph, current, visited)\n    if (!hop) break\n    path.push(hop.nextService)\n    edges.push(hop.edge)\n    visited.add(hop.nextService)\n    current = hop.nextService\n  }\n\n  if (edges.length === 0) return null\n  return { path, edges, culprit: current }\n}\n\n// A CALLS edge whose live signal has gone quiet: STALE provenance (ADR-209). The\n// topology was OBSERVED once and remains in the graph, but the error signal\n// `isFailingCallEdge` reads is gone — a stale snapshot lost it — so the failing\n// chain above finds nothing to follow even though the causal chain is still here.\nfunction isStaleCallEdge(e: GraphEdge): boolean {\n  return e.type === EdgeType.CALLS && e.provenance === Provenance.STALE\n}\n\n// Did stale edge `e` to service `id` beat the current best stale hop? There is no\n// error signal left to rank on — that is exactly what went quiet — so rank by the\n// last-observed call volume (the hotter known path is the likelier carrier), then\n// target id, deterministic like `failingCallDominates`.\nfunction staleCallDominates(e: GraphEdge, id: string, curEdge: GraphEdge, curId: string): boolean {\n  const ev = e.signal?.spanCount ?? e.callCount ?? 0\n  const cv = curEdge.signal?.spanCount ?? curEdge.callCount ?? 0\n  if (ev !== cv) return ev > cv\n  return id < curId\n}\n\n// The dominant STALE outbound CALLS from a service, used only as the fallback when\n// no fresh failing chain exists (ADR-209). Among the service's own edges and those\n// of the files/symbols it owns, take the best-provenance CALLS edge PER callee\n// service first — so a callee reachable by any fresher (OBSERVED/INFERRED/\n// EXTRACTED) edge is represented by that fresher edge — then keep only the callees\n// whose best edge is STALE. That PROV_RANK gate is the \"nothing fresher is\n// reachable\" guard: a target the graph still knows freshly is never walked stalely.\nfunction dominantStaleCall(\n  graph: NeatGraph,\n  serviceId: string,\n  visited: Set<string>,\n): { nextService: string; edge: GraphEdge } | null {\n  const bestByCallee = new Map<string, GraphEdge>()\n  for (const src of callSourcesForService(graph, serviceId)) {\n    for (const edgeId of graph.outboundEdges(src)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type !== EdgeType.CALLS) continue\n      if (isFrontierNode(graph, e.target) || isFrontierEdge(e)) continue\n      const owner = resolveOwningService(graph, e.target)\n      if (!owner || visited.has(owner.id)) continue\n      const cur = bestByCallee.get(owner.id)\n      if (!cur || rankOf(e.provenance) > rankOf(cur.provenance)) {\n        bestByCallee.set(owner.id, e)\n      }\n    }\n  }\n  let best: { nextService: string; edge: GraphEdge } | null = null\n  for (const [id, edge] of bestByCallee) {\n    if (!isStaleCallEdge(edge)) continue\n    if (!best || staleCallDominates(edge, id, best.edge, best.nextService)) {\n      best = { nextService: id, edge }\n    }\n  }\n  return best\n}\n\n// Walk the STALE CALLS chain outbound from a service to its deepest stale-only\n// callee — the last node the last-observed topology still reaches (ADR-209). The\n// stale analogue of `followFailingCallChain`: same shape, but each hop is a target\n// the graph knows ONLY stalely, so the whole chain is a low-confidence, honestly-\n// provenanced hypothesis rather than a signal-backed verdict. Returns null when no\n// stale-only outbound CALLS exists — a node with only fresh or no downstream edges.\nfunction followStaleCallChain(\n  graph: NeatGraph,\n  originServiceId: string,\n  maxDepth: number,\n): { path: string[]; edges: GraphEdge[]; culprit: string } | null {\n  const path = [originServiceId]\n  const edges: GraphEdge[] = []\n  const visited = new Set<string>([originServiceId])\n  let current = originServiceId\n\n  for (let depth = 0; depth < maxDepth; depth++) {\n    const hop = dominantStaleCall(graph, current, visited)\n    if (!hop) break\n    path.push(hop.nextService)\n    edges.push(hop.edge)\n    visited.add(hop.nextService)\n    current = hop.nextService\n  }\n\n  if (edges.length === 0) return null\n  return { path, edges, culprit: current }\n}\n\n// Localize a cross-service failure (#589). An entry ServiceNode surfaces a 500\n// that originates downstream: follow the failing CALLS chain to the culprit and\n// describe its handler, never the caller's mis-attributed CLIENT span. Returns\n// null when no outbound call is failing — the failure is in process here and the\n// caller falls through to the origin's own incident store.\nfunction crossServiceRootCause(\n  graph: NeatGraph,\n  originId: string,\n  incidents: ErrorEvent[] | undefined,\n  errorEvent: ErrorEvent | undefined,\n): RootCauseResult | null {\n  const chain = followFailingCallChain(graph, originId, ROOT_CAUSE_MAX_DEPTH)\n  if (!chain) return null\n\n  const culprit = chain.culprit\n  const path = [...chain.path]\n  const edgeProvenances = chain.edges.map((e) => e.provenance)\n\n  // Cross-service confidence cascades over the failing CALLS edges and the\n  // incident-localization hop, so it lands below an edge-walked compat result.\n  const baseConfidence = confidenceFromMix(chain.edges)\n  const confidence = Math.max(0, Math.min(1, baseConfidence * INCIDENT_ROOT_CAUSE_CONFIDENCE))\n\n  const loc = localizeFromIncidents(culprit, incidents, errorEvent)\n  if (loc) {\n    let rootCauseNode = culprit\n    if (loc.fileNode) {\n      path.push(loc.fileNode)\n      edgeProvenances.push(Provenance.OBSERVED)\n      rootCauseNode = loc.fileNode\n    }\n    return RootCauseResultSchema.parse({\n      rootCauseNode,\n      rootCauseReason: loc.rootCauseReason,\n      traversalPath: path,\n      edgeProvenances,\n      confidence,\n      ...(loc.fixRecommendation ? { fixRecommendation: loc.fixRecommendation } : {}),\n    })\n  }\n\n  // No recorded incident for the culprit — still better than blaming the caller.\n  // Name the culprit service and read the reason off the failing edge.\n  const lastEdge = chain.edges[chain.edges.length - 1]!\n  const errs = lastEdge.signal?.errorCount ?? 0\n  const culpritName = culprit.replace(/^service:/, '')\n  return RootCauseResultSchema.parse({\n    rootCauseNode: culprit,\n    rootCauseReason: `${culpritName} is failing downstream calls (${errs} observed error${errs === 1 ? '' : 's'})`,\n    traversalPath: path,\n    edgeProvenances,\n    confidence,\n    fixRecommendation: `Inspect ${culpritName}'s failing handler`,\n  })\n}\n\n// BFS along *inbound* edges from origin — the origin's dependents, i.e. what\n// breaks if the origin changes or fails (get-blast-radius.md, superseding\n// ADR-038's outbound direction). An edge `A ──depends-on──▶ B` means A breaks\n// when B changes, so the blast radius of B walks back along inbound edges to A\n// and everything that transitively depends on it. For an inbound edge the\n// neighbour is the edge's `source` (the dependent), so selection uses\n// bestEdgeBySource — the same machinery getRootCause walks inbound with.\n// Records each reachable dependent with the shortest distance back to origin\n// and the provenance of the edge that brought us to it. A sink (a database,\n// shared lib, leaf util) has no outbound edges but does have inbound ones, so\n// this is what makes its blast radius non-empty.\nexport function getBlastRadius(\n  graph: NeatGraph,\n  nodeId: string,\n  maxDepth = BLAST_RADIUS_DEFAULT_DEPTH,\n): BlastRadiusResult {\n  if (!graph.hasNode(nodeId)) {\n    return BlastRadiusResultSchema.parse({ origin: nodeId, affectedNodes: [], totalAffected: 0 })\n  }\n\n  // Each frame carries its full predecessor chain so the affected-node payload\n  // can surface `path` (origin → ... → nodeId) and `confidence` (cascaded over\n  // every edge along that path). The BFS visits each reachable node once on\n  // its shortest-distance path; later frames at greater distance are dropped.\n  interface Frame {\n    nodeId: string\n    distance: number\n    path: string[]\n    pathEdges: GraphEdge[]\n  }\n\n  const seen = new Map<string, BlastRadiusAffectedNode>()\n  const queue: Frame[] = [{ nodeId, distance: 0, path: [nodeId], pathEdges: [] }]\n  const enqueued = new Set<string>([nodeId])\n\n  while (queue.length > 0) {\n    const frame = queue.shift()!\n    if (frame.distance > 0 && frame.pathEdges.length > 0) {\n      const lastEdge = frame.pathEdges[frame.pathEdges.length - 1]!\n      // Blast radius KEEPS CONTAINS: walked inbound, `file ◀─CONTAINS─ service`\n      // means the service owns an affected file, so the service is genuinely in\n      // the blast radius (file-awareness §36 — file-grained dependents plus the\n      // owning service). Only get_dependencies filters CONTAINS (ADR-140), where\n      // it's walked outbound and a service doesn't depend on its own files.\n      seen.set(frame.nodeId, {\n        nodeId: frame.nodeId,\n        distance: frame.distance,\n        edgeProvenance: lastEdge.provenance,\n        path: frame.path,\n        confidence: confidenceFromMix(frame.pathEdges),\n      })\n    }\n    if (frame.distance >= maxDepth) continue\n\n    const incoming = bestEdgeBySource(graph, graph.inboundEdges(frame.nodeId))\n    for (const [srcId, edge] of incoming) {\n      if (enqueued.has(srcId)) continue\n      enqueued.add(srcId)\n      queue.push({\n        nodeId: srcId,\n        distance: frame.distance + 1,\n        path: [...frame.path, srcId],\n        pathEdges: [...frame.pathEdges, edge],\n      })\n    }\n  }\n\n  const affectedNodes = [...seen.values()].sort(\n    (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n  )\n  return BlastRadiusResultSchema.parse({\n    origin: nodeId,\n    affectedNodes,\n    totalAffected: affectedNodes.length,\n  })\n}\n\n// Default + max depth for transitive get_dependencies (issue #144). Default\n// 3 keeps the output legible at the agent layer; the contract caps the\n// caller-supplied value at 10 to prevent BFS blow-up on dense graphs.\nexport const TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH = 3\nexport const TRANSITIVE_DEPENDENCIES_MAX_DEPTH = 10\n\n// Transitive get_dependencies (ADR-039 / #144). BFS outbound from origin to\n// `depth` hops, returning a flat list with distance, edgeType, and provenance\n// per dependency. Origin is never in the list. Direct-only consumers pass\n// depth=1; the MCP get_dependencies tool defaults to 3.\n//\n// Reuses bestEdgeByTarget (FRONTIER filtered, PROV_RANK-best per pair) so\n// dedup behavior matches the rest of traversal. Result is schema-validated\n// before return per ADR-036 §Result schema validation.\nexport function getTransitiveDependencies(\n  graph: NeatGraph,\n  nodeId: string,\n  depth: number = TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n): TransitiveDependenciesResult {\n  if (!graph.hasNode(nodeId)) {\n    return TransitiveDependenciesResultSchema.parse({\n      origin: nodeId,\n      depth,\n      dependencies: [],\n      total: 0,\n    })\n  }\n\n  interface Frame {\n    nodeId: string\n    distance: number\n    edge: GraphEdge | null\n  }\n\n  const seen = new Map<string, TransitiveDependency>()\n  const queue: Frame[] = [{ nodeId, distance: 0, edge: null }]\n  const enqueued = new Set<string>([nodeId])\n\n  while (queue.length > 0) {\n    const frame = queue.shift()!\n    // Traverse THROUGH CONTAINS to reach a service's file-grained targets, but\n    // never REPORT a CONTAINS edge as a dependency: a service doesn't depend on\n    // its own files (file-awareness §36 refinement, ADR-140). The real target\n    // reached via a genuine dependency edge downstream still surfaces.\n    if (frame.distance > 0 && frame.edge && frame.edge.type !== EdgeType.CONTAINS) {\n      seen.set(frame.nodeId, {\n        nodeId: frame.nodeId,\n        distance: frame.distance,\n        edgeType: frame.edge.type,\n        provenance: frame.edge.provenance,\n      })\n    }\n    if (frame.distance >= depth) continue\n\n    const outgoing = bestEdgeByTarget(graph, graph.outboundEdges(frame.nodeId))\n    for (const [tgtId, edge] of outgoing) {\n      if (enqueued.has(tgtId)) continue\n      enqueued.add(tgtId)\n      queue.push({ nodeId: tgtId, distance: frame.distance + 1, edge })\n    }\n  }\n\n  const dependencies = [...seen.values()].sort(\n    (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n  )\n  return TransitiveDependenciesResultSchema.parse({\n    origin: nodeId,\n    depth,\n    dependencies,\n    total: dependencies.length,\n  })\n}\n\n// Observed-only dependencies (issue #578). \"What does this node actually call at\n// runtime?\" — its OBSERVED outbound edges, file-grained.\n//\n// The subtlety the previous edges-only query missed: the call-site processor\n// lands OBSERVED CALLS on the FileNode that made the call, not on the owning\n// ServiceNode (file-awareness §4). So a query that starts at a ServiceNode sees\n// only its structural `CONTAINS` edges and reports \"no runtime traffic,\" while\n// the real dependency sits one hop away on a file it owns. When the origin is a\n// ServiceNode we therefore also read the OBSERVED outbound of the FileNodes it\n// `CONTAINS` and surface those file→target edges. This is not a service rollup\n// (file-awareness §3): the edges stay file-grained with the owning file as the\n// source; the service is only the grouping the query entered through.\n//\n// `observed` and `inboundObservedCount` separate two cases the old copy\n// conflated: a pure receiver — a node runtime hits but which calls nothing\n// downstream — has zero dependencies yet is plainly seen by OTel, so the caller\n// must not ask \"is OTel running?\" at it. That question is honest only when there\n// is no OBSERVED traffic at all and EXTRACTED outbound edges exist\n// (`hasExtractedOutbound`).\nexport function getObservedDependencies(\n  graph: NeatGraph,\n  nodeId: string,\n): ObservedDependenciesResult {\n  if (!graph.hasNode(nodeId)) {\n    return ObservedDependenciesResultSchema.parse({\n      origin: nodeId,\n      dependencies: [],\n      observed: false,\n      inboundObservedCount: 0,\n      hasExtractedOutbound: false,\n      inboundVolume: 0,\n      window: 'lifetime',\n    })\n  }\n\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n\n  // The origin plus, when it's a service, the files it owns — the set of nodes\n  // whose OBSERVED edges belong to \"what this thing does at runtime.\"\n  const scope: string[] = [nodeId]\n  if (attrs.type === NodeType.ServiceNode) {\n    for (const edgeId of graph.outboundEdges(nodeId)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type !== EdgeType.CONTAINS) continue\n      const owned = graph.getNodeAttributes(e.target) as GraphNode\n      if (owned.type === NodeType.FileNode) scope.push(e.target)\n    }\n  }\n\n  const dependencies: GraphEdge[] = []\n  const seenEdge = new Set<string>()\n  let hasExtractedOutbound = false\n  for (const src of scope) {\n    for (const edgeId of graph.outboundEdges(src)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      // CONTAINS is structural ownership, never a runtime dependency.\n      if (e.type === EdgeType.CONTAINS) continue\n      if (e.provenance === Provenance.OBSERVED) {\n        if (!seenEdge.has(e.id)) {\n          seenEdge.add(e.id)\n          dependencies.push(e)\n        }\n      } else if (e.provenance === Provenance.EXTRACTED) {\n        hasExtractedOutbound = true\n      }\n    }\n  }\n\n  // Was this node (or a file it owns) seen receiving traffic? Counting OBSERVED\n  // inbound edges is the pure-receiver signal — the \"hit N times, calls nothing\"\n  // shape that must read differently from \"never observed.\" Alongside the count,\n  // the node-level inbound block (ADR-190): inboundVolume sums those edges' call\n  // counts (how hard production hits this node — distinct from the edge count),\n  // and inboundLastObserved is the most-recent inbound observation (when it was\n  // last hit), raw, so a consumer formats recency itself.\n  let inboundObservedCount = 0\n  let inboundVolume = 0\n  let inboundLastObserved: string | undefined\n  for (const tgt of scope) {\n    for (const edgeId of graph.inboundEdges(tgt)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type === EdgeType.CONTAINS) continue\n      if (e.provenance === Provenance.OBSERVED) {\n        inboundObservedCount += 1\n        inboundVolume += e.callCount ?? e.signal?.spanCount ?? 1\n        if (e.lastObserved && (!inboundLastObserved || e.lastObserved > inboundLastObserved)) {\n          inboundLastObserved = e.lastObserved\n        }\n      }\n    }\n  }\n\n  dependencies.sort(\n    (a, b) =>\n      a.target.localeCompare(b.target) ||\n      a.source.localeCompare(b.source) ||\n      a.id.localeCompare(b.id),\n  )\n\n  return ObservedDependenciesResultSchema.parse({\n    origin: nodeId,\n    dependencies,\n    observed: dependencies.length > 0 || inboundObservedCount > 0,\n    inboundObservedCount,\n    hasExtractedOutbound,\n    // The signal is cumulative, so the honest window label is \"lifetime\" (ADR-190).\n    inboundVolume,\n    window: 'lifetime',\n    ...(inboundLastObserved ? { inboundLastObserved } : {}),\n  })\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Agent-driven navigation (ADR-189): Expand, Relate, per-node classification, and\n// the candidate set that turns getRootCause from one verdict into navigation.\n// Composes the traversal primitives above — no new engine. Branches only on\n// node.type / edge.type / provenance / signal, never a provider, platform,\n// framework, or language name (traversal.md agnosticity invariant).\n// ─────────────────────────────────────────────────────────────────────────────\n\n// A node's outbound p95 counts as saturated above this absolute latency. Absolute,\n// not baseline-relative — matching how the signal is read (ADR-190) and how\n// PRAXIS's classifier consumes pre-thresholded alerts. A hardcoded contract\n// constant like ROOT_CAUSE_MAX_DEPTH.\nconst SATURATION_P95_MS = 1000\n\n// The node plus, when it is a service, the files it owns — the set whose edges\n// belong to \"what this thing does at runtime\" (the scope getObservedDependencies\n// walks). A service's runtime signal lands on its files (file-awareness.md §4).\nfunction nodeScope(graph: NeatGraph, nodeId: string): string[] {\n  const scope = [nodeId]\n  if (!graph.hasNode(nodeId)) return scope\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  if (attrs.type === NodeType.ServiceNode) {\n    for (const edgeId of graph.outboundEdges(nodeId)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type !== EdgeType.CONTAINS) continue\n      const owned = graph.getNodeAttributes(e.target) as GraphNode\n      if (owned.type === NodeType.FileNode) scope.push(e.target)\n    }\n  }\n  return scope\n}\n\n// How many recorded incidents localize to this node — errors emitted here.\nfunction incidentCountForNode(nodeId: string, incidents: ErrorEvent[] | undefined): number {\n  if (!incidents || incidents.length === 0) return 0\n  return incidents.filter((ev) => incidentMatchesNode(ev, nodeId)).length\n}\n\n// #1114 — the dependency edge types that count as a node's real outbound deps.\n// Mirrors the monitor's OBSERVED_DEP_EDGE_TYPES: CALLS + the connection/queue\n// families. CONTAINS ownership is not a dependency.\nconst DEP_EDGE_TYPES: ReadonlySet<string> = new Set([\n  EdgeType.CALLS,\n  EdgeType.CONNECTS_TO,\n  EdgeType.PUBLISHES_TO,\n  EdgeType.CONSUMES_FROM,\n])\n\n// #1114 — is this incident a gateway/TIMEOUT-class failure, the observable\n// shadow of a downstream that hung and exported nothing? A 504 gateway timeout,\n// a gRPC DEADLINE_EXCEEDED, an ETIMEDOUT / \"timed out\". Mirrors ADR-220's\n// deadline-exceeded/timeout families (kept local to avoid a divergences↔traverse\n// import cycle) and deliberately EXCLUDES the fast-fails (UNAVAILABLE /\n// ECONNREFUSED / other 5xx) that export an erroring edge NEAT can root-cause.\nconst TIMEOUT_ERROR_PATTERNS: readonly RegExp[] = [\n  /\\bDEADLINE_EXCEEDED\\b/i,\n  /\\bdeadline exceeded\\b/i,\n  /\\bETIMEDOUT\\b/i,\n  /\\btimed[\\s-]?out\\b/i,\n  /\\btimeout\\b/i,\n]\nfunction isBoundaryTimeoutError(ev: ErrorEvent): boolean {\n  if (ev.httpStatusCode === 504) return true\n  const haystack = [ev.errorType, ev.exceptionType, ev.errorMessage]\n    .filter((s): s is string => typeof s === 'string')\n    .join(' \\n ')\n  return TIMEOUT_ERROR_PATTERNS.some((re) => re.test(haystack))\n}\n\n// The separated classification inputs for a node (ADR-189). Reads real edge +\n// incident signal only — nothing synthesized (file-awareness.md §6).\nexport function nodeContext(\n  graph: NeatGraph,\n  nodeId: string,\n  incidents?: ErrorEvent[],\n  now = Date.now(),\n): NodeContext {\n  const scope = nodeScope(graph, nodeId)\n  let errorsFromCallers = 0\n  let inboundVolume = 0\n  let outboundVolume = 0\n  let outboundErrors = 0\n  let latestInboundMs: number | undefined\n  let latencyP95Ms: number | undefined\n  let stale = false\n  let observedErroringDownstream = false\n  let hasOutboundDeps = false\n\n  for (const n of scope) {\n    if (!graph.hasNode(n)) continue\n    for (const edgeId of graph.inboundEdges(n)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type === EdgeType.CONTAINS) continue\n      // A FRONTIER edge is a staged surface, not settled signal (ADR-226): it\n      // carries no observed traffic and must not feed classification context.\n      if (isFrontierEdge(e)) continue\n      errorsFromCallers += e.signal?.errorCount ?? 0\n      inboundVolume += e.callCount ?? e.signal?.spanCount ?? 0\n      if (e.provenance === Provenance.STALE) stale = true\n      const p95 = e.signal?.latencyMs?.p95\n      if (p95 !== undefined) latencyP95Ms = Math.max(latencyP95Ms ?? 0, p95)\n      if (e.lastObserved) {\n        const t = Date.parse(e.lastObserved)\n        if (Number.isFinite(t)) latestInboundMs = Math.max(latestInboundMs ?? 0, t)\n      }\n    }\n    for (const edgeId of graph.outboundEdges(n)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type === EdgeType.CONTAINS) continue\n      if (isFrontierEdge(e)) continue\n      outboundVolume += e.callCount ?? e.signal?.spanCount ?? 0\n      if (e.type === EdgeType.CALLS) outboundErrors += e.signal?.errorCount ?? 0\n      if (e.provenance === Provenance.STALE) stale = true\n      if (DEP_EDGE_TYPES.has(e.type)) {\n        hasOutboundDeps = true\n        if ((e.signal?.errorCount ?? 0) > 0) observedErroringDownstream = true\n      }\n    }\n  }\n\n  const errorsEmittedHere = incidentCountForNode(nodeId, incidents) + outboundErrors\n  const lastObservedAgeMs =\n    latestInboundMs !== undefined ? Math.max(0, now - latestInboundMs) : undefined\n  const boundaryTimeout = (incidents ?? []).some(\n    (ev) => incidentMatchesNode(ev, nodeId) && isBoundaryTimeoutError(ev),\n  )\n\n  return {\n    errorsEmittedHere,\n    errorsFromCallers,\n    callCount: inboundVolume,\n    outboundVolume,\n    ...(lastObservedAgeMs !== undefined ? { lastObservedAgeMs } : {}),\n    ...(latencyP95Ms !== undefined ? { latencyP95Ms } : {}),\n    stale,\n    boundaryTimeout,\n    observedErroringDownstream,\n    hasOutboundDeps,\n  }\n}\n\nfunction isSaturated(ctx: NodeContext): boolean {\n  return ctx.latencyP95Ms !== undefined && ctx.latencyP95Ms >= SATURATION_P95_MS\n}\n\n// #1114 — a boundary timeout is the observable shadow of an unobservable\n// downstream: a symptom, not the fault. It emits a timeout-class error, fronts a\n// downstream (has outbound deps), no caller is erroring into it, and — the\n// load-bearing guard — nothing it can see downstream is erroring. A fast-fail\n// (scaled-to-0 UNAVAILABLE, ECONNREFUSED) exports an erroring edge, so\n// `observedErroringDownstream` is true there and this does NOT fire — the\n// existing walk keeps root-causing the real culprit. A hang exports nothing, so\n// there is no erroring downstream edge and the boundary 504 is the only signal.\nexport function isBoundaryTimeoutSymptom(ctx: NodeContext): boolean {\n  return (\n    ctx.errorsEmittedHere > 0 &&\n    ctx.boundaryTimeout === true &&\n    ctx.errorsFromCallers === 0 &&\n    ctx.hasOutboundDeps === true &&\n    ctx.observedErroringDownstream !== true\n  )\n}\n\n// #1123 — the \"unreachable\" shape: a node that RECEIVED calls which predominantly\n// failed but produced NO telemetry of its own — no incidents, no outbound calls.\n// It never served: the requests never reached a running handler (a startup\n// failure, a crash before the first span, an unschedulable / unhealthy pod). Its\n// failure is real and OBSERVED (the erroring inbound edges), but the CAUSE is not\n// in the trace, so it must be named honestly (\"unreachable, cause unobserved\")\n// rather than as a primary-failure that invites an agent to hunt a nonexistent\n// code fault. A node that actually ran leaves a trace — an own incident, or an\n// outbound call of its own — so `errorsEmittedHere === 0 && outboundVolume === 0`\n// is what separates \"never served\" from \"served and failed\".\nconst UNREACHABLE_INBOUND_ERROR_RATE = 0.5\nconst UNREACHABLE_MIN_INBOUND = 3\nfunction isUnreachableSeed(ctx: NodeContext): boolean {\n  return (\n    ctx.callCount >= UNREACHABLE_MIN_INBOUND &&\n    ctx.errorsFromCallers > 0 &&\n    ctx.errorsFromCallers >= UNREACHABLE_INBOUND_ERROR_RATE * ctx.callCount &&\n    ctx.errorsEmittedHere === 0 &&\n    ctx.outboundVolume === 0\n  )\n}\n\n// Classify a node from its separated context (ADR-189). A node that emits errors\n// of its own is a primary-failure — unless it is stale/saturated and absorbs at\n// least as much failure as it emits, i.e. it is drowning in load, a symptom; or\n// it is a boundary timing out on an unobservable downstream (#1114). A node with\n// errors arriving but none emitted is a downstream symptom. No signal → unrelated.\nexport function classifyNode(ctx: NodeContext): NodeClassification {\n  if (ctx.errorsEmittedHere > 0) {\n    if ((ctx.stale || isSaturated(ctx)) && ctx.errorsFromCallers >= ctx.errorsEmittedHere) {\n      return 'symptom-only'\n    }\n    if (isBoundaryTimeoutSymptom(ctx)) return 'symptom-only'\n    return 'primary-failure'\n  }\n  // #1123 — received failing calls but produced nothing of its own: never served.\n  if (isUnreachableSeed(ctx)) return 'unreachable'\n  if (ctx.errorsFromCallers > 0) return 'symptom-only'\n  return 'unrelated'\n}\n\n// The seed is a saturated/stale victim — a starved downstream node the load hit,\n// not the fault. When it is, navigation walks up to the load origin instead of\n// naming it (ADR-189): errors arrive, the node emits no more than it receives,\n// and it has gone stale or saturated.\nfunction isVictimSeed(ctx: NodeContext): boolean {\n  return (\n    ctx.errorsFromCallers > 0 &&\n    (ctx.stale || isSaturated(ctx)) &&\n    ctx.errorsEmittedHere <= ctx.errorsFromCallers\n  )\n}\n\n// Generic connection-failure phrases that mark a node's failure as an outbound\n// one in its own incident text — a name-resolution failure, a refused or reset\n// connection, an \"unable to connect\", a lookup that never resolved. These are\n// error *semantics*, never provider or datastore names: the reasoning core never\n// learns what any particular data store is (traversal.md agnosticity), only that\n// the node reported it could not reach something downstream. Matched\n// case-insensitively against the incident's message / type / stacktrace.\nconst OUTBOUND_CONNECTION_FAILURE_PATTERNS = [\n  'name resolution',\n  'resolve host',\n  'getaddrinfo',\n  'enotfound',\n  'connection refused',\n  'econnrefused',\n  'connection reset',\n  'econnreset',\n  'able to connect',\n  'failed to connect',\n  'cannot connect',\n  'could not connect',\n  'unable to connect',\n  'connection timed out',\n  'etimedout',\n  'no route to host',\n  'host unreachable',\n  'network is unreachable',\n  'connection closed',\n]\n\n// Does this incident's own error text read as a failure to reach an outbound\n// dependency (a datastore connection, a name lookup, a downstream call) rather\n// than an in-process throw? The fallback signal when the outbound edge carries\n// no error count of its own — the connection died before a span could record it,\n// so the edge looks clean while the incident holds the real story.\nfunction incidentTextIndicatesOutboundFailure(ev: ErrorEvent): boolean {\n  const haystack = [ev.errorMessage, ev.errorType, ev.exceptionType, ev.exceptionStacktrace]\n    .filter((s): s is string => typeof s === 'string')\n    .join(' ')\n    .toLowerCase()\n  return OUTBOUND_CONNECTION_FAILURE_PATTERNS.some((p) => haystack.includes(p))\n}\n\n// Does the node fail because of its OWN outbound dependency rather than the load\n// hitting it? A downstream edge that recorded errors — a CALLS to another service\n// OR a CONNECTS_TO a datastore — means the fault originates in a dependency this\n// node drives, so the victim → load-origin move must not bury it behind the\n// traffic source (#1075). Scans every outbound edge type, not just CALLS:\n// isFailingCallEdge is CALLS-only, so a datastore auth/connection failure riding\n// a CONNECTS_TO edge would otherwise be invisible to the victim gate. When the\n// seed came from the incident store and carries no failing outbound edge (the\n// connection died before a span landed), its error text is the fallback signal —\n// an outbound connection failure in the message counts the same as a failing edge.\nfunction hasFailingOutbound(\n  graph: NeatGraph,\n  nodeId: string,\n  seedSource: LegacyCauseSource,\n  incidents: ErrorEvent[] | undefined,\n): boolean {\n  for (const n of nodeScope(graph, nodeId)) {\n    if (!graph.hasNode(n)) continue\n    for (const edgeId of graph.outboundEdges(n)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (e.type === EdgeType.CONTAINS) continue\n      if ((e.signal?.errorCount ?? 0) > 0) return true\n    }\n  }\n  if (seedSource === 'incident' && incidents) {\n    for (const ev of incidents) {\n      if (incidentMatchesNode(ev, nodeId) && incidentTextIndicatesOutboundFailure(ev)) return true\n    }\n  }\n  return false\n}\n\n// The node's own deploy fault, read off its OBSERVED deploy context (ADR-243,\n// #1400). A workload that dies at startup on a bad config exits before it opens a\n// single connection, so it leaves no failing outbound edge and no outbound-failure\n// text: its callers hold the connection-refused, and by its inbound signal alone it\n// reads as a starved victim. The deploy context is the one place its own failure\n// shows. It counts as the node's own fault when the image never pulled, or when the\n// process exited non-zero on its own (exit 1..127). A process killed by a signal\n// (exit 128+: out of memory, a failed liveness probe, an eviction) may have been\n// killed by the load itself, so it is left to the victim gate, as is a fault with\n// no pod-level cause. The context counts only while the incident it was observed\n// with is on record for the node.\nfunction ownDeployFault(\n  graph: NeatGraph,\n  nodeId: string,\n  incidents: ErrorEvent[] | undefined,\n): DeployContext | null {\n  if (!graph.hasNode(nodeId)) return null\n  const parsed = ObservedDeployContextSchema.safeParse(\n    (graph.getNodeAttributes(nodeId) as { observedDeployContext?: unknown }).observedDeployContext,\n  )\n  if (!parsed.success) return null\n  const { incidentId, observedAt: _observedAt, ...ctx } = parsed.data\n  if (incidents && !incidents.some((ev) => ev.id === incidentId && incidentMatchesNode(ev, nodeId))) {\n    return null\n  }\n  if (ctx.fault === 'image-pull') return ctx\n  if (ctx.exitCode !== undefined) return ctx.exitCode >= 1 && ctx.exitCode <= 127 ? ctx : null\n  return ctx.fault === 'crash-loop' ? ctx : null\n}\n\n// One phrase for a deploy fault inside a reason sentence.\nfunction deployFaultPhrase(ctx: DeployContext): string {\n  const bits: string[] = []\n  if (ctx.waitingReason) bits.push(ctx.waitingReason)\n  if (ctx.restartCount !== undefined) bits.push(`restarts ${ctx.restartCount}`)\n  if (ctx.exitCode !== undefined) bits.push(`last exit ${ctx.exitCode}`)\n  if (ctx.terminatedReason) bits.push(ctx.terminatedReason)\n  const fault = ctx.fault ?? 'deploy fault'\n  return bits.length > 0 ? `${fault} (${bits.join(', ')})` : fault\n}\n\n// The grain of a node, for a Relate path annotation.\nfunction grainOf(graph: NeatGraph, nodeId: string): string {\n  if (!graph.hasNode(nodeId)) return 'unknown'\n  const t = (graph.getNodeAttributes(nodeId) as GraphNode).type\n  if (t === NodeType.ServiceNode) return 'service'\n  if (t === NodeType.FileNode) return 'file'\n  if (t === NodeType.SymbolNode) return 'symbol'\n  return t\n}\n\ninterface FoundPath {\n  nodes: string[]\n  edges: GraphEdge[]\n}\n\n// Shortest directed path from `from` to `to`, depth-bounded, in one direction.\n// 'up' walks inbound (bestEdgeBySource — callers/dependents), 'down' walks\n// outbound (bestEdgeByTarget — callees/dependencies): the same PROV_RANK-best,\n// FRONTIER-terminating primitives the rest of traversal uses, deterministic in\n// neighbour order. Returns null when `to` is unreachable within maxDepth — a\n// depth-bounded absence, honestly.\nfunction findPath(\n  graph: NeatGraph,\n  from: string,\n  to: string,\n  direction: 'up' | 'down',\n  maxDepth: number,\n): FoundPath | null {\n  if (!graph.hasNode(from) || !graph.hasNode(to)) return null\n  if (from === to) return { nodes: [from], edges: [] }\n\n  interface Frame {\n    nodeId: string\n    depth: number\n    nodes: string[]\n    edges: GraphEdge[]\n  }\n  const queue: Frame[] = [{ nodeId: from, depth: 0, nodes: [from], edges: [] }]\n  const enqueued = new Set<string>([from])\n\n  while (queue.length > 0) {\n    const frame = queue.shift()!\n    if (frame.depth >= maxDepth) continue\n    const best =\n      direction === 'up'\n        ? bestEdgeBySource(graph, graph.inboundEdges(frame.nodeId))\n        : bestEdgeByTarget(graph, graph.outboundEdges(frame.nodeId))\n    const neighbours = [...best.entries()].sort((a, b) => a[0].localeCompare(b[0]))\n    for (const [nid, edge] of neighbours) {\n      if (nid === to) return { nodes: [...frame.nodes, nid], edges: [...frame.edges, edge] }\n      if (enqueued.has(nid)) continue\n      enqueued.add(nid)\n      queue.push({\n        nodeId: nid,\n        depth: frame.depth + 1,\n        nodes: [...frame.nodes, nid],\n        edges: [...frame.edges, edge],\n      })\n    }\n  }\n  return null\n}\n\nconst EMPTY_CONTEXT: NodeContext = {\n  errorsEmittedHere: 0,\n  errorsFromCallers: 0,\n  callCount: 0,\n  outboundVolume: 0,\n  stale: false,\n}\n\n// Expand(node, up | down) — one bidirectional neighbourhood step (ADR-189).\n// `up` = inbound (callers/dependents), `down` = outbound (callees/dependencies).\n// Returns the stepped node's own classification + context and its immediate\n// runtime neighbours', so a caller navigates one legible hop at a time.\nexport function expandNode(\n  graph: NeatGraph,\n  nodeId: string,\n  direction: 'up' | 'down',\n  incidents?: ErrorEvent[],\n  now = Date.now(),\n): ExpandResult {\n  if (!graph.hasNode(nodeId)) {\n    return ExpandResultSchema.parse({\n      origin: nodeId,\n      direction,\n      node: { id: nodeId, classification: 'unrelated', context: EMPTY_CONTEXT },\n      neighbours: [],\n    })\n  }\n  const ctx = nodeContext(graph, nodeId, incidents, now)\n  const best =\n    direction === 'up'\n      ? bestEdgeBySource(graph, graph.inboundEdges(nodeId))\n      : bestEdgeByTarget(graph, graph.outboundEdges(nodeId))\n  const neighbours: ExpandNeighbour[] = []\n  for (const [nid, edge] of best) {\n    // CONTAINS is structural ownership, not a runtime caller/callee.\n    if (edge.type === EdgeType.CONTAINS) continue\n    const nctx = nodeContext(graph, nid, incidents, now)\n    neighbours.push({\n      node: nid,\n      edgeType: edge.type,\n      provenance: edge.provenance,\n      classification: classifyNode(nctx),\n      context: nctx,\n    })\n  }\n  neighbours.sort((a, b) => a.node.localeCompare(b.node))\n  return ExpandResultSchema.parse({\n    origin: nodeId,\n    direction,\n    node: { id: nodeId, classification: classifyNode(ctx), context: ctx },\n    neighbours,\n  })\n}\n\n// Relate(a, b) — pairwise directed link-confirmation (ADR-189). Searches both\n// ways but labels the direction it found, preferring a→b (cause→symptom). Each\n// path carries per-hop provenance + grain and a carriesSignal summary — whether\n// the failure runs end to end. No path within maxDepth → related: false with the\n// honest \"no path within N hops\" note, never \"unrelated.\"\nexport function relate(\n  graph: NeatGraph,\n  a: string,\n  b: string,\n  maxDepth = ROOT_CAUSE_MAX_DEPTH,\n): RelateResult {\n  const buildPath = (fp: FoundPath): RelatePath => ({\n    nodes: fp.nodes,\n    edgeTypes: fp.edges.map((e) => e.type),\n    provenance: fp.edges.map((e) => e.provenance),\n    grain: fp.nodes.map((n) => grainOf(graph, n)),\n    // The failure runs end to end when every hop carries error / latency / alert\n    // signal — that is what turns reachability into cause-confirmation.\n    carriesSignal:\n      fp.edges.length > 0 &&\n      fp.edges.every(\n        (e) =>\n          (e.signal?.errorCount ?? 0) > 0 ||\n          e.signal?.latencyMs !== undefined ||\n          e.signal?.anomalous !== undefined,\n      ),\n  })\n\n  if (!graph.hasNode(a) || !graph.hasNode(b)) {\n    return RelateResultSchema.parse({\n      a,\n      b,\n      related: false,\n      direction: null,\n      paths: [],\n      note: !graph.hasNode(a) ? `node not found: ${a}` : `node not found: ${b}`,\n    })\n  }\n\n  // a→b means a is upstream (its outbound chain reaches b); b→a means b is\n  // upstream (a's inbound chain reaches b).\n  const down = findPath(graph, a, b, 'down', maxDepth)\n  const up = findPath(graph, a, b, 'up', maxDepth)\n\n  if (!down && !up) {\n    return RelateResultSchema.parse({\n      a,\n      b,\n      related: false,\n      direction: null,\n      paths: [],\n      note: `no path within ${maxDepth} hops`,\n    })\n  }\n\n  const paths: RelatePath[] = []\n  const direction: 'a->b' | 'b->a' = down ? 'a->b' : 'b->a'\n  if (down) paths.push(buildPath(down))\n  if (up) paths.push(buildPath(up))\n\n  // Grain gap: a and b are both finer than service, but the connecting path only\n  // links through a service-grain hop — the fine link was never observed, so the\n  // coarser path is returned and the gap flagged (file-awareness.md §6).\n  const endpointsFine = grainOf(graph, a) !== 'service' && grainOf(graph, b) !== 'service'\n  const grainGap = endpointsFine && paths[0]!.grain.some((g) => g === 'service')\n\n  return RelateResultSchema.parse({\n    a,\n    b,\n    related: true,\n    direction,\n    paths,\n    ...(grainGap ? { grainGap: true } : {}),\n  })\n}\n\n// The load origin feeding a saturated/stale subgraph: among the nodes upstream of\n// the alert (its inbound-reachable dependents, the get_blast_radius set), the pure\n// source — nothing observed drives it — that itself drives the most outbound\n// volume. This is the topology move ADR-189 names (\"walk up to the highest-volume\n// feeder\"), selected by graph shape, never by a provider or service name.\nfunction findLoadOrigin(\n  graph: NeatGraph,\n  alertNodeId: string,\n  incidents: ErrorEvent[] | undefined,\n  now: number,\n): { node: string; ctx: NodeContext } | null {\n  const upstream = getBlastRadius(graph, alertNodeId).affectedNodes.map((n) => n.nodeId)\n  let best: { node: string; ctx: NodeContext; isSource: boolean } | null = null\n  for (const nid of upstream) {\n    if (nid === alertNodeId) continue\n    const ctx = nodeContext(graph, nid, incidents, now)\n    if (ctx.outboundVolume === 0) continue // drives nothing — not a feeder\n    const isSource = ctx.callCount === 0 // nothing observed calls it — a pure driver\n    const better =\n      !best ||\n      (isSource !== best.isSource\n        ? isSource\n        : ctx.outboundVolume !== best.ctx.outboundVolume\n          ? ctx.outboundVolume > best.ctx.outboundVolume\n          : nid < best.node)\n    if (better) best = { node: nid, ctx, isSource }\n  }\n  return best ? { node: best.node, ctx: best.ctx } : null\n}\n\n// An OBSERVED-grade ceiling on the promoted load origin's confidence. The cause is\n// inferred from several converging runtime signals rather than one captured\n// incident, so it earns a high but never-certain score — honest for a multi-signal\n// OBSERVED inference, which never claims 1.0.\nconst LOAD_ORIGIN_CONFIDENCE_CEILING = 0.9\n\n// Confidence for the promoted load origin (ADR-189), graded by the strength of the\n// separated evidence the navigation already computed — the ADR-189 classification\n// inputs and the ADR-190 latency signal — rather than a flat floor. Each\n// corroborating signal lifts it toward the OBSERVED ceiling: a clean cause/symptom\n// split (errors arrive from the victim's callers, none originate there), the victim\n// gone STALE under load, its inbound latency saturated, and the volume of load the\n// origin drives. Bounded [0, LOAD_ORIGIN_CONFIDENCE_CEILING].\nfunction loadOriginConfidence(originCtx: NodeContext, seedCtx: NodeContext): number {\n  // The core signal: how cleanly the victim reads as a symptom. Errors arrive from\n  // its callers, and none (a clean split) — or fewer (a partial one) — originate\n  // locally.\n  const cleanSplit = seedCtx.errorsFromCallers > 0 && seedCtx.errorsEmittedHere === 0\n  const partialSplit = seedCtx.errorsFromCallers > seedCtx.errorsEmittedHere\n\n  let evidence = 0\n  evidence += cleanSplit ? 0.45 : partialSplit ? 0.2 : 0\n  evidence += seedCtx.stale ? 0.2 : 0\n  evidence += isSaturated(seedCtx) ? 0.15 : 0\n  // A high-volume driver is a stronger load origin than a trickle. volumeWeight maps\n  // a call/span count into [0.5, 1]; rescale its headroom into [0, 0.2].\n  evidence += (volumeWeight(originCtx.outboundVolume) - 0.5) * 0.4\n\n  // An anchor keeps a single signal from ever reading as certainty; the evidence\n  // then climbs toward the ceiling. isVictimSeed already guarantees real victim\n  // signal (errors from callers, plus STALE or saturation) before we reach here.\n  const anchor = 0.45\n  const confidence = anchor + Math.min(1, evidence) * (LOAD_ORIGIN_CONFIDENCE_CEILING - anchor)\n  return Math.max(0, Math.min(LOAD_ORIGIN_CONFIDENCE_CEILING, confidence))\n}\n\n// Human display name for a node id inside a reason sentence — strips the `type:`\n// prefix the same way the cross-service reason does.\nfunction displayNameOf(nodeId: string): string {\n  return nodeId.replace(/^[a-z]+:/, '')\n}\n\n// getRootCause (ADR-189): navigation over the fused graph. Seeds from the single\n// verdict (legacyRootCause), classifies that seed, and — when the seed is a\n// saturated/stale victim — walks up to the load origin instead of naming the\n// victim. Returns a ranked candidate set with per-node classification + evidence\n// alongside the legacy verdict fields, which stay populated (candidates[0] is the\n// top cause and rootCauseNode tracks it) for one deprecation cycle.\n// NEAT_RCA_NAVIGATION=0 (or opts.navigation === false) returns the pre-navigation\n// single verdict verbatim.\nexport function getRootCause(\n  graph: NeatGraph,\n  errorNodeId: string,\n  errorEvent?: ErrorEvent,\n  incidents?: ErrorEvent[],\n  opts?: { navigation?: boolean; now?: number },\n): RootCauseResult | null {\n  const tagged = legacyRootCause(graph, errorNodeId, errorEvent, incidents)\n  if (!tagged) return null\n  const navigation = opts?.navigation ?? process.env.NEAT_RCA_NAVIGATION !== '0'\n  if (!navigation) return tagged.result\n  return enrichWithNavigation(graph, errorNodeId, tagged, incidents, opts?.now ?? Date.now())\n}\n\n// #1114 — the failing request's route, from the boundary's own incident. Used to\n// narrow the structural walk to the declared edge that serves THAT route, not the\n// boundary's whole fan-out.\nfunction boundaryIncidentRoute(\n  nodeId: string,\n  incidents: ErrorEvent[] | undefined,\n): string | undefined {\n  for (const ev of incidents ?? []) {\n    if (!incidentMatchesNode(ev, nodeId)) continue\n    const r =\n      ev.attributes?.['http.route'] ?? ev.attributes?.['http.target'] ?? ev.attributes?.['url.path']\n    if (typeof r === 'string' && r.length > 0) return r\n  }\n  return undefined\n}\n\n// A node's DECLARED (EXTRACTED) outbound dependency callees, each with the route\n// its declared edge serves when the extractor captured one. Declared, because a\n// hang leaves no observed edge — the declared call graph is the only path left.\nfunction declaredOutboundCallees(\n  graph: NeatGraph,\n  nodeId: string,\n): Array<{ target: string; route?: string }> {\n  const byTarget = new Map<string, { target: string; route?: string }>()\n  for (const n of nodeScope(graph, nodeId)) {\n    if (!graph.hasNode(n)) continue\n    for (const edgeId of graph.outboundEdges(n)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (!DEP_EDGE_TYPES.has(e.type)) continue\n      if (e.provenance !== Provenance.EXTRACTED) continue\n      if (e.target === nodeId || byTarget.has(e.target)) continue\n      const route = e.evidence?.pathTemplate\n      byTarget.set(\n        e.target,\n        route !== undefined ? { target: e.target, route } : { target: e.target },\n      )\n    }\n  }\n  return [...byTarget.values()]\n}\n\nfunction normalizeRoute(s: string): string {\n  return s.replace(/\\/+$/, '').toLowerCase()\n}\nfunction routeMatches(declared: string, incident: string): boolean {\n  const a = normalizeRoute(declared)\n  const b = normalizeRoute(incident)\n  return a === b || a.startsWith(b) || b.startsWith(a)\n}\n\n// The single declared (EXTRACTED) callee a node serves for a route, or null when\n// the route doesn't narrow to one (or the node declares nothing). The first\n// unobservable hop on the declared serving path.\nfunction firstDeclaredCallee(\n  graph: NeatGraph,\n  node: string,\n  route: string | undefined,\n): string | null {\n  const callees = declaredOutboundCallees(graph, node)\n  if (callees.length === 0) return null\n  const narrowed =\n    route !== undefined\n      ? callees.filter((c) => c.route !== undefined && routeMatches(c.route, route))\n      : callees\n  const chosen = narrowed.length === 1 ? narrowed[0]! : callees.length === 1 ? callees[0]! : null\n  return chosen ? chosen.target : null\n}\n\n// The OBSERVED outbound next-services of a node (the runtime dependency families,\n// not CONTAINS). Used to cross ONE observed hop when an infra boundary declares\n// nothing for the failing route — the observed layer reached the next service even\n// though the hung culprit beyond it exported no span.\nfunction observedOutboundNextServices(graph: NeatGraph, nodeId: string): string[] {\n  const targets = new Set<string>()\n  for (const n of nodeScope(graph, nodeId)) {\n    if (!graph.hasNode(n)) continue\n    for (const edgeId of graph.outboundEdges(n)) {\n      const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n      if (!DEP_EDGE_TYPES.has(e.type)) continue\n      if (e.provenance !== Provenance.OBSERVED) continue\n      if (e.target !== nodeId) targets.add(e.target)\n    }\n  }\n  return [...targets]\n}\n\n// #1114b / ADR-226 — the unobservable hop the hang sensor stages a FRONTIER surface\n// on: the edge NEAT reached toward but cannot see because its far end hung. Route-\n// driven — resolve the failing route (from the boundary's incident) against the\n// boundary's OWN declared callees; when the boundary declares nothing for that\n// route (an infra proxy like frontend-proxy), cross ONE observed hop into the next\n// service and resolve there. The crossing is taken only when exactly one observed\n// next-service yields a resolving declared callee — never a fan-out, never an\n// observed healthy branch mistaken for the hang path. Returns the hop\n// `{ source, target }` to stage, or null (honest-coarse — propose nothing).\nexport function resolveHangHop(\n  graph: NeatGraph,\n  boundaryNode: string,\n  incidents: ErrorEvent[] | undefined,\n): { source: string; target: string; route?: string } | null {\n  const route = boundaryIncidentRoute(boundaryNode, incidents)\n  // 1) the boundary's own declared first callee.\n  const own = firstDeclaredCallee(graph, boundaryNode, route)\n  if (own) {\n    return route !== undefined\n      ? { source: boundaryNode, target: own, route }\n      : { source: boundaryNode, target: own }\n  }\n  // 2) cross one observed hop; resolve the route at the single observed next-service.\n  const resolved = observedOutboundNextServices(graph, boundaryNode)\n    .map((n) => ({ source: n, target: firstDeclaredCallee(graph, n, route) }))\n    .filter((r): r is { source: string; target: string } => r.target !== null)\n  if (resolved.length === 1) {\n    const hop = resolved[0]!\n    return route !== undefined ? { ...hop, route } : hop\n  }\n  return null\n}\n\n// ADR-226 — read the staged FRONTIER surface for a boundary-timeout hang: the hop\n// the sensor staged (hang-sensor.ts), located by the same resolver and confirmed to\n// exist as a FRONTIER edge in the graph. Returns the proposed culprit (the surface's\n// target) + route, or null when no surface is staged — honest-coarse (the sensor\n// hasn't seen this hang yet, or nothing resolved). The reader reads the surface; it\n// does not re-invent a cause the graph does not carry.\nfunction stagedHangProposal(\n  graph: NeatGraph,\n  boundaryNode: string,\n  incidents: ErrorEvent[] | undefined,\n): { node: string; route?: string } | null {\n  const hop = resolveHangHop(graph, boundaryNode, incidents)\n  if (!hop) return null\n  if (!graph.hasEdge(frontierEdgeId(hop.source, hop.target, EdgeType.CALLS))) return null\n  return hop.route !== undefined ? { node: hop.target, route: hop.route } : { node: hop.target }\n}\n\nfunction enrichWithNavigation(\n  graph: NeatGraph,\n  errorNodeId: string,\n  tagged: TaggedRootCause,\n  incidents: ErrorEvent[] | undefined,\n  now: number,\n): RootCauseResult {\n  const legacy = tagged.result\n  const seedNode = legacy.rootCauseNode\n  const seedCtx = graph.hasNode(seedNode) ? nodeContext(graph, seedNode, incidents, now) : null\n  const lastProv = legacy.edgeProvenances[legacy.edgeProvenances.length - 1]\n  const candidates: RootCauseCandidate[] = []\n\n  // The dead-end the STALE-chain fallback exists to fix (ADR-209): the single\n  // verdict localized the failure to the queried node itself (`source === 'incident'`,\n  // no causal edge walked), yet a STALE-only outbound CALLS chain runs downstream —\n  // the topology is still in the graph, only its live signal went quiet. Walking\n  // nothing and naming the queried node hands the agent the symptom. `isVictimSeed`\n  // (errors arriving) takes precedence; a compat / cross-service seed is never\n  // second-guessed; a genuinely isolated node (no stale chain) stays primary-failure.\n  const deadEndOnSymptom =\n    tagged.source === 'incident' &&\n    seedNode === errorNodeId &&\n    legacy.traversalPath.length === 1\n  const staleChain =\n    deadEndOnSymptom && !(seedCtx && isVictimSeed(seedCtx))\n      ? followStaleCallChain(graph, errorNodeId, ROOT_CAUSE_MAX_DEPTH)\n      : null\n\n  // The seed reads as a saturated/stale victim by its inbound signal alone, but\n  // that gate never looks downstream (#1075). Before demoting it to a symptom and\n  // promoting the load origin, check whether the seed genuinely fails because of\n  // its OWN outbound dependency — a failing CONNECTS_TO datastore, a failing\n  // downstream call, or an incident whose text is an outbound connection failure.\n  // When it does, the load-origin verdict would bury the real cause behind the\n  // traffic source, so keep the seed. We check the seed, not the queried node: in\n  // a genuine cross-service overload the queried entry relays load down a failing\n  // CALLS chain to the starved victim, so its own outbound is failing by design —\n  // it is the seed (the victim itself) that must have no downstream fault for the\n  // load-origin move to be right. A deploy fault of the seed's own (#1400) counts\n  // the same: a workload that crashed at startup never reached its dependencies,\n  // so its deploy context is the only place its own failure shows.\n  const seedDeployFault = seedCtx !== null ? ownDeployFault(graph, seedNode, incidents) : null\n  const seedFailsOutbound =\n    seedCtx !== null &&\n    (seedDeployFault !== null || hasFailingOutbound(graph, seedNode, tagged.source, incidents))\n\n  if (seedCtx && isVictimSeed(seedCtx) && !seedFailsOutbound) {\n    // The seed is a starved/saturated downstream victim — do not name it. Walk up\n    // to the load origin and lead with that.\n    const origin = findLoadOrigin(graph, errorNodeId, incidents, now)\n    const staleNote = seedCtx.stale ? '; it has gone STALE under load' : ''\n    const satNote = isSaturated(seedCtx)\n      ? `; its inbound p95 ${Math.round(seedCtx.latencyP95Ms!)}ms is saturated`\n      : ''\n    if (origin) {\n      // Lead the headline reason with the causal relation, not the raw call count:\n      // the named origin is the fault *because* it overloads the subgraph, and the\n      // alerting node is its downstream symptom (errors arrive from callers, none\n      // originate there). The volume is corroborating evidence, so it comes last.\n      const originName = displayNameOf(origin.node)\n      const seedName = displayNameOf(seedNode)\n      candidates.push({\n        node: origin.node,\n        classification: 'primary-failure',\n        reason: `${originName} is the root cause: it overloads the failing subgraph, and the alerting node ${seedName} is a downstream symptom, not the fault — errors reach ${seedName} from its callers (${seedCtx.errorsFromCallers}), none originate there${staleNote}${satNote}. ${originName} is the upstream source driving that load (${origin.ctx.outboundVolume} observed outbound calls).`,\n        context: origin.ctx,\n        confidence: loadOriginConfidence(origin.ctx, seedCtx),\n        provenance: Provenance.OBSERVED,\n      })\n    }\n    candidates.push({\n      node: seedNode,\n      classification: 'symptom-only',\n      reason: `Errors arrive from callers (${seedCtx.errorsFromCallers}) but none originate here${staleNote}${satNote} — a downstream victim of load, not the fault.`,\n      context: seedCtx,\n      confidence: Math.min(legacy.confidence, 0.4),\n      ...(lastProv ? { provenance: lastProv } : {}),\n    })\n  } else if (seedCtx && isUnreachableSeed(seedCtx)) {\n    // #1123 — the seed is a target that received calls which predominantly failed\n    // but produced no telemetry of its own: no incidents, no outbound calls. It\n    // never served — it is unreachable. Name it as such, and say the cause is NOT\n    // in the trace (a startup failure, a crash before the first span, or an\n    // unschedulable / unhealthy pod), so an agent inspects deploy state / logs\n    // instead of hunting a nonexistent code fault here. The unreachability is\n    // OBSERVED; only the WHY is unknown — kept honest-coarse, never fabricated.\n    const name = displayNameOf(seedNode)\n    candidates.push({\n      node: seedNode,\n      classification: 'unreachable',\n      reason: `${name} is unreachable: its callers' requests fail (${seedCtx.errorsFromCallers} erroring inbound calls) and it produced no telemetry of its own — no server spans, no outbound calls — so it never served. The failure is observed, but its cause is not in the trace: a startup failure, a crash before the first span, or an unschedulable / unhealthy pod. Inspect ${name}'s deploy state and logs — there is no code fault to find in the graph here.`,\n      context: seedCtx,\n      confidence: legacy.confidence,\n      provenance: Provenance.OBSERVED,\n    })\n  } else if (seedCtx && isBoundaryTimeoutSymptom(seedCtx)) {\n    // #1114 / ADR-226 — the seed is a boundary that timed out on an unobservable\n    // downstream. Its timeout is the only span that exported; the real culprit hung\n    // and emitted nothing, so there is no observed edge to walk and no settled cause\n    // to name. The settled verdict LEADS: the boundary is candidates[0] and the\n    // rootCauseNode, a symptom. BELOW it, when the hang sensor has staged a FRONTIER\n    // surface on the unobservable hop, read it back and surface the proposed culprit\n    // at FRONTIER provenance — a claim outside the settled graph, ranked below every\n    // settled cause, a hypothesis to graduate (it turns OBSERVED when the service\n    // recovers) or cull. Never laundered as a settled INFERRED cause. No surface\n    // staged → honest-coarse: name no cause, say it is downstream and unobserved.\n    const seedName = displayNameOf(seedNode)\n    const proposal = stagedHangProposal(graph, seedNode, incidents)\n    const routeNote = proposal?.route ? ` serving ${proposal.route}` : ''\n    // Settled verdict first: the boundary is the symptom, and the rootCauseNode.\n    candidates.push({\n      node: seedNode,\n      classification: 'symptom-only',\n      reason: proposal\n        ? `${seedName} timed out waiting on a downstream that hung and exported no span — a boundary reporting an upstream fault, not the fault itself. The cause is unobservable; NEAT proposes the staged FRONTIER surface below, a hypothesis to confirm, not an observed cause.`\n        : `${seedName} timed out but nothing it can see downstream is erroring — the cause is downstream and unobserved (the culprit hung and exported no span). No FRONTIER surface${routeNote} is staged, so no cause is proposed; inspect ${seedName}'s declared downstream and restore instrumentation.`,\n      context: seedCtx,\n      confidence: Math.min(legacy.confidence, 0.3),\n      ...(lastProv ? { provenance: lastProv } : {}),\n    })\n    // The staged surface, read back as a FRONTIER proposal, ranked below the symptom.\n    if (proposal) {\n      const causeName = displayNameOf(proposal.node)\n      candidates.push({\n        node: proposal.node,\n        classification: 'primary-failure',\n        reason: `${causeName} is the proposed hang cause (FRONTIER — a hypothesis, not observed): the boundary ${seedName} only timed out waiting and the culprit hung without exporting a span, so NEAT staged a FRONTIER surface on the unobservable hop${routeNote}. It graduates to OBSERVED when ${causeName} comes back; until then, inspect it / restore instrumentation to confirm, or it is culled.`,\n        context: nodeContext(graph, proposal.node, incidents, now),\n        confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.FRONTIER!),\n        provenance: Provenance.FRONTIER,\n      })\n    }\n  } else if (staleChain) {\n    // Stale-only causal chain (ADR-209). Fresh signal has gone quiet, but the\n    // last-observed topology still traces from the symptom down to a deepest\n    // stale-only callee. Lead with that callee as a low-confidence, STALE-\n    // provenanced hypothesis — honest about the uncertainty — instead of naming\n    // the symptom with no edges walked. The seed becomes the surface it is.\n    const culprit = staleChain.culprit\n    const culpritName = displayNameOf(culprit)\n    const seedName = displayNameOf(seedNode)\n    // Confidence rides the STALE ceiling (≤ 0.3) through confidenceFromMix — the\n    // provenance itself caps how far it can climb, so the number reads as the low\n    // trust it is without a hand-set floor.\n    const staleConfidence = confidenceFromMix(staleChain.edges, now)\n    candidates.push({\n      node: culprit,\n      classification: 'primary-failure',\n      reason: `${culpritName} is the stale-derived root cause (low confidence): live telemetry for this subgraph has gone quiet, but the last-observed topology traces the failure surfacing at ${seedName} downstream through a STALE call chain to ${culpritName}. Provenance is STALE, so confidence is capped low — restore instrumentation and re-run to confirm before acting.`,\n      context: nodeContext(graph, culprit, incidents, now),\n      confidence: staleConfidence,\n      provenance: Provenance.STALE,\n    })\n    candidates.push({\n      node: seedNode,\n      classification: 'symptom-only',\n      reason: `The failure surfaced here, but the only causal chain the graph still holds is STALE and runs downstream — ${seedName} is the surface of a stale-traced failure, not a proven origin.`,\n      context: seedCtx ?? EMPTY_CONTEXT,\n      confidence: Math.min(legacy.confidence, PROVENANCE_CEILING.STALE!),\n      ...(lastProv ? { provenance: lastProv } : {}),\n    })\n  } else {\n    // The seed originates the failure (or its node isn't in the graph — an\n    // incident-only localization). Confirm it as the primary cause. When its own\n    // deploy fault is what kept it here, the reason names that fault, and the\n    // claim is OBSERVED: the fault was read off the running workload.\n    const seedName = displayNameOf(seedNode)\n    candidates.push({\n      node: seedNode,\n      classification: 'primary-failure',\n      reason: seedDeployFault\n        ? `${seedName} is the root cause: its own deploy is failing — ${deployFaultPhrase(seedDeployFault)}. The errors its callers see (${seedCtx?.errorsFromCallers ?? 0}) follow from that, not from load. Its deploy context (env, args, process log) holds the why.`\n        : legacy.rootCauseReason,\n      context: seedCtx ?? EMPTY_CONTEXT,\n      confidence: legacy.confidence,\n      ...(seedDeployFault\n        ? { provenance: Provenance.OBSERVED }\n        : lastProv\n          ? { provenance: lastProv }\n          : {}),\n    })\n  }\n\n  const top = candidates[0]!\n  // The legacy verdict tracks the top candidate so old consumers get the fixed\n  // answer too; when the top is the promoted origin, retrace the path up to it so\n  // traversalPath still ends at rootCauseNode (get-root-cause.md invariant).\n  let traversalPath = legacy.traversalPath\n  let edgeProvenances = legacy.edgeProvenances\n  if (staleChain && top.node === staleChain.culprit) {\n    // The stale chain already IS the origin → ... → culprit path, walked outbound;\n    // use it verbatim so traversalPath ends at the named cause and every hop's\n    // STALE provenance is on the path (get-root-cause.md invariant).\n    traversalPath = staleChain.path\n    edgeProvenances = staleChain.edges.map((e) => e.provenance)\n  } else if (top.node !== seedNode) {\n    const path = findPath(graph, errorNodeId, top.node, 'up', ROOT_CAUSE_MAX_DEPTH)\n    if (path) {\n      traversalPath = path.nodes\n      edgeProvenances = path.edges.map((e) => e.provenance)\n    } else {\n      traversalPath = [errorNodeId, top.node]\n      edgeProvenances = [top.provenance ?? Provenance.OBSERVED]\n    }\n  }\n\n  // fixRecommendation has to name the node we hand back as rootCauseNode (top),\n  // not the downstream victim the legacy verdict walked to.\n  const fixRecommendation = fixRecommendationForTop(top, seedNode, legacy)\n\n  return RootCauseResultSchema.parse({\n    rootCauseNode: top.node,\n    rootCauseReason: top.reason,\n    traversalPath,\n    edgeProvenances,\n    confidence: top.confidence,\n    ...(fixRecommendation ? { fixRecommendation } : {}),\n    candidates,\n  })\n}\n\n// The fix recommendation must point at whichever node getRootCause returns as\n// rootCauseNode — the top candidate — never at a symptom-only victim. When the\n// seed is itself the primary failure, the legacy verdict already derived a\n// recommendation aimed at it, so keep it. When navigation promoted an upstream\n// load origin (the seed turned out to be a starved symptom-only victim), the\n// legacy recommendation still targets that victim, so rebuild it to name the\n// overloading source. A symptom-only top — the case where no load origin was\n// found — is sent to its inbound load, never to its own handler.\nfunction fixRecommendationForTop(\n  top: RootCauseCandidate,\n  seedNode: string,\n  legacy: RootCauseResult,\n): string | undefined {\n  if (top.classification === 'primary-failure' && top.node === seedNode) {\n    return legacy.fixRecommendation\n  }\n  const name = top.node.replace(/^service:/, '')\n  // ADR-226 — a boundary that timed out is a symptom-only top whose cause is\n  // unobservable. It is not a load victim, so it never gets the inbound-load\n  // wording; send the agent to the FRONTIER surface proposed in the candidates.\n  if (top.classification === 'symptom-only' && top.context.boundaryTimeout === true) {\n    return `${name} timed out waiting on a downstream that hung and exported no span — the cause is unobservable from traces. Inspect the FRONTIER surface NEAT staged on the unobservable hop (see candidates); it graduates to OBSERVED when that service recovers. Restore instrumentation on that path to confirm, rather than treating ${name} as the fault.`\n  }\n  // A stale-derived promotion (ADR-209) isn't an overload — the signal simply went\n  // quiet — so it gets its own recommendation, never the throttle-the-load wording.\n  if (top.provenance === Provenance.STALE) {\n    return `Live telemetry for this path has gone quiet; the last-observed topology traces the failure downstream to ${name}. Restore instrumentation (or re-run with live traces) to confirm, then inspect ${name}.`\n  }\n  if (top.classification === 'primary-failure') {\n    return `Reduce or throttle the load from ${name} (or scale the saturated downstream capacity it drives) — the failure originates at this overloading source, not the starved callee.`\n  }\n  return `${name} is a saturated/starved downstream victim; investigate its inbound load and upstream callers, not its own handler.`\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport Python from 'tree-sitter-python'\nimport Go from 'tree-sitter-go'\nimport Ruby from 'tree-sitter-ruby'\nimport Php from 'tree-sitter-php'\nimport Rust from 'tree-sitter-rust'\nimport type { GraphEdge, RouteNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  routeId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, snippet, toPosix, type SourceFile } from './calls/shared.js'\nimport { resolveJsImport, loadTsPathConfig, type TsPathConfig } from './imports.js'\n\n// Server-route extraction (ADR-119). Reads a mainstream router's route table —\n// Express (`app.get`/`router.post`/…), Fastify (`fastify.get`, `fastify.route`),\n// Next.js (app-router `route.*` handlers, pages `api/` handlers) — and\n// materialises each route as a RouteNode at (method, path-template) grain, owned\n// by its service through a `service ──CONTAINS──▶ route` edge. This is the\n// server half of the static contract-matching in calls/route-match.ts: a\n// client call site is matched to the route it names, bridging the two static\n// islands into a route-grained cross-service CALLS edge.\n//\n// Scope is mainstream routers only, gated by manifest dependency (the extensible\n// registry pattern — coverage grows one router at a time, not by exhaustive\n// heuristics). A service with none of these deps is skipped.\n\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction makeJsParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(JavaScript)\n  return p\n}\n\nfunction makePyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Python)\n  return p\n}\n\nfunction makeGoParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Go)\n  return p\n}\n\nfunction makeRubyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Ruby)\n  return p\n}\n\n// Laravel's route files are pure PHP (a controller + route definitions, no HTML\n// islands), so the grammar's `php_only` variant is the right parser — `.php`\n// would accept `?>`-delimited HTML the route files never carry (ADR-177).\nfunction makePhpParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Php.php_only)\n  return p\n}\n\nfunction makeRustParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Rust)\n  return p\n}\n\n// The HTTP verbs an Express / Fastify router registers a route under. `all`\n// registers a method-agnostic route; it normalises to the `ALL` method token.\nconst ROUTER_METHODS = new Set([\n  'get',\n  'post',\n  'put',\n  'patch',\n  'delete',\n  'options',\n  'head',\n  'all',\n])\n\n// The exported handler names a Next.js app-router `route.*` file uses, one per\n// HTTP method it serves.\nconst NEXT_APP_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])\n\n// The HTTP methods a Go 1.22 `net/http` ServeMux pattern may lead with\n// (`\"GET /orders/{id}\"`). This precise set is half the structural gate: the\n// leading token must be one of these AND the remainder must start with `/`,\n// which is what keeps a generic `HandleFunc(\"literal\", h)` — or a pre-1.22\n// bare-prefix registration — from minting a route (ADR-182).\nconst NET_HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'])\n\nconst JS_ROUTE_EXTENSIONS = new Set(['.js', '.jsx', '.mjs', '.cjs', '.ts', '.tsx'])\n\nexport interface ExtractedRoute {\n  method: string // upper-cased HTTP method, or 'ALL' for a method-agnostic route\n  pathTemplate: string // canonicalised declared template, e.g. '/users/:id'\n  line: number // 1-indexed line the route is declared on\n  framework: string // Router registry label; NestJS joins the existing JS/Python set in ADR-155.\n  // The route's `controller#action` handler, when the recogniser knows it —\n  // Rails' resourceful expansion derives it (ADR-173). RouteNode carries no\n  // handler field today, so `addRoutes` keeps this off the graph; it exists so\n  // the recogniser tests can assert the module/pluralisation logic the path\n  // template alone can't show (a `scope module:` route differs only here).\n  controller?: string\n}\n\n// Gin, Echo, and Fiber all declare their route table the same way — a router\n// value carries an HTTP-verb method (`r.GET(...)`, `e.GET(...)`, `app.Get(...)`)\n// whose first argument is the path, and `<router>.Group(\"/prefix\")` returns a\n// sub-router that composes a prefix onto everything registered on it. At the Go\n// AST that is one grammar: a `call_expression` on a `selector_expression`, the\n// verb differing only in casing (Gin/Echo upper-case `GET`, Fiber title-case\n// `Get`) which the lower-cased method check already absorbs. So one walker reads\n// all three; they differ only in the framework label and the manifest dependency\n// that gates them (`addRoutes`). A group variable is tracked the way the receiver\n// var is: `admin := r.Group(\"/admin\")` records `admin → /admin`, and a group\n// opened off another group (`v1 := admin.Group(\"/v1\")`) composes onto its\n// parent's prefix, so nested groups reach `/admin/v1`. Both `:=` and `var x = …`\n// forms are read. Route-param constraints and middleware-only / `Static` mounts\n// are deferred.\nfunction goRouterRoutesFromSource(\n  source: string,\n  parser: Parser,\n  framework: string,\n): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const prefixes = new Map<string, string>()\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type === 'short_var_declaration' || node.type === 'var_spec') {\n      const name =\n        node.childForFieldName('left')?.namedChild(0)?.text ?? node.childForFieldName('name')?.text\n      const value =\n        node.childForFieldName('right')?.namedChild(0) ?? node.childForFieldName('value')\n      if (name && value?.type === 'call_expression') {\n        const fn = value.childForFieldName('function')\n        if (fn?.childForFieldName('field')?.text === 'Group') {\n          const leaf = goStringLiteral(value.childForFieldName('arguments')?.namedChild(0))\n          if (leaf !== null) {\n            const parent = fn.childForFieldName('operand')?.text ?? ''\n            prefixes.set(name, (prefixes.get(parent) ?? '') + leaf)\n          }\n        }\n      }\n      return\n    }\n    if (node.type !== 'call_expression') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'selector_expression') return\n    const method = fn.childForFieldName('field')?.text?.toUpperCase()\n    if (!method || !ROUTER_METHODS.has(method.toLowerCase())) return\n    const receiver = fn.childForFieldName('operand')?.text ?? ''\n    const leaf = goStringLiteral(node.childForFieldName('arguments')?.namedChild(0))\n    if (leaf === null) return\n    out.push({\n      method,\n      pathTemplate: canonicalizeTemplate((prefixes.get(receiver) ?? '') + leaf),\n      line: node.startPosition.row + 1,\n      framework,\n    })\n  })\n  return out\n}\n\n// Read a Go string literal's inner text. Both the double-quoted\n// (`interpreted_string_literal`) and back-quoted (`raw_string_literal`) forms\n// carry their delimiters in `.text`, so slicing one char off each end yields the\n// path; a non-literal argument (a computed path) returns null and is skipped.\nfunction goStringLiteral(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (node?.type === 'interpreted_string_literal' || node?.type === 'raw_string_literal') {\n    return node.text.slice(1, -1)\n  }\n  return null\n}\n\n// Gin (`github.com/gin-gonic/gin`).\nexport function ginRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  return goRouterRoutesFromSource(source, parser, 'gin')\n}\n\n// Echo (`github.com/labstack/echo/v4`, also plain `.../echo`). `otelecho` sets\n// `http.route` from `c.Path()` — the group-composed template — so the extracted\n// node fuses through `normalizePathTemplate` with no ingest change.\nexport function echoRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  return goRouterRoutesFromSource(source, parser, 'echo')\n}\n\n// Fiber (`github.com/gofiber/fiber/v2`, also `/v3`). Both the v2 `otelfiber` and\n// the v3 middleware set `http.route` from `c.Route().Path` — the group-composed\n// template — so the node fuses with no ingest change. Fiber's optional-param\n// `:id?` reduces to `:param` like `:id`; a bare `*` / `+` wildcard stays literal\n// on both the extracted template and `c.Route().Path`, so it still matches.\nexport function fiberRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  return goRouterRoutesFromSource(source, parser, 'fiber')\n}\n\n// ── Chi (`github.com/go-chi/chi/v5`, also pre-modules `.../chi`) ─────────────\n//\n// Chi declares verbs the Fiber way — title-cased `r.Get/Post/Put/Patch/Delete`\n// on a router value, first argument the path — so the verb read is the same one\n// the Gin/Echo/Fiber walker does. What Chi does differently is prefix\n// composition. Gin/Echo/Fiber name a sub-router (`admin := r.Group(\"/admin\")`)\n// and the prefix follows that variable; Chi's `Route(\"/articles\", func(r\n// chi.Router){ … })` has no assignment — the prefix is lexically scoped to the\n// closure body and the inner `r` shadows the outer. So a variable Map can't\n// track it; a prefix STACK can. This walker recurses the tree carrying the\n// accumulated prefix: a `Route(strLit, funcLit)` pushes the literal and recurses\n// into the `func_literal` body, nested `Route`s compose (`/articles` +\n// `/{articleID}`), and the prefix pops on return (the recursion frame). A\n// `Group(funcLit)` — first argument a closure, not a string — is middleware\n// grouping: it contributes no prefix, just recurses. A `Mount(\"/admin\", h)` is\n// deferred: the mounted sub-router is usually built in another func or file, the\n// same cross-func/cross-file resolution Express `app.use` needed before ADR-160,\n// so it's skipped here (costing one fused edge, since otelchi emits the full\n// composed path).\n//\n// Inline regex constraints (`{id:[0-9]+}`) are stripped to `{id}` so the stored\n// template stays clean and `canonicalizeTemplate` can't read a `?` inside the\n// regex as a query delimiter; either way `normalizePathTemplate` collapses a\n// `{…}` segment to `:param`, so fusion is unaffected.\n//\n// FUSION CAVEAT (ADR-182): Chi fuses only under `otelchi`\n// (`github.com/riandyrn/otelchi`), which reads `chi.RouteContext(r).RoutePattern()`\n// — the composed template — and sets `http.route` to it (path-only), the same\n// shape echo's `c.Path()` / fiber's `c.Route().Path` produce. Under bare\n// `otelhttp` a Chi app sets NO `http.route` (Chi never populates `r.Pattern`),\n// so these RouteNodes stay EXTRACTED-only with nothing to fuse onto.\nexport function chiRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  chiWalk(tree.rootNode, '', out)\n  return out\n}\n\n// Strip a Chi inline-regex constraint from each param segment: `{id:[0-9]+}` →\n// `{id}`. Handles the common single-level case (a regex with no nested braces);\n// a regex carrying its own `{n,m}` quantifier is left as-is, and still collapses\n// to `:param` at match time.\nfunction stripChiRegex(path: string): string {\n  return path.replace(/\\{([^{}:]+):[^{}]*\\}/g, '{$1}')\n}\n\n// Recurse the tree carrying the accumulated route prefix. A `Route`/`Group` call\n// is handled specially (its closure body is recursed with the pushed/unchanged\n// prefix and the generic descent stops there); a verb call emits; everything\n// else descends with the same prefix.\nfunction chiWalk(node: Parser.SyntaxNode, prefix: string, out: ExtractedRoute[]): void {\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) chiHandle(child, prefix, out)\n  }\n}\n\nfunction chiHandle(node: Parser.SyntaxNode, prefix: string, out: ExtractedRoute[]): void {\n  if (node.type === 'call_expression') {\n    const fn = node.childForFieldName('function')\n    if (fn?.type === 'selector_expression') {\n      const field = fn.childForFieldName('field')?.text\n      const args = node.childForFieldName('arguments')\n      if (field === 'Route') {\n        const leaf = goStringLiteral(args?.namedChild(0))\n        const closure = args?.namedChild(1)\n        if (leaf !== null && closure?.type === 'func_literal') {\n          const body = closure.childForFieldName('body')\n          if (body) chiWalk(body, prefix + leaf, out)\n        }\n        return // handled — the string arg and closure carry no other routes\n      }\n      if (field === 'Group') {\n        // Chi's `Group(func(r chi.Router){ … })` is middleware grouping: the\n        // first argument is a closure, not a path, so it adds no prefix.\n        const closure = args?.namedChild(0)\n        if (closure?.type === 'func_literal') {\n          const body = closure.childForFieldName('body')\n          if (body) chiWalk(body, prefix, out)\n        }\n        return\n      }\n      if (field === 'Mount') {\n        return // deferred (ADR-182) — the mounted router is resolved elsewhere\n      }\n      if (field && ROUTER_METHODS.has(field.toLowerCase())) {\n        const leaf = goStringLiteral(args?.namedChild(0))\n        if (leaf !== null) {\n          out.push({\n            method: field.toUpperCase(),\n            pathTemplate: canonicalizeTemplate(stripChiRegex(prefix + leaf)),\n            line: node.startPosition.row + 1,\n            framework: 'chi',\n          })\n        }\n        return\n      }\n    }\n  }\n  // Not a Chi routing call — descend into its children at the same prefix.\n  chiWalk(node, prefix, out)\n}\n\n// ── net/http (Go 1.22+ ServeMux method patterns) ────────────────────────────\n//\n// Go 1.22's `ServeMux` carries the method and the path template in ONE string\n// literal: `mux.HandleFunc(\"GET /orders/{id}\", h)`, `http.HandleFunc(…)`,\n// `mux.Handle(…)`, `http.Handle(…)`. Read the first string-literal argument and\n// split on the first space; emit a RouteNode ONLY when the leading token is an\n// HTTP method AND the remainder starts with `/`. That precision is the whole\n// gate: net/http is stdlib, so there's no go.mod dependency to key on the way\n// Gin/Echo/Fiber/Chi are. Instead this recogniser self-gates STRUCTURALLY — the\n// file must `import \"net/http\"`, and only the method-prefixed pattern shape\n// mints a route, which is what keeps a generic `HandleFunc(\"literal\", h)` or a\n// pre-1.22 bare-prefix `HandleFunc(\"/orders/\", h)` (no method, coarse subtree —\n// the biggest false-positive source) from being read (ADR-182). A pre-1.22 exact\n// path (`HandleFunc(\"/hotels\", h)`, no trailing slash) is read as method ALL\n// (ADR-254): ServeMux matches it exactly, so it is as precise as a template.\n//\n// `{id}` (single segment), `{path...}` (multi-segment wildcard), and `{$}` (the\n// end-of-path anchor) all sit under `normalizePathTemplate` unchanged — each is a\n// `{…}` segment that collapses to `:param` — so fusion needs no special casing.\n//\n// Fusion is automatic on a modern stack (ADR-182): Go 1.23's `Request.Pattern` +\n// otelhttp ≥ v1.36 set `http.route` to the path-only template (method stripped),\n// exactly the template stored here. On an older stack `http.route` is absent and\n// the node stays EXTRACTED-only — an honest version gate, documented not guessed.\nexport function netHttpRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  if (!goImportsNetHttp(tree.rootNode)) return []\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call_expression') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'selector_expression') return\n    const field = fn.childForFieldName('field')?.text\n    if (field !== 'HandleFunc' && field !== 'Handle') return\n    const leaf = goStringLiteral(node.childForFieldName('arguments')?.namedChild(0))\n    if (leaf === null) return\n    const sp = leaf.indexOf(' ')\n    if (sp < 0) {\n      // No method token (ADR-254). ServeMux matches a pattern with no trailing\n      // slash exactly, so `\"/hotels\"` is one route serving every method; a\n      // trailing-slash pattern (`\"/orders/\"`) is a subtree and `\"/\"` matches\n      // everything, so both stay skipped (ADR-182).\n      if (!leaf.startsWith('/') || leaf === '/' || leaf.endsWith('/')) return\n      out.push({\n        method: 'ALL',\n        pathTemplate: canonicalizeTemplate(leaf),\n        line: node.startPosition.row + 1,\n        framework: 'net/http',\n      })\n      return\n    }\n    const method = leaf.slice(0, sp)\n    const rest = leaf.slice(sp + 1)\n    if (!NET_HTTP_METHODS.has(method)) return\n    if (!rest.startsWith('/')) return // a host-prefixed pattern isn't composed\n    out.push({\n      method,\n      pathTemplate: canonicalizeTemplate(rest),\n      line: node.startPosition.row + 1,\n      framework: 'net/http',\n    })\n  })\n  return out\n}\n\n// Whether the file imports the `net/http` package — the structural half of the\n// net/http gate. Reads both the grouped `import ( … )` and the single\n// `import \"net/http\"` forms (each yields an `import_spec` with a string path).\nfunction goImportsNetHttp(root: Parser.SyntaxNode): boolean {\n  let found = false\n  walk(root, (node) => {\n    if (found || node.type !== 'import_spec') return\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (goStringLiteral(child) === 'net/http') found = true\n    }\n  })\n  return found\n}\n\n// The HTTP verbs FastAPI/Starlette register a route decorator under\n// (`@router.get(...)`, `@app.post(...)`, …). `api_route` is handled separately —\n// it carries its methods in a `methods=[…]` keyword argument.\nconst FASTAPI_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'options', 'head', 'trace'])\n\nconst NESTJS_METHODS = new Map([\n  ['Get', 'GET'],\n  ['Post', 'POST'],\n  ['Put', 'PUT'],\n  ['Patch', 'PATCH'],\n  ['Delete', 'DELETE'],\n  ['Options', 'OPTIONS'],\n  ['Head', 'HEAD'],\n  ['All', 'ALL'],\n])\n\n// ── path-template canonicalisation ──────────────────────────────────────────\n\n// Canonicalise a declared route path for use as a RouteNode's stable template:\n// drop any query/hash, ensure a leading slash, drop a trailing slash (except\n// root). The template keeps its declared params verbatim (`:id`, `{id}`) so an\n// OBSERVED server span carrying the same `http.route` lands on the same node.\nexport function canonicalizeTemplate(raw: string): string {\n  let p = raw.split('?')[0]!.split('#')[0]!\n  if (!p.startsWith('/')) p = '/' + p\n  if (p.length > 1 && p.endsWith('/')) p = p.slice(0, -1)\n  return p\n}\n\n// A path segment is dynamic when it names a parameter rather than a literal.\n// Covers the router param syntaxes (`:id`, `{id}`, `[id]`, `[...slug]`), a\n// reconstructed client interpolation (`:param`), and a concrete value a client\n// URL carries in a param position (all-digits, uuid, long hex / Mongo id).\nfunction isDynamicSegment(seg: string): boolean {\n  if (seg.length === 0) return false\n  if (seg.includes(':')) return true // :id (express/fastify) or reconstructed :param\n  if (seg.startsWith('{') || seg.startsWith('[')) return true // {id} openapi; Next [id]/[...slug]/[[...slug]]\n  if (/^\\d+$/.test(seg)) return true // concrete numeric id\n  if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(seg)) return true // uuid\n  if (/^[0-9a-f]{24,}$/i.test(seg)) return true // mongo objectid / long hex token\n  return false\n}\n\n// Normalise a path-template to a param-agnostic matching key: every dynamic\n// segment collapses to `:param`, every literal segment lowercases. This is the\n// comparison form both a server route's declared template and a client call's\n// URL path reduce to, so `/users/:id` (server) matches `/users/123` and\n// `/users/${userId}` (client). The declared template is kept intact on the\n// node; only matching uses this reduction.\nexport function normalizePathTemplate(raw: string): string {\n  const canonical = canonicalizeTemplate(raw)\n  const segments = canonical.split('/').filter((s) => s.length > 0)\n  const normalised = segments.map((seg) => (isDynamicSegment(seg) ? ':param' : seg.toLowerCase()))\n  return '/' + normalised.join('/')\n}\n\n// ── AST helpers ─────────────────────────────────────────────────────────────\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) walk(child, visit)\n  }\n}\n\n// The interior text of a string literal, stripped of quotes. Returns null for a\n// template string carrying interpolation (a route path is a static literal).\nfunction staticStringText(node: Parser.SyntaxNode): string | null {\n  if (node.type === 'string') {\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child?.type === 'string_fragment') return child.text\n    }\n    // Empty string literal ('' — no fragment child).\n    return ''\n  }\n  if (node.type === 'template_string') {\n    // Only a template with no substitution is a usable static path.\n    for (let i = 0; i < node.namedChildCount; i++) {\n      if (node.namedChild(i)?.type === 'template_substitution') return null\n    }\n    const raw = node.text\n    return raw.length >= 2 ? raw.slice(1, -1) : ''\n  }\n  return null\n}\n\n// Read a string-valued property off an object-expression node (`{ url: '/x' }`).\nfunction objectStringProp(objNode: Parser.SyntaxNode, key: string): string | null {\n  for (let i = 0; i < objNode.namedChildCount; i++) {\n    const pair = objNode.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    if (!k) continue\n    const kText = k.type === 'string' ? staticStringText(k) : k.text\n    if (kText !== key) continue\n    const v = pair.childForFieldName('value')\n    if (v) return staticStringText(v)\n  }\n  return null\n}\n\n// Read the `method` property off a Fastify route-options object. Accepts a\n// single string (`method: 'GET'`) or an array (`method: ['GET','POST']`).\nfunction fastifyRouteMethods(objNode: Parser.SyntaxNode): string[] {\n  for (let i = 0; i < objNode.namedChildCount; i++) {\n    const pair = objNode.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    const kText = k ? (k.type === 'string' ? staticStringText(k) : k.text) : null\n    if (kText !== 'method') continue\n    const v = pair.childForFieldName('value')\n    if (!v) return []\n    if (v.type === 'string' || v.type === 'template_string') {\n      const s = staticStringText(v)\n      return s ? [s.toUpperCase()] : []\n    }\n    if (v.type === 'array') {\n      const out: string[] = []\n      for (let j = 0; j < v.namedChildCount; j++) {\n        const el = v.namedChild(j)\n        if (el && (el.type === 'string' || el.type === 'template_string')) {\n          const s = staticStringText(el)\n          if (s) out.push(s.toUpperCase())\n        }\n      }\n      return out\n    }\n  }\n  return []\n}\n\n// ── NestJS decorator routes ────────────────────────────────────────────────\n\n// Collect only route decorators imported by name from `@nestjs/common`.\n// The local name is the key, so `Get as Read` remains deterministic without\n// admitting an unrelated decorator that happens to be named `Get`.\nfunction nestDecoratorImports(root: Parser.SyntaxNode): Map<string, string> {\n  const imports = new Map<string, string>()\n  walk(root, (node) => {\n    if (node.type !== 'import_statement') return\n    const source = node.childForFieldName('source')\n    if (!source || staticStringText(source) !== '@nestjs/common') return\n    walk(node, (child) => {\n      if (child.type !== 'import_specifier') return\n      const imported = child.childForFieldName('name')?.text\n      const local = child.childForFieldName('alias')?.text ?? imported\n      if (!imported || !local) return\n      if (imported === 'Controller' || NESTJS_METHODS.has(imported)) {\n        imports.set(local, imported)\n      }\n    })\n  })\n  return imports\n}\n\nfunction decoratorCall(node: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  if (node.type !== 'decorator') return null\n  const expression = node.namedChild(0)\n  return expression?.type === 'call_expression' ? expression : null\n}\n\nfunction decoratorCanonicalName(\n  decorator: Parser.SyntaxNode,\n  imports: Map<string, string>,\n): string | null {\n  const call = decoratorCall(decorator)\n  const fn = call?.childForFieldName('function')\n  if (!fn || fn.type !== 'identifier') return null\n  return imports.get(fn.text) ?? null\n}\n\n// Nest accepts one path or an array of paths on both Controller and method\n// decorators. Keep only static alternatives; a computed member contributes no\n// guessed route. No argument is the empty path segment.\nfunction nestStaticPaths(call: Parser.SyntaxNode): string[] {\n  const args = call.childForFieldName('arguments')\n  const first = args?.namedChild(0)\n  if (!first) return ['']\n  const single = staticStringText(first)\n  if (single !== null) return [single]\n  if (first.type !== 'array') return []\n  const paths: string[] = []\n  for (let i = 0; i < first.namedChildCount; i++) {\n    const item = first.namedChild(i)\n    if (!item) continue\n    const value = staticStringText(item)\n    if (value !== null) paths.push(value)\n  }\n  return paths\n}\n\nfunction nestJoinedPath(prefix: string, leaf: string): string {\n  const segments = [prefix, leaf]\n    .map((part) => part.replace(/^\\/+|\\/+$/g, ''))\n    .filter((part) => part.length > 0)\n  return canonicalizeTemplate(segments.join('/'))\n}\n\n// Nest composes class-level `@Controller()` metadata with method-level HTTP\n// decorators. The method decorator is the definition site, so its line is the\n// evidence line and matches where a maintainer edits the route.\nexport function nestjsRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const imports = nestDecoratorImports(tree.rootNode)\n  if (![...imports.values()].includes('Controller')) return []\n\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class_declaration') return\n    const decoratorOwner = node.parent?.type === 'export_statement' ? node.parent : node\n    const classDecorators: Parser.SyntaxNode[] = []\n    for (let i = 0; i < decoratorOwner.namedChildCount; i++) {\n      const child = decoratorOwner.namedChild(i)\n      if (child?.type === 'decorator') classDecorators.push(child)\n    }\n    const controller = classDecorators.find(\n      (decorator) => decoratorCanonicalName(decorator, imports) === 'Controller',\n    )\n    const controllerCall = controller ? decoratorCall(controller) : null\n    if (!controllerCall) return\n    const prefixes = nestStaticPaths(controllerCall)\n    if (prefixes.length === 0) return\n\n    const body = node.childForFieldName('body')\n    if (!body) return\n    for (let i = 0; i < body.namedChildCount; i++) {\n      const methodNode = body.namedChild(i)\n      if (methodNode?.type !== 'method_definition') continue\n      for (let j = 0; j < methodNode.namedChildCount; j++) {\n        const decorator = methodNode.namedChild(j)\n        if (decorator?.type !== 'decorator') continue\n        const canonical = decoratorCanonicalName(decorator, imports)\n        const method = canonical ? NESTJS_METHODS.get(canonical) : undefined\n        const call = decoratorCall(decorator)\n        if (!method || !call) continue\n        const leaves = nestStaticPaths(call)\n        for (const prefix of prefixes) {\n          for (const leaf of leaves) {\n            out.push({\n              method,\n              pathTemplate: nestJoinedPath(prefix, leaf),\n              line: decorator.startPosition.row + 1,\n              framework: 'nestjs',\n            })\n          }\n        }\n      }\n    }\n  })\n  return out\n}\n\n// ── Express / Fastify / Hono call-expression routes ─────────────────────────\n\n// Recognise route registrations of the shape `<router>.<method>('/path', …)`\n// — Express, Fastify, and Hono (`hono.get('/path', handler)` etc.) all share\n// this exact call shape (ADR-133 §5: same registry pattern, Cloudflare\n// Worker's route-grain fast-follow) — and Fastify's own generic\n// `<fastify>.route({ method, url })` form. The guard that keeps this off\n// `db.get('key')` / `_.get(obj, path)` is a string first argument that starts\n// with '/', combined with the caller-side dep gate in addRoutes (only\n// services that depend on express / fastify / hono reach here). This per-file\n// scan captures the leaf path as declared; the Express mount prefix\n// (`app.use('/api', router)`) is composed onto it afterwards by\n// `expressMountPrefixes` (ADR-160), the whole-program pass that resolves the\n// mounted router across files. `.route().get()` chaining and Hono's own\n// `app.on([...methods], '/path', handler)` form remain out of scope for this\n// slice. Coverage grows one router at a time, same discipline as the registry.\nexport function serverRoutesFromSource(\n  source: string,\n  parser: Parser,\n  hasExpress: boolean,\n  hasFastify: boolean,\n  hasHono = false,\n): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  const framework = hasExpress ? 'express' : hasFastify ? 'fastify' : hasHono ? 'hono' : 'unknown'\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call_expression') return\n    const fn = node.childForFieldName('function')\n    if (!fn || fn.type !== 'member_expression') return\n    const prop = fn.childForFieldName('property')\n    if (!prop) return\n    const method = prop.text.toLowerCase()\n    const args = node.childForFieldName('arguments')\n    const first = args?.namedChild(0)\n    if (!first) return\n    const line = node.startPosition.row + 1\n\n    if (ROUTER_METHODS.has(method)) {\n      const p = staticStringText(first)\n      if (p && p.startsWith('/')) {\n        out.push({\n          method: method === 'all' ? 'ALL' : method.toUpperCase(),\n          pathTemplate: canonicalizeTemplate(p),\n          line,\n          framework,\n        })\n      }\n      return\n    }\n\n    // Fastify's generic form: fastify.route({ method, url }).\n    if (method === 'route' && hasFastify && first.type === 'object') {\n      const url = objectStringProp(first, 'url')\n      if (!url || !url.startsWith('/')) return\n      const methods = fastifyRouteMethods(first)\n      const list = methods.length > 0 ? methods : ['ALL']\n      for (const m of list) {\n        out.push({\n          method: m === 'ALL' ? 'ALL' : m.toUpperCase(),\n          pathTemplate: canonicalizeTemplate(url),\n          line,\n          framework: 'fastify',\n        })\n      }\n    }\n  })\n  return out\n}\n\n// ── Next.js file-convention routes ──────────────────────────────────────────\n\nfunction segmentsOf(relFile: string): string[] {\n  return toPosix(relFile).split('/').filter((s) => s.length > 0)\n}\n\n// An app-router route handler file: `<…>/app/**/route.{js,ts,jsx,tsx,…}` (also\n// `src/app`). Route handlers live only in a file literally named `route`.\nexport function isNextAppRouteFile(relFile: string): boolean {\n  const segs = segmentsOf(relFile)\n  if (!segs.includes('app')) return false\n  const base = segs[segs.length - 1] ?? ''\n  return /^route\\.(?:js|jsx|mjs|cjs|ts|tsx)$/.test(base)\n}\n\n// A pages-router API file: `<…>/pages/api/**/*.{js,ts,…}`. Skips Next's special\n// `_app` / `_document` / `_middleware` files, which aren't routes.\nexport function isNextPagesApiFile(relFile: string): boolean {\n  const segs = segmentsOf(relFile)\n  const pagesIdx = segs.indexOf('pages')\n  if (pagesIdx === -1 || segs[pagesIdx + 1] !== 'api') return false\n  const base = segs[segs.length - 1] ?? ''\n  if (/^_(app|document|middleware)\\./.test(base)) return false\n  return JS_ROUTE_EXTENSIONS.has(path.extname(base))\n}\n\n// Convert one Next path segment to its template form: route groups `(group)`\n// drop out, `[...slug]` / `[[...slug]]` catch-alls and `[id]` dynamics become\n// `:name`, everything else stays literal.\nfunction nextSegment(seg: string): string | null {\n  if (seg.startsWith('(') && seg.endsWith(')')) return null // route group — not in the URL\n  const catchAll = seg.match(/^\\[\\[?\\.\\.\\.(.+?)\\]?\\]$/)\n  if (catchAll) return ':' + catchAll[1]\n  const dynamic = seg.match(/^\\[(.+?)\\]$/)\n  if (dynamic) return ':' + dynamic[1]\n  return seg\n}\n\n// Derive the URL path-template from an app-router `route.*` file's directory:\n// `app/users/[id]/route.ts` → `/users/:id`.\nfunction nextAppPathTemplate(relFile: string): string {\n  const segs = segmentsOf(relFile)\n  const appIdx = segs.lastIndexOf('app')\n  const between = segs.slice(appIdx + 1, segs.length - 1) // dirs between app/ and route.*\n  const parts: string[] = []\n  for (const seg of between) {\n    const mapped = nextSegment(seg)\n    if (mapped !== null) parts.push(mapped)\n  }\n  return '/' + parts.join('/')\n}\n\n// Derive the URL path-template from a pages `api/` file:\n// `pages/api/users/[id].ts` → `/api/users/:id`, `pages/api/index.ts` → `/api`.\nfunction nextPagesApiPathTemplate(relFile: string): string {\n  const segs = segmentsOf(relFile)\n  const pagesIdx = segs.indexOf('pages')\n  const rest = segs.slice(pagesIdx + 1) // api/...\n  const parts: string[] = []\n  for (let i = 0; i < rest.length; i++) {\n    let seg = rest[i]!\n    if (i === rest.length - 1) {\n      seg = seg.replace(/\\.(?:js|jsx|mjs|cjs|ts|tsx)$/, '')\n      if (seg === 'index') continue\n    }\n    const mapped = nextSegment(seg)\n    if (mapped !== null) parts.push(mapped)\n  }\n  return '/' + parts.join('/')\n}\n\n// The exported HTTP-method handler names in an app-router `route.*` file:\n// `export async function GET() {}` / `export const POST = …`. Each is one route.\nfunction nextAppMethods(root: Parser.SyntaxNode): { method: string; line: number }[] {\n  const out: { method: string; line: number }[] = []\n  walk(root, (node) => {\n    if (node.type !== 'export_statement') return\n    const decl = node.childForFieldName('declaration')\n    if (!decl) return\n    const line = node.startPosition.row + 1\n    if (decl.type === 'function_declaration') {\n      const name = decl.childForFieldName('name')?.text\n      if (name && NEXT_APP_METHODS.has(name)) out.push({ method: name, line })\n      return\n    }\n    if (decl.type === 'lexical_declaration' || decl.type === 'variable_declaration') {\n      for (let i = 0; i < decl.namedChildCount; i++) {\n        const d = decl.namedChild(i)\n        if (d?.type !== 'variable_declarator') continue\n        const name = d.childForFieldName('name')?.text\n        if (name && NEXT_APP_METHODS.has(name)) out.push({ method: name, line })\n      }\n    }\n  })\n  return out\n}\n\nfunction nextRoutesFromFile(\n  source: string,\n  relFile: string,\n  parser: Parser,\n): ExtractedRoute[] {\n  if (isNextAppRouteFile(relFile)) {\n    const tree = parseSource(parser, source)\n    const template = nextAppPathTemplate(relFile)\n    return nextAppMethods(tree.rootNode).map(({ method, line }) => ({\n      method,\n      pathTemplate: canonicalizeTemplate(template),\n      line,\n      framework: 'next',\n    }))\n  }\n  if (isNextPagesApiFile(relFile)) {\n    // A pages API handler is the module's default export and serves every\n    // method — recorded as a single method-agnostic route.\n    return [\n      {\n        method: 'ALL',\n        pathTemplate: canonicalizeTemplate(nextPagesApiPathTemplate(relFile)),\n        line: 1,\n        framework: 'next',\n      },\n    ]\n  }\n  return []\n}\n\n// ── Python / FastAPI decorator routes ───────────────────────────────────────\n\n// The interior text of a Python string literal, stripped of quotes. Returns\n// null for an f-string carrying interpolation (a route path is a static\n// literal); returns '' for an empty string (no `string_content` child).\nfunction pyStaticStringText(node: Parser.SyntaxNode): string | null {\n  if (node.type !== 'string') return null\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child?.type === 'interpolation') return null // f-string — not a static path\n    if (child?.type === 'string_content') return child.text\n  }\n  return ''\n}\n\n// Read a keyword argument whose value is a list of string literals:\n// `methods=['GET','POST']` → ['GET','POST']. Anything else → [].\nfunction keywordArrayStrings(argsNode: Parser.SyntaxNode, key: string): string[] {\n  for (let i = 0; i < argsNode.namedChildCount; i++) {\n    const arg = argsNode.namedChild(i)\n    if (arg?.type !== 'keyword_argument') continue\n    if (arg.childForFieldName('name')?.text !== key) continue\n    const val = arg.childForFieldName('value')\n    if (!val || val.type !== 'list') return []\n    const out: string[] = []\n    for (let j = 0; j < val.namedChildCount; j++) {\n      const el = val.namedChild(j)\n      if (el?.type === 'string') {\n        const s = pyStaticStringText(el)\n        if (s) out.push(s)\n      }\n    }\n    return out\n  }\n  return []\n}\n\n// Map an in-file router/blueprint variable to its declared literal prefix:\n// FastAPI `router = APIRouter(prefix='/items')` → { router: '/items' }, Flask\n// `bp = Blueprint('x', __name__, url_prefix='/api')` → { bp: '/api' }. Handles\n// bare and dotted constructors (`fastapi.APIRouter(...)`), the prefix kwarg in\n// any position. A prefix built from a config symbol or an f-string\n// (`prefix=settings.API_V1_STR`) stays unmapped — the router contributes no\n// prefix rather than a guessed one, and the leaf-relative path is kept honestly.\nfunction collectPythonRouterPrefixes(root: Parser.SyntaxNode): Map<string, string> {\n  const prefixes = new Map<string, string>()\n  walk(root, (node) => {\n    if (node.type !== 'assignment') return\n    const right = node.childForFieldName('right')\n    if (!right || right.type !== 'call') return\n    const fn = right.childForFieldName('function')\n    if (!fn) return\n    const ctor = fn.type === 'attribute' ? fn.childForFieldName('attribute')?.text : fn.text\n    // FastAPI's APIRouter names its mount `prefix`; Flask's Blueprint names it\n    // `url_prefix`. Any other constructor contributes no prefix.\n    const prefixKey = ctor === 'APIRouter' ? 'prefix' : ctor === 'Blueprint' ? 'url_prefix' : null\n    if (!prefixKey) return\n    const left = node.childForFieldName('left')\n    if (!left || left.type !== 'identifier') return\n    const args = right.childForFieldName('arguments')\n    if (!args) return\n    for (let i = 0; i < args.namedChildCount; i++) {\n      const arg = args.namedChild(i)\n      if (arg?.type !== 'keyword_argument') continue\n      if (arg.childForFieldName('name')?.text !== prefixKey) continue\n      const val = arg.childForFieldName('value')\n      const p = val ? pyStaticStringText(val) : null\n      if (p !== null) prefixes.set(left.text, p)\n    }\n  })\n  return prefixes\n}\n\n// Module-level string constants, for resolving a mount prefix given as a symbol\n// (`prefix=API_V1_STR` or `prefix=settings.API_V1_STR`) rather than a literal.\nfunction collectStringConstants(root: Parser.SyntaxNode): Map<string, string> {\n  const consts = new Map<string, string>()\n  walk(root, (node) => {\n    if (node.type !== 'assignment') return\n    const left = node.childForFieldName('left')\n    const right = node.childForFieldName('right')\n    if (left?.type !== 'identifier' || right?.type !== 'string') return\n    const v = pyStaticStringText(right)\n    if (v !== null) consts.set(left.text, v)\n  })\n  return consts\n}\n\n// Resolve a mount-prefix argument: a literal string, a bare constant\n// (`API_V1_STR`), or an attribute (`settings.API_V1_STR`) whose trailing name is\n// a known in-file constant. Anything else → null (unmapped, kept honest).\nfunction resolvePrefixArg(node: Parser.SyntaxNode | null, consts: Map<string, string>): string | null {\n  if (!node) return null\n  if (node.type === 'string') return pyStaticStringText(node)\n  if (node.type === 'identifier') return consts.get(node.text) ?? null\n  if (node.type === 'attribute') {\n    const attr = node.childForFieldName('attribute')?.text\n    return attr ? (consts.get(attr) ?? null) : null\n  }\n  return null\n}\n\n// In-file mounts — `app.include_router(<router>, prefix=<p>)` (FastAPI) and\n// `app.register_blueprint(<bp>, url_prefix=<p>)` (Flask). Maps the mounted\n// router/blueprint variable to its resolved mount prefix, so a route on that\n// router carries the mounted path. A cross-file mount (the router imported from\n// another module) and nested `include_router` chains are a follow-on — the\n// one-level prefix is composed, honestly.\nfunction collectMountPrefixes(\n  root: Parser.SyntaxNode,\n  consts: Map<string, string>,\n): Map<string, string> {\n  const mounts = new Map<string, string>()\n  walk(root, (node) => {\n    if (node.type !== 'call') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'attribute') return\n    const method = fn.childForFieldName('attribute')?.text\n    const prefixKey =\n      method === 'include_router' ? 'prefix' : method === 'register_blueprint' ? 'url_prefix' : null\n    if (!prefixKey) return\n    const args = node.childForFieldName('arguments')\n    const first = args?.namedChild(0)\n    if (first?.type !== 'identifier') return // only a bare in-file router var\n    let prefix: string | null = null\n    for (let i = 0; i < (args?.namedChildCount ?? 0); i++) {\n      const a = args!.namedChild(i)\n      if (a?.type !== 'keyword_argument') continue\n      if (a.childForFieldName('name')?.text !== prefixKey) continue\n      prefix = resolvePrefixArg(a.childForFieldName('value'), consts)\n    }\n    if (prefix !== null && prefix.length > 0) mounts.set(first.text, prefix)\n  })\n  return mounts\n}\n\n// The decorator forms `<router>.<verb>('/path')` (FastAPI + Flask 2.0 shortcuts),\n// FastAPI's `<router>.api_route('/path', methods=[…])`, and Flask's\n// `<router>.route('/path', methods=[…])` (default GET). `<router>` is the app, an\n// APIRouter, or a Blueprint; the path is the first positional string, read off\n// the call's argument list (so a multi-line decorator still lands). A route's\n// full path composes the in-file mount prefix (`app.include_router(r,\n// prefix='/api/v1')`, resolving a config constant) + the router's own\n// `APIRouter(prefix='/x')` / `Blueprint(url_prefix='/x')` + the decorator path.\n// The declared template keeps its `{id}` params verbatim so an OBSERVED server\n// span's `http.route` lands on the same node.\n//\n// Out of scope, deferred like express `app.use('/api', router)`: cross-file /\n// nested mounting. The one-level, in-file prefix is composed as-is.\nexport function pythonRoutesFromSource(\n  source: string,\n  parser: Parser,\n  framework: string,\n): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const prefixes = collectPythonRouterPrefixes(tree.rootNode)\n  const consts = collectStringConstants(tree.rootNode)\n  const mounts = collectMountPrefixes(tree.rootNode, consts)\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'decorator') return\n    const call = node.namedChild(0)\n    if (!call || call.type !== 'call') return\n    const fn = call.childForFieldName('function')\n    if (!fn || fn.type !== 'attribute') return\n    const method = fn.childForFieldName('attribute')?.text?.toLowerCase()\n    if (!method) return\n    const isVerb = FASTAPI_METHODS.has(method)\n    const isFlaskRoute = method === 'route' // Flask `.route(...)`, defaults to GET\n    const isApiRoute = method === 'api_route' // FastAPI multi-method\n    if (!isVerb && !isFlaskRoute && !isApiRoute) return\n\n    const args = call.childForFieldName('arguments')\n    const first = args?.namedChild(0)\n    if (!first || first.type !== 'string') return\n    const rawPath = pyStaticStringText(first)\n    if (rawPath === null || !rawPath.startsWith('/')) return\n\n    const obj = fn.childForFieldName('object')?.text\n    const routerPrefix = obj ? (prefixes.get(obj) ?? '') : ''\n    const mountPrefix = obj ? (mounts.get(obj) ?? '') : ''\n    const pathTemplate = canonicalizeTemplate(mountPrefix + routerPrefix + rawPath)\n    const line = node.startPosition.row + 1\n\n    if (isVerb) {\n      out.push({ method: method.toUpperCase(), pathTemplate, line, framework })\n      return\n    }\n    // `.route` (Flask, default GET) / `.api_route` (FastAPI) — one route per method.\n    const methods = keywordArrayStrings(args!, 'methods')\n    const list = methods.length > 0 ? methods : isFlaskRoute ? ['GET'] : ['ALL']\n    for (const m of list) {\n      out.push({ method: m === 'ALL' ? 'ALL' : m.toUpperCase(), pathTemplate, line, framework })\n    }\n  })\n  return out\n}\n\n// Back-compat alias — FastAPI is the framework-labelled specialisation.\nexport function fastapiRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  return pythonRoutesFromSource(source, parser, 'fastapi')\n}\n\n// Django URLconf routes — `urlpatterns = [path('orders/<int:pk>/', view), …]`.\n// Django dispatches HTTP methods inside the view, not at the URLconf, so a route\n// is method-agnostic (`ALL`). Only the modern `path()` converter form is\n// recognised; an `include(...)` mount (cross-file, the Python analog of express\n// `app.use`) and legacy `re_path` regex patterns are a follow-on. The `<int:pk>`\n// converter param is kept verbatim and collapses to `:param` at match time.\nexport function djangoRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'assignment') return\n    if (node.childForFieldName('left')?.text !== 'urlpatterns') return\n    const list = node.childForFieldName('right')\n    if (!list || list.type !== 'list') return\n    for (let i = 0; i < list.namedChildCount; i++) {\n      const el = list.namedChild(i)\n      if (el?.type !== 'call') continue\n      if (el.childForFieldName('function')?.text !== 'path') continue // path() only\n      const args = el.childForFieldName('arguments')\n      const first = args?.namedChild(0)\n      if (first?.type !== 'string') continue\n      const raw = pyStaticStringText(first)\n      if (raw === null) continue\n      // Skip an `include(...)` mount — cross-file, deferred.\n      const second = args?.namedChild(1)\n      if (second?.type === 'call' && second.childForFieldName('function')?.text === 'include') continue\n      out.push({\n        method: 'ALL',\n        pathTemplate: canonicalizeTemplate(raw),\n        line: el.startPosition.row + 1,\n        framework: 'django',\n      })\n    }\n  })\n  return out\n}\n\n// ── Rails config/routes.rb routes (ADR-173) ─────────────────────────────────\n//\n// Reads a Rails router table out of `config/routes.rb` and emits a RouteNode per\n// (HTTP method, path template). Explicit verb routes and `root` are read from\n// the source directly; `resources`/`resource` fan out through Rails' resourceful\n// expansion, `namespace`/`scope` contribute a path and/or a controller-module\n// prefix, `member`/`collection` add routes to the enclosing resource, and one\n// level of nesting stamps the parent's `:<singular>_id` param onto the child.\n//\n// The declared template keeps Rails' `:id` form verbatim: the action_pack OTel\n// instrumentation (Rails ≥ 7.1) sets `http.route` to exactly that string with\n// the trailing `(.:format)` stripped, and `normalizePathTemplate` already\n// collapses every `:word` segment to `:param`, so a route-grain server span\n// fuses onto this node with no normalisation. What can't be resolved statically\n// — routes.rb metaprogramming, `draw(:file)` split files, mounted engines,\n// `constraints`, nesting past one level — is left out rather than guessed; those\n// routes still appear at runtime, as an honest observed-but-not-declared\n// divergence rather than a wrong RouteNode.\n\nconst RAILS_VERBS = new Set(['get', 'post', 'put', 'patch', 'delete', 'options', 'head'])\n\n// The member routes a `resources` (plural) declaration fans out to. `update`\n// lands on both PATCH and PUT — Rails registers both and a runtime request can\n// carry either. `new`/`edit` are the form-rendering GETs.\ninterface ResourceRow {\n  action: string\n  methods: string[]\n  suffix: string\n}\nconst RAILS_PLURAL_ROWS: ResourceRow[] = [\n  { action: 'index', methods: ['GET'], suffix: '' },\n  { action: 'new', methods: ['GET'], suffix: '/new' },\n  { action: 'create', methods: ['POST'], suffix: '' },\n  { action: 'show', methods: ['GET'], suffix: '/:id' },\n  { action: 'edit', methods: ['GET'], suffix: '/:id/edit' },\n  { action: 'update', methods: ['PATCH', 'PUT'], suffix: '/:id' },\n  { action: 'destroy', methods: ['DELETE'], suffix: '/:id' },\n]\n// The singular `resource` set — no index and no `:id` segment (there is only ever\n// one), and the controller is pluralised (`resource :profile` → `profiles`).\nconst RAILS_SINGULAR_ROWS: ResourceRow[] = [\n  { action: 'new', methods: ['GET'], suffix: '/new' },\n  { action: 'create', methods: ['POST'], suffix: '' },\n  { action: 'show', methods: ['GET'], suffix: '' },\n  { action: 'edit', methods: ['GET'], suffix: '/edit' },\n  { action: 'update', methods: ['PATCH', 'PUT'], suffix: '' },\n  { action: 'destroy', methods: ['DELETE'], suffix: '' },\n]\n\n// Minimal English inflection — enough for the common resource names. Rails uses\n// ActiveSupport's fuller irregular table; a resource's own path segments are the\n// literal symbol it declares, so only the derived controller name and the nested\n// `:<singular>_id` param depend on this — and the param name never affects fusion\n// (`normalizePathTemplate` collapses any `:word` to `:param`). Irregular plurals\n// (person/people) are a later refinement, not a fusion risk.\nfunction railsPluralize(word: string): string {\n  if (/[^aeiou]y$/i.test(word)) return word.slice(0, -1) + 'ies'\n  if (/(s|x|z|ch|sh)$/i.test(word)) return word + 'es'\n  return word + 's'\n}\nfunction railsSingularize(word: string): string {\n  if (/ies$/i.test(word)) return word.slice(0, -3) + 'y'\n  if (/(x|z|ch|sh)es$/i.test(word)) return word.slice(0, -2)\n  if (/s$/i.test(word) && !/ss$/i.test(word)) return word.slice(0, -1)\n  return word\n}\n\n// The interior text of a Ruby string literal, or a symbol's name without its\n// leading colon (`:orders` → 'orders'). Returns null for an interpolated string\n// (it carries a child that isn't `string_content`) — a route path or handler is\n// a static literal.\nfunction rubyLiteral(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  if (node.type === 'simple_symbol') return node.text.replace(/^:/, '')\n  if (node.type === 'string') {\n    let text = ''\n    let sawContent = false\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (!child) continue\n      if (child.type === 'string_content' || child.type === 'escape_sequence') {\n        text += child.text\n        sawContent = true\n      } else {\n        return null // interpolation or anything non-literal\n      }\n    }\n    return sawContent ? text : '' // an empty string literal has no content child\n  }\n  return null\n}\n\nfunction rubyArgs(call: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  return call.childForFieldName('arguments')\n}\n\n// The positional (non-`pair`) arguments of a call, in order.\nfunction rubyPositional(args: Parser.SyntaxNode | null): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!args) return out\n  for (let i = 0; i < args.namedChildCount; i++) {\n    const c = args.namedChild(i)\n    if (c && c.type !== 'pair') out.push(c)\n  }\n  return out\n}\n\n// The value node of a keyword argument `key: …` — a `pair` whose key is a\n// `hash_key_symbol` with the given name.\nfunction rubyKwarg(args: Parser.SyntaxNode | null, key: string): Parser.SyntaxNode | null {\n  if (!args) return null\n  for (let i = 0; i < args.namedChildCount; i++) {\n    const pair = args.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    if (k?.type === 'hash_key_symbol' && k.text === key) return pair.childForFieldName('value')\n  }\n  return null\n}\n\nfunction rubyKwargText(args: Parser.SyntaxNode | null, key: string): string | null {\n  return rubyLiteral(rubyKwarg(args, key))\n}\n\n// The hash-rocket verb shorthand `get 'path' => 'controller#action'` — a `pair`\n// whose key is a string literal. Returns the path and the handler target.\nfunction rubyRocketRoute(\n  args: Parser.SyntaxNode | null,\n): { path: string; target: string | null } | null {\n  if (!args) return null\n  for (let i = 0; i < args.namedChildCount; i++) {\n    const pair = args.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    if (k?.type !== 'string') continue\n    const path = rubyLiteral(k)\n    if (path === null) continue\n    return { path, target: rubyLiteral(pair.childForFieldName('value')) }\n  }\n  return null\n}\n\n// The statement `call` nodes directly inside a `do … end` block. tree-sitter-ruby\n// wraps multiple statements in a `body_statement`; fall back to the block's own\n// direct children for the single-statement shape.\nfunction rubyBlockCalls(block: Parser.SyntaxNode | null): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!block) return out\n  const pushCalls = (n: Parser.SyntaxNode): void => {\n    for (let i = 0; i < n.namedChildCount; i++) {\n      const c = n.namedChild(i)\n      if (c?.type === 'call') out.push(c)\n    }\n  }\n  let sawBody = false\n  for (let i = 0; i < block.namedChildCount; i++) {\n    const c = block.namedChild(i)\n    if (c?.type === 'body_statement') {\n      pushCalls(c)\n      sawBody = true\n    }\n  }\n  if (!sawBody) pushCalls(block)\n  return out\n}\n\n// Join an accumulated prefix with a leaf path, tolerating a leading slash on the\n// leaf. `canonicalizeTemplate` finishes the job (leading slash, no trailing).\nfunction railsJoin(prefix: string, leaf: string): string {\n  return prefix + '/' + leaf.replace(/^\\/+/, '')\n}\n\nfunction railsEmit(\n  out: ExtractedRoute[],\n  method: string,\n  rawPath: string,\n  controller: string | null,\n  line: number,\n): void {\n  out.push({\n    method,\n    pathTemplate: canonicalizeTemplate(rawPath === '' ? '/' : rawPath),\n    line,\n    framework: 'rails',\n    ...(controller ? { controller } : {}),\n  })\n}\n\n// `only:` / `except:` restrict a resource's emitted action set. A value is a\n// single symbol (`except: :destroy`) or an array (`only: [:index, :show]`).\nfunction railsActionFilter(args: Parser.SyntaxNode | null): (action: string) => boolean {\n  const collect = (key: string): Set<string> | null => {\n    const val = rubyKwarg(args, key)\n    if (!val) return null\n    const set = new Set<string>()\n    if (val.type === 'array') {\n      for (let i = 0; i < val.namedChildCount; i++) {\n        const name = rubyLiteral(val.namedChild(i))\n        if (name) set.add(name)\n      }\n    } else {\n      const name = rubyLiteral(val)\n      if (name) set.add(name)\n    }\n    return set\n  }\n  const only = collect('only')\n  const except = collect('except')\n  return (action: string) =>\n    (only ? only.has(action) : true) && (except ? !except.has(action) : true)\n}\n\n// A bare `get :recent` verb inside a resource block — emits one route relative to\n// `pathBase` (a member path carries `:id`, a collection path does not).\nfunction railsSingleVerb(\n  verb: Parser.SyntaxNode,\n  pathBase: string,\n  controller: string,\n  out: ExtractedRoute[],\n): void {\n  const vm = verb.childForFieldName('method')?.text\n  if (!vm || !RAILS_VERBS.has(vm)) return\n  const action = rubyLiteral(rubyPositional(rubyArgs(verb))[0])\n  if (action === null) return\n  railsEmit(out, vm.toUpperCase(), railsJoin(pathBase, action), `${controller}#${action}`, verb.startPosition.row + 1)\n}\n\n// The `member do … end` / `collection do … end` verb lists inside a resource.\nfunction railsBlockVerbs(\n  call: Parser.SyntaxNode,\n  pathBase: string,\n  controller: string,\n  out: ExtractedRoute[],\n): void {\n  for (const verb of rubyBlockCalls(call.childForFieldName('block'))) {\n    railsSingleVerb(verb, pathBase, controller, out)\n  }\n}\n\ninterface RailsCtx {\n  path: string // accumulated path prefix, '' at the draw root, no trailing slash\n  module: string // accumulated controller-module prefix, '' or e.g. 'admin/'\n  depth: number // resource-nesting depth; 0 at the top level\n}\n\n// An explicit verb route: `get '/x', to: 'c#a'`, the hash-rocket `get 'x' => 'c#a'`,\n// or a bare `get 'about'` (handler inferred `about#index`-style).\nfunction railsVerbRoute(\n  call: Parser.SyntaxNode,\n  method: string,\n  ctx: RailsCtx,\n  out: ExtractedRoute[],\n  line: number,\n): void {\n  const args = rubyArgs(call)\n  let rawPath: string | null\n  let target: string | null\n  const rocket = rubyRocketRoute(args)\n  if (rocket) {\n    rawPath = rocket.path\n    target = rocket.target\n  } else {\n    rawPath = rubyLiteral(rubyPositional(args)[0])\n    target = rubyKwargText(args, 'to')\n  }\n  if (rawPath === null) return\n  if (target === null) target = railsInferHandler(rawPath)\n  railsEmit(out, method, railsJoin(ctx.path, rawPath), target ? ctx.module + target : null, line)\n}\n\n// Infer a `controller#action` for a bare verb route with no `to:`: a single\n// segment maps to `<segment>#index`, a multi-segment path splits the last off as\n// the action. Handler metadata only — the path template is what fuses.\nfunction railsInferHandler(rawPath: string): string {\n  const segs = rawPath\n    .replace(/^\\/+|\\/+$/g, '')\n    .split('/')\n    .filter((s) => s.length > 0 && !s.startsWith(':'))\n  if (segs.length === 0) return 'index'\n  if (segs.length === 1) return `${segs[0]}#index`\n  return `${segs.slice(0, -1).join('/')}#${segs[segs.length - 1]}`\n}\n\n// `resources :orders` (plural) / `resource :profile` (singular) — Rails'\n// resourceful expansion, plus the resource's own `member`/`collection`/nested\n// block. One level of nesting is composed; deeper nesting is deferred.\nfunction railsResource(\n  call: Parser.SyntaxNode,\n  ctx: RailsCtx,\n  out: ExtractedRoute[],\n  plural: boolean,\n): void {\n  if (ctx.depth >= 2) return // one level of nesting only (ADR-173)\n  const args = rubyArgs(call)\n  const name = rubyLiteral(rubyPositional(args)[0])\n  if (!name) return\n  const base = `${ctx.path}/${name}`\n  const controller = ctx.module + (plural ? name : railsPluralize(name))\n  const allow = railsActionFilter(args)\n  const line = call.startPosition.row + 1\n\n  for (const row of plural ? RAILS_PLURAL_ROWS : RAILS_SINGULAR_ROWS) {\n    if (!allow(row.action)) continue\n    for (const m of row.methods) railsEmit(out, m, base + row.suffix, `${controller}#${row.action}`, line)\n  }\n\n  const block = call.childForFieldName('block')\n  if (!block) return\n  const memberBase = plural ? `${base}/:id` : base // a singular member has no :id\n  const nestedPath = plural ? `${base}/:${railsSingularize(name)}_id` : base\n  for (const child of rubyBlockCalls(block)) {\n    const cm = child.childForFieldName('method')?.text\n    if (cm === 'member') railsBlockVerbs(child, memberBase, controller, out)\n    else if (cm === 'collection') railsBlockVerbs(child, base, controller, out)\n    else if (cm && RAILS_VERBS.has(cm)) railsSingleVerb(child, base, controller, out)\n    else if (cm === 'resources' || cm === 'resource' || cm === 'namespace' || cm === 'scope') {\n      railsProcess([child], { path: nestedPath, module: ctx.module, depth: ctx.depth + 1 }, out)\n    }\n    // concerns, member-less helpers, etc. — deferred\n  }\n}\n\n// Walk a list of routes.rb statements in a routing context, dispatching each\n// `call` on its method name.\nfunction railsProcess(statements: Parser.SyntaxNode[], ctx: RailsCtx, out: ExtractedRoute[]): void {\n  for (const call of statements) {\n    const method = call.childForFieldName('method')?.text\n    if (!method) continue\n    const args = rubyArgs(call)\n    const line = call.startPosition.row + 1\n\n    if (method === 'root') {\n      const target = rubyKwargText(args, 'to') ?? rubyLiteral(rubyPositional(args)[0])\n      railsEmit(out, 'GET', ctx.path || '/', target ? ctx.module + target : null, line)\n      continue\n    }\n    if (RAILS_VERBS.has(method)) {\n      railsVerbRoute(call, method.toUpperCase(), ctx, out, line)\n      continue\n    }\n    if (method === 'resources' || method === 'resource') {\n      railsResource(call, ctx, out, method === 'resources')\n      continue\n    }\n    if (method === 'namespace') {\n      const name = rubyLiteral(rubyPositional(args)[0])\n      if (!name) continue\n      railsProcess(rubyBlockCalls(call.childForFieldName('block')), {\n        path: `${ctx.path}/${name}`,\n        module: `${ctx.module}${name}/`,\n        depth: ctx.depth,\n      }, out)\n      continue\n    }\n    if (method === 'scope') {\n      // A positional string/symbol scopes the path; `path:`/`module:` scope each\n      // axis explicitly. A `scope module: 'admin'` shifts only the controller\n      // module, leaving the URL unchanged — the case only the handler shows.\n      const scopePath = rubyKwargText(args, 'path') ?? rubyLiteral(rubyPositional(args)[0])\n      const scopeModule = rubyKwargText(args, 'module')\n      railsProcess(rubyBlockCalls(call.childForFieldName('block')), {\n        path: scopePath ? railsJoin(ctx.path, scopePath) : ctx.path,\n        module: scopeModule ? `${ctx.module}${scopeModule}/` : ctx.module,\n        depth: ctx.depth,\n      }, out)\n      continue\n    }\n    // mount, constraints, `%i[…].each { resources … }`, concerns — deferred.\n  }\n}\n\n// Read `config/routes.rb`: find the `Rails.application.routes.draw do … end`\n// block and expand its body. `draw(:file)` split-route files carry no block and\n// are deferred.\nexport function railsRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call') return\n    if (node.childForFieldName('method')?.text !== 'draw') return\n    const block = node.childForFieldName('block')\n    if (!block) return\n    railsProcess(rubyBlockCalls(block), { path: '', module: '', depth: 0 }, out)\n  })\n  return out\n}\n\n// ── Ruby Sinatra routes (ADR-206) ───────────────────────────────────────────\n//\n// Sinatra declares a route with a bare verb DSL call carrying a string pattern\n// and a block — `post '/send_order_confirmation' do … end`, `get '/health' do …\n// end`. The call has no receiver (it sends to the app `self`), the verb is the\n// HTTP method, and the first argument is the path. Unlike Rails' single\n// conventional `config/routes.rb`, a Sinatra app declares routes throughout its\n// source, so this reads every `.rb` file and self-gates two ways: the file must\n// itself reference Sinatra (a `require 'sinatra'` or a `Sinatra::Base`\n// superclass), AND each call must be the receiver-less verb-with-string-path-and-\n// block shape. That is the precision that keeps a bare `get` / `post` method call\n// in unrelated Ruby (an HTTP client, a config setting) from minting a route.\n//\n// The declared template keeps Sinatra's `:id` param form verbatim: the Rack /\n// Sinatra OTel instrumentation sets `http.route` to the matched pattern, and\n// `normalizePathTemplate` collapses every `:word` segment to `:param`, so a\n// route-grain server span fuses onto this node with no ingest change. Gated per\n// service on the `sinatra` gem (extract/ruby.ts's Gemfile reader). Regex routes,\n// `Sinatra::Namespace` prefix composition, and routes in files that don't\n// themselves reference Sinatra are deferred — those surface as an honest\n// observed-but-not-declared divergence rather than a fabricated node.\n\nconst SINATRA_VERBS = new Set(['get', 'post', 'put', 'patch', 'delete', 'options', 'head'])\n\nexport function sinatraRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  if (!fileReferencesSinatra(tree.rootNode)) return []\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call') return\n    if (node.childForFieldName('receiver')) return // a receiver'd call is not the bare DSL\n    const method = node.childForFieldName('method')?.text\n    if (!method || !SINATRA_VERBS.has(method)) return\n    if (!node.childForFieldName('block')) return // a Sinatra route always takes a block\n    const first = node.childForFieldName('arguments')?.namedChild(0)\n    if (first?.type !== 'string') return // a regex / symbol pattern is not read\n    const p = rubyLiteral(first)\n    if (p === null || !p.startsWith('/')) return\n    out.push({\n      method: method.toUpperCase(),\n      pathTemplate: canonicalizeTemplate(p),\n      line: node.startPosition.row + 1,\n      framework: 'sinatra',\n    })\n  })\n  return out\n}\n\n// Whether the file references Sinatra — a `require` / `require_relative` of a\n// `sinatra…` path, or a `Sinatra`(`::Base`) constant (the modular-app\n// superclass). The file-level precision gate: a `.rb` file in a Sinatra service\n// that names no route surface (a model, an initializer) reads no routes.\nfunction fileReferencesSinatra(root: Parser.SyntaxNode): boolean {\n  let found = false\n  walk(root, (node) => {\n    if (found) return\n    if (node.type === 'call') {\n      const m = node.childForFieldName('method')?.text\n      if (m === 'require' || m === 'require_relative') {\n        const s = rubyLiteral(node.childForFieldName('arguments')?.namedChild(0))\n        if (s !== null && /^sinatra\\b/.test(s)) found = true\n      }\n      return\n    }\n    if (\n      (node.type === 'constant' && node.text === 'Sinatra') ||\n      (node.type === 'scope_resolution' && node.text.startsWith('Sinatra'))\n    ) {\n      found = true\n    }\n  })\n  return found\n}\n\n// ── Laravel routes/web.php + routes/api.php (ADR-177) ───────────────────────\n//\n// Reads a Laravel router table out of `routes/web.php` and `routes/api.php` and\n// emits a RouteNode per (HTTP method, path template). Explicit verb routes\n// (`Route::get('/orders/{id}', …)`) are read from the source directly;\n// `Route::resource`/`apiResource` fan out through Laravel's resourceful\n// convention; `Route::prefix('admin')->group(…)` (and the `middleware`,\n// `controller`, `name` group forms) compose a path prefix across nesting; and\n// every route in `routes/api.php` gets the automatic `/api` prefix the framework\n// adds (it isn't in the source), passed in as the base prefix.\n//\n// The declared template keeps Laravel's `{id}` form verbatim: Laravel's\n// OpenTelemetry auto-instrumentation sets `http.route` to exactly the templated\n// URI (`orders/{id}` for a request to `/orders/42`), and `normalizePathTemplate`\n// already drops the leading slash and collapses every `{…}` segment to `:param`,\n// so a route-grain server span fuses onto this node with no ingest change.\n//\n// Deferred (ADR-177): Symfony entirely — its OTel emits the route NAME, not the\n// path, so it needs a distinct extractor + ingest name-join; `config/routes.yaml`;\n// controller-array handler resolution beyond the template; `match`, `redirect`,\n// `view`, `fallback`, singleton and domain routing; and resource `->only`/`->except`\n// filtering. Those routes surface as observed-but-not-declared divergence rather\n// than a fabricated node.\n\nconst LARAVEL_VERBS = new Set(['get', 'post', 'put', 'patch', 'delete', 'options'])\n\n// The rows a `Route::resource` fans out to — Laravel's convention, reimplemented\n// (it isn't in the source text). `{param}` is the singularized resource name;\n// `update` lands on both PUT and PATCH, since Laravel registers both and a\n// runtime request can carry either. `apiResource` drops the two form-rendering\n// GETs (`create`, `edit`).\ninterface LaravelResourceRow {\n  action: string\n  methods: string[]\n  suffix: string\n}\nconst LARAVEL_RESOURCE_ROWS: LaravelResourceRow[] = [\n  { action: 'index', methods: ['GET'], suffix: '' },\n  { action: 'create', methods: ['GET'], suffix: '/create' },\n  { action: 'store', methods: ['POST'], suffix: '' },\n  { action: 'show', methods: ['GET'], suffix: '/{param}' },\n  { action: 'edit', methods: ['GET'], suffix: '/{param}/edit' },\n  { action: 'update', methods: ['PUT', 'PATCH'], suffix: '/{param}' },\n  { action: 'destroy', methods: ['DELETE'], suffix: '/{param}' },\n]\nconst LARAVEL_API_RESOURCE_SKIP = new Set(['create', 'edit'])\n\n// A deliberately simple singularizer — strip one trailing `s`. The resource param\n// is DISPLAY ONLY: `normalizePathTemplate` collapses every `{…}` segment to\n// `:param` before fusion, so `{photo}` vs `{photos}` never changes the matching\n// key (ADR-177). Reproducing Laravel's fuller inflection isn't a fusion\n// requirement, so the cheap rule stands.\nfunction laravelSingularize(word: string): string {\n  return word.endsWith('s') ? word.slice(0, -1) : word\n}\n\n// The interior text of a PHP single-quoted `string` or double-quoted\n// `encapsed_string`, or null when it carries interpolation (a route path is a\n// static literal). An empty literal returns ''.\nfunction phpStaticString(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  if (node.type !== 'string' && node.type !== 'encapsed_string') return null\n  let text = ''\n  let sawContent = false\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (!child) continue\n    if (child.type === 'string_content') {\n      text += child.text\n      sawContent = true\n    } else {\n      return null // interpolation / escape / anything non-literal\n    }\n  }\n  return sawContent ? text : ''\n}\n\n// The value nodes of a call's positional arguments. tree-sitter-php wraps each in\n// an `argument`; the value is its last named child (a PHP-8 named argument\n// `name: value` carries a `name` field that precedes the value).\nfunction phpArgumentValues(argsNode: Parser.SyntaxNode | null | undefined): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!argsNode) return out\n  for (let i = 0; i < argsNode.namedChildCount; i++) {\n    const arg = argsNode.namedChild(i)\n    if (!arg || arg.type !== 'argument') continue\n    const val = arg.namedChild(arg.namedChildCount - 1)\n    if (val) out.push(val)\n  }\n  return out\n}\n\n// The first positional argument as a static string (the route path / resource\n// name), or null.\nfunction phpFirstString(argsNode: Parser.SyntaxNode | null | undefined): string | null {\n  const vals = phpArgumentValues(argsNode)\n  return vals.length > 0 ? phpStaticString(vals[0]) : null\n}\n\n// Join path parts into a canonical `/`-leading, no-trailing-slash template,\n// trimming any embedded leading/trailing slashes on each part (Laravel's own\n// prefix-composition discipline). An empty set of parts is the root, `/`.\nfunction laravelJoinPath(...parts: string[]): string {\n  const segs: string[] = []\n  for (const part of parts) {\n    for (const s of part.split('/')) {\n      if (s.length > 0) segs.push(s)\n    }\n  }\n  return '/' + segs.join('/')\n}\n\ninterface LaravelSeg {\n  method: string\n  args: Parser.SyntaxNode | null\n  node: Parser.SyntaxNode\n}\n\n// Flatten a `Route::…->…->…` fluent chain into its ordered (method, args)\n// segments, innermost first. `Route::prefix('admin')->group(fn)` →\n// [prefix, group]; a bare `Route::get('/x')` → [get]. Returns null when the chain\n// doesn't root at the `Route` facade (bare, leading-backslash, or the\n// fully-qualified `Illuminate\\Support\\Facades\\Route`).\nfunction laravelUnrollChain(node: Parser.SyntaxNode): LaravelSeg[] | null {\n  const segs: LaravelSeg[] = []\n  let cur: Parser.SyntaxNode | null = node\n  while (cur && cur.type === 'member_call_expression') {\n    const name = cur.childForFieldName('name')?.text\n    if (!name) return null\n    segs.unshift({ method: name, args: cur.childForFieldName('arguments'), node: cur })\n    cur = cur.childForFieldName('object')\n  }\n  if (!cur || cur.type !== 'scoped_call_expression') return null\n  const method = cur.childForFieldName('name')?.text\n  if (!method) return null\n  segs.unshift({ method, args: cur.childForFieldName('arguments'), node: cur })\n  const scopeText = cur.childForFieldName('scope')?.text ?? ''\n  const rooted = scopeText === 'Route' || scopeText.endsWith('\\\\Route')\n  return rooted ? segs : null\n}\n\n// The closure a `->group(…)` call carries — a `function () { … }`\n// (`anonymous_function_creation_expression`) or a `fn () => …` (`arrow_function`).\nfunction laravelGroupClosure(argsNode: Parser.SyntaxNode | null): Parser.SyntaxNode | null {\n  for (const v of phpArgumentValues(argsNode)) {\n    if (v.type === 'anonymous_function_creation_expression' || v.type === 'arrow_function') return v\n  }\n  return null\n}\n\n// The route-call statements inside a group closure body — a `{ … }` block of\n// `expression_statement`s, or a single-expression arrow body.\nfunction laravelClosureCalls(closure: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  const push = (n: Parser.SyntaxNode | null): void => {\n    if (n && (n.type === 'member_call_expression' || n.type === 'scoped_call_expression')) out.push(n)\n  }\n  const body = closure.childForFieldName('body')\n  if (!body) return out\n  if (closure.type === 'arrow_function') {\n    push(body)\n    return out\n  }\n  for (let i = 0; i < body.namedChildCount; i++) {\n    const stmt = body.namedChild(i)\n    if (stmt?.type === 'expression_statement') push(stmt.namedChild(0))\n  }\n  return out\n}\n\nfunction laravelEmit(out: ExtractedRoute[], method: string, rawPath: string, line: number): void {\n  // An optional param `{id?}` drops its `?` so the stored template stays clean —\n  // `canonicalizeTemplate` reads a literal `?` as a query-string delimiter and\n  // would truncate `/users/{id?}` to `/users/{id`. Fusion is unaffected either\n  // way (`normalizePathTemplate` collapses every `{…}` segment to `:param`); this\n  // only keeps the declared template readable and honest.\n  const cleaned = rawPath.replace(/\\{([^}?]+)\\?\\}/g, '{$1}')\n  out.push({\n    method,\n    pathTemplate: canonicalizeTemplate(cleaned === '' ? '/' : cleaned),\n    line,\n    framework: 'laravel',\n  })\n}\n\n// `Route::resource('photos', …)` / `apiResource` — Laravel's resourceful\n// expansion. A dotted name (`photos.comments`) composes into a nested path with\n// the parent param stamped on (`/photos/{photo}/comments/{comment}`), best-effort.\nfunction laravelResource(\n  seg: LaravelSeg,\n  prefix: string,\n  out: ExtractedRoute[],\n  api: boolean,\n): void {\n  const name = phpFirstString(seg.args)\n  if (name === null || name.length === 0) return\n  const line = seg.node.startPosition.row + 1\n  const parts = name.split('.')\n  const leaf = parts[parts.length - 1]!\n  let base = prefix\n  for (let i = 0; i < parts.length - 1; i++) {\n    base = laravelJoinPath(base, parts[i]!, `{${laravelSingularize(parts[i]!)}}`)\n  }\n  base = laravelJoinPath(base, leaf)\n  const param = laravelSingularize(leaf)\n  for (const row of LARAVEL_RESOURCE_ROWS) {\n    if (api && LARAVEL_API_RESOURCE_SKIP.has(row.action)) continue\n    const suffix = row.suffix.replace('{param}', `{${param}}`)\n    const template = laravelJoinPath(base, suffix)\n    for (const m of row.methods) laravelEmit(out, m, template, line)\n  }\n}\n\n// Process one `Route::…` statement in a routing context (the accumulated path\n// prefix). A `->group(…)` composes its `prefix('x')` contributions onto the\n// prefix and recurses into the closure; a verb emits a route; `any` is a\n// method-agnostic `ALL`; `resource`/`apiResource` fan out. Per-route modifiers\n// chained after a verb (`->name(…)`, `->where(…)`, `->middleware(…)`) don't\n// change the template, so they fall out — the verb sits at the base of the chain.\nfunction laravelProcessCall(callNode: Parser.SyntaxNode, prefix: string, out: ExtractedRoute[]): void {\n  const segs = laravelUnrollChain(callNode)\n  if (!segs) return\n\n  const groupSeg = segs.find((s) => s.method === 'group')\n  if (groupSeg) {\n    let composed = prefix\n    for (const s of segs) {\n      if (s === groupSeg) break\n      if (s.method === 'prefix') {\n        const p = phpFirstString(s.args)\n        if (p !== null) composed = laravelJoinPath(composed, p)\n      }\n    }\n    const closure = laravelGroupClosure(groupSeg.args)\n    if (!closure) return\n    for (const child of laravelClosureCalls(closure)) {\n      laravelProcessCall(child, composed, out)\n    }\n    return\n  }\n\n  const base = segs[0]!\n  const line = base.node.startPosition.row + 1\n  if (LARAVEL_VERBS.has(base.method)) {\n    const p = phpFirstString(base.args)\n    if (p === null) return\n    laravelEmit(out, base.method.toUpperCase(), laravelJoinPath(prefix, p), line)\n    return\n  }\n  if (base.method === 'any') {\n    const p = phpFirstString(base.args)\n    if (p === null) return\n    laravelEmit(out, 'ALL', laravelJoinPath(prefix, p), line)\n    return\n  }\n  if (base.method === 'resource' || base.method === 'apiResource') {\n    laravelResource(base, prefix, out, base.method === 'apiResource')\n  }\n}\n\n// Read `routes/web.php` (no prefix) or `routes/api.php` (`basePrefix` = '/api',\n// the framework's automatic prefix, not in the source). Walk the top-level route\n// statements; groups nest and are recursed into explicitly.\nexport function laravelRoutesFromSource(\n  source: string,\n  parser: Parser,\n  basePrefix = '',\n): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  const root = tree.rootNode\n  for (let i = 0; i < root.namedChildCount; i++) {\n    const stmt = root.namedChild(i)\n    if (stmt?.type !== 'expression_statement') continue\n    const call = stmt.namedChild(0)\n    if (call && (call.type === 'member_call_expression' || call.type === 'scoped_call_expression')) {\n      laravelProcessCall(call, basePrefix, out)\n    }\n  }\n  return out\n}\n\n// ── PHP Slim routes (ADR-206) ───────────────────────────────────────────────\n//\n// Slim declares routes on its `App` value — `$app->post('/getquote', …)`,\n// `$app->get(…)`, the multi-method `$app->map(['GET','POST'], '/x', …)`, the\n// method-agnostic `$app->any('/x', …)`, and route groups `$app->group('/prefix',\n// function ($group) { $group->get('/y', …) })` whose prefix composes across\n// nesting. Unlike Laravel's two conventional files, a Slim app has no fixed route\n// location, so this reads every `.php` file and self-gates on finding a Slim App\n// value in the file: a variable assigned from `AppFactory::create()` (Slim 4) or\n// `new …App` (Slim 3), OR a function/closure parameter typed `Slim\\App` — the Slim\n// skeleton (which the otel-demo `quote` service uses) builds the app in\n// `public/index.php` and registers its routes in a separate `app/routes.php` that\n// returns `function (App $app) { $app->post('/getquote', …) }`, so the route file\n// never constructs the app and the `App` type hint is the local gate. Either way a\n// `$x->get('key')` on some other, untyped object never mints a route. Inside a group\n// closure the proxy parameter (and `$this`, which Slim binds to the app in the\n// closure form) joins the app-var set for that scope only, so a nested\n// `$group->get(…)` composes the group prefix.\n//\n// The declared template keeps Slim's `{id}` param form verbatim: the Slim OTel\n// instrumentation sets `http.route` to the matched pattern (`/getquote`), and\n// `normalizePathTemplate` collapses every `{…}` segment to `:param`, so a\n// route-grain server span fuses onto this node with no ingest change. Gated per\n// service on the `slim/slim` dependency (extract/php.ts's composer.json reader).\n// Cross-file route registration where the route file gives no local Slim signal\n// (the app is neither constructed nor `App`-typed in it) and controller-array\n// handlers are deferred — those routes surface as an honest observed-but-not-declared\n// divergence rather than a fabricated node.\n\nconst SLIM_VERBS = new Set(['get', 'post', 'put', 'patch', 'delete', 'options', 'head'])\n\n// Whether a PHP expression constructs a Slim `App` — `AppFactory::create()` (the\n// Slim 4 idiom) or `new \\Slim\\App(...)` / `new App(...)` (Slim 3). Keys the app-var\n// set the route reader scopes to; gated on slim/slim already, so a bare `App` in a\n// Slim service is the framework app.\nfunction isSlimAppCtor(node: Parser.SyntaxNode | null | undefined): boolean {\n  if (!node) return false\n  if (node.type === 'scoped_call_expression') {\n    const scope = node.childForFieldName('scope')?.text ?? ''\n    const name = node.childForFieldName('name')?.text\n    return name === 'create' && (scope === 'AppFactory' || scope.endsWith('\\\\AppFactory'))\n  }\n  if (node.type === 'object_creation_expression') {\n    const cls = node.namedChild(0)?.text ?? ''\n    return cls === 'App' || cls.endsWith('\\\\App') || cls.includes('Slim')\n  }\n  return false\n}\n\n// Whether a parameter type hint names the Slim `App` — `App` (imported via `use\n// Slim\\App`), the qualified `Slim\\App`, or the fully-qualified `\\Slim\\App`. Same\n// precision bar as the object-creation branch of `isSlimAppCtor` (`=== 'App'` or a\n// trailing `\\App`): a bare `App` in a slim/slim-gated service is the framework app.\nfunction isSlimAppType(node: Parser.SyntaxNode | null | undefined): boolean {\n  if (!node || node.type !== 'named_type') return false\n  const text = node.text\n  return text === 'App' || text.endsWith('\\\\App')\n}\n\n// The Slim app variables a file declares — a `$app = AppFactory::create()` style\n// assignment, OR a function/closure parameter typed `Slim\\App`. The second form is\n// the Slim skeleton (the shape the otel-demo `quote` service uses): `public/index.php`\n// builds the app and `app/routes.php` returns `function (App $app) { $app->post(…) }`,\n// so the route file never constructs the app — the `App` type hint on the passed-in\n// `$app` is the only local Slim signal, and an authoritative one. The route reader\n// treats only these vars (plus a group closure's proxy param) as routers, which is\n// the file-level precision gate.\nfunction collectSlimAppVars(root: Parser.SyntaxNode): Set<string> {\n  const vars = new Set<string>()\n  walk(root, (node) => {\n    if (node.type === 'assignment_expression') {\n      const left = node.childForFieldName('left')\n      if (left?.type === 'variable_name' && isSlimAppCtor(node.childForFieldName('right'))) {\n        vars.add(left.text)\n      }\n      return\n    }\n    if (node.type === 'simple_parameter' && isSlimAppType(node.childForFieldName('type'))) {\n      const name = node.childForFieldName('name')\n      if (name?.type === 'variable_name') vars.add(name.text)\n    }\n  })\n  return vars\n}\n\n// The variable names a group closure binds as its router proxy — the closure's\n// formal parameters, plus `$this` (Slim binds the closure to the app). Scoped to\n// that closure only.\nfunction slimClosureParamVars(closure: Parser.SyntaxNode): string[] {\n  const out: string[] = ['$this']\n  for (let i = 0; i < closure.namedChildCount; i++) {\n    const params = closure.namedChild(i)\n    if (params?.type !== 'formal_parameters') continue\n    for (let j = 0; j < params.namedChildCount; j++) {\n      const param = params.namedChild(j)\n      if (param?.type !== 'simple_parameter') continue\n      for (let k = 0; k < param.namedChildCount; k++) {\n        const v = param.namedChild(k)\n        if (v?.type === 'variable_name') {\n          out.push(v.text)\n          break\n        }\n      }\n    }\n  }\n  return out\n}\n\n// The string literals in a PHP array literal `['GET','POST']` — the methods a\n// Slim `->map([...], …)` names. A non-string / interpolated element is skipped.\nfunction phpStringArray(node: Parser.SyntaxNode | null | undefined): string[] {\n  const out: string[] = []\n  if (node?.type !== 'array_creation_expression') return out\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const el = node.namedChild(i)\n    if (el?.type !== 'array_element_initializer') continue\n    const s = phpStaticString(el.namedChild(0))\n    if (s !== null) out.push(s)\n  }\n  return out\n}\n\nexport function slimRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const appVars = collectSlimAppVars(tree.rootNode)\n  if (appVars.size === 0) return [] // no Slim app in this file — nothing to read\n  const out: ExtractedRoute[] = []\n  slimWalk(tree.rootNode, '', appVars, out)\n  return out\n}\n\nfunction slimWalk(\n  node: Parser.SyntaxNode,\n  prefix: string,\n  appVars: Set<string>,\n  out: ExtractedRoute[],\n): void {\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) slimHandle(child, prefix, appVars, out)\n  }\n}\n\nfunction slimHandle(\n  node: Parser.SyntaxNode,\n  prefix: string,\n  appVars: Set<string>,\n  out: ExtractedRoute[],\n): void {\n  if (node.type === 'member_call_expression') {\n    const obj = node.childForFieldName('object')\n    const method = node.childForFieldName('name')?.text\n    const args = node.childForFieldName('arguments')\n    if (obj?.type === 'variable_name' && method && appVars.has(obj.text)) {\n      const line = node.startPosition.row + 1\n\n      if (method === 'group') {\n        const groupPrefix = phpFirstString(args)\n        const closure = laravelGroupClosure(args)\n        if (groupPrefix !== null && closure) {\n          const inner = new Set(appVars)\n          for (const v of slimClosureParamVars(closure)) inner.add(v)\n          const body = closure.childForFieldName('body')\n          if (body) slimWalk(body, laravelJoinPath(prefix, groupPrefix), inner, out)\n        }\n        return\n      }\n      if (SLIM_VERBS.has(method)) {\n        const p = phpFirstString(args)\n        if (p !== null) {\n          out.push({\n            method: method.toUpperCase(),\n            pathTemplate: laravelJoinPath(prefix, p),\n            line,\n            framework: 'slim',\n          })\n        }\n        return\n      }\n      if (method === 'any') {\n        const p = phpFirstString(args)\n        if (p !== null) {\n          out.push({ method: 'ALL', pathTemplate: laravelJoinPath(prefix, p), line, framework: 'slim' })\n        }\n        return\n      }\n      if (method === 'map') {\n        const vals = phpArgumentValues(args)\n        const methods = phpStringArray(vals[0])\n        const p = vals.length > 1 ? phpStaticString(vals[1]) : null\n        if (p !== null) {\n          for (const m of methods) {\n            out.push({\n              method: m.toUpperCase(),\n              pathTemplate: laravelJoinPath(prefix, p),\n              line,\n              framework: 'slim',\n            })\n          }\n        }\n        return\n      }\n      // Any other method on the app var (`->run()`, `->add()`,\n      // `->addErrorMiddleware()`) carries no route — fall through and descend, so a\n      // route call chained onto it (`$app->get(…)->setName(…)`) is still reached.\n    }\n  }\n  slimWalk(node, prefix, appVars, out)\n}\n\n// ── Rust Actix-Web routes (ADR-206) ─────────────────────────────────────────\n//\n// Actix-Web declares a route two ways, and this reads both. The idiomatic form is\n// an attribute macro on the handler fn — `#[post(\"/ship-order\")]`,\n// `#[get(\"/get-quote\")]`, or the multi-method `#[route(\"/x\", method = \"GET\",\n// method = \"POST\")]` — where the macro NAME is the HTTP method and its first\n// string literal is the path; the handler is then wired in with\n// `.service(handler)`, which carries no path of its own (the macro already did),\n// so `.service` needs no separate read. The second form is the builder\n// `App::new().route(\"/health\", web::get().to(handler))`, where the path is the\n// first argument and the method is the `web::<verb>()` in the second — a bare\n// `web::route()` (method-agnostic) or a `.route(...)` whose method doesn't resolve\n// to a known verb mints nothing, so a generic `.route` in unrelated code can't\n// manufacture a route.\n//\n// The declared template keeps Actix's `{id}` param form verbatim: the actix-web\n// OTel instrumentation sets `http.route` to the matched pattern, and\n// `normalizePathTemplate` collapses every `{…}` segment to `:param`, so a\n// route-grain server span fuses onto this node with no ingest change. Gated per\n// service on the `actix-web` dependency (extract/rust.ts's Cargo reader), the same\n// manifest gate Gin/Echo/Fiber use; an attribute / `.route` idiom in a non-Actix\n// Rust service never reaches here. Scope-, resource-, and `web::scope(\"/prefix\")`\n// prefix composition is deferred — those routes surface as an honest\n// observed-but-not-declared divergence rather than a fabricated node.\n\nconst ACTIX_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'])\n\n// The inner text of a Rust string literal (`\"…\"`), quotes stripped, via its\n// `string_content` child. An empty `\"\"` literal (no content child) returns '';\n// a non-string node returns null.\nfunction rustStringContent(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node || node.type !== 'string_literal') return null\n  for (let i = 0; i < node.namedChildCount; i++) {\n    if (node.namedChild(i)?.type === 'string_content') return node.namedChild(i)!.text\n  }\n  return ''\n}\n\nexport function actixRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type === 'attribute_item') {\n      actixAttributeRoute(node, out)\n      return\n    }\n    if (node.type === 'call_expression') {\n      actixBuilderRoute(node, out)\n    }\n  })\n  return out\n}\n\n// An attribute-macro route `#[post(\"/x\")]` / `#[route(\"/x\", method = \"GET\", …)]`.\n// The macro name is the HTTP method (a verb macro) or the multi-method `route`;\n// the first string literal in the macro's token tree is the path.\nfunction actixAttributeRoute(attrItem: Parser.SyntaxNode, out: ExtractedRoute[]): void {\n  const attr = attrItem.namedChild(0)\n  if (!attr || attr.type !== 'attribute') return\n  const nameNode = attr.namedChild(0)\n  if (!nameNode) return\n  // The macro name — `post` (a bare identifier) or `actix_web::post` (scoped, its\n  // trailing segment the verb).\n  const macro =\n    nameNode.type === 'identifier'\n      ? nameNode.text\n      : nameNode.type === 'scoped_identifier'\n        ? (nameNode.childForFieldName('name')?.text ?? null)\n        : null\n  if (!macro) return\n  const tokens = attr.childForFieldName('arguments')\n  if (!tokens || tokens.type !== 'token_tree') return\n\n  const strings: string[] = []\n  for (let i = 0; i < tokens.namedChildCount; i++) {\n    const s = rustStringContent(tokens.namedChild(i))\n    if (s !== null) strings.push(s)\n  }\n  const pathStr = strings[0]\n  if (pathStr === undefined || !pathStr.startsWith('/')) return\n  const line = attrItem.startPosition.row + 1\n  const template = canonicalizeTemplate(pathStr)\n\n  if (ACTIX_METHODS.has(macro)) {\n    out.push({ method: macro.toUpperCase(), pathTemplate: template, line, framework: 'actix-web' })\n    return\n  }\n  if (macro === 'route') {\n    // `#[route(\"/x\", method = \"GET\", method = \"POST\")]` — the method values are\n    // the `\"GET\"`/`\"POST\"` string literals after the path; a `guard = \"…\"` string\n    // that isn't a known verb is filtered out. No method resolved → method-agnostic.\n    const methods = strings.slice(1).filter((m) => ACTIX_METHODS.has(m.toLowerCase()))\n    const list = methods.length > 0 ? methods.map((m) => m.toUpperCase()) : ['ALL']\n    for (const m of list) {\n      out.push({ method: m, pathTemplate: template, line, framework: 'actix-web' })\n    }\n  }\n}\n\n// A builder route `<App>.route(\"/x\", web::get().to(h))`. The path is the first\n// argument; the method is the `web::<verb>()` named in the second. Mints only when\n// a known verb resolves, so a bare `web::route()` or a non-Actix `.route(...)` is\n// left alone.\nfunction actixBuilderRoute(call: Parser.SyntaxNode, out: ExtractedRoute[]): void {\n  const fn = call.childForFieldName('function')\n  if (fn?.type !== 'field_expression') return\n  if (fn.childForFieldName('field')?.text !== 'route') return\n  const args = call.childForFieldName('arguments')\n  const pathStr = rustStringContent(args?.namedChild(0))\n  if (pathStr === null || !pathStr.startsWith('/')) return\n  const second = args?.namedChild(1)\n  if (!second) return\n  const method = actixBuilderMethod(second)\n  if (!method) return\n  out.push({\n    method,\n    pathTemplate: canonicalizeTemplate(pathStr),\n    line: call.startPosition.row + 1,\n    framework: 'actix-web',\n  })\n}\n\n// Resolve the HTTP method a `.route(...)` second argument declares by finding the\n// `web::<verb>()` call in it (`web::post().to(h)` → POST). Returns null when no\n// known verb is named (a bare `web::route()` or a non-builder expression), so the\n// caller mints nothing rather than guessing.\nfunction actixBuilderMethod(node: Parser.SyntaxNode): string | null {\n  let method: string | null = null\n  walk(node, (n) => {\n    if (method || n.type !== 'scoped_identifier') return\n    const verb = n.childForFieldName('name')?.text\n    const scopeLeaf = n.childForFieldName('path')?.text?.split('::').pop()\n    if (scopeLeaf === 'web' && verb && ACTIX_METHODS.has(verb)) method = verb.toUpperCase()\n  })\n  return method\n}\n\n// ── Express cross-file mount-prefix composition (ADR-160) ───────────────────\n\n// Real Express apps mount a router under a prefix — `app.use('/api', router)` —\n// with the router and its routes defined in other files. The per-file scan above\n// captures each leaf path (`/tags`) without the prefix, so a production span for\n// `/api/tags` never fuses onto the static route. This whole-program pass composes\n// the prefix onto the routes it mounts, resolving the mounted router across files\n// through the same import graph `imports.ts` walks (the ADR-149 mechanism the\n// Mongoose cross-file pass established).\n//\n// The discipline is the ADR-149 discipline: a prefix that isn't a `/`-leading\n// string literal (a config symbol or computed expression), or a mounted router\n// that resolves to no file, leaves the leaf path un-prefixed rather than guessing.\n// A route at the wrong grain is an honest partial; a fabricated one is not.\n\n// One `<router>.use(<prefix>, <mounted>)` mount. `prefix` is '' when the router is\n// mounted at root (`app.use(router)`); `target` is the mounted binding's local\n// name, or null when the argument isn't a bare identifier (middleware, a computed\n// prefix followed by a router, a factory call — none of which we compose).\ninterface Mount {\n  prefix: string\n  target: string | null\n}\n\ninterface RouterVarInfo {\n  declares: boolean // has a direct `<var>.get('/…')` route call\n  mounts: Mount[] // the routers this var mounts, via `.use()`\n  aliasOf?: string // `const r2 = r1` — r2 is r1 under another name\n}\n\ninterface RawBinding {\n  local: string\n  specifier: string\n  sel: string // 'default' | 'namespace' | an export name\n}\n\ninterface FileRouterInfo {\n  dir: string // absolute directory of the file, for import resolution\n  routerVars: Map<string, RouterVarInfo>\n  appVars: Set<string> // vars bound to `express()` — the recursion roots\n  exportDefaultName: string | null // routerVars key the default export resolves to\n  exportNamed: Map<string, string> // export name → routerVars key\n  rawBindings: RawBinding[] // imports, before cross-file resolution\n  importedRouters: Map<string, { file: string; sel: string }> // local → target file + export\n}\n\n// The named arguments of a call, comments skipped.\nfunction namedArgs(argsNode: Parser.SyntaxNode | null | undefined): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!argsNode) return out\n  for (let i = 0; i < argsNode.namedChildCount; i++) {\n    const c = argsNode.namedChild(i)\n    if (c && c.type !== 'comment') out.push(c)\n  }\n  return out\n}\n\n// Parse a `.use(...)` call into a Mount, or null when it mounts no resolvable\n// router. `.use('/api', router)` → prefix '/api'; `.use(router)` → prefix '';\n// `.use(cors())` / `.use(PREFIX, router)` / `.use(mw, router)` → null. A computed\n// (non-literal) prefix is deliberately dropped — we compose only a literal one.\nfunction parseUseMount(callNode: Parser.SyntaxNode): Mount | null {\n  const args = namedArgs(callNode.childForFieldName('arguments'))\n  if (args.length === 0) return null\n  const first = args[0]!\n  const firstStr =\n    first.type === 'string' || first.type === 'template_string' ? staticStringText(first) : null\n  if (firstStr !== null && firstStr.startsWith('/')) {\n    const prefix = canonicalizeTemplate(firstStr)\n    const second = args[1]\n    const target = second && second.type === 'identifier' ? second.text : null\n    return { prefix: prefix === '/' ? '' : prefix, target }\n  }\n  // A single bare identifier is a router mounted at root (`app.use(router)`).\n  // Two args led by an identifier is a computed prefix or a middleware — not\n  // something we can compose, so we leave it alone.\n  if (args.length === 1 && first.type === 'identifier') return { prefix: '', target: first.text }\n  return null\n}\n\n// Unwrap a router expression to its base and the `.use()` mounts chained onto it.\n// `Router().use(a).use('/x', b)` → base 'newRouter', mounts [a, /x→b]; `express()`\n// → base 'app'; a bare `router` identifier → base { alias: 'router' }. Returns\n// null when the expression isn't a router value.\nfunction unwrapRouterExpr(\n  node: Parser.SyntaxNode,\n  expressLocals: Set<string>,\n  routerCtors: Set<string>,\n): { base: 'app' | 'newRouter' | { alias: string }; mounts: Mount[] } | null {\n  if (node.type === 'identifier') return { base: { alias: node.text }, mounts: [] }\n  if (node.type !== 'call_expression') return null\n  const fn = node.childForFieldName('function')\n  if (!fn) return null\n\n  if (fn.type === 'member_expression') {\n    const prop = fn.childForFieldName('property')?.text\n    const obj = fn.childForFieldName('object')\n    if (!prop || !obj) return null\n    if (prop === 'use') {\n      const inner = unwrapRouterExpr(obj, expressLocals, routerCtors)\n      if (!inner) return null\n      const mount = parseUseMount(node)\n      return { base: inner.base, mounts: mount ? [...inner.mounts, mount] : inner.mounts }\n    }\n    // `express.Router()`\n    if (prop === 'Router' && obj.type === 'identifier' && expressLocals.has(obj.text)) {\n      return { base: 'newRouter', mounts: [] }\n    }\n    return null\n  }\n\n  if (fn.type === 'identifier') {\n    if (expressLocals.has(fn.text)) return { base: 'app', mounts: [] } // express()\n    if (routerCtors.has(fn.text)) return { base: 'newRouter', mounts: [] } // Router()\n  }\n  return null\n}\n\n// Import bindings + which locals name express() / the Router ctor. Both ESM\n// (`import express, { Router } from 'express'`) and CJS (`const { Router } =\n// require('express')`) forms.\nfunction collectExpressImports(root: Parser.SyntaxNode): {\n  expressLocals: Set<string>\n  routerCtors: Set<string>\n  bindings: RawBinding[]\n} {\n  const expressLocals = new Set<string>()\n  const routerCtors = new Set<string>()\n  const bindings: RawBinding[] = []\n\n  const addFromExpress = (local: string, sel: string, exported: string): void => {\n    if (sel === 'default' || sel === 'namespace') expressLocals.add(local)\n    else if (exported === 'Router') routerCtors.add(local)\n  }\n\n  walk(root, (node) => {\n    if (node.type === 'import_statement') {\n      const source = node.childForFieldName('source')\n      const spec = source ? staticStringText(source) : null\n      if (!spec) return\n      let clause: Parser.SyntaxNode | null = null\n      for (let i = 0; i < node.namedChildCount; i++) {\n        const c = node.namedChild(i)\n        if (c?.type === 'import_clause') clause = c\n      }\n      if (!clause) return\n      for (let i = 0; i < clause.namedChildCount; i++) {\n        const c = clause.namedChild(i)\n        if (!c) continue\n        if (c.type === 'identifier') {\n          if (spec === 'express') addFromExpress(c.text, 'default', 'default')\n          else bindings.push({ local: c.text, specifier: spec, sel: 'default' })\n        } else if (c.type === 'namespace_import') {\n          const id = c.namedChild(0)\n          if (id?.type === 'identifier') {\n            if (spec === 'express') addFromExpress(id.text, 'namespace', 'namespace')\n            else bindings.push({ local: id.text, specifier: spec, sel: 'namespace' })\n          }\n        } else if (c.type === 'named_imports') {\n          for (let j = 0; j < c.namedChildCount; j++) {\n            const s = c.namedChild(j)\n            if (s?.type !== 'import_specifier') continue\n            const name = s.childForFieldName('name')?.text\n            if (!name) continue\n            const local = s.childForFieldName('alias')?.text ?? name\n            if (spec === 'express') addFromExpress(local, name, name)\n            else bindings.push({ local, specifier: spec, sel: name })\n          }\n        }\n      }\n      return\n    }\n\n    if (node.type === 'variable_declarator') {\n      const value = node.childForFieldName('value')\n      if (value?.type !== 'call_expression') return\n      const fn = value.childForFieldName('function')\n      if (fn?.type !== 'identifier' || fn.text !== 'require') return\n      const arg = namedArgs(value.childForFieldName('arguments'))[0]\n      const spec = arg ? staticStringText(arg) : null\n      if (!spec) return\n      const name = node.childForFieldName('name')\n      if (name?.type === 'identifier') {\n        if (spec === 'express') expressLocals.add(name.text)\n        else bindings.push({ local: name.text, specifier: spec, sel: 'default' }) // require = module.exports\n      } else if (name?.type === 'object_pattern') {\n        for (let i = 0; i < name.namedChildCount; i++) {\n          const el = name.namedChild(i)\n          if (!el) continue\n          let local: string | undefined\n          let exported: string | undefined\n          if (el.type === 'shorthand_property_identifier_pattern') {\n            local = el.text\n            exported = el.text\n          } else if (el.type === 'pair_pattern') {\n            exported = el.childForFieldName('key')?.text\n            local = el.childForFieldName('value')?.text ?? exported\n          }\n          if (!local || !exported) continue\n          if (spec === 'express') addFromExpress(local, exported, exported)\n          else bindings.push({ local, specifier: spec, sel: exported })\n        }\n      }\n    }\n  })\n\n  return { expressLocals, routerCtors, bindings }\n}\n\n// Analyse one file's router topology: which vars are routers, what each mounts,\n// which declare routes, and what the file exports.\nfunction analyzeExpressFile(root: Parser.SyntaxNode, dir: string): FileRouterInfo {\n  const { expressLocals, routerCtors, bindings } = collectExpressImports(root)\n  const routerVars = new Map<string, RouterVarInfo>()\n  const appVars = new Set<string>()\n  const exportNamed = new Map<string, string>()\n  let exportDefaultName: string | null = null\n\n  const getVar = (name: string): RouterVarInfo => {\n    let rv = routerVars.get(name)\n    if (!rv) {\n      rv = { declares: false, mounts: [] }\n      routerVars.set(name, rv)\n    }\n    return rv\n  }\n\n  // Resolve an exported expression to a routerVars key. A bare identifier names\n  // a var directly; a `Router().use(...)` chain becomes a synthetic entry keyed\n  // `key`, so every export is expressible as a var reference.\n  const refFromExpr = (expr: Parser.SyntaxNode, key: string): string | null => {\n    if (expr.type === 'identifier') return expr.text\n    const u = unwrapRouterExpr(expr, expressLocals, routerCtors)\n    if (!u) return null\n    const rv = getVar(key)\n    for (const m of u.mounts) rv.mounts.push(m)\n    if (typeof u.base === 'object') rv.aliasOf = u.base.alias\n    return key\n  }\n\n  const isExported = (declarator: Parser.SyntaxNode): boolean => {\n    const decl = declarator.parent // lexical_declaration / variable_declaration\n    return decl?.parent?.type === 'export_statement'\n  }\n\n  walk(root, (node) => {\n    if (node.type === 'variable_declarator') {\n      const value = node.childForFieldName('value')\n      const name = node.childForFieldName('name')\n      if (name?.type !== 'identifier' || !value) return\n      if (value.type === 'call_expression') {\n        const fn = value.childForFieldName('function')\n        if (fn?.type === 'identifier' && fn.text === 'require') return // an import, handled above\n      }\n      const u = unwrapRouterExpr(value, expressLocals, routerCtors)\n      if (!u) return\n      const rv = getVar(name.text)\n      for (const m of u.mounts) rv.mounts.push(m)\n      if (u.base === 'app') appVars.add(name.text)\n      else if (typeof u.base === 'object') rv.aliasOf = u.base.alias\n      if (isExported(node)) exportNamed.set(name.text, name.text)\n      return\n    }\n\n    if (node.type === 'call_expression') {\n      const fn = node.childForFieldName('function')\n      if (fn?.type !== 'member_expression') return\n      const obj = fn.childForFieldName('object')\n      const prop = fn.childForFieldName('property')?.text\n      if (obj?.type !== 'identifier' || !prop) return\n      if (prop === 'use') {\n        const m = parseUseMount(node)\n        if (m) getVar(obj.text).mounts.push(m)\n      } else if (ROUTER_METHODS.has(prop.toLowerCase())) {\n        const first = namedArgs(node.childForFieldName('arguments'))[0]\n        const p = first ? staticStringText(first) : null\n        if (p !== null && p.startsWith('/')) getVar(obj.text).declares = true\n      }\n      return\n    }\n\n    if (node.type === 'export_statement') {\n      // Named clause: `export { router, r as default }`.\n      let clause: Parser.SyntaxNode | null = null\n      for (let i = 0; i < node.namedChildCount; i++) {\n        const c = node.namedChild(i)\n        if (c?.type === 'export_clause') clause = c\n      }\n      if (clause) {\n        for (let i = 0; i < clause.namedChildCount; i++) {\n          const spec = clause.namedChild(i)\n          if (spec?.type !== 'export_specifier') continue\n          const local = spec.childForFieldName('name')?.text\n          if (!local) continue\n          const exportedAs = spec.childForFieldName('alias')?.text ?? local\n          if (exportedAs === 'default') exportDefaultName = local\n          else exportNamed.set(exportedAs, local)\n        }\n        return\n      }\n      // `export const NAME = …` — the declarator handler registers it.\n      if (node.childForFieldName('declaration')) return\n      // `export default <expr>`.\n      for (let i = 0; i < node.namedChildCount; i++) {\n        const c = node.namedChild(i)\n        if (c && c.type !== 'export_clause') {\n          exportDefaultName = refFromExpr(c, '#default')\n          break\n        }\n      }\n      return\n    }\n\n    if (node.type === 'assignment_expression') {\n      const left = node.childForFieldName('left')\n      const right = node.childForFieldName('right')\n      if (left?.type !== 'member_expression' || !right) return\n      const lobj = left.childForFieldName('object')?.text\n      const lprop = left.childForFieldName('property')?.text\n      if (lobj === 'module' && lprop === 'exports') exportDefaultName = refFromExpr(right, '#default')\n      else if (lobj === 'exports' && lprop) {\n        const key = refFromExpr(right, `#exp:${lprop}`)\n        if (key) exportNamed.set(lprop, key)\n      }\n    }\n  })\n\n  return {\n    dir,\n    routerVars,\n    appVars,\n    exportDefaultName,\n    exportNamed,\n    rawBindings: bindings,\n    importedRouters: new Map(),\n  }\n}\n\n/**\n * Whole-program pass (ADR-160): compose Express cross-file mount prefixes onto\n * the routes they mount. Returns a map from a route-declaring file's\n * service-relative path to the prefix its routes serve under — e.g. a controller\n * mounted through `app.use(routes)` → `Router().use('/api', api)` → `.use(ctrl)`\n * lands `'/api'`. Files with no composed prefix are absent (their leaf paths\n * stand as declared). `files` should be the service's source files; only Express\n * `.js`/`.ts` files are analysed.\n */\nexport async function expressMountPrefixes(\n  files: SourceFile[],\n  serviceDir: string,\n  tsPaths: TsPathConfig | null,\n): Promise<Map<string, string>> {\n  const jsParser = makeJsParser()\n  const fileInfo = new Map<string, FileRouterInfo>()\n\n  for (const f of files) {\n    if (!JS_ROUTE_EXTENSIONS.has(path.extname(f.path))) continue\n    if (isTestPath(f.path)) continue\n    const rel = toPosix(path.relative(serviceDir, f.path))\n    try {\n      const tree = parseSource(jsParser, f.content)\n      fileInfo.set(rel, analyzeExpressFile(tree.rootNode, path.dirname(f.path)))\n    } catch {\n      // A file that won't parse contributes no mounts; leave its routes bare.\n    }\n  }\n  if (fileInfo.size === 0) return new Map()\n\n  // Resolve each import binding to its defining file through the import graph —\n  // the same specifier→file resolution imports.ts uses (ADR-149). A specifier\n  // that leaves the service (node_modules, a Node builtin) resolves to null and\n  // is dropped, so it can never carry a prefix.\n  for (const info of fileInfo.values()) {\n    for (const b of info.rawBindings) {\n      const resolved = await resolveJsImport(b.specifier, info.dir, serviceDir, tsPaths)\n      if (!resolved || !fileInfo.has(resolved)) continue\n      info.importedRouters.set(b.local, { file: resolved, sel: b.sel === 'namespace' ? 'default' : b.sel })\n    }\n  }\n\n  // Resolve a mounted identifier to (file, routerVars-key) — a local router var,\n  // or a cross-file import's selected export. null when it names no router we can\n  // reach, which leaves the leaf un-prefixed.\n  const resolveTarget = (name: string, file: string): { file: string; name: string } | null => {\n    const info = fileInfo.get(file)\n    if (!info) return null\n    if (info.routerVars.has(name)) return { file, name }\n    const imp = info.importedRouters.get(name)\n    if (!imp) return null\n    const target = fileInfo.get(imp.file)\n    if (!target) return null\n    const key = imp.sel === 'default' ? target.exportDefaultName : target.exportNamed.get(imp.sel)\n    if (!key) return null\n    return { file: imp.file, name: key }\n  }\n\n  const filePrefix = new Map<string, string>()\n  const conflicted = new Set<string>()\n  const apply = (file: string, prefix: string): void => {\n    if (conflicted.has(file)) return\n    const existing = filePrefix.get(file)\n    if (existing === undefined) filePrefix.set(file, prefix)\n    else if (existing !== prefix) {\n      // The same file reached at two different prefixes — genuinely ambiguous.\n      // Drop it rather than pick one (ADR-160 discipline).\n      filePrefix.delete(file)\n      conflicted.add(file)\n    }\n  }\n\n  const visited = new Set<string>()\n  const collect = (file: string, name: string, accPrefix: string): void => {\n    const key = `${file}|${name}|${accPrefix}`\n    if (visited.has(key)) return\n    visited.add(key)\n    const info = fileInfo.get(file)\n    const rv = info?.routerVars.get(name)\n    if (!info || !rv) return\n    // A file that also hosts an express() app serves its declared routes at the\n    // app root; don't push a mount prefix onto them.\n    if (rv.declares && info.appVars.size === 0) apply(file, accPrefix)\n    for (const m of rv.mounts) {\n      if (!m.target) continue\n      const t = resolveTarget(m.target, file)\n      if (t) collect(t.file, t.name, accPrefix + m.prefix)\n    }\n    if (rv.aliasOf) {\n      const t = resolveTarget(rv.aliasOf, file)\n      if (t) collect(t.file, t.name, accPrefix)\n    }\n  }\n\n  // Root the walk at each express() app. What the app mounts is what the server\n  // actually serves, so the prefix path from the app down is the real one.\n  for (const [rel, info] of fileInfo) {\n    for (const appVar of info.appVars) collect(rel, appVar, '')\n  }\n\n  const out = new Map<string, string>()\n  for (const [file, prefix] of filePrefix) if (prefix && prefix !== '/') out.set(file, prefix)\n  return out\n}\n\n// ── producer ────────────────────────────────────────────────────────────────\n\nexport async function addRoutes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const jsParser = makeJsParser()\n  const pyParser = makePyParser()\n  const goParser = makeGoParser()\n  const rubyParser = makeRubyParser()\n  const phpParser = makePhpParser()\n  const rustParser = makeRustParser()\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const deps = {\n      ...(service.pkg.dependencies ?? {}),\n      ...(service.pkg.devDependencies ?? {}),\n    }\n    const hasExpress = deps['express'] !== undefined\n    const hasFastify = deps['fastify'] !== undefined\n    const hasHono = deps['hono'] !== undefined\n    const hasNext = deps['next'] !== undefined\n    const hasNestjs = deps['@nestjs/core'] !== undefined\n    // FastAPI / Flask are discovered on a Python service the same dependency-gated\n    // way: the manifest reader (extract/python.ts) strips the `fastapi[standard]`\n    // extra to the bare `fastapi` distribution name.\n    const hasFastapi = deps['fastapi'] !== undefined\n    const hasFlask = deps['flask'] !== undefined\n    const hasDjango = deps['django'] !== undefined\n    const hasGin = deps['github.com/gin-gonic/gin'] !== undefined\n    // Echo and Fiber join Go's route recognizers (ADR-181): the go.mod require\n    // path carries the major-version suffix, so gate on both the versioned module\n    // and the pre-modules path. Each declares routes the same shape Gin does.\n    const hasEcho =\n      deps['github.com/labstack/echo/v4'] !== undefined ||\n      deps['github.com/labstack/echo'] !== undefined\n    const hasFiber =\n      deps['github.com/gofiber/fiber/v2'] !== undefined ||\n      deps['github.com/gofiber/fiber/v3'] !== undefined\n    // Chi joins the Go recognizers (ADR-182); the go.mod require path carries the\n    // major-version suffix, so gate on both the versioned module and the\n    // pre-modules path. Its verbs read like Fiber's; its `Route` prefix\n    // composition is closure-scoped (a stack, not a var map).\n    const hasChi =\n      deps['github.com/go-chi/chi/v5'] !== undefined ||\n      deps['github.com/go-chi/chi'] !== undefined\n    // net/http is stdlib — there's no dependency to gate on, so a service can't be\n    // pre-selected for it the way a framework service is. Any Go service may carry\n    // ServeMux routes, so a Go service is admitted on its language alone and the\n    // net/http recognizer self-gates per file (import + method-pattern shape).\n    const isGoService = service.node.language === 'go'\n    // Rails is discovered from the Gemfile (extract/ruby.ts) the same\n    // dependency-gated way; its routes live in one conventional file (ADR-173).\n    const hasRails = deps['rails'] !== undefined\n    // Laravel is discovered from composer.json (extract/php.ts) the same\n    // dependency-gated way; its routes live in routes/web.php + api.php (ADR-177).\n    const hasLaravel = deps['laravel/framework'] !== undefined\n    // Slim is discovered from composer.json alongside Laravel; unlike Laravel it\n    // has no conventional route file, so its recognizer reads every .php file and\n    // self-gates on finding a Slim App value (ADR-206).\n    const hasSlim = deps['slim/slim'] !== undefined\n    // Sinatra is discovered from the Gemfile alongside Rails; like Slim it has no\n    // conventional route file, so its recognizer reads every .rb file and\n    // self-gates on the file referencing Sinatra (ADR-206).\n    const hasSinatra = deps['sinatra'] !== undefined\n    // Actix-Web is discovered from Cargo.toml (extract/rust.ts) the same\n    // dependency-gated way; its routes live in attribute macros / the App builder\n    // (ADR-206).\n    const hasActix = deps['actix-web'] !== undefined\n    if (\n      !hasExpress &&\n      !hasFastify &&\n      !hasHono &&\n      !hasNext &&\n      !hasNestjs &&\n      !hasFastapi &&\n      !hasFlask &&\n      !hasDjango &&\n      !hasGin &&\n      !hasEcho &&\n      !hasFiber &&\n      !hasChi &&\n      !isGoService &&\n      !hasRails &&\n      !hasLaravel &&\n      !hasSlim &&\n      !hasSinatra &&\n      !hasActix\n    )\n      continue\n\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    // Cross-file Express mount-prefix composition (ADR-160). Resolved once per\n    // service after the file list is loaded; the per-file scan below prepends the\n    // composed prefix so a mounted controller's leaf path (`/tags`) becomes the\n    // full path a production span carries (`/api/tags`), and the two fuse.\n    const mountPrefixes = hasExpress\n      ? await expressMountPrefixes(files, service.dir, await loadTsPathConfig(service.dir))\n      : new Map<string, string>()\n\n    for (const file of files) {\n      // ADR-065 #1 — test-scope exclusion. A test that spins up a router isn't\n      // the service's declared route surface.\n      if (isTestPath(file.path)) continue\n      const ext = path.extname(file.path)\n      const isPy = ext === '.py'\n      const isGo = ext === '.go'\n      const isRb = ext === '.rb'\n      const isPhp = ext === '.php'\n      const isRs = ext === '.rs'\n      if (!JS_ROUTE_EXTENSIONS.has(ext) && !isPy && !isGo && !isRb && !isPhp && !isRs) continue\n      const relFile = toPosix(path.relative(service.dir, file.path))\n\n      let routes: ExtractedRoute[]\n      try {\n        if (isPhp) {\n          // Laravel declares its HTTP surface in two conventional files; every\n          // route in routes/api.php gets the framework's automatic `/api` prefix\n          // (not in the source), passed as the base prefix. Other `.php` files\n          // carry no Laravel routes (ADR-177).\n          routes =\n            hasLaravel && (relFile === 'routes/web.php' || relFile === 'routes/api.php')\n              ? laravelRoutesFromSource(\n                  file.content,\n                  phpParser,\n                  relFile === 'routes/api.php' ? '/api' : '',\n                )\n              : []\n          // Slim has no conventional route file, so it runs on every .php file and\n          // self-gates on finding a Slim App value in the file (ADR-206).\n          if (hasSlim) routes = routes.concat(slimRoutesFromSource(file.content, phpParser))\n        } else if (isRb) {\n          // Rails declares its whole route table in one conventional file; other\n          // `.rb` files carry no Rails routes (ADR-173).\n          routes =\n            hasRails && relFile === 'config/routes.rb'\n              ? railsRoutesFromSource(file.content, rubyParser)\n              : []\n          // Sinatra has no conventional route file, so it runs on every .rb file\n          // and self-gates on the file referencing Sinatra (ADR-206).\n          if (hasSinatra) routes = routes.concat(sinatraRoutesFromSource(file.content, rubyParser))\n        } else if (isRs) {\n          // Actix-Web routes live in attribute macros / the App builder, gated on\n          // the actix-web crate; a non-Actix Rust service reads no routes (ADR-206).\n          routes = hasActix ? actixRoutesFromSource(file.content, rustParser) : []\n        } else if (isGo) {\n          // One framework recognizer per service — Gin, Echo, Fiber, and Chi are\n          // dependency-gated, so a file is read by whichever the manifest names.\n          if (hasGin) routes = ginRoutesFromSource(file.content, goParser)\n          else if (hasEcho) routes = echoRoutesFromSource(file.content, goParser)\n          else if (hasFiber) routes = fiberRoutesFromSource(file.content, goParser)\n          else if (hasChi) routes = chiRoutesFromSource(file.content, goParser)\n          else routes = []\n          // net/http has no dependency to gate on, so it runs additively on every\n          // Go file and self-gates on the `net/http` import plus the\n          // method-prefixed ServeMux pattern shape (ADR-182). A framework file\n          // won't carry that shape, so there's no double count.\n          routes = routes.concat(netHttpRoutesFromSource(file.content, goParser))\n        } else if (isPy) {\n          routes =\n            hasFastapi || hasFlask\n              ? pythonRoutesFromSource(file.content, pyParser, hasFastapi ? 'fastapi' : 'flask')\n              : []\n          // Django's URLconf shape (a urlpatterns list) is independent of the\n          // decorator shape, so a Django service's routes come from here too.\n          if (hasDjango) routes = routes.concat(djangoRoutesFromSource(file.content, pyParser))\n        } else if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {\n          routes = nextRoutesFromFile(file.content, relFile, jsParser)\n        } else if (hasNestjs) {\n          routes = nestjsRoutesFromSource(file.content, jsParser)\n        } else if (hasExpress || hasFastify || hasHono) {\n          routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify, hasHono)\n        } else {\n          routes = []\n        }\n      } catch (err) {\n        recordExtractionError('route extraction', file.path, err)\n        continue\n      }\n      if (routes.length === 0) continue\n\n      // A cross-file Express mount prefix for this file's routes, if one resolved.\n      const mountPrefix = mountPrefixes.get(relFile)\n\n      for (const route of routes) {\n        const pathTemplate = mountPrefix\n          ? canonicalizeTemplate(mountPrefix + route.pathTemplate)\n          : route.pathTemplate\n        const rid = routeId(service.pkg.name, route.method, pathTemplate)\n        if (!graph.hasNode(rid)) {\n          const node: RouteNode = {\n            id: rid,\n            type: NodeType.RouteNode,\n            name: `${route.method} ${pathTemplate}`,\n            service: service.pkg.name,\n            method: route.method,\n            pathTemplate,\n            path: relFile,\n            line: route.line,\n            framework: route.framework,\n            discoveredVia: 'static',\n          }\n          graph.addNode(rid, node)\n          nodesAdded++\n        }\n        // `service ──CONTAINS──▶ route` — the service owns its routes the same\n        // way it owns its files (file-awareness.md §2). Structural ownership,\n        // evidence pinned to the defining file:line.\n        const containsId = extractedEdgeId(service.node.id, rid, EdgeType.CONTAINS)\n        if (!graph.hasEdge(containsId)) {\n          const edge: GraphEdge = {\n            id: containsId,\n            source: service.node.id,\n            target: rid,\n            type: EdgeType.CONTAINS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: {\n              file: relFile,\n              line: route.line,\n              snippet: snippet(file.content, route.line),\n            },\n          }\n          graph.addEdgeWithKey(containsId, service.node.id, rid, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseYaml } from 'yaml'\nimport type { ServiceNode } from '@neat.is/types'\n\nexport interface PackageJson {\n  name: string\n  version?: string\n  dependencies?: Record<string, string>\n  devDependencies?: Record<string, string>\n  engines?: { node?: string }\n}\n\nexport interface DiscoveredService {\n  pkg: PackageJson\n  dir: string\n  node: ServiceNode\n  // ADR-200 — nearest-service-wins file ownership. Absolute directories of OTHER\n  // discovered services nested strictly under `dir`. A source file belongs to the\n  // deepest discovered service that contains it, so an ancestor's file walk skips\n  // these subtrees rather than re-minting a nested service's symbols/routes/ORM\n  // nodes under itself. Populated by `discoverServices` for every service (empty\n  // when nothing is nested — a single-service or leaf service walks its whole\n  // tree exactly as before). ADR-255 also lists individual files here: a Go binary\n  // that shares its module root with its siblings excludes the files it doesn't own,\n  // so every walker skips an entry whether it names a directory or a file.\n  excludeDirs?: string[]\n}\n\n// C++ (ADR-202) contributes only the unambiguous extensions — `.cpp`/`.cc`/`.cxx`/\n// `.c++` impl, `.hpp`/`.hh`/`.hxx`/`.h++` C++-only headers. `.h`/`.c` are omitted:\n// shared with C, they'd pull pure-C source into the C++ symbol walker (see\n// SYMBOL_GRAMMAR_BY_EXT in symbols.ts).\nexport const SERVICE_FILE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.py', '.go', '.rb', '.php', '.cs', '.java', '.kt', '.rs', '.cpp', '.cc', '.cxx', '.c++', '.hpp', '.hh', '.hxx', '.h++'])\nexport const CONFIG_FILE_EXTENSIONS = new Set(['.yaml', '.yml'])\n\n// A curated allowlist of JSON build/app-config files that get a ConfigNode by\n// exact basename (ADR-185). `.json` is deliberately NOT recognized wholesale —\n// that would pull in `tsconfig.json`, `package-lock.json`, and every JSON\n// fixture as \"config\" and churn every project's graph. These three name real\n// build configuration a failure can point at: Expo's `app.json` / `app.config.json`\n// and EAS's `eas.json`. Like every ConfigNode they record file existence only,\n// never contents (ADR-016, CLAUDE.md § Don't do). `package.json` is intentionally\n// absent — it already materializes as a ServiceNode, so recognizing it here too\n// would twin that and churn every repo; a dependency-phase EAS incident anchors\n// to the ServiceNode instead (ADR-185).\nexport const JSON_CONFIG_FILENAMES = new Set(['app.json', 'app.config.json', 'eas.json'])\nexport const IGNORED_DIRS = new Set([\n  'node_modules',\n  '.git',\n  '.turbo',\n  'dist',\n  'build',\n  '.next',\n  // `_next` is the *emitted* half of the pair above — `next build`'s output as\n  // it is served or exported. `.next` was listed and `_next` wasn't, so an\n  // exported bundle walked in as first-party source: minified chunks, one file\n  // per line, hundreds of KB each (#1254).\n  '_next',\n  // Agent scratch space. `.claude/worktrees/` holds a full checkout per agent\n  // session, so walking it re-extracts the whole repo once per worktree — and\n  // pulls in whatever build output those checkouts happen to carry. It is\n  // gitignored in practice, but the file walk doesn't read .gitignore, so the\n  // name has to be listed here.\n  '.claude',\n  // Python virtualenv shapes (issue #344). Walking into a venv pulls in the\n  // entire CPython stdlib + every installed package as if it were first-party\n  // service code — 20k+ files, none of which the user wrote. The shape names\n  // cover the three common venv tools (`venv` / `python -m venv`,\n  // `virtualenv`) and the tox + PEP 582 conventions.\n  '.venv',\n  'venv',\n  '__pypackages__',\n  '.tox',\n  // `site-packages` shows up nested inside venvs that don't carry one of the\n  // outer names (system Python on macOS, in-place pyenv layouts). Listing it\n  // here means we stop the walk at the boundary even when the wrapper dir\n  // wasn't recognisable.\n  'site-packages',\n  // Checked-in third-party code: Go's `vendor/` (golang/dep and `go mod vendor`),\n  // PHP Composer's `vendor/`, Ruby's `vendor/bundle`. Never first-party, never a\n  // service (ADR-256): a Dockerfile under `vendor/golang.org/x/net/http2/` minted\n  // a phantom `http2` service.\n  'vendor',\n])\n\n// Marker file `python -m venv` and `virtualenv` both drop at the venv root.\n// Used by the walkers to recognise venvs whose top-level directory doesn't\n// happen to match one of the canonical `IGNORED_DIRS` names (issue #344).\n// Cached per process to keep the recursion hot path off the fs after the\n// first walk; venv contents don't change inside one extract pass.\nconst PYVENV_MARKER_CACHE = new Map<string, boolean>()\n\nexport async function isPythonVenvDir(dir: string): Promise<boolean> {\n  const cached = PYVENV_MARKER_CACHE.get(dir)\n  if (cached !== undefined) return cached\n  try {\n    const stat = await fs.stat(path.join(dir, 'pyvenv.cfg'))\n    const ok = stat.isFile()\n    PYVENV_MARKER_CACHE.set(dir, ok)\n    return ok\n  } catch {\n    PYVENV_MARKER_CACHE.set(dir, false)\n    return false\n  }\n}\n\nexport function isConfigFile(name: string): { match: boolean; fileType: string } {\n  const ext = path.extname(name)\n  if (CONFIG_FILE_EXTENSIONS.has(ext)) return { match: true, fileType: ext.slice(1) }\n  // Curated JSON build-config files (ADR-185) — exact basename only, never all\n  // `.json`. fileType 'json' so a consumer can tell them from yaml/env config.\n  if (JSON_CONFIG_FILENAMES.has(name)) return { match: true, fileType: 'json' }\n  // .env, .env.local, .env.production. Bare filename or any dotted-suffix\n  // variant; folder names get filtered upstream by walking files only.\n  // ADR-065 #4 filters .env.template / .env.example / .env.sample (and the\n  // dotted-suffix variants) at the producer level — those are documentation,\n  // not runtime config.\n  if (name === '.env' || name.startsWith('.env.')) {\n    if (isEnvTemplateFile(name)) return { match: false, fileType: '' }\n    // NEAT writes `.env.neat` itself during `--apply` (ADR-069 §4). Ingesting\n    // it would record our own instrumentation env as if it were the user's\n    // declared config — self-pollution. Skip it the same way the template\n    // filter skips onboarding docs.\n    if (isNeatAuthoredEnvFile(name)) return { match: false, fileType: '' }\n    return { match: true, fileType: 'env' }\n  }\n  return { match: false, fileType: '' }\n}\n\n// NEAT-authored artifacts the installer drops into the user's tree during\n// `--apply` (ADR-069). Extraction skips them: they're our own runtime hooks,\n// not first-party config or source. Ingesting them pollutes the graph with\n// NEAT's instrumentation as though the user had written it.\n//\n//   `.env.neat`         — per-package env carrying `OTEL_SERVICE_NAME`.\n//   `otel-init.{ext}`   — generated SDK bootstrap (js/cjs/mjs/ts), including\n//                         the framework variants (`src/otel-init.*`,\n//                         `server/plugins/otel-init.*`) — basename is stable.\nexport function isNeatAuthoredEnvFile(name: string): boolean {\n  return name === '.env.neat'\n}\n\nexport function isNeatAuthoredSourceFile(name: string): boolean {\n  return /^otel-init\\.(?:js|cjs|mjs|ts|tsx)$/i.test(name) || name === 'neat_otel.go'\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ADR-065 precision-filter helpers. Pre-emit gates inside the producer pass.\n// Filtered candidates are never written to the graph (idempotency intact).\n// ─────────────────────────────────────────────────────────────────────────\n\n// ADR-065 #1 — test-scope exclusion. Returns true when the file path matches\n// any test-scope pattern. Path is normalised to forward slashes before\n// matching so callers can pass either form.\n//\n// Patterns:\n//   - any segment named __tests__, __fixtures__, or integration-tests\n//   - basename matches *.spec.{ts,tsx,js,jsx,mjs,cjs,py}\n//   - basename matches *.test.{ts,tsx,js,jsx,mjs,cjs,py}\nexport function isTestPath(filePath: string): boolean {\n  const normalised = filePath.replace(/\\\\/g, '/')\n  const segments = normalised.split('/')\n  for (const seg of segments) {\n    if (\n      seg === '__tests__' ||\n      seg === '__fixtures__' ||\n      seg === 'integration-tests' ||\n      // Cypress end-to-end specs (ADR-242): `cypress/e2e/*.cy.ts` drives the app\n      // from outside, so a flag key it names is not a reader of that flag.\n      seg === 'cypress'\n    ) {\n      return true\n    }\n  }\n  const base = segments[segments.length - 1] ?? ''\n  if (base.endsWith('_test.go')) return true\n  return /\\.(spec|test|cy)\\.(?:tsx?|jsx?|mjs|cjs|py)$/i.test(base)\n}\n\n// ADR-065 #4 — `.env.template` exclusion. Matches:\n//   .env.template / .env.example / .env.sample\n//   .env.*.template / .env.*.example / .env.*.sample\n// These are docs/onboarding artifacts, not runtime config. ConfigNodes are\n// bound to runtime existence (ADR-016); templates fail that test.\nexport function isEnvTemplateFile(name: string): boolean {\n  if (\n    name === '.env.template' ||\n    name === '.env.example' ||\n    name === '.env.sample'\n  ) {\n    return true\n  }\n  // `.env.*.template` / `.env.*.example` / `.env.*.sample`\n  return /^\\.env\\.[^.]+\\.(?:template|example|sample)$/i.test(name)\n}\n\n// ADR-065 #2 — comment-body exclusion. Replaces every JS/TS comment span in\n// the source with an equal-length run of spaces, preserving line/column for\n// downstream line-mapping. Strings that contain `//` sequences (URLs) are\n// preserved by tracking the string context as we scan.\n//\n// Not a full parser — good enough for the medusa-shape failures. The HTTP\n// extractor's AST walk already gets comment-awareness for free; this helper\n// is for the regex-based extractors (redis, kafka, aws, grpc).\nexport function maskCommentsInSource(src: string): string {\n  const len = src.length\n  const out: string[] = new Array(len)\n  let i = 0\n  // String context: ' \" ` (template) — open-quote char, 0 when not in a string.\n  let inString: string | 0 = 0\n  let escaped = false\n  while (i < len) {\n    const c = src[i]!\n    if (inString !== 0) {\n      out[i] = c\n      if (escaped) {\n        escaped = false\n      } else if (c === '\\\\') {\n        escaped = true\n      } else if (c === inString) {\n        inString = 0\n      }\n      i++\n      continue\n    }\n    if (c === '/' && i + 1 < len) {\n      const next = src[i + 1]!\n      if (next === '/') {\n        out[i] = ' '\n        out[i + 1] = ' '\n        let j = i + 2\n        while (j < len && src[j] !== '\\n') {\n          out[j] = ' '\n          j++\n        }\n        i = j\n        continue\n      }\n      if (next === '*') {\n        out[i] = ' '\n        out[i + 1] = ' '\n        let j = i + 2\n        while (j < len) {\n          if (src[j] === '\\n') {\n            out[j] = '\\n'\n            j++\n            continue\n          }\n          if (src[j] === '*' && j + 1 < len && src[j + 1] === '/') {\n            out[j] = ' '\n            out[j + 1] = ' '\n            j += 2\n            break\n          }\n          out[j] = ' '\n          j++\n        }\n        i = j\n        continue\n      }\n    }\n    out[i] = c\n    if (c === \"'\" || c === '\"' || c === '`') inString = c\n    i++\n  }\n  return out.join('')\n}\n\n// ADR-065 #5 — exact hostname match for cross-service URL inference. Returns\n// true if `urlString` looks like an actual URL — has an explicit `scheme://`\n// or starts with a scheme-relative `//` — and its hostname matches `host`\n// exactly (case-insensitive). No `.includes()` containment, and no bare-string\n// matching: a literal like `'admin-bundler'` would otherwise parse as\n// `http://admin-bundler` and match the basename of every service directory,\n// which is how the v0.3.3 medusa pre-check produced 279 false positives.\n//\n// Accepts a `host` that may include a port (`api.example.com:8080`); in that\n// case the URL's hostname AND port must both match.\nconst URL_LIKE = /^(?:[a-z][a-z0-9+.-]*:)?\\/\\//i\n\nexport function urlMatchesHost(urlString: string, host: string): boolean {\n  if (typeof urlString !== 'string' || urlString.length === 0) return false\n  // Require the literal to look like a URL — scheme + `://` or scheme-relative\n  // `//host`. Bare hostnames are rejected; they're the load-bearing source of\n  // false positives.\n  if (!URL_LIKE.test(urlString)) return false\n  const [wantedHost, wantedPort] = host.split(':')\n  let parsed: URL\n  try {\n    // For scheme-relative `//host/path`, prepend `http:` so URL accepts it.\n    const candidate = urlString.startsWith('//') ? `http:${urlString}` : urlString\n    parsed = new URL(candidate)\n  } catch {\n    return false\n  }\n  if (parsed.hostname.toLowerCase() !== (wantedHost ?? '').toLowerCase()) return false\n  if (wantedPort && parsed.port !== wantedPort) return false\n  return true\n}\n\n// Strip semver range prefixes (^, ~, >=, etc.) and bare \"v\" so the extracted\n// version is usable for compat checks. We don't try to resolve ranges to actual\n// installed versions — that's a published-lockfile concern, not extraction's job.\nexport function cleanVersion(raw: string | undefined): string | undefined {\n  if (!raw) return undefined\n  return raw.replace(/^[\\^~><=v\\s]+/, '').trim() || undefined\n}\n\nexport async function readJson<T>(filePath: string): Promise<T> {\n  const raw = await fs.readFile(filePath, 'utf8')\n  return JSON.parse(raw) as T\n}\n\nexport async function readYaml<T>(filePath: string): Promise<T> {\n  const raw = await fs.readFile(filePath, 'utf8')\n  return parseYaml(raw) as T\n}\n\nexport async function exists(p: string): Promise<boolean> {\n  try {\n    await fs.access(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\n// Thin re-export so existing callers (calls/, configs.ts, databases/, infra/)\n// keep their import path. Wire format lives in @neat.is/types/identity.ts per\n// ADR-029.\nexport { extractedEdgeId as makeEdgeId } from '@neat.is/types'\n","// ADR-065 — loud failure mode for static extraction.\n//\n// Per-file extraction failures used to land as a single `console.warn` line\n// with no aggregate count and no on-disk record. The 2026-05-12 medusa\n// experiment ran `neat init` against ~90 files that all silently failed\n// extraction with \"Invalid argument\"; the snapshot shipped with those files\n// missing, the user had no signal it had happened, and the divergence query\n// couldn't surface gaps it didn't know it had.\n//\n// This module is the failure-mode plumbing: a process-local sink that every\n// producer appends to when a per-file parse fails, with helpers to drain the\n// sink to `<projectDir>/neat-out/errors.ndjson` and to surface the aggregate\n// count in init / watch banners.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { EdgeEvidence, ExtractionCoverage } from '@neat.is/types'\n\nexport interface ExtractionError {\n  // Producer name (e.g. \"http\", \"services\", \"infra docker-compose\"). Stable\n  // human-readable identifier for logs and contract assertions.\n  producer: string\n  // Absolute or relative path of the file that failed. Stored verbatim from\n  // the call site; no normalisation here.\n  file: string\n  // The error's `.message`. Stringified if the throw value wasn't an Error.\n  error: string\n  // Optional stack trace (captured at the call site). Useful for diagnosing\n  // tree-sitter \"Invalid argument\" cases where the message alone is generic.\n  stack?: string\n  // ISO timestamp of when the error was recorded.\n  ts: string\n  // Discriminator for `errors.ndjson` consumers — separates extract failures\n  // from OTel error events that share the same file (ADR-033).\n  source: 'extract'\n}\n\nconst sink: ExtractionError[] = []\n\n// Record a per-file extraction failure. Preserves the visible warn line so\n// existing scripts/CI consumers still see a per-file message; appends to the\n// process-local sink so the aggregate count + sidecar write can fire later.\nexport function recordExtractionError(\n  producer: string,\n  file: string,\n  err: unknown,\n): void {\n  const e = err instanceof Error ? err : new Error(String(err))\n  sink.push({\n    producer,\n    file,\n    error: e.message,\n    stack: e.stack,\n    ts: new Date().toISOString(),\n    source: 'extract',\n  })\n  // Visible warn preserved (pre-ADR-065 callers logged this). Banners\n  // aggregate, but per-file context still useful for tail -f sessions.\n  console.warn(`[neat] ${producer} skipped ${file}: ${e.message}`)\n}\n\n// Drain all queued errors. Idempotent — subsequent calls return an empty\n// array until new errors land. Callers (extractFromDirectory) drain at start\n// to clear stale state from prior runs, then drain again at end to collect\n// the pass's failures.\nexport function drainExtractionErrors(): ExtractionError[] {\n  return sink.splice(0, sink.length)\n}\n\n// Read-only count of currently-queued errors. Used by callers that want the\n// count without consuming the sink (the banner case — we want the count for\n// display and the entries for `errors.ndjson`).\nexport function pendingExtractionErrors(): number {\n  return sink.length\n}\n\n// Append the drained entries to `<projectDir>/neat-out/errors.ndjson`. The\n// file is shared with OTel error events (per ADR-033); the `source: 'extract'`\n// discriminator separates them for consumers. Creates the directory if\n// missing. Append-only — never rewritten.\nexport async function writeExtractionErrors(\n  errors: ExtractionError[],\n  errorsPath: string,\n): Promise<void> {\n  if (errors.length === 0) return\n  await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n  const lines = errors.map((e) => JSON.stringify(e)).join('\\n') + '\\n'\n  await fs.appendFile(errorsPath, lines, 'utf8')\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #883 — extraction coverage in the query surface.\n//\n// errors.ndjson is append-only and shared with OTel error events, so it can't\n// answer \"is the CURRENT graph complete?\" — its extract lines accumulate across\n// every pass. This sidecar is overwritten each full pass (zero included), so it\n// always reflects the latest coverage, and a daemon reads it to put the count on\n// /health. Without it, a partial extraction is invisible to anything querying\n// the graph.\n// ─────────────────────────────────────────────────────────────────────────\n\n// The health sidecar sits beside errors.ndjson and mirrors its per-project\n// naming: errors.ndjson → extraction-health.json;\n// errors.<project>.ndjson → extraction-health.<project>.json.\nexport function extractionHealthPathFor(errorsPath: string): string {\n  const dir = path.dirname(errorsPath)\n  const suffix = path.basename(errorsPath).replace(/^errors/, '').replace(/\\.ndjson$/, '')\n  return path.join(dir, `extraction-health${suffix}.json`)\n}\n\n// Up to this many failed-file paths are sampled into the sidecar; the count is\n// always exact, the list is a bounded aid.\nconst HEALTH_FILE_SAMPLE = 100\n\n// Overwrite the sidecar with this pass's coverage. Called on every full pass so\n// a clean re-run clears a prior gap (skippedFiles: 0). Best-effort at the call\n// site; failure to write never fails extraction.\nexport async function writeExtractionHealth(\n  errors: ExtractionError[],\n  healthPath: string,\n  now: string = new Date().toISOString(),\n): Promise<void> {\n  const byProducer: Record<string, number> = {}\n  for (const e of errors) byProducer[e.producer] = (byProducer[e.producer] ?? 0) + 1\n  const coverage: ExtractionCoverage = {\n    skippedFiles: errors.length,\n    byProducer,\n    files: errors.slice(0, HEALTH_FILE_SAMPLE).map((e) => e.file),\n    updatedAt: now,\n  }\n  await fs.mkdir(path.dirname(healthPath), { recursive: true })\n  await fs.writeFile(healthPath, JSON.stringify(coverage), 'utf8')\n}\n\n// Read the coverage sidecar. Returns undefined when absent or malformed —\n// discovery is convenience, never fatal, so a missing/garbled file just means\n// \"no recorded coverage,\" not an error.\nexport async function readExtractionHealth(\n  healthPath: string,\n): Promise<ExtractionCoverage | undefined> {\n  let raw: string\n  try {\n    raw = await fs.readFile(healthPath, 'utf8')\n  } catch {\n    return undefined\n  }\n  try {\n    const obj = JSON.parse(raw) as ExtractionCoverage\n    if (typeof obj?.skippedFiles !== 'number' || !obj.byProducer || !Array.isArray(obj.files)) {\n      return undefined\n    }\n    return obj\n  } catch {\n    return undefined\n  }\n}\n\n// ADR-065 — `NEAT_STRICT_EXTRACTION=1` makes any per-file extraction failure\n// cause the calling command to exit non-zero. Default is forgiving (banner\n// only). The check is at the caller (cli.ts / server.ts / watch.ts) so the\n// extraction phase itself stays library-shaped.\nexport function isStrictExtractionEnabled(): boolean {\n  const raw = process.env.NEAT_STRICT_EXTRACTION\n  return raw === '1' || raw === 'true'\n}\n\n// Format the unconditional summary banner. Zero errors is a positive signal\n// (\"0 files skipped\") so callers print this even on clean runs.\nexport function formatExtractionBanner(count: number): string {\n  if (count === 1) return `[neat] 1 file skipped due to parse errors`\n  return `[neat] ${count} files skipped due to parse errors`\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// ADR-066 — precision-floor drop accounting.\n//\n// EXTRACTED candidates whose graded confidence falls below\n// NEAT_EXTRACTED_PRECISION_FLOOR (default 0.7) are computed but never added\n// to the graph. The drop count surfaces on the extraction banner;\n// NEAT_EXTRACTED_REJECTED_LOG=1 routes the per-candidate detail to\n// `<projectDir>/neat-out/rejected.ndjson`. The default keeps the sidecar\n// surface quiet.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface DroppedExtractedEdge {\n  source: string\n  target: string\n  type: string\n  confidence: number\n  confidenceKind: string\n  evidence: EdgeEvidence\n}\n\nconst droppedSink: DroppedExtractedEdge[] = []\n\nexport function noteExtractedDropped(edge: DroppedExtractedEdge): void {\n  droppedSink.push(edge)\n}\n\nexport function drainDroppedExtracted(): DroppedExtractedEdge[] {\n  return droppedSink.splice(0, droppedSink.length)\n}\n\nexport function pendingDroppedExtracted(): number {\n  return droppedSink.length\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #1258 — files read but deliberately not parsed.\n//\n// A minified bundle is machine output: thousands of one-character declarations\n// on a single line, each of which would mint a SymbolNode nobody can navigate\n// to. The file still exists in the graph — its FileNode is a true fact about\n// the repo — but nothing is extracted *from* it. Silently doing that would be\n// worse than the symbols, so the skip is counted and named the way a parse\n// error or a precision-floor drop is.\n\nexport interface SkippedSourceFile {\n  path: string\n  reason: 'minified'\n  detail: string\n}\n\n// Keyed by path, because every producer reads the tree separately: symbols,\n// calls, routes, imports, actions, zod and the edge builders each come through\n// `loadSourceFiles`, so one skipped file is noted once per producer. Counting\n// reads instead of files reported six minified files in a repo that had one.\nconst skippedSink = new Map<string, SkippedSourceFile>()\n\nexport function noteSkippedFile(file: SkippedSourceFile): void {\n  if (!skippedSink.has(file.path)) skippedSink.set(file.path, file)\n}\n\nexport function drainSkippedFiles(): SkippedSourceFile[] {\n  const out = [...skippedSink.values()]\n  skippedSink.clear()\n  return out\n}\n\nexport function pendingSkippedFiles(): number {\n  return skippedSink.size\n}\n\n// Silent on zero — unlike the parse banner, which reports a clean run as\n// evidence it ran. A repo with no minified files should say nothing about them.\nexport function formatSkippedBanner(count: number): string | null {\n  if (count <= 0) return null\n  if (count === 1) return `[neat] 1 minified file read but not parsed (FileNode kept, no symbols or calls)`\n  return `[neat] ${count} minified files read but not parsed (FileNodes kept, no symbols or calls)`\n}\n\nexport function isRejectedLogEnabled(): boolean {\n  const raw = process.env.NEAT_EXTRACTED_REJECTED_LOG\n  return raw === '1' || raw === 'true'\n}\n\nexport async function writeRejectedExtracted(\n  drops: DroppedExtractedEdge[],\n  rejectedPath: string,\n): Promise<void> {\n  if (drops.length === 0) return\n  await fs.mkdir(path.dirname(rejectedPath), { recursive: true })\n  const lines = drops.map((d) => JSON.stringify({ ...d, ts: new Date().toISOString() })).join('\\n') + '\\n'\n  await fs.appendFile(rejectedPath, lines, 'utf8')\n}\n\nexport function formatPrecisionFloorBanner(count: number): string {\n  if (count === 1) return `[neat] 1 extracted edge dropped below precision floor`\n  return `[neat] ${count} extracted edges dropped below precision floor`\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { EdgeEvidence, ExtractedConfidenceKind, FileNode, GraphEdge } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  fileId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { noteSkippedFile } from '../errors.js'\nimport { loadIgnoreChain, extendIgnoreChain, isIgnored, decide, type IgnoreChain } from '../gitignore.js'\nimport {\n  IGNORED_DIRS,\n  SERVICE_FILE_EXTENSIONS,\n  isNeatAuthoredSourceFile,\n  isPythonVenvDir,\n  type DiscoveredService,\n} from '../shared.js'\n\n// Host → owning ServiceNode id, the cross-service resolution the HTTP call-site\n// producers share (ADR-065 #5, ADR-119). A service is reachable by either its\n// directory basename or its manifest name; both map to the same node id. Reused\n// by http.ts (host-level CALLS edges) and route-match.ts (client↔route\n// matching) so the two producers resolve a URL's host to a service identically.\nexport interface ServiceHostIndex {\n  knownHosts: Set<string>\n  hostToNodeId: Map<string, string>\n}\n\nexport function buildServiceHostIndex(services: DiscoveredService[]): ServiceHostIndex {\n  const knownHosts = new Set<string>()\n  const hostToNodeId = new Map<string, string>()\n  for (const service of services) {\n    const base = path.basename(service.dir)\n    knownHosts.add(base)\n    knownHosts.add(service.pkg.name)\n    hostToNodeId.set(base, service.node.id)\n    hostToNodeId.set(service.pkg.name, service.node.id)\n  }\n  return { knownHosts, hostToNodeId }\n}\n\nexport interface SourceFile {\n  path: string\n  content: string\n}\n\nexport interface ExternalEndpoint {\n  // Stable id of the InfraNode this evidence implies. Format\n  // `infra:<kind>:<name>` so the orchestrator can dedupe across services.\n  infraId: string\n  // Display name on the InfraNode (e.g., \"orders\" for kafka-topic:orders).\n  name: string\n  kind: string\n  edgeType: 'CALLS' | 'PUBLISHES_TO' | 'CONSUMES_FROM'\n  evidence: EdgeEvidence\n  // Confidence grade per ADR-066 — set by the per-shape detector. The\n  // orchestrator (calls/index.ts) writes this onto the EXTRACTED edge and\n  // applies the precision floor before adding the edge to the graph.\n  confidenceKind: ExtractedConfidenceKind\n  // Declared schema columns for a `sql-table` endpoint (ADR-157 §3), at\n  // database-name fidelity. Set only by a schema-column producer (the Drizzle\n  // recognizer today); the orchestrator folds these onto the table node's\n  // `columns` list with EXTRACTED provenance. Absent on every other endpoint.\n  columns?: string[]\n  // Per-written-field SDK tags for a `firestore-collection` endpoint (ADR-167):\n  // which SDK (`client` = firebase/firestore, `admin` = firebase-admin/firestore)\n  // wrote each field. Set only by calls/firestore.ts; the orchestrator folds these\n  // onto the collection node's columns via `foldSdkWrites` (the parallel of the\n  // `columns` fold — `foldColumns` stays untouched). The write-SDK dimension is the\n  // seam the field-guard policy (ADR-169) joins on. Absent on every other endpoint.\n  sdkWrites?: Record<string, ('client' | 'admin')[]>\n}\n\n// A foreign-key relationship between two SQL tables (ADR-161) — the data-axis\n// sibling of a symbol INHERITS edge. `childTable` declares the FK, `parentTable`\n// is the referenced table; both are the DATABASE table name (the fusion key\n// `infra:sql-table:<name>` the column/table extractors and OTLP already target),\n// reproduced verbatim the way the ORM names the table, not the code model name.\n// A schema-FK producer (Drizzle / Prisma / SQLAlchemy) emits one per resolved\n// reference; a computed or unresolvable parent is left unclaimed (the producer\n// returns nothing), never guessed. `table-edges.ts` mints the EXTRACTED\n// `child ──REFERENCES──▶ parent` edge from these, with `evidence` pinned to the\n// FK declaration site.\nexport interface TableReference {\n  childTable: string\n  parentTable: string\n  evidence: EdgeEvidence\n}\n\n// ADR-200 — nearest-service-wins ownership. `excludeDirs` names the subtrees this\n// walk must not descend into: the dirs of other discovered services nested under\n// `dir`. Skipping the subtree at its root drops every file beneath it, so an\n// ancestor service never re-enumerates a nested service's source. Default empty —\n// a single-service or leaf walk is unchanged.\n// A gitignored path is absent from the graph, not present-but-unextracted\n// (#1255): the walk never yields it, so no FileNode is minted and no recogniser\n// runs over it. Directory-level pruning is how git thinks about it and the\n// cheaper shape — skipping `dist/` at its root costs one test, not one per file\n// underneath.\n// `extensions` defaults to the source languages; the flag-file walk (ADR-242)\n// passes `.json` to reuse the same gitignore-aware traversal.\nexport async function walkSourceFiles(\n  dir: string,\n  excludeDirs: string[] = [],\n  extensions: ReadonlySet<string> = SERVICE_FILE_EXTENSIONS,\n): Promise<string[]> {\n  const excluded = new Set(excludeDirs.map((d) => path.resolve(d)))\n  const out: string[] = []\n  // The rules governing `dir` itself: every `.gitignore` from the repo root\n  // down. A service nested in a monorepo inherits its ancestors' rules the same\n  // way it would on the command line.\n  const rootChain = await loadIgnoreChain(dir)\n  async function walk(current: string, inherited: IgnoreChain): Promise<void> {\n    const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n    // This directory's own `.gitignore` governs everything below it. Reading the\n    // listing we already have beats probing for the file: a blind `readFile` per\n    // directory is a failed open on almost every one of them, and on a repo the\n    // size of this one that alone doubled the walk.\n    const chain = entries.some((e) => e.isFile() && e.name === '.gitignore')\n      ? await extendIgnoreChain(inherited, current)\n      : inherited\n    for (const entry of entries) {\n      const full = path.join(current, entry.name)\n      if (entry.isDirectory()) {\n        if (IGNORED_DIRS.has(entry.name)) continue\n        if (excluded.has(path.resolve(full))) continue\n        // `subtree` is the chain minus anything a deeper rule overrode for this\n        // directory, so a re-included dir isn't re-excluded file by file.\n        const verdict = decide(chain, full, true)\n        if (verdict.ignored) continue\n        if (await isPythonVenvDir(full)) continue\n        await walk(full, verdict.subtree)\n      } else if (\n        entry.isFile() &&\n        extensions.has(path.extname(entry.name)) &&\n        // Skip NEAT's own generated `otel-init.*` bootstrap — extracting it\n        // would attribute our instrumentation imports to the user's service.\n        !isNeatAuthoredSourceFile(entry.name) &&\n        !excluded.has(path.resolve(full)) &&\n        !isIgnored(chain, full, false)\n      ) {\n        out.push(full)\n      }\n    }\n  }\n  // `loadIgnoreChain` already includes `dir`'s own file, and `walk` would add it\n  // a second time from the listing — harmless but pointless, so start from the\n  // chain above it and let the walk pick `dir`'s up like every other directory.\n  await walk(dir, rootChain.filter((l) => path.resolve(l.dir) !== path.resolve(dir)))\n  return out\n}\n\n// Hand-written source does not put five thousand characters on one line.\n// Measured across this repo — 632 source files — the longest legitimate line is\n// 2,977 characters, an inline SVG path, and nothing else exceeds 3,000. A\n// minified chunk runs to 100,000+ on a single line. The threshold sits between\n// the two with room on both sides rather than at either edge (#1258).\nconst MINIFIED_LINE_CHARS = 5_000\n\n/** `*.min.js` and friends — the convention, checked before the content. */\nfunction hasMinifiedName(filePath: string): boolean {\n  return /\\.min\\.(js|mjs|cjs|jsx|ts|tsx)$/i.test(filePath)\n}\n\n/**\n * Is this machine output rather than something a person wrote?\n *\n * Two signals, either sufficient: the `.min.` naming convention, and a line too\n * long to have been typed. The line test is what catches an unnamed bundle —\n * `main-4f2a.js` under a build directory follows no convention at all — and is\n * measured without splitting the file, so a 200 KB one-liner costs one scan and\n * not a 200 KB array.\n */\nexport function isMinifiedSource(\n  filePath: string,\n  content: string,\n): { minified: boolean; detail: string } {\n  if (hasMinifiedName(filePath)) return { minified: true, detail: 'named *.min.js' }\n  let longest = 0\n  let start = 0\n  for (;;) {\n    const nl = content.indexOf('\\n', start)\n    const len = (nl === -1 ? content.length : nl) - start\n    if (len > longest) longest = len\n    if (nl === -1) break\n    start = nl + 1\n  }\n  if (longest > MINIFIED_LINE_CHARS) {\n    return { minified: true, detail: `longest line ${longest} chars` }\n  }\n  return { minified: false, detail: '' }\n}\n\n// The one place every producer reads file *contents* — symbols, calls, routes,\n// imports, actions, zod and the edge builders all come through here, while\n// `addFiles` takes paths from `walkSourceFiles`. So skipping a minified file\n// here leaves its FileNode standing, which is a true fact about the repo, and\n// stops anything being extracted from it. That is exactly the split #1258 asks\n// for, in one place rather than eleven.\nexport async function loadSourceFiles(\n  dir: string,\n  excludeDirs: string[] = [],\n): Promise<SourceFile[]> {\n  const paths = await walkSourceFiles(dir, excludeDirs)\n  const out: SourceFile[] = []\n  for (const p of paths) {\n    try {\n      const content = await fs.readFile(p, 'utf8')\n      const verdict = isMinifiedSource(p, content)\n      if (verdict.minified) {\n        noteSkippedFile({ path: p, reason: 'minified', detail: verdict.detail })\n        continue\n      }\n      out.push({ path: p, content })\n    } catch {\n      // unreadable, skip\n    }\n  }\n  return out\n}\n\n// Locate the line of the first occurrence of `needle` in `text`, 1-indexed.\n// Falls back to line 1 if the needle isn't found verbatim — better to point at\n// the file than to drop the evidence entirely.\nexport function lineOf(text: string, needle: string): number {\n  const idx = text.indexOf(needle)\n  if (idx < 0) return 1\n  return text.slice(0, idx).split('\\n').length\n}\n\n// static-extraction.md §evidence: `snippet?: string // small source fragment,\n// max ~120 chars`. The cap is the contract's, not a new rule — evidence is a\n// pointer to the source, and the source is already on disk at `file:line`.\n//\n// Uncapped, the snippet is the whole line, and one line is not bounded by\n// anything: a minified bundle can put a 227 KB file on a single line, and every\n// edge into that file then carries the entire file. A real repo reached 1,012 MB\n// of edges that way and the snapshot could not be written at all (#1254).\nconst SNIPPET_MAX_CHARS = 120\n\nexport function snippet(text: string, line: number): string {\n  const lines = text.split('\\n')\n  const raw = (lines[line - 1] ?? '').trim()\n  if (raw.length <= SNIPPET_MAX_CHARS) return raw\n  // Say it was cut and by how much, so a reader can tell a truncated fragment\n  // from a genuinely short line — and spot a minified file for what it is.\n  return `${raw.slice(0, SNIPPET_MAX_CHARS)}… (+${raw.length - SNIPPET_MAX_CHARS} chars)`\n}\n\n// Forward-slash a path so a FileNode id is byte-stable across platforms (the\n// `relPath` segment of `file:<service>:<relPath>` must not vary by OS).\nexport function toPosix(p: string): string {\n  return p.split('\\\\').join('/')\n}\n\n// Extension → language tag for a FileNode. Returns undefined for extensions we\n// don't name rather than guessing — evidence is never fabricated (§6).\nexport function languageForPath(relPath: string): string | undefined {\n  switch (path.extname(relPath).toLowerCase()) {\n    case '.py':\n      return 'python'\n    case '.go':\n      return 'go'\n    case '.rb':\n      return 'ruby'\n    case '.php':\n      return 'php'\n    case '.cs':\n      return 'csharp'\n    case '.java':\n      return 'java'\n    case '.kt':\n      return 'kotlin'\n    case '.rs':\n      return 'rust'\n    case '.cpp':\n    case '.cc':\n    case '.cxx':\n    case '.c++':\n    case '.hpp':\n    case '.hh':\n    case '.hxx':\n    case '.h++':\n      return 'cpp'\n    case '.ts':\n    case '.tsx':\n      return 'typescript'\n    case '.js':\n    case '.jsx':\n    case '.mjs':\n    case '.cjs':\n      return 'javascript'\n    default:\n      return undefined\n  }\n}\n\n// File-first emission (file-awareness.md §1–2). Ensure the FileNode for\n// `relPath` and the owning `service ──CONTAINS──▶ file` edge both exist, then\n// return the FileNode id so the caller can originate a relationship from it.\n// `relPath` must already be service-relative and forward-slashed (use toPosix).\n// CONTAINS is structural ownership — graded at the 'structural' tier like\n// CONFIGURED_BY, never a flat value. Idempotent: re-running extraction over an\n// unchanged file is a no-op.\n/**\n * What this pass is extracting FROM (ADR-233) — a token that outlives the\n * directory being read: the bound repo hosted, the project name locally.\n *\n * Pass-scoped module state, like the ignore chain and the skipped-file sink in\n * this file. `extractFromDirectory` sets it at the start of a pass and clears it\n * at the end, so every producer stamps the same source without threading an\n * argument through all of them. Unset means no source was named, and the retire\n * sweep then behaves exactly as it always has.\n */\nlet currentSource: string | undefined\n\nexport function setExtractionSource(source: string | undefined): void {\n  currentSource = source\n}\n\nexport function extractionSource(): string | undefined {\n  return currentSource\n}\n\nexport function ensureFileNode(\n  graph: NeatGraph,\n  serviceName: string,\n  serviceNodeId: string,\n  relPath: string,\n): { fileNodeId: string; nodesAdded: number; edgesAdded: number } {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  const fileNodeId = fileId(serviceName, relPath)\n  if (!graph.hasNode(fileNodeId)) {\n    const language = languageForPath(relPath)\n    const node: FileNode = {\n      id: fileNodeId,\n      type: NodeType.FileNode,\n      service: serviceName,\n      path: relPath,\n      ...(language ? { language } : {}),\n      ...(currentSource ? { source: currentSource } : {}),\n      discoveredVia: 'static',\n    }\n    graph.addNode(fileNodeId, node)\n    nodesAdded++\n  } else if (currentSource) {\n    // A file this pass just read belongs to this pass's source, whoever minted\n    // the node — a snapshot restored from before sources existed, or a repo\n    // re-bound under a different name. Claiming it here is what keeps the next\n    // pass from reading it as another source's and leaving it untouched forever.\n    const existing = graph.getNodeAttributes(fileNodeId) as FileNode\n    if (existing.source !== currentSource) {\n      graph.replaceNodeAttributes(fileNodeId, { ...existing, source: currentSource })\n    }\n  }\n  const containsId = extractedEdgeId(serviceNodeId, fileNodeId, EdgeType.CONTAINS)\n  if (!graph.hasEdge(containsId)) {\n    const edge: GraphEdge = {\n      id: containsId,\n      source: serviceNodeId,\n      target: fileNodeId,\n      type: EdgeType.CONTAINS,\n      provenance: Provenance.EXTRACTED,\n      confidence: confidenceForExtracted('structural'),\n      evidence: { file: relPath },\n    }\n    graph.addEdgeWithKey(containsId, serviceNodeId, fileNodeId, edge)\n    edgesAdded++\n  }\n  return { fileNodeId, nodesAdded, edgesAdded }\n}\n","// `.gitignore`, the way git reads it: the file in every directory from the repo\n// root down to the one being walked, with a deeper file able to override a\n// shallower one.\n//\n// Service discovery honoured the root `.gitignore` and file enumeration honoured\n// nothing (#1255), so a gitignored directory was skipped when looking for\n// services and then walked in full when collecting one service's files. A built\n// bundle under an ignored path came into the graph as first-party source, and\n// the first anyone knew was a snapshot too large to write (#1254).\n//\n// Root *and* nested matters for the shape NEAT is usually pointed at: a monorepo\n// whose packages carry their own `.gitignore`, and a service directory that sits\n// well below the repo root. Walking up to the repo root is what makes an\n// ancestor's rules apply to a service nested under it, with no scan-root\n// plumbing through `addFiles` → `walkSourceFiles`.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport ignore, { type Ignore } from 'ignore'\n\n/** One `.gitignore`, and the directory its patterns are relative to. */\nexport interface IgnoreLayer {\n  dir: string\n  ig: Ignore\n}\n\n/** Layers outermost first — the order git resolves them in. */\nexport type IgnoreChain = readonly IgnoreLayer[]\n\n// One process-lifetime cache of \"what does this directory's .gitignore say\".\n// The walk asks per directory, and a miss is a failed `readFile`; without this\n// a deep tree pays that on every descent. `null` records \"no file here\", which\n// is the common answer and worth remembering too.\nconst LAYER_CACHE = new Map<string, IgnoreLayer | null>()\n\n/** Reset between scans in tests; the cache is keyed by absolute path. */\nexport function clearIgnoreCache(): void {\n  LAYER_CACHE.clear()\n}\n\nasync function layerFor(dir: string): Promise<IgnoreLayer | null> {\n  const cached = LAYER_CACHE.get(dir)\n  if (cached !== undefined) return cached\n  let layer: IgnoreLayer | null = null\n  try {\n    const raw = await fs.readFile(path.join(dir, '.gitignore'), 'utf8')\n    layer = { dir, ig: ignore().add(raw) }\n  } catch {\n    layer = null\n  }\n  LAYER_CACHE.set(dir, layer)\n  return layer\n}\n\nasync function isRepoRoot(dir: string): Promise<boolean> {\n  try {\n    // `.git` is a directory in a normal clone and a file in a worktree or\n    // submodule, so existence is the test, not `isDirectory()`.\n    await fs.stat(path.join(dir, '.git'))\n    return true\n  } catch {\n    return false\n  }\n}\n\n/**\n * The chain governing `startDir`: every `.gitignore` from the repo root down to\n * it, outermost first.\n *\n * Stops at the directory holding `.git`, or at the filesystem root when there\n * isn't one — a scan of a plain directory still honours whatever `.gitignore`\n * files it contains, and never climbs into a parent project that has nothing to\n * do with it.\n */\nexport async function loadIgnoreChain(startDir: string): Promise<IgnoreChain> {\n  const dirs: string[] = []\n  let current = path.resolve(startDir)\n  for (;;) {\n    dirs.push(current)\n    if (await isRepoRoot(current)) break\n    const parent = path.dirname(current)\n    if (parent === current) break\n    current = parent\n  }\n  dirs.reverse() // outermost first\n  const layers: IgnoreLayer[] = []\n  for (const dir of dirs) {\n    const layer = await layerFor(dir)\n    if (layer) layers.push(layer)\n  }\n  return layers\n}\n\n/** The chain plus `dir`'s own `.gitignore`, if it has one. */\nexport async function extendIgnoreChain(chain: IgnoreChain, dir: string): Promise<IgnoreChain> {\n  const layer = await layerFor(path.resolve(dir))\n  return layer ? [...chain, layer] : chain\n}\n\n/**\n * Whether git would ignore this path.\n *\n * Layers are applied outermost first so a deeper `.gitignore` can re-include\n * something an ancestor excluded — `ignore`'s `test()` reports an explicit\n * un-ignore, which a plain boolean `ignores()` cannot. A path outside a layer's\n * directory is not that layer's business and is skipped.\n */\nexport function isIgnored(chain: IgnoreChain, fullPath: string, isDir: boolean): boolean {\n  return decide(chain, fullPath, isDir).ignored\n}\n\n/**\n * The verdict, plus the chain that governs this path's subtree.\n *\n * git prunes at the directory: an excluded directory is never descended into, so\n * a pattern like `build/` excludes what's underneath by never looking rather\n * than by matching each file. That distinction is load-bearing once a deeper\n * `.gitignore` re-includes such a directory — git then walks it, and the\n * ancestor's `build/` does not apply to the files inside, because it matches a\n * directory named `build` and not `build/keep.js`. Testing each file against the\n * whole chain independently would re-exclude them and quietly lose the\n * re-include, so a layer that explicitly un-ignores a directory also ends the\n * reach of everything above it for that subtree.\n */\nexport function decide(\n  chain: IgnoreChain,\n  fullPath: string,\n  isDir: boolean,\n): { ignored: boolean; subtree: IgnoreChain } {\n  if (chain.length === 0) return { ignored: false, subtree: chain }\n  const abs = path.resolve(fullPath)\n  let ignored = false\n  let unignoredAt = -1\n  for (let i = 0; i < chain.length; i++) {\n    const layer = chain[i]!\n    const rel = path.relative(layer.dir, abs)\n    // A path outside this layer's directory is not its business.\n    if (!rel || rel.startsWith('..') || path.isAbsolute(rel)) continue\n    // Trailing slash so a directory pattern (`dist/`) matches; `ignore`\n    // distinguishes the file and directory tests.\n    const candidate = rel.split(path.sep).join('/') + (isDir ? '/' : '')\n    const result = layer.ig.test(candidate)\n    if (result.ignored) ignored = true\n    else if (result.unignored) {\n      ignored = false\n      unignoredAt = i\n    }\n  }\n  return {\n    ignored,\n    subtree: unignoredAt >= 0 ? chain.slice(unignoredAt) : chain,\n  }\n}\n","import { readGoModule } from './go.js'\nimport path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport Python from 'tree-sitter-python'\nimport Go from 'tree-sitter-go'\nimport type { GraphEdge } from '@neat.is/types'\nimport {\n  EdgeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  fileId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, toPosix } from './calls/shared.js'\n\n// Phase 2 — import graph extraction (ADR-092, file-awareness.md §10). Walks\n// every source file's AST for import / require statements and emits IMPORTS\n// edges between FileNodes within the same service. Cross-service and\n// unresolvable specifiers are silent skips — Phase 3's CALLS producers cover\n// the cross-service case where an external-call pattern matches.\n\n// Same chunked-parse approach as calls/shared.ts — tree-sitter's bare string\n// path throws \"Invalid argument\" once the source clears ~32K code units. The\n// callback form streams the source in bounded slices instead.\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction makeJsParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(JavaScript)\n  return p\n}\n\nfunction makePyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Python)\n  return p\n}\n\nfunction makeGoParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Go)\n  return p\n}\n\n// ── string-literal text ────────────────────────────────────────────────────\n\n// The interior text of a string literal node, stripped of quote characters.\n// tree-sitter-javascript wraps the content in a `string_fragment` child;\n// fall back to slicing the raw text when that shape isn't present (e.g. an\n// empty string literal has no fragment child at all).\nfunction stringLiteralText(node: Parser.SyntaxNode): string | null {\n  for (let i = 0; i < node.childCount; i++) {\n    const child = node.child(i)\n    if (child?.type === 'string_fragment') return child.text\n  }\n  const raw = node.text\n  if (raw.length >= 2) return raw.slice(1, -1)\n  return raw.length === 0 ? null : ''\n}\n\nfunction clipSnippet(text: string): string {\n  const oneLine = text.split('\\n')[0] ?? text\n  return oneLine.length > 120 ? oneLine.slice(0, 120) : oneLine\n}\n\n// ── JS / TS import collection ──────────────────────────────────────────────\n\ninterface RawImport {\n  specifier: string\n  line: number // 1-indexed\n  snippet: string\n}\n\nfunction collectGoImports(node: Parser.SyntaxNode, out: RawImport[]): void {\n  if (node.type === 'import_spec') {\n    const pathNode = node.childForFieldName('path')\n    if (pathNode) {\n      const specifier = pathNode.text.replace(/^`|`$/g, '').replace(/^\"|\"$/g, '')\n      if (specifier) out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n    }\n    return\n  }\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) collectGoImports(child, out)\n  }\n}\n\n// Walks the AST for `import ... from 'spec'` / `import 'spec'` (ES modules)\n// and `require('spec')` (CommonJS). Doesn't recurse into import_statement —\n// its only string child is the source specifier, never a nested import.\nfunction collectJsImports(node: Parser.SyntaxNode, out: RawImport[]): void {\n  if (node.type === 'import_statement') {\n    const source = node.childForFieldName('source')\n    if (source) {\n      const specifier = stringLiteralText(source)\n      if (specifier) {\n        out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n      }\n    }\n    return\n  }\n\n  if (node.type === 'call_expression') {\n    const fn = node.childForFieldName('function')\n    if (fn?.type === 'identifier' && fn.text === 'require') {\n      const args = node.childForFieldName('arguments')\n      const firstArg = args?.namedChild(0)\n      if (firstArg?.type === 'string') {\n        const specifier = stringLiteralText(firstArg)\n        if (specifier) {\n          out.push({ specifier, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n        }\n      }\n    }\n  }\n\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) collectJsImports(child, out)\n  }\n}\n\n// ── Python import collection ───────────────────────────────────────────────\n\ninterface RawPyImport {\n  modulePath: string // dotted path with the leading dots stripped, e.g. 'utils.auth'\n  level: number // count of leading dots; 0 = absolute import\n  names: string[] // the imported names after `import` — each may be a submodule\n  line: number\n  snippet: string\n}\n\n// Collects the imported names from the tail of a `from`-import — the part\n// after the `import` keyword. Pushes each `name` (and the original name of an\n// `as`-aliased import); descends into a parenthesised list so `from app import\n// (config, db)` reads the same as the unparenthesised form. A wildcard `*`\n// has no name and is left for the module-file fallback in resolution.\nfunction collectImportedNames(node: Parser.SyntaxNode, out: string[]): void {\n  if (node.type === 'aliased_import') {\n    const nameNode = node.childForFieldName('name')\n    if (nameNode) out.push(nameNode.text)\n    return\n  }\n  if (node.type === 'dotted_name') {\n    out.push(node.text)\n    return\n  }\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) collectImportedNames(child, out)\n  }\n}\n\n// Walks the AST for `from X import a, b` / `from .X import a`. Bare `import X`\n// statements name modules without resolving to a single file (`import os.path`\n// doesn't tell us which file in `os` got used), so Phase 2 limits itself to\n// the `from`-form per the resolution rules in the contract. The imported names\n// matter: `from app import config` names the `config` submodule, not a symbol\n// on `app/__init__.py`, so resolution keys on them (see resolvePyImport).\nfunction collectPyImports(node: Parser.SyntaxNode, out: RawPyImport[]): void {\n  if (node.type === 'import_from_statement') {\n    let level = 0\n    let modulePath = ''\n    const names: string[] = []\n    let pastFrom = false\n    let pastImport = false\n\n    for (let i = 0; i < node.childCount; i++) {\n      const child = node.child(i)\n      if (!child) continue\n      if (!pastFrom) {\n        if (child.type === 'from') pastFrom = true\n        continue\n      }\n      if (!pastImport) {\n        if (child.type === 'import') {\n          pastImport = true\n          continue\n        }\n        // The `from`-module spec, before the `import` keyword.\n        if (child.type === 'relative_import') {\n          for (let j = 0; j < child.childCount; j++) {\n            const rc = child.child(j)\n            if (!rc) continue\n            // tree-sitter-python groups every leading dot into a single\n            // import_prefix node — `..` parses as one import_prefix with two\n            // `.` children, not two import_prefix nodes. Count the `.` tokens,\n            // not the prefix nodes, or multi-dot imports under-count `level`\n            // and resolve onto the wrong (sometimes self) target (#457).\n            if (rc.type === 'import_prefix') {\n              for (let k = 0; k < rc.childCount; k++) {\n                if (rc.child(k)?.type === '.') level++\n              }\n            } else if (rc.type === 'dotted_name') modulePath = rc.text\n          }\n        } else if (child.type === 'dotted_name') {\n          modulePath = child.text\n        }\n        continue\n      }\n      // Past the `import` keyword — the imported names.\n      collectImportedNames(child, names)\n    }\n\n    if (level > 0 || modulePath) {\n      out.push({ modulePath, level, names, line: node.startPosition.row + 1, snippet: clipSnippet(node.text) })\n    }\n  }\n\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) collectPyImports(child, out)\n  }\n}\n\n// ── filesystem resolution helpers ──────────────────────────────────────────\n\nasync function fileExists(p: string): Promise<boolean> {\n  try {\n    await fs.access(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\n// An import that escapes the service directory (`../../other-service/x`)\n// isn't an intra-service edge — Phase 2 is scoped to within-service module\n// dependencies (file-awareness.md §10).\nfunction isWithinServiceDir(candidate: string, serviceDir: string): boolean {\n  const rel = path.relative(serviceDir, candidate)\n  return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel)\n}\n\nconst JS_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nconst JS_INDEX_FILES = JS_EXTENSIONS.map((ext) => `index${ext}`)\n\n// Try `base`, `base.<ext>`, and `base/index.<ext>` in TypeScript-resolution\n// order. Returns the service-relative posix path of the first hit.\nasync function firstExistingCandidate(\n  base: string,\n  serviceDir: string,\n): Promise<string | null> {\n  for (const ext of JS_EXTENSIONS) {\n    const candidate = base + ext\n    if (isWithinServiceDir(candidate, serviceDir) && (await fileExists(candidate))) {\n      return toPosix(path.relative(serviceDir, candidate))\n    }\n  }\n  for (const indexFile of JS_INDEX_FILES) {\n    const candidate = path.join(base, indexFile)\n    if (isWithinServiceDir(candidate, serviceDir) && (await fileExists(candidate))) {\n      return toPosix(path.relative(serviceDir, candidate))\n    }\n  }\n  return null\n}\n\nexport interface TsPathConfig {\n  paths: Record<string, string[]>\n  baseDir: string // absolute directory compilerOptions.baseUrl resolves against\n}\n\n// `tsconfig.json` at the service root. The contract names scanPath as a\n// fallback location too, but every discovered service already carries its own\n// root — the scanPath fallback only matters for configs that live above the\n// service tree, which the resolver doesn't have a path back to from here.\nexport async function loadTsPathConfig(serviceDir: string): Promise<TsPathConfig | null> {\n  const tsconfigPath = path.join(serviceDir, 'tsconfig.json')\n  let raw: string\n  try {\n    raw = await fs.readFile(tsconfigPath, 'utf8')\n  } catch {\n    return null\n  }\n  try {\n    const parsed = JSON.parse(raw) as {\n      compilerOptions?: { paths?: Record<string, string[]>; baseUrl?: string }\n    }\n    const paths = parsed.compilerOptions?.paths\n    if (!paths || Object.keys(paths).length === 0) return null\n    const baseUrl = parsed.compilerOptions?.baseUrl\n    return { paths, baseDir: baseUrl ? path.resolve(serviceDir, baseUrl) : serviceDir }\n  } catch (err) {\n    recordExtractionError('import alias resolution', tsconfigPath, err)\n    return null\n  }\n}\n\n// Resolve a bare specifier against `compilerOptions.paths`. Matches the first\n// alias whose pattern fits — exact (`@db`) or wildcard (`@db/*`) — and tries\n// each mapped target in declaration order. No match anywhere → null, the\n// silent-skip the contract calls for.\nasync function resolveTsAlias(\n  specifier: string,\n  config: TsPathConfig,\n  serviceDir: string,\n): Promise<string | null> {\n  for (const [pattern, targets] of Object.entries(config.paths)) {\n    let suffix: string | null = null\n    if (pattern === specifier) {\n      suffix = ''\n    } else if (pattern.endsWith('/*')) {\n      const prefix = pattern.slice(0, -1) // keep the trailing '/'\n      if (specifier.startsWith(prefix)) suffix = specifier.slice(prefix.length)\n    }\n    if (suffix === null) continue\n\n    for (const target of targets) {\n      const targetBase = target.endsWith('/*') ? target.slice(0, -2) : target.replace(/\\*$/, '')\n      const resolvedBase = path.resolve(config.baseDir, targetBase, suffix)\n      const hit = await firstExistingCandidate(resolvedBase, serviceDir)\n      if (hit) return hit\n      // The candidate may already carry its own extension (`@db/mongo.ts`).\n      if (isWithinServiceDir(resolvedBase, serviceDir) && (await fileExists(resolvedBase))) {\n        return toPosix(path.relative(serviceDir, resolvedBase))\n      }\n    }\n  }\n  return null\n}\n\n// Resolves a JS/TS module specifier to a service-relative posix path, or\n// null when it names something outside the service (node_modules, Node\n// builtins, an alias with no tsconfig match, an escaping relative path).\n// Exported so the cross-file mongoose resolver (ADR-149) can reuse the same\n// specifier→FileNode resolution — extensions, index/barrel files, the .js→.ts\n// sibling convention — instead of re-implementing it. Relative specifiers\n// resolve without `tsPaths`; a bare specifier needs the alias table (pass null\n// to skip aliases).\nexport async function resolveJsImport(\n  specifier: string,\n  importerDir: string,\n  serviceDir: string,\n  tsPaths: TsPathConfig | null,\n): Promise<string | null> {\n  if (!specifier) return null\n\n  if (specifier.startsWith('./') || specifier.startsWith('../')) {\n    const base = path.resolve(importerDir, specifier)\n    const ext = path.extname(specifier)\n\n    if (ext) {\n      // `./foo.js` written against a `.ts` source — the TypeScript ESM\n      // convention of naming the post-build extension in source. Try the\n      // TS sibling before the literal path.\n      if (ext === '.js' || ext === '.jsx') {\n        const tsExt = ext === '.jsx' ? '.tsx' : '.ts'\n        const tsSibling = base.slice(0, -ext.length) + tsExt\n        if (isWithinServiceDir(tsSibling, serviceDir) && (await fileExists(tsSibling))) {\n          return toPosix(path.relative(serviceDir, tsSibling))\n        }\n      }\n      if (isWithinServiceDir(base, serviceDir) && (await fileExists(base))) {\n        return toPosix(path.relative(serviceDir, base))\n      }\n      // `path.extname` reads the tail of a dotted module name — `foo.controller`,\n      // `bar.model`, `x.service` (the NestJS / Angular / RealWorld convention) — as\n      // an extension, but the file on disk is `foo.controller.ts`. When the literal\n      // path doesn't exist and the \"extension\" isn't one we compile, the dot is part\n      // of the module name: resolve the whole specifier as extensionless.\n      if (!JS_EXTENSIONS.includes(ext)) {\n        return firstExistingCandidate(base, serviceDir)\n      }\n      return null\n    }\n\n    return firstExistingCandidate(base, serviceDir)\n  }\n\n  // Bare specifier — only a registered TS path alias can make this\n  // intra-service. Anything else is node_modules / a Node builtin.\n  if (tsPaths) return resolveTsAlias(specifier, tsPaths, serviceDir)\n  return null\n}\n\n// Resolves a Python `from`-import to the service-relative posix paths it\n// touches — one per imported module. Relative imports (level > 0) walk up from\n// the importing module's directory; absolute imports match against the service\n// source tree directly.\n//\n// `from app import config` names the `config` *submodule* (app/config.py), not\n// a symbol re-exported by app/__init__.py. Resolving the whole statement onto\n// the package's __init__.py was wrong: every intra-package import collapsed\n// onto one target and the per-(source,target) edge dedup then made the second\n// such dependency invisible. So we key on each imported name, resolving it to\n// its own module file, and fall back to the package/module file only for names\n// that aren't submodules (plain symbols, or a `*` wildcard).\nasync function resolvePyImport(\n  imp: RawPyImport,\n  importerPath: string,\n  serviceDir: string,\n): Promise<string[]> {\n  let baseDir: string\n  if (imp.level > 0) {\n    baseDir = path.dirname(importerPath)\n    for (let i = 1; i < imp.level; i++) baseDir = path.dirname(baseDir)\n  } else {\n    baseDir = serviceDir\n  }\n\n  // The on-disk base of the `from`-module. `from app import x` → app/ ;\n  // `from . import x` → the importer's own package directory (modulePath empty).\n  const moduleBase = imp.modulePath\n    ? path.join(baseDir, imp.modulePath.split('.').join('/'))\n    : baseDir\n\n  const resolved = new Set<string>()\n  let needModuleFile = imp.names.length === 0 // wildcard / unparsed → the module itself\n\n  for (const name of imp.names) {\n    const submoduleFile = path.join(moduleBase, `${name}.py`)\n    const subpackageInit = path.join(moduleBase, name, '__init__.py')\n    if (isWithinServiceDir(submoduleFile, serviceDir) && (await fileExists(submoduleFile))) {\n      resolved.add(toPosix(path.relative(serviceDir, submoduleFile)))\n    } else if (isWithinServiceDir(subpackageInit, serviceDir) && (await fileExists(subpackageInit))) {\n      resolved.add(toPosix(path.relative(serviceDir, subpackageInit)))\n    } else {\n      // Not a submodule — the name is a symbol defined in the module itself.\n      needModuleFile = true\n    }\n  }\n\n  if (needModuleFile) {\n    // An empty modulePath (`from . import x`) has no module file of its own —\n    // the package is the directory, so only its __init__.py applies.\n    const moduleFileCandidates = imp.modulePath\n      ? [`${moduleBase}.py`, path.join(moduleBase, '__init__.py')]\n      : [path.join(moduleBase, '__init__.py')]\n    for (const candidate of moduleFileCandidates) {\n      if (isWithinServiceDir(candidate, serviceDir) && (await fileExists(candidate))) {\n        resolved.add(toPosix(path.relative(serviceDir, candidate)))\n        break\n      }\n    }\n  }\n\n  return [...resolved]\n}\n\nasync function resolveGoImport(\n  specifier: string,\n  modulePath: string,\n  serviceDir: string,\n): Promise<string | null> {\n  if (specifier !== modulePath && !specifier.startsWith(`${modulePath}/`)) return null\n  const suffix = specifier === modulePath ? '' : specifier.slice(modulePath.length + 1)\n  const dir = path.join(serviceDir, suffix)\n  const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])\n  const candidates = entries\n    .filter((entry) => entry.isFile() && entry.name.endsWith('.go') && !entry.name.endsWith('_test.go'))\n    .map((entry) => path.join(dir, entry.name))\n  if (candidates.length !== 1) return null\n  return toPosix(path.relative(serviceDir, candidates[0]!))\n}\n\n// ── edge emission ──────────────────────────────────────────────────────────\n\nfunction emitImportEdge(\n  graph: NeatGraph,\n  serviceName: string,\n  importerFileId: string,\n  importerRelPath: string,\n  importeeRelPath: string,\n  line: number,\n  snippet: string,\n): number {\n  const importeeFileId = fileId(serviceName, importeeRelPath)\n  // Phase 1 enumerates every source file unconditionally; a resolved path\n  // that isn't a FileNode is outside SERVICE_FILE_EXTENSIONS or otherwise\n  // wasn't walked — not an intra-service module edge.\n  if (!graph.hasNode(importeeFileId)) return 0\n\n  // A file whose import resolves to itself (barrel re-export / path-alias cycle)\n  // is not a dependency edge, and a self-loop throws in graphology (allowSelfLoops\n  // is off) — which today kills the whole extraction. Skip it: a self-import is a\n  // non-edge, not a per-file failure worth logging. [surfaced extracting n8n]\n  if (importerFileId === importeeFileId) return 0\n\n  const edgeId = extractedEdgeId(importerFileId, importeeFileId, EdgeType.IMPORTS)\n  if (graph.hasEdge(edgeId)) return 0\n\n  const edge: GraphEdge = {\n    id: edgeId,\n    source: importerFileId,\n    target: importeeFileId,\n    type: EdgeType.IMPORTS,\n    provenance: Provenance.EXTRACTED,\n    confidence: confidenceForExtracted('structural'),\n    evidence: { file: importerRelPath, line, snippet },\n  }\n  graph.addEdgeWithKey(edgeId, importerFileId, importeeFileId, edge)\n  return 1\n}\n\n// ── producer ───────────────────────────────────────────────────────────────\n\nexport async function addImports(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const jsParser = makeJsParser()\n  const pyParser = makePyParser()\n  const goParser = makeGoParser()\n  let edgesAdded = 0\n\n  const goModulePaths = new Map<string, string | null>()\n  for (const service of services) {\n    const tsPaths = await loadTsPathConfig(service.dir)\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n\n    for (const file of files) {\n      // ADR-065 §1 — test-scope exclusion. The file stays a FileNode (Phase 1);\n      // only its outbound module edges are filtered (file-awareness.md §10).\n      if (isTestPath(file.path)) continue\n\n      const relFile = toPosix(path.relative(service.dir, file.path))\n      const importerFileId = fileId(service.pkg.name, relFile)\n      const isPython = path.extname(file.path) === '.py'\n      const isGo = path.extname(file.path) === '.go'\n\n      // Ruby is a route-and-service-grain pilot (ADR-173): `.rb` files are\n      // FileNodes and their routes.rb is read, but Ruby's autoload-driven\n      // require graph isn't modelled yet — parsing it with the JS grammar would\n      // fabricate nothing useful, so skip. Ruby import resolution is a later rung.\n      if (path.extname(file.path) === '.rb') continue\n\n      // PHP is a route-and-service-grain pilot (ADR-177): `.php` files are\n      // FileNodes and Laravel's routes/*.php are read, but PHP's PSR-4 autoload\n      // require graph isn't modelled yet — parsing it with the JS grammar would\n      // fabricate nothing useful, so skip. PHP import resolution is a later rung.\n      if (path.extname(file.path) === '.php') continue\n\n      if (isGo) {\n        let goImports: RawImport[] = []\n        try {\n          const tree = parseSource(goParser, file.content)\n          collectGoImports(tree.rootNode, goImports)\n        } catch (err) {\n          recordExtractionError('import extraction', file.path, err)\n          continue\n        }\n        // go.mod's module line, or a dep-layout repo's inferred import path (ADR-256).\n        let modulePath = goModulePaths.get(service.dir)\n        if (modulePath === undefined) {\n          modulePath = (await readGoModule(service.dir))?.module ?? null\n          goModulePaths.set(service.dir, modulePath)\n        }\n        if (!modulePath) continue\n        for (const imp of goImports) {\n          const resolved = await resolveGoImport(imp.specifier, modulePath, service.dir)\n          if (!resolved) continue\n          edgesAdded += emitImportEdge(graph, service.pkg.name, importerFileId, relFile, resolved, imp.line, imp.snippet)\n        }\n        continue\n      }\n\n      if (isPython) {\n        let pyImports: RawPyImport[] = []\n        try {\n          const tree = parseSource(pyParser, file.content)\n          collectPyImports(tree.rootNode, pyImports)\n        } catch (err) {\n          recordExtractionError('import extraction', file.path, err)\n          continue\n        }\n        for (const imp of pyImports) {\n          const resolvedPaths = await resolvePyImport(imp, file.path, service.dir)\n          for (const resolved of resolvedPaths) {\n            edgesAdded += emitImportEdge(\n              graph,\n              service.pkg.name,\n              importerFileId,\n              relFile,\n              resolved,\n              imp.line,\n              imp.snippet,\n            )\n          }\n        }\n        continue\n      }\n\n      let jsImports: RawImport[] = []\n      try {\n        const tree = parseSource(jsParser, file.content)\n        collectJsImports(tree.rootNode, jsImports)\n      } catch (err) {\n        recordExtractionError('import extraction', file.path, err)\n        continue\n      }\n      for (const imp of jsImports) {\n        const resolved = await resolveJsImport(imp.specifier, path.dirname(file.path), service.dir, tsPaths)\n        if (!resolved) continue\n        edgesAdded += emitImportEdge(\n          graph,\n          service.pkg.name,\n          importerFileId,\n          relFile,\n          resolved,\n          imp.line,\n          imp.snippet,\n        )\n      }\n    }\n  }\n\n  return { nodesAdded: 0, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport type { DiscoveredService, PackageJson } from './shared.js'\nimport { IGNORED_DIRS } from './shared.js'\n\nexport interface GoModule {\n  module: string\n  goVersion?: string\n  dependencies: Record<string, string>\n}\n\nexport function parseGoMod(source: string): GoModule | null {\n  const module = source.match(/^\\s*module\\s+(\\S+)\\s*$/m)?.[1]\n  if (!module) return null\n  const goVersion = source.match(/^\\s*go\\s+(\\S+)\\s*$/m)?.[1]\n  const dependencies: Record<string, string> = {}\n  const block = source.match(/^\\s*require\\s*\\(([^]*?)^\\s*\\)/m)?.[1] ?? ''\n  for (const line of block.split(/\\r?\\n/)) {\n    const m = line.replace(/\\/\\/.*$/, '').trim().match(/^(\\S+)\\s+(v\\S+)$/)\n    if (m) dependencies[m[1]!] = m[2]!\n  }\n  for (const m of source.matchAll(/^\\s*require\\s+(\\S+)\\s+(v\\S+)(?:\\s*\\/\\/.*)?$/gm)) {\n    dependencies[m[1]!] = m[2]!\n  }\n  return { module, ...(goVersion ? { goVersion } : {}), dependencies }\n}\n\n// The web framework a Go service declares, for the ServiceNode's `framework`\n// label — the same package-name → label discipline the JS/Python readers use.\n// The go.mod require path carries the major-version suffix (`.../echo/v4`), so\n// the versioned and pre-modules module paths both map to one label.\nfunction goFramework(deps: Record<string, string>): string | undefined {\n  if (deps['github.com/gin-gonic/gin']) return 'gin'\n  if (deps['github.com/labstack/echo/v4'] || deps['github.com/labstack/echo']) return 'echo'\n  if (deps['github.com/gofiber/fiber/v2'] || deps['github.com/gofiber/fiber/v3']) return 'fiber'\n  if (deps['github.com/go-chi/chi/v5'] || deps['github.com/go-chi/chi']) return 'chi'\n  return undefined\n}\n\nconst IMPORT_BLOCK = /^\\s*import\\s*\\(([^]*?)^\\s*\\)/gm\nconst IMPORT_SINGLE = /^\\s*import\\s+(?:[\\w.]+\\s+)?\"([^\"]+)\"/gm\nconst IMPORT_LINE = /^\\s*(?:[\\w.]+\\s+)?\"([^\"]+)\"/\n\n// The import paths a Go file names. Only the header matters, and the regexes stop\n// at the first match shape, so a string in a function body never reads as one.\nexport function goImports(source: string): string[] {\n  const out: string[] = []\n  for (const m of source.matchAll(IMPORT_BLOCK)) {\n    for (const line of m[1]!.split(/\\r?\\n/)) {\n      const im = IMPORT_LINE.exec(line.replace(/\\/\\/.*$/, ''))\n      if (im) out.push(im[1]!)\n    }\n  }\n  for (const m of source.matchAll(IMPORT_SINGLE)) out.push(m[1]!)\n  return out\n}\n\n// golang/dep's lock file: one `[[projects]]` table per dependency, carrying its\n// `name` and a `version` (else `branch`, else `revision`). Read for the same\n// dependency map a go.mod `require` block gives (ADR-256).\nexport function parseGopkgLock(source: string): Record<string, string> {\n  const deps: Record<string, string> = {}\n  for (const block of source.split(/^\\s*\\[\\[(?:projects|constraint)\\]\\]\\s*$/m).slice(1)) {\n    const field = (k: string): string | undefined => block.match(new RegExp(`^\\\\s*${k}\\\\s*=\\\\s*\"([^\"]+)\"`, 'm'))?.[1]\n    const name = field('name')\n    if (!name) continue\n    deps[name] = field('version') ?? field('branch') ?? field('revision') ?? '*'\n  }\n  return deps\n}\n\n// The directories under `root` that hold Go source of their own (a Go package is a\n// directory), relative and slash-separated. `vendor/`, nested modules and the\n// usual ignored directories are skipped.\nasync function goPackageDirs(root: string): Promise<string[]> {\n  const out = new Set<string>()\n  async function walk(current: string, isRoot: boolean): Promise<void> {\n    const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n    if (!isRoot && entries.some((e) => e.isFile() && (e.name === 'go.mod' || e.name === 'Gopkg.toml'))) return\n    for (const e of entries) {\n      const full = path.join(current, e.name)\n      if (e.isDirectory()) {\n        if (IGNORED_DIRS.has(e.name) || e.name.startsWith('.')) continue\n        await walk(full, false)\n      } else if (e.isFile() && e.name.endsWith('.go')) {\n        out.add(path.relative(root, current).split(path.sep).join('/'))\n      }\n    }\n  }\n  await walk(root, true)\n  return [...out]\n}\n\n// A dep-layout repository names its own import path nowhere in a file. Recover it\n// from its own source: an import that ends in one of the repo's package\n// directories (`…/services/geo` while `services/geo/` exists) names the module as\n// everything before that directory. The prefix most imports agree on wins, which\n// keeps a stray coincidental match from deciding it.\nexport async function inferGoModulePath(root: string): Promise<string | null> {\n  const dirs = (await goPackageDirs(root)).filter((d) => d.length > 0)\n  if (dirs.length === 0) return null\n  const counts = new Map<string, number>()\n  for (const dir of dirs) {\n    const abs = path.join(root, ...dir.split('/'))\n    const entries = await fs.readdir(abs).catch(() => [] as string[])\n    for (const f of entries) {\n      if (!f.endsWith('.go')) continue\n      const src = await fs.readFile(path.join(abs, f), 'utf8').catch(() => '')\n      for (const imp of goImports(src)) {\n        for (const d of dirs) {\n          if (!imp.endsWith('/' + d)) continue\n          const prefix = imp.slice(0, imp.length - d.length - 1)\n          if (prefix.length > 0) counts.set(prefix, (counts.get(prefix) ?? 0) + 1)\n        }\n      }\n    }\n  }\n  let best: string | null = null\n  let bestCount = 0\n  for (const [prefix, n] of [...counts].sort(([a], [b]) => a.localeCompare(b))) {\n    if (n > bestCount) {\n      best = prefix\n      bestCount = n\n    }\n  }\n  return best\n}\n\n// The Go module rooted at `dir`: from go.mod, else from golang/dep's\n// `Gopkg.toml` / `Gopkg.lock` (ADR-256), whose import path is inferred from the\n// repo's own imports, falling back to the directory name.\nexport async function readGoModule(dir: string): Promise<GoModule | null> {\n  const goMod = await fs.readFile(path.join(dir, 'go.mod'), 'utf8').catch(() => null)\n  if (goMod !== null) return parseGoMod(goMod)\n  const lock = await fs.readFile(path.join(dir, 'Gopkg.lock'), 'utf8').catch(() => null)\n  const toml = await fs.readFile(path.join(dir, 'Gopkg.toml'), 'utf8').catch(() => null)\n  if (lock === null && toml === null) return null\n  const module = (await inferGoModulePath(dir)) ?? path.basename(path.resolve(dir))\n  return { module, dependencies: parseGopkgLock(lock ?? toml ?? '') }\n}\n\nexport async function discoverGoService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  const mod = await readGoModule(dir)\n  if (!mod) return null\n  const name = mod.module.split('/').filter(Boolean).pop() ?? mod.module\n  const pkg: PackageJson = { name, dependencies: mod.dependencies }\n  const framework = goFramework(mod.dependencies)\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'go',\n    dependencies: mod.dependencies,\n    repoPath: path.relative(scanPath, dir),\n    ...(framework ? { framework } : {}),\n  }\n  return { pkg, dir, node }\n}\n","import { NodeType } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { SourceBaseline } from '@neat.is/types'\nexport type { SourceBaseline } from '@neat.is/types'\n\nexport interface SourceCommit {\n  repository: string\n  sha: string\n}\n\ninterface Entry {\n  baseline: SourceBaseline\n  // The pass that owns this entry's next verdict. A newer pass or an\n  // invalidation replaces it, so an older pass can never restore its claim.\n  generation: symbol\n  // Services this repo's files belonged to when its pass finished. Node ids are\n  // keyed by service, not repository, so two repos sharing a service name share\n  // nodes, and neither one's evidence describes them alone.\n  services: Set<string>\n}\n\ninterface State {\n  repos: Map<string, Entry>\n  active: Set<symbol>\n  conflicted: Set<symbol>\n}\n\n// Not graph attributes: evidence cannot survive a snapshot/load or be supplied\n// by an incoming snapshot. Weak keys also keep project removal independent.\nconst states = new WeakMap<NeatGraph, State>()\n\nconst REPOSITORY = /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/\n\nfunction validCommit(commit: SourceCommit | undefined, repository: string): commit is SourceCommit {\n  return !!commit && commit.repository === repository && /^[0-9a-f]{40}$/.test(commit.sha)\n}\n\nfunction stateOf(graph: NeatGraph): State {\n  let state = states.get(graph)\n  if (!state) {\n    state = { repos: new Map(), active: new Set(), conflicted: new Set() }\n    states.set(graph, state)\n  }\n  return state\n}\n\nfunction setEntry(\n  state: State,\n  repository: string,\n  baseline: SourceBaseline,\n  generation: symbol = Symbol(),\n): void {\n  state.repos.set(repository, {\n    baseline,\n    generation,\n    services: state.repos.get(repository)?.services ?? new Set(),\n  })\n}\n\n/** One entry per repository with evidence, sorted by repository. Copies. */\nexport function readSourceBaselines(graph: NeatGraph): SourceBaseline[] {\n  const state = states.get(graph)\n  if (!state) return []\n  return [...state.repos.entries()]\n    .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))\n    .map(([, entry]) => ({ ...entry.baseline }))\n}\n\n/**\n * Drop evidence. With a repository, only that repo's entry, superseding any\n * pass of its own in flight. Without one, every entry, because the write that\n * called it may have touched any repo's nodes; a pass running at the time is\n * marked conflicted, so it cannot restore a claim over a graph that changed\n * underneath it.\n */\nexport function invalidateSourceBaseline(\n  graph: NeatGraph,\n  repository?: string,\n  status: 'unavailable' | 'syncing' = 'unavailable',\n): void {\n  if (repository !== undefined) {\n    if (REPOSITORY.test(repository)) setEntry(stateOf(graph), repository, { status, repository })\n    return\n  }\n  const state = states.get(graph)\n  if (!state) return\n  for (const generation of state.active) state.conflicted.add(generation)\n  for (const name of state.repos.keys()) {\n    setEntry(state, name, { status: 'unavailable', repository: name })\n  }\n}\n\n/** Keep entries only for the repositories still bound to this project. */\nexport function retainSourceBaselines(graph: NeatGraph, repositories: Iterable<string>): void {\n  const state = states.get(graph)\n  if (!state) return\n  const keep = new Set(repositories)\n  for (const name of [...state.repos.keys()]) if (!keep.has(name)) state.repos.delete(name)\n}\n\n/**\n * Called when a pass starts. `source` is the repo the pass is scoped to\n * (ADR-233). A pass scoped to no repo may rewrite any repo's nodes, so it\n * invalidates every entry.\n */\nexport function beginSourceExtraction(\n  graph: NeatGraph,\n  source: string | undefined,\n  commit?: SourceCommit,\n): symbol {\n  const generation = Symbol()\n  const state = stateOf(graph)\n  if (source === undefined) {\n    invalidateSourceBaseline(graph)\n    state.active.add(generation)\n    return generation\n  }\n  state.active.add(generation)\n  if (!REPOSITORY.test(source)) return generation\n  setEntry(\n    state,\n    source,\n    validCommit(commit, source)\n      ? { status: 'syncing', repository: source }\n      : { status: 'unavailable', repository: source },\n    generation,\n  )\n  return generation\n}\n\nfunction servicesOf(graph: NeatGraph, repository: string): Set<string> {\n  const services = new Set<string>()\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as { type?: string; source?: string; service?: string }\n    if (node.type === NodeType.FileNode && node.source === repository && node.service) {\n      services.add(node.service)\n    }\n  })\n  return services\n}\n\nexport function finishSourceExtraction(\n  graph: NeatGraph,\n  generation: symbol,\n  source: string | undefined,\n  commit: SourceCommit | undefined,\n  result: { extractionErrors: number; skippedFiles: number },\n): void {\n  const state = states.get(graph)\n  if (!state) return\n  state.active.delete(generation)\n  const conflicted = state.conflicted.delete(generation)\n  if (source === undefined || !REPOSITORY.test(source)) return\n  const entry = state.repos.get(source)\n  // Another pass or invalidation has superseded this one.\n  if (!entry || entry.generation !== generation) return\n  entry.services = servicesOf(graph, source)\n  let shared = false\n  for (const [name, other] of state.repos) {\n    if (name === source || ![...entry.services].some((s) => other.services.has(s))) continue\n    shared = true\n    setEntry(state, name, { status: 'unavailable', repository: name }, other.generation)\n  }\n  entry.baseline =\n    !conflicted &&\n    !shared &&\n    validCommit(commit, source) &&\n    result.extractionErrors === 0 &&\n    result.skippedFiles === 0\n      ? { status: 'ready', repository: source, sha: commit.sha }\n      : { status: 'unavailable', repository: source }\n}\n","import type { GraphEdge, InfraNode } from '@neat.is/types'\nimport { EdgeTypeValue, NodeType, Provenance, confidenceForExtracted, infraId } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { makeEdgeId } from '../shared.js'\n\n// ADR-010 reserves the `infra:` prefix; the kind segment lets traversal and\n// MCP tools sub-type without inventing a new top-level NodeType per source.\nexport function makeInfraNode(\n  kind: string,\n  name: string,\n  provider = 'self',\n  extras?: { region?: string },\n): InfraNode {\n  return {\n    id: infraId(kind, name),\n    type: NodeType.InfraNode,\n    name,\n    provider,\n    kind,\n    ...(extras?.region ? { region: extras.region } : {}),\n  }\n}\n\n// Stable kind for an image string like \"postgres:15-alpine\" or \"mysql:8\".\n// The image name itself ends up in the InfraNode `name` field; this function\n// only classifies what the image *is*, so callers can group similar runtimes.\n// The datastore engine a bare name denotes, or undefined when it names no engine\n// NEAT recognizes. One list, one home: `classifyImage` (image strings) and the\n// opentracing datastore-client resolver (ingest, `peer.service`, #1415) both read it,\n// so the recognized-engine set is defined once here rather than duplicated. Message\n// brokers (kafka, rabbitmq) are deliberately out — they are not datastores.\nexport function knownDatastoreEngine(name: string | undefined): string | undefined {\n  if (!name) return undefined\n  const n = name.toLowerCase()\n  if (n.startsWith('postgres')) return 'postgres'\n  if (n.startsWith('mysql') || n.startsWith('mariadb')) return 'mysql'\n  if (n.startsWith('mongo')) return 'mongodb'\n  if (n.startsWith('redis')) return 'redis'\n  if (n.startsWith('memcached')) return 'memcached'\n  return undefined\n}\n\nexport function classifyImage(image: string): string {\n  const lower = image.toLowerCase()\n  const repo = lower.split(':')[0]!\n  const last = repo.split('/').pop() ?? repo\n  const engine = knownDatastoreEngine(last)\n  if (engine) return engine\n  if (last.startsWith('rabbitmq')) return 'rabbitmq'\n  if (last.startsWith('kafka') || last.includes('kafka')) return 'kafka'\n  return 'container'\n}\n\n// Best-effort 1-indexed line for a declared value in a config file's raw text —\n// the same \"read config as data\" text search cloudflare.ts and terraform.ts use\n// rather than a real AST.\nexport function lineContaining(raw: string, needle: string | undefined): number | undefined {\n  if (!needle) return undefined\n  const idx = raw.indexOf(needle)\n  if (idx === -1) return undefined\n  let line = 1\n  for (let i = 0; i < idx; i++) if (raw[i] === '\\n') line++\n  return line\n}\n\n// One declared-resource InfraNode + an edge from the anchor (a ServiceNode or an\n// entry FileNode). Idempotent; every edge carries evidence.file. Shared by the\n// platform extractors (vercel/railway/supabase); cloudflare.ts predates this and\n// keeps its own local copy. No self-loop when a resource id equals the anchor.\nexport function emitPlatformResourceEdge(\n  graph: NeatGraph,\n  anchorId: string,\n  edgeType: EdgeTypeValue,\n  kind: string,\n  name: string,\n  provider: string,\n  evidenceFile: string,\n  line?: number,\n): { nodesAdded: number; edgesAdded: number } {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  const node = makeInfraNode(kind, name, provider)\n  if (!graph.hasNode(node.id)) {\n    graph.addNode(node.id, node)\n    nodesAdded++\n  }\n  if (node.id === anchorId) return { nodesAdded, edgesAdded }\n  const edgeId = makeEdgeId(anchorId, node.id, edgeType)\n  if (!graph.hasEdge(edgeId)) {\n    const edge: GraphEdge = {\n      id: edgeId,\n      source: anchorId,\n      target: node.id,\n      type: edgeType,\n      provenance: Provenance.EXTRACTED,\n      confidence: confidenceForExtracted('structural'),\n      evidence: { file: evidenceFile, ...(line !== undefined ? { line } : {}) },\n    }\n    graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n    edgesAdded++\n  }\n  return { nodesAdded, edgesAdded }\n}\n","// Column-grain provenance fold (ADR-157). Columns are a provenanced attribute\n// list on a `sql-table` InfraNode, never their own nodes. This module is the one\n// place that folds a column presence onto that list; the graph mutation itself\n// stays with the two lifecycle authorities that call it — `ingest.ts` for the\n// OBSERVED read off `db.statement`, and `extract/calls/*` for the EXTRACTED read\n// off a schema definition (lifecycle.md §3). The divergence detector\n// (divergences.ts) only reads the list. Keeping the fold pure here (no graph\n// handle) lets extract call in without importing ingest — ingest already imports\n// extract, so the reverse would be a cycle.\n//\n// A column records each provenance it has been seen with in a deduped\n// `provenances` set: a column that is both declared and observed carries\n// `[EXTRACTED, OBSERVED]`, and the column-drift query (ADR-157 §4) reads the\n// declared set and the observed set straight off that one entry. `confidence` is\n// the strongest evidence's grade (max) — a column seen on both sides is the most\n// certain, and a one-sided (drift) column's confidence is just that side's grade.\n\nimport { Provenance, type ColumnAttr, type ProvenanceValue } from '@neat.is/types'\n\n// OBSERVED columns are read verbatim from a parameterized `db.statement`: the\n// value is redacted but the column NAME is present in the text, so the read is\n// near-certain. Graded just below 1.0 to acknowledge the parser's conservative\n// reach (it degrades on JOIN / subquery / `SELECT *`) rather than claim total\n// coverage. EXTRACTED columns carry their producer's grade instead.\nexport const OBSERVED_COLUMN_CONFIDENCE = 0.9\n\n// Deterministic, deduped provenance order so a node's serialized shape is stable\n// regardless of the order extract / ingest passes ran in. Alphabetical happens to\n// read EXTRACTED, INFERRED, OBSERVED, STALE.\nfunction normalizeProvenances(provenances: ProvenanceValue[]): ProvenanceValue[] {\n  return [...new Set(provenances)].sort()\n}\n\n// Fold a set of column names onto a table node's `columns` list at one\n// provenance, returning a fresh array (pure — the caller writes it back). Column\n// names are lowercased so the declared read fuses with the observed read, which\n// already lowercases: an unquoted SQL identifier is case-folded by the database\n// anyway, so lowercasing both sides is the fusion-safe normalization and stops a\n// case difference from minting a phantom drift. An unseen column is added with the\n// one provenance; a column already present gains this provenance in its set\n// (deduped) and keeps the stronger confidence — never duplicated. Order-stable and\n// idempotent, so an OBSERVED fold and an EXTRACTED fold compose either way round.\nexport function foldColumns(\n  existing: readonly ColumnAttr[] | undefined,\n  names: readonly string[],\n  provenance: ProvenanceValue,\n  confidence: number,\n): ColumnAttr[] {\n  const out: ColumnAttr[] = (existing ?? []).map((c) => ({\n    ...c,\n    provenances: [...c.provenances],\n  }))\n  const byName = new Map(out.map((c) => [c.name, c]))\n  for (const raw of names) {\n    const name = raw.toLowerCase()\n    const prior = byName.get(name)\n    if (!prior) {\n      const col: ColumnAttr = { name, provenances: [provenance], confidence }\n      byName.set(name, col)\n      out.push(col)\n      continue\n    }\n    if (!prior.provenances.includes(provenance)) {\n      prior.provenances = normalizeProvenances([...prior.provenances, provenance])\n    }\n    if (confidence > prior.confidence) prior.confidence = confidence\n  }\n  return out\n}\n\n// Fold per-field write-SDK tags onto a table/collection node's `columns` list\n// (ADR-167), returning a fresh array — the parallel of `foldColumns`, kept\n// separate so `foldColumns` (shared by Drizzle / Prisma / SQLAlchemy / OBSERVED\n// ingest) stays byte-identical. `writes` maps a field name to the SDK(s) that\n// wrote it (`client` = firebase/firestore, `admin` = firebase-admin/firestore); it\n// merges into each column's `sdkWrites` set, deduped and order-stable the way\n// `provenances` is. Field names are lowercased to match `foldColumns` (which the\n// column entries went through first), so the tag lands on the right column. A\n// written field with no existing column entry is skipped — the columns fold runs\n// first with the same field set, so the entry is already present; this is the\n// defensive path. This is the declared interface ADR-169's field-guard policy\n// consumes (`col.sdkWrites ?? []`).\nexport function foldSdkWrites(\n  existing: readonly ColumnAttr[] | undefined,\n  writes: Readonly<Record<string, readonly ('client' | 'admin')[]>>,\n): ColumnAttr[] {\n  const out: ColumnAttr[] = (existing ?? []).map((c) => ({\n    ...c,\n    provenances: [...c.provenances],\n    ...(c.sdkWrites ? { sdkWrites: [...c.sdkWrites] } : {}),\n  }))\n  const byName = new Map(out.map((c) => [c.name, c]))\n  for (const [raw, sdks] of Object.entries(writes)) {\n    const col = byName.get(raw.toLowerCase())\n    if (!col) continue\n    const merged = new Set<'client' | 'admin'>([...(col.sdkWrites ?? []), ...sdks])\n    col.sdkWrites = [...merged].sort()\n  }\n  return out\n}\n\n// Read helpers the divergence detector uses so the \"is this column declared /\n// observed\" test lives with the model rather than being re-derived per caller.\nexport function columnIsDeclared(col: ColumnAttr): boolean {\n  return col.provenances.includes(Provenance.EXTRACTED)\n}\nexport function columnIsObserved(col: ColumnAttr): boolean {\n  return col.provenances.includes(Provenance.OBSERVED)\n}\n","// Flag grain (ADR-242). A feature-flag store is a dependency the services call,\n// like a database, and its flags are its grain the way columns are a table's\n// (ADR-157). The store is a `flag-store` InfraNode; each flag is a provenanced\n// entry in its `flags` list. This module is the one place that parses a flag\n// definition and folds one onto that list. The graph mutation stays with the\n// lifecycle authorities that call it: `extract/flags.ts` for the committed\n// definitions and the code that reads each key, `ingest.ts` for what the store is\n// serving and what an evaluation reported. The divergence detector only reads the\n// list. Pure, no graph handle, so extract and ingest can both call in.\n\nimport {\n  Provenance,\n  type FlagAttr,\n  type FlagDefinition,\n  type ProvenanceValue,\n} from '@neat.is/types'\n\nexport const FLAG_STORE_KIND = 'flag-store'\n\n// The four fields that decide what a flag evaluates to. Everything else a flag\n// carries (`description`, `metadata`, a provider's `source`/`selector`/\n// `flagSetId`) is bookkeeping and never part of the compare.\nconst DEFINITION_FIELDS = ['state', 'defaultVariant', 'variants', 'targeting'] as const\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\n// Recursively key-sorted copy, so two definitions that differ only in key order\n// serialize the same.\nfunction sortKeys(v: unknown): unknown {\n  if (Array.isArray(v)) return v.map(sortKeys)\n  if (!isRecord(v)) return v\n  const out: Record<string, unknown> = {}\n  for (const k of Object.keys(v).sort()) out[k] = sortKeys(v[k])\n  return out\n}\n\n// One flag's raw definition → its canonical form, or null when it isn't a flag\n// definition at all (no `state`, or no `variants` object).\nexport function canonicalFlag(raw: unknown): FlagDefinition | null {\n  if (!isRecord(raw)) return null\n  if (typeof raw['state'] !== 'string' || !isRecord(raw['variants'])) return null\n  const dv = raw['defaultVariant']\n  const def: FlagDefinition = {\n    state: raw['state'],\n    defaultVariant: typeof dv === 'string' ? dv : null,\n    variants: sortKeys(raw['variants']) as Record<string, unknown>,\n  }\n  // An empty targeting object is the same as none.\n  const t = raw['targeting']\n  if (t !== undefined && t !== null && !(isRecord(t) && Object.keys(t).length === 0)) {\n    def.targeting = sortKeys(t)\n  }\n  return def\n}\n\n// The top-level definition fields that differ between two canonical forms, in a\n// fixed order. Empty means the two would evaluate the same.\nexport function flagFieldsChanged(a: FlagDefinition, b: FlagDefinition): string[] {\n  const out: string[] = []\n  for (const f of DEFINITION_FIELDS) {\n    if (JSON.stringify(a[f] ?? null) !== JSON.stringify(b[f] ?? null)) out.push(f)\n  }\n  return out\n}\n\n// A flag document's `flags` object → key → canonical definition. Recognition is\n// structural: the document has a top-level `flags` object and at least one entry\n// is a flag definition. Returns null for anything else, so an arbitrary JSON file\n// costs one parse and yields nothing. Only the `flags` object is read (ADR-242's\n// one fenced content read; ADR-016 keeps every other config file paths-only).\nexport function parseFlagDocument(doc: unknown): Map<string, FlagDefinition> | null {\n  if (!isRecord(doc) || !isRecord(doc['flags'])) return null\n  const out = new Map<string, FlagDefinition>()\n  for (const [key, raw] of Object.entries(doc['flags'])) {\n    const def = canonicalFlag(raw)\n    if (def) out.set(key, def)\n  }\n  return out.size > 0 ? out : null\n}\n\nfunction provenancesOf(f: FlagAttr): ProvenanceValue[] {\n  const out: ProvenanceValue[] = []\n  if (f.declared) out.push(Provenance.EXTRACTED)\n  if (f.observed || f.observedVariant !== undefined) out.push(Provenance.OBSERVED)\n  return out.sort()\n}\n\nfunction clone(existing: readonly FlagAttr[] | undefined): FlagAttr[] {\n  return (existing ?? []).map((f) => ({\n    ...f,\n    provenances: [...f.provenances],\n    ...(f.readers ? { readers: f.readers.map((r) => ({ ...r })) } : {}),\n  }))\n}\n\nfunction finish(flags: FlagAttr[]): FlagAttr[] {\n  return flags\n    .map((f) => ({ ...f, provenances: provenancesOf(f) }))\n    .filter((f) => f.provenances.length > 0)\n    .sort((a, b) => a.key.localeCompare(b.key))\n}\n\nexport interface DeclaredFlag {\n  key: string\n  definition: FlagDefinition\n  declaredIn: string\n  readers: { file: string; service: string; line?: number }[]\n}\n\n// The EXTRACTED side, replaced whole on every extraction pass: this pass's\n// declarations and readers are the truth, so a flag deleted from the file or a\n// reader deleted from the code drops out. The OBSERVED side of each flag is kept.\nexport function foldDeclaredFlags(\n  existing: readonly FlagAttr[] | undefined,\n  declared: readonly DeclaredFlag[],\n): FlagAttr[] {\n  const byKey = new Map<string, FlagAttr>()\n  for (const f of clone(existing)) {\n    const { declared: _d, declaredIn: _i, readers: _r, ...observedOnly } = f\n    byKey.set(f.key, observedOnly)\n  }\n  for (const d of declared) {\n    const cur = byKey.get(d.key) ?? { key: d.key, provenances: [] }\n    cur.declared = d.definition\n    cur.declaredIn = d.declaredIn\n    if (d.readers.length > 0) cur.readers = d.readers.map((r) => ({ ...r }))\n    byKey.set(d.key, cur)\n  }\n  return finish([...byKey.values()])\n}\n\n// The OBSERVED side from the store's own reader: what it is serving now. Folded\n// only onto flags the code base declares. A served flag with no committed\n// declaration mints nothing and comes back in `undeclared`, so the reader can\n// count it without the graph growing a flag nobody wrote down.\nexport function foldObservedFlags(\n  existing: readonly FlagAttr[] | undefined,\n  served: ReadonlyMap<string, FlagDefinition>,\n  at: string,\n): { flags: FlagAttr[]; undeclared: string[] } {\n  const flags = clone(existing)\n  const byKey = new Map(flags.map((f) => [f.key, f]))\n  const undeclared: string[] = []\n  for (const [key, def] of served) {\n    const cur = byKey.get(key)\n    if (!cur || !cur.declared) {\n      undeclared.push(key)\n      continue\n    }\n    cur.observed = def\n    cur.observedAt = at\n  }\n  // A declared flag the store no longer serves keeps no stale observed copy.\n  for (const f of flags) {\n    if (f.observed && !served.has(f.key)) {\n      delete f.observed\n      delete f.observedAt\n    }\n  }\n  return { flags: finish(flags), undeclared: undeclared.sort() }\n}\n\n// The OBSERVED side from a service's own evaluation (a `feature_flag.evaluation`\n// span event): the variant it got and why. Same rule as the reader: only a\n// declared flag takes it.\nexport function foldObservedVariant(\n  existing: readonly FlagAttr[] | undefined,\n  key: string,\n  variant: string,\n  reason: string | undefined,\n  at: string,\n): FlagAttr[] | null {\n  const flags = clone(existing)\n  const cur = flags.find((f) => f.key === key)\n  if (!cur || !cur.declared) return null\n  cur.observedVariant = variant\n  if (reason) cur.observedVariantReason = reason\n  else delete cur.observedVariantReason\n  cur.observedVariantAt = at\n  return finish(flags)\n}\n","// Bounded streaming latency-percentile estimator (ADR-190, otel-ingest.md\n// §Per-edge latency). `upsertObservedEdge` records each span's duration into a\n// per-edge histogram and re-derives `latencyMs: { p50, p95 }` from it. The\n// contract forbids retaining raw durations — the ingest path is non-blocking and\n// edge cardinality is unbounded — so this is a fixed-resolution log-linear\n// (HDR-style) histogram: one span updates it in O(1), and the bucket count is\n// bounded regardless of how many spans an edge accumulates.\n//\n// Storage is a sparse `Record<bucketIndex, count>` carried on the edge signal, so\n// a narrow latency distribution costs a handful of keys and the whole thing rides\n// the graph snapshot as additive schema growth. The estimator is deterministic:\n// the same span durations always yield the same buckets and the same percentiles.\n\nexport type LatencyHistogram = Record<string, number>\n\n// Log-linear bucketing. Each power-of-two octave is split into SUB linear\n// sub-buckets, giving ~1/SUB relative resolution (SUB=16 → ~6% bucket width,\n// tight enough to tell a saturated p95 from a healthy one). The covered range\n// runs from 2^MIN_EXP ms (~1µs) to 2^(MAX_EXP+1) ms (~70min); anything below\n// lands in the zero/underflow bucket, anything above in the overflow bucket.\nconst SUB = 16\nconst MIN_EXP = -10\nconst MAX_EXP = 22\n// Index 0 is the zero/underflow bucket; 1..(OCTAVES*SUB) are the log-linear\n// buckets; the last index is the overflow bucket.\nconst OCTAVES = MAX_EXP - MIN_EXP + 1\nconst OVERFLOW_INDEX = OCTAVES * SUB + 1\n\n// The bucket a duration (in ms) falls into. Non-finite, zero, and negative\n// durations land in the underflow bucket rather than throwing — a span with a\n// missing or degenerate duration records as ~0 latency, honestly.\nexport function latencyBucketIndex(ms: number): number {\n  if (!Number.isFinite(ms) || ms <= 0) return 0\n  const e = Math.floor(Math.log2(ms))\n  if (e < MIN_EXP) return 0\n  if (e > MAX_EXP) return OVERFLOW_INDEX\n  const base = 2 ** e\n  const raw = Math.floor((ms / base - 1) * SUB)\n  const s = raw < 0 ? 0 : raw >= SUB ? SUB - 1 : raw\n  return (e - MIN_EXP) * SUB + s + 1\n}\n\n// The representative latency (ms) a bucket stands for — the midpoint of its\n// value range — used when a percentile lands in that bucket.\nfunction bucketRepresentativeMs(index: number): number {\n  if (index <= 0) return 0\n  if (index >= OVERFLOW_INDEX) return 2 ** (MAX_EXP + 1)\n  const zeroBased = index - 1\n  const e = MIN_EXP + Math.floor(zeroBased / SUB)\n  const s = zeroBased % SUB\n  const base = 2 ** e\n  const lower = base * (1 + s / SUB)\n  const upper = base * (1 + (s + 1) / SUB)\n  return (lower + upper) / 2\n}\n\n// Record one duration into the histogram in place. Returns the same object for\n// convenience. Callers pass the edge signal's `latencyHist` (creating it on\n// first observation).\nexport function recordLatency(hist: LatencyHistogram, ms: number): LatencyHistogram {\n  const key = String(latencyBucketIndex(ms))\n  hist[key] = (hist[key] ?? 0) + 1\n  return hist\n}\n\nfunction quantile(hist: LatencyHistogram, q: number): number {\n  const entries = Object.entries(hist)\n    .map(([k, c]) => [Number(k), c] as const)\n    .filter(([idx, c]) => Number.isFinite(idx) && c > 0)\n    .sort((a, b) => a[0] - b[0])\n  let total = 0\n  for (const [, c] of entries) total += c\n  if (total === 0) return 0\n  // Nearest-rank: the smallest bucket whose cumulative count reaches ⌈q·total⌉.\n  const rank = Math.max(1, Math.ceil(q * total))\n  let cumulative = 0\n  for (const [idx, c] of entries) {\n    cumulative += c\n    if (cumulative >= rank) return bucketRepresentativeMs(idx)\n  }\n  return bucketRepresentativeMs(entries[entries.length - 1]![0])\n}\n\nfunction round(ms: number): number {\n  // Two significant-ish decimals — enough to read a p95 without pretending the\n  // bucketed estimate is exact.\n  return Math.round(ms * 100) / 100\n}\n\n// Derive { p50, p95 } from the histogram, or undefined when it holds no\n// observations — an edge with no recorded latency reads honestly absent, never a\n// fabricated zero (file-awareness.md §6).\nexport function latencyPercentiles(\n  hist: LatencyHistogram | undefined,\n): { p50: number; p95: number } | undefined {\n  if (!hist) return undefined\n  let total = 0\n  for (const c of Object.values(hist)) total += c\n  if (total === 0) return undefined\n  return { p50: round(quantile(hist, 0.5)), p95: round(quantile(hist, 0.95)) }\n}\n","// ──────────────────────────────────────────────────────────────────────────\n// Stacktrace code-locus recovery (ADR-216)\n//\n// An OBSERVED exception span often carries `exception.stacktrace` but no\n// `code.*` semconv attributes — Python auto-instrumentation records the\n// exception through `record_exception` without stamping a call site, and the\n// same is true of many runtimes' exception recording. The declaring file:line\n// is still named, plainly, inside the stacktrace text. This module recovers the\n// deepest APPLICATION frame from that text so incident localization can join it\n// to a FileNode / SymbolNode the graph already carries — turning a service-level\n// incident back into the code-grain locus the fusion query needs.\n//\n// It keys STRICTLY on generic frame syntax and generic vendor-prefix markers,\n// never on a language / framework / provider name (ADR-158 §6). A new frame\n// shape is a new row in FRAME_SHAPES; a new vendor marker a new row in\n// VENDOR_MARKERS. There is no per-language branch anywhere below.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface StackFrame {\n  file: string\n  line: number\n  fn?: string\n}\n\n// One frame syntax. `deepest` records where the throw-site frame sits among the\n// matches of THIS shape — a property of the syntax, not of any language: the\n// `File \"…\", line N` shape lists most-recent last (the raising line is at the\n// bottom of the trace), the `at …` shapes list most-recent first (the throw\n// site is at the top). Keying an ordering convention on the frame syntax is\n// keying on syntax, which ADR-158 §6 permits; keying on the language that uses\n// the syntax is what it forbids.\ninterface FrameShape {\n  re: RegExp\n  file: number // capture-group index of the file path\n  line: number // capture-group index of the line number\n  fn?: number // capture-group index of the function name, when the shape carries one\n  deepest: 'first' | 'last'\n}\n\nconst FRAME_SHAPES: readonly FrameShape[] = [\n  // `File \"<path>\", line <N>, in <func>` — the \"most recent call last\" shape.\n  { re: /File \"([^\"]+)\", line (\\d+)(?:, in (\\S+))?/, file: 1, line: 2, fn: 3, deepest: 'last' },\n  // `at <func> (<path>:<line>:<col>)` — named call frame, most recent first.\n  { re: /\\bat\\s+(.+?)\\s+\\((.+?):(\\d+):\\d+\\)/, file: 2, line: 3, fn: 1, deepest: 'first' },\n  // `at <path>:<line>:<col>` — anonymous call frame, most recent first.\n  { re: /\\bat\\s+(.+?):(\\d+):\\d+/, file: 1, line: 2, deepest: 'first' },\n  // `at <qualified.method>(<File.ext>:<line>)` — JVM-style, most recent first.\n  { re: /\\bat\\s+(.+?)\\((\\S+\\.\\w+):(\\d+)\\)/, file: 2, line: 3, fn: 1, deepest: 'first' },\n]\n\n// Generic markers for a non-application (runtime / vendor / dependency) frame —\n// directory conventions and synthetic-frame forms, no language or provider name.\n// A frame whose file path contains any of these is dependency / runtime code,\n// not the application's own. The graph join stays the ultimate arbiter: even if\n// a frame slips through, incident localization attributes to a code node ONLY\n// when the frame resolves to a FileNode the graph carries — so this list picks\n// the right application frame, it does not gate honesty.\nconst VENDOR_MARKERS: readonly string[] = [\n  'node_modules', // dependency root\n  'site-packages', // installed-package root\n  'dist-packages', // distro-packaged root\n  'node:', // runtime-internal module scheme (a stdlib/runtime-root frame)\n]\n\ninterface OrientedFrame {\n  frame: StackFrame\n  deepest: 'first' | 'last'\n}\n\nfunction matchFrame(line: string): OrientedFrame | null {\n  for (const shape of FRAME_SHAPES) {\n    const m = shape.re.exec(line)\n    if (!m) continue\n    const file = m[shape.file]\n    const lineNo = Number(m[shape.line])\n    if (!file || !Number.isFinite(lineNo)) continue\n    const fn = shape.fn !== undefined ? m[shape.fn] : undefined\n    return { frame: { file, line: lineNo, ...(fn ? { fn } : {}) }, deepest: shape.deepest }\n  }\n  return null\n}\n\nfunction isApplicationFrame(file: string): boolean {\n  // Synthetic frames (`<frozen importlib._bootstrap>`, `<anonymous>`, `<string>`)\n  // name no real source file, so they are never application code.\n  if (file.startsWith('<')) return false\n  const norm = file.split('\\\\').join('/')\n  for (const marker of VENDOR_MARKERS) {\n    if (norm.includes(marker)) return false\n  }\n  return true\n}\n\n// Recover the deepest application frame — the frame nearest the throw site that\n// is not runtime / vendor code. Returns null when the stacktrace names no\n// application frame at all: an all-vendor trace recovers nothing, so the caller\n// keeps its honest service attribution and nothing is fabricated (ADR-158 §6).\nexport function deepestApplicationFrame(stacktrace: string | undefined): StackFrame | null {\n  if (!stacktrace) return null\n\n  const appFrames: OrientedFrame[] = []\n  for (const raw of stacktrace.split('\\n')) {\n    const matched = matchFrame(raw)\n    if (!matched) continue\n    if (!isApplicationFrame(matched.frame.file)) continue\n    appFrames.push(matched)\n  }\n  if (appFrames.length === 0) return null\n\n  // Orientation is a property of the frame syntax, and a real trace is written\n  // in one syntax: the `File \"…\"` shape puts the throw site last, the `at …`\n  // shapes put it first. Read the dominant orientation off the frames we matched\n  // and pick the throw-site-nearest application frame among that orientation.\n  const orientation: 'first' | 'last' = appFrames.some((f) => f.deepest === 'last')\n    ? 'last'\n    : 'first'\n  const oriented = appFrames.filter((f) => f.deepest === orientation)\n  const chosen = orientation === 'last' ? oriented[oriented.length - 1] : oriented[0]\n  return chosen ? chosen.frame : null\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport ignore, { type Ignore } from 'ignore'\nimport { minimatch } from 'minimatch'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n  IGNORED_DIRS,\n  exists,\n  isPythonVenvDir,\n  readJson,\n  type DiscoveredService,\n  type PackageJson,\n} from './shared.js'\nimport { discoverPythonService, pythonToPackage } from './python.js'\nimport { discoverGoService } from './go.js'\nimport { splitGoBinaries } from './go-binaries.js'\nimport { discoverRubyService } from './ruby.js'\nimport { discoverPhpService } from './php.js'\nimport { discoverCsharpService, hasCsharpProject } from './csharp.js'\nimport { discoverJavaService, hasJavaManifest } from './java.js'\nimport { discoverKotlinService } from './kotlin.js'\nimport { discoverRustService, hasRustManifest } from './rust.js'\nimport { discoverCppService, hasCppManifest } from './cpp.js'\nimport {\n  discoverDockerfileService,\n  hasDockerfileDeclaredService,\n} from './dockerfile-service.js'\nimport { computeServiceOwner, loadCodeowners } from './owners.js'\nimport { recordExtractionError } from './errors.js'\n\nconst DEFAULT_SCAN_DEPTH = 5\n\ninterface RootPackageJson extends PackageJson {\n  workspaces?: string[] | { packages?: string[] }\n}\n\nfunction parseScanDepth(): number {\n  const raw = process.env.NEAT_SCAN_DEPTH\n  if (!raw) return DEFAULT_SCAN_DEPTH\n  const n = Number.parseInt(raw, 10)\n  return Number.isFinite(n) && n >= 0 ? n : DEFAULT_SCAN_DEPTH\n}\n\nfunction workspaceGlobs(pkg: RootPackageJson): string[] | null {\n  const ws = pkg.workspaces\n  if (!ws) return null\n  if (Array.isArray(ws)) return ws.length > 0 ? ws : null\n  if (Array.isArray(ws.packages)) return ws.packages.length > 0 ? ws.packages : null\n  return null\n}\n\nasync function hasPythonManifest(dir: string): Promise<boolean> {\n  return (\n    (await exists(path.join(dir, 'pyproject.toml'))) ||\n    (await exists(path.join(dir, 'requirements.txt'))) ||\n    (await exists(path.join(dir, 'setup.py')))\n  )\n}\n\n// go.mod, or golang/dep's Gopkg.toml / Gopkg.lock for a repository that predates\n// modules (ADR-256).\nasync function hasGoManifest(dir: string): Promise<boolean> {\n  return (\n    (await exists(path.join(dir, 'go.mod'))) ||\n    (await exists(path.join(dir, 'Gopkg.toml'))) ||\n    (await exists(path.join(dir, 'Gopkg.lock')))\n  )\n}\n\nasync function hasRubyManifest(dir: string): Promise<boolean> {\n  return exists(path.join(dir, 'Gemfile'))\n}\n\nasync function hasPhpManifest(dir: string): Promise<boolean> {\n  return exists(path.join(dir, 'composer.json'))\n}\n\n// C#'s marker is a glob (`*.csproj` / `*.sln`), not a fixed filename, so it can't\n// be a single `exists` check the way the others are — `hasCsharpProject` reads the\n// directory (extract/csharp.ts).\nasync function hasCsharpManifest(dir: string): Promise<boolean> {\n  return hasCsharpProject(dir)\n}\n\nasync function loadGitignore(scanPath: string): Promise<Ignore | null> {\n  const gitignorePath = path.join(scanPath, '.gitignore')\n  if (!(await exists(gitignorePath))) return null\n  const raw = await fs.readFile(gitignorePath, 'utf8')\n  return ignore().add(raw)\n}\n\ninterface WalkOptions {\n  maxDepth: number\n  ig: Ignore | null\n}\n\nasync function walkDirs(\n  start: string,\n  scanPath: string,\n  options: WalkOptions,\n  visit: (dir: string) => Promise<void> | void,\n): Promise<void> {\n  async function recurse(current: string, depth: number): Promise<void> {\n    if (depth > options.maxDepth) return\n    const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n    for (const entry of entries) {\n      if (!entry.isDirectory()) continue\n      if (IGNORED_DIRS.has(entry.name)) continue\n      const child = path.join(current, entry.name)\n      if (options.ig) {\n        const rel = path.relative(scanPath, child).split(path.sep).join('/')\n        // Trailing slash so `ignore` evaluates the entry as a directory; without\n        // it, gitignore patterns like `dist/` won't match because the lib\n        // distinguishes file vs. directory tests.\n        if (rel && options.ig.ignores(rel + '/')) continue\n      }\n      // Issue #344 — `pyvenv.cfg` marks every directory that `python -m venv`\n      // or `virtualenv` creates, regardless of what the wrapper dir is called.\n      // The `IGNORED_DIRS` name list catches the common shapes (`.venv`,\n      // `venv`, `.tox`); this catches the long-tail ones (`env-3.11`,\n      // `.direnv`, ad-hoc names).\n      if (await isPythonVenvDir(child)) continue\n      await visit(child)\n      await recurse(child, depth + 1)\n    }\n  }\n  await recurse(start, 0)\n}\n\nasync function expandWorkspaceGlobs(\n  scanPath: string,\n  globs: string[],\n): Promise<string[]> {\n  const found = new Set<string>()\n  const scanDepth = parseScanDepth()\n\n  for (const raw of globs) {\n    const pattern = raw.replace(/^\\.\\//, '')\n\n    if (!pattern.includes('*')) {\n      const candidate = path.join(scanPath, pattern)\n      if (await exists(path.join(candidate, 'package.json'))) found.add(candidate)\n      continue\n    }\n\n    const segments = pattern.split('/')\n    const staticSegments: string[] = []\n    for (const seg of segments) {\n      if (seg.includes('*')) break\n      staticSegments.push(seg)\n    }\n    const start = path.join(scanPath, ...staticSegments)\n    if (!(await exists(start))) continue\n\n    const hasDoubleStar = pattern.includes('**')\n    const walkDepth = hasDoubleStar\n      ? scanDepth\n      : Math.max(0, segments.length - staticSegments.length - 1)\n\n    await walkDirs(start, scanPath, { maxDepth: walkDepth, ig: null }, async (dir) => {\n      const rel = path.relative(scanPath, dir).split(path.sep).join('/')\n      if (minimatch(rel, pattern) && (await exists(path.join(dir, 'package.json')))) {\n        found.add(dir)\n      }\n    })\n  }\n\n  return [...found]\n}\n\n// Framework detection from package.json deps (ADR-074 §3). Mirrors the\n// installer dispatch precedence so a project the installer recognises as\n// Remix records `framework: 'remix'` on its ServiceNode. The static\n// extractor sees only manifest data, so detection is dep-presence based —\n// it doesn't crack open config files. Detection precedence: Next → Remix\n// → SvelteKit → Nuxt → Astro → NestJS → vanilla Node.\nfunction detectJsFramework(pkg: PackageJson): string | undefined {\n  const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n  if (deps['next'] !== undefined) return 'next'\n  if (deps['remix'] !== undefined) return 'remix'\n  for (const k of Object.keys(deps)) {\n    if (k.startsWith('@remix-run/')) return 'remix'\n  }\n  if (deps['@sveltejs/kit'] !== undefined) return 'sveltekit'\n  if (deps['nuxt'] !== undefined) return 'nuxt'\n  if (deps['astro'] !== undefined) return 'astro'\n  if (deps['@nestjs/core'] !== undefined) return 'nestjs'\n  return undefined\n}\n\n// A JS-manifest service is TypeScript when its package depends on `typescript`\n// or carries a tsconfig — otherwise we default to javascript. The per-file\n// extractor already routes by extension (`languageForPath`); this only sets the\n// ServiceNode's own `language` field, which the static walker can't read off a\n// single file. One readdir, conservative on the javascript side.\nasync function detectJsServiceLanguage(\n  dir: string,\n  pkg: PackageJson,\n): Promise<'typescript' | 'javascript'> {\n  const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n  if (deps['typescript'] !== undefined) return 'typescript'\n  const entries = await fs.readdir(dir).catch(() => [] as string[])\n  if (entries.some((name) => /^tsconfig(\\..+)?\\.json$/.test(name))) return 'typescript'\n  return 'javascript'\n}\n\nasync function discoverNodeService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  const pkgPath = path.join(dir, 'package.json')\n  if (!(await exists(pkgPath))) return null\n  let pkg: PackageJson\n  try {\n    pkg = await readJson<PackageJson>(pkgPath)\n  } catch (err) {\n    recordExtractionError('services', path.relative(scanPath, pkgPath), err)\n    return null\n  }\n  if (!pkg.name) return null\n  const framework = detectJsFramework(pkg)\n  const language = await detectJsServiceLanguage(dir, pkg)\n  const node: ServiceNode = {\n    id: serviceId(pkg.name),\n    type: NodeType.ServiceNode,\n    name: pkg.name,\n    language,\n    version: pkg.version,\n    dependencies: pkg.dependencies ?? {},\n    repoPath: path.relative(scanPath, dir),\n    ...(pkg.engines?.node ? { nodeEngine: pkg.engines.node } : {}),\n    ...(framework ? { framework } : {}),\n  }\n  return { pkg, dir, node }\n}\n\nasync function discoverPyService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  const py = await discoverPythonService(dir)\n  if (!py) return null\n  const pkg = pythonToPackage(py)\n  const node: ServiceNode = {\n    id: serviceId(py.name),\n    type: NodeType.ServiceNode,\n    name: py.name,\n    language: 'python',\n    version: py.version,\n    dependencies: py.dependencies,\n    repoPath: path.relative(scanPath, dir),\n  }\n  return { pkg, dir, node }\n}\n\n// Phase 1 — discover service directories under scanPath. A service is any\n// directory containing a language manifest — a JS/TS `package.json`, a Python\n// `pyproject.toml` / `requirements.txt` / `setup.py`, a Go `go.mod`, a Ruby\n// `Gemfile`, a PHP `composer.json`, a C#/.NET `*.csproj` / `*.sln` (ADR-196), or a\n// Java or Kotlin `pom.xml` / `build.gradle` / `build.gradle.kts` (ADR-197, ADR-199 —\n// the JVM manifest is shared, so the `.kt`-vs-`.java` source decides which language),\n// or a Rust `Cargo.toml` (ADR-201), or a C++ `CMakeLists.txt` (ADR-202) — with the\n// manifest paths tried in that order so an earlier one wins on tie. A\n// manifest-less directory that a `Dockerfile` plus source declares is discovered last\n// (ADR-194), so a manifest always takes precedence and nothing double-mints.\n//\n// If the root `package.json` declares `workspaces`, those globs are\n// authoritative — we don't fall back to a free recursive walk. Otherwise we\n// walk recursively, depth-bounded by `NEAT_SCAN_DEPTH` (default 5), skipping\n// `IGNORED_DIRS` and anything matched by the root `.gitignore`.\n//\n// Two manifests sharing a `name` collapse to one node per ADR-010; the\n// duplicate logs a warning naming both paths.\nexport async function discoverServices(scanPath: string): Promise<DiscoveredService[]> {\n  const rootPkgPath = path.join(scanPath, 'package.json')\n  let rootPkg: RootPackageJson | null = null\n  if (await exists(rootPkgPath)) {\n    try {\n      rootPkg = await readJson<RootPackageJson>(rootPkgPath)\n    } catch (err) {\n      recordExtractionError(\n        'services workspaces',\n        path.relative(scanPath, rootPkgPath),\n        err,\n      )\n    }\n  }\n  const wsGlobs = rootPkg ? workspaceGlobs(rootPkg) : null\n\n  const candidateDirs: string[] = []\n  if (wsGlobs) {\n    candidateDirs.push(...(await expandWorkspaceGlobs(scanPath, wsGlobs)))\n  } else {\n    if (rootPkg && rootPkg.name) {\n      candidateDirs.push(scanPath)\n    } else if (\n      (await hasPythonManifest(scanPath)) ||\n      (await hasGoManifest(scanPath)) ||\n      (await hasRubyManifest(scanPath)) ||\n      (await hasPhpManifest(scanPath)) ||\n      (await hasCsharpManifest(scanPath)) ||\n      (await hasJavaManifest(scanPath)) ||\n      (await hasRustManifest(scanPath)) ||\n      (await hasCppManifest(scanPath))\n    ) {\n      // A Python / Go / Rails / Laravel / .NET / Java / Rust / C++ project commonly keeps\n      // its manifest at the repo root with the code in a subpackage and no\n      // package.json anywhere. The walk only visits descendants, so without this\n      // the root manifest is never seen and the whole project discovers zero\n      // services.\n      candidateDirs.push(scanPath)\n    }\n    const ig = await loadGitignore(scanPath)\n    await walkDirs(\n      scanPath,\n      scanPath,\n      { maxDepth: parseScanDepth(), ig },\n      async (dir) => {\n        if (await exists(path.join(dir, 'package.json'))) {\n          candidateDirs.push(dir)\n        } else if (\n          (await hasPythonManifest(dir)) ||\n          (await hasGoManifest(dir)) ||\n          (await hasRubyManifest(dir)) ||\n          (await hasPhpManifest(dir)) ||\n          (await hasCsharpManifest(dir)) ||\n          (await hasJavaManifest(dir)) ||\n          (await hasRustManifest(dir)) ||\n          (await hasCppManifest(dir))\n        ) {\n          candidateDirs.push(dir)\n        } else if (await hasDockerfileDeclaredService(dir)) {\n          // A manifest-less dir that a Dockerfile plus source declares a service\n          // (ADR-194). Ordered last so any manifest wins; the walk has already\n          // skipped IGNORED_DIRS and .gitignore, so vendored dirs never land here.\n          candidateDirs.push(dir)\n        }\n      },\n    )\n  }\n\n  candidateDirs.sort()\n\n  const seen = new Map<string, string>()\n  const seenDirs = new Set<string>()\n  const out: DiscoveredService[] = []\n  for (const dir of candidateDirs) {\n    const service =\n      (await discoverNodeService(scanPath, dir)) ??\n      (await discoverPyService(scanPath, dir)) ??\n      (await discoverGoService(scanPath, dir)) ??\n      (await discoverRubyService(scanPath, dir)) ??\n      (await discoverPhpService(scanPath, dir)) ??\n      (await discoverCsharpService(scanPath, dir)) ??\n      // Kotlin runs ahead of Java: both mark a service with the same Maven/Gradle\n      // manifest, so Kotlin claims a JVM-manifest dir whose source is `.kt` (ADR-199)\n      // and a `.java`-dominant one falls through to the Java reader unchanged.\n      (await discoverKotlinService(scanPath, dir)) ??\n      (await discoverJavaService(scanPath, dir)) ??\n      // Rust keys on a `Cargo.toml`, a manifest no other language shares (ADR-201),\n      // so its order among the distinct-manifest discoverers doesn't matter.\n      (await discoverRustService(scanPath, dir)) ??\n      // C++ keys on a `CMakeLists.txt`, likewise a manifest no other language shares\n      // (ADR-202), so it too sits anywhere among the distinct-manifest discoverers.\n      (await discoverCppService(scanPath, dir)) ??\n      (await discoverDockerfileService(scanPath, dir))\n    if (!service) continue\n\n    // A C# service root and its nested `src/` project resolve to the same service\n    // directory (ADR-196), and the recursive walk surfaces both as candidates.\n    // Collapse them silently on that resolved directory — before the name check,\n    // so the nested layout never double-mints and never trips the duplicate-name\n    // warning. Every other discoverer anchors on the candidate dir itself, which\n    // is unique per candidate, so this only ever folds the C# root/src pair.\n    if (seenDirs.has(service.dir)) continue\n    seenDirs.add(service.dir)\n\n    const existingDir = seen.get(service.node.name)\n    if (existingDir !== undefined) {\n      const a = path.relative(scanPath, existingDir) || '.'\n      const b = path.relative(scanPath, dir) || '.'\n      console.warn(\n        `[neat] duplicate package name \"${service.node.name}\" — keeping ${a}, ignoring ${b}`,\n      )\n      continue\n    }\n    seen.set(service.node.name, dir)\n    out.push(service)\n\n    // ADR-255 — a Go module with two or more `cmd/<name>/main.go` is one service\n    // per binary, plus the module service for the code they share.\n    for (const bin of await splitGoBinaries(service)) {\n      const taken = seen.get(bin.node.name)\n      if (taken !== undefined) {\n        console.warn(\n          `[neat] duplicate package name \"${bin.node.name}\" — keeping ${path.relative(scanPath, taken) || '.'}, ignoring the Go binary cmd/${bin.node.name}`,\n        )\n        continue\n      }\n      seen.set(bin.node.name, dir)\n      out.push(bin)\n    }\n  }\n\n  // Owner extraction (ADR-054). CODEOWNERS first, package.json `author`\n  // fallback, undefined otherwise. Read once per discovery pass; the file\n  // is small and parsing it per-service would be wasteful.\n  const codeowners = await loadCodeowners(scanPath)\n  for (const service of out) {\n    const owner = await computeServiceOwner(codeowners, service.node.repoPath, service.dir)\n    if (owner !== undefined) service.node.owner = owner\n  }\n\n  // ADR-200 — nearest-service-wins file ownership. A source file belongs to the\n  // deepest discovered service that contains it. When the root manifest has a\n  // name but no `workspaces`, the root becomes a service at `scanPath` *and* the\n  // recursive walk discovers every nested service under it; without ownership the\n  // root's file walk re-visits each nested service's subtree and re-mints its\n  // symbols/routes/ORM nodes under the root — inert repo-relative phantoms that\n  // never fuse and double-count every nested service. So for each service, record\n  // the dirs of the other discovered services nested strictly under it; the shared\n  // file walk skips those subtrees. Applied uniformly to every service (root,\n  // no-workspace, and workspace member alike) — a workspace member that nests a\n  // discovered service excludes it the same way.\n  const resolvedDirs = out.map((s) => path.resolve(s.dir))\n  for (let i = 0; i < out.length; i++) {\n    const self = resolvedDirs[i]!\n    const nested: string[] = []\n    for (let j = 0; j < out.length; j++) {\n      if (i === j) continue\n      const other = resolvedDirs[j]!\n      if (other.startsWith(self + path.sep)) nested.push(other)\n    }\n    // Appended, not replaced: a Go binary split (ADR-255) has already excluded the\n    // files it doesn't own.\n    out[i]!.excludeDirs = [...(out[i]!.excludeDirs ?? []), ...nested]\n  }\n\n  return out\n}\n\nexport function addServiceNodes(graph: NeatGraph, services: DiscoveredService[]): number {\n  let nodesAdded = 0\n  for (const service of services) {\n    if (!graph.hasNode(service.node.id)) {\n      graph.addNode(service.node.id, { ...service.node, discoveredVia: 'static' })\n      nodesAdded++\n      continue\n    }\n    // OTel ingest may have auto-created a minimal node at this id. Merge per\n    // ADR-033 / identity contract: static fields override OTel-derived fields,\n    // and discoveredVia flips to 'merged' when both layers contributed.\n    const existing = graph.getNodeAttributes(service.node.id) as ServiceNode\n    const mergedDiscoveredVia: 'static' | 'otel' | 'merged' =\n      existing.discoveredVia === 'otel' ? 'merged' : 'static'\n    graph.replaceNodeAttributes(service.node.id, {\n      ...existing,\n      ...service.node,\n      discoveredVia: mergedDiscoveredVia,\n    })\n  }\n  return nodesAdded\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport { exists, type PackageJson } from './shared.js'\n\n// Lines like `psycopg2==2.7.0`, `psycopg2 == 2.7.0`, `psycopg2[extras]==2.7`,\n// or `psycopg2~=2.7,<3`. We capture the package name and the first version\n// that follows an `==` operator. Anything else (range, no pin, no version) is\n// recorded with an empty version — the compat matrix's semver coercer treats\n// those as \"can't reason\" and under-flags rather than over-flags.\nconst REQUIREMENT_LINE = /^\\s*([A-Za-z0-9_.-]+)(?:\\[[^\\]]*\\])?\\s*(?:(==)\\s*([A-Za-z0-9_.+-]+))?/\n\nfunction parseRequirementsTxt(content: string): Record<string, string> {\n  const out: Record<string, string> = {}\n  for (const rawLine of content.split('\\n')) {\n    const line = rawLine.split('#')[0]?.trim()\n    if (!line) continue\n    if (line.startsWith('-')) continue // -r requirements-dev.txt etc.\n    const match = REQUIREMENT_LINE.exec(line)\n    if (!match) continue\n    const name = match[1]!.toLowerCase()\n    const version = match[3] ?? ''\n    out[name] = version\n  }\n  return out\n}\n\ninterface PyProjectFile {\n  project?: {\n    name?: string\n    version?: string\n    dependencies?: string[]\n  }\n  tool?: {\n    poetry?: {\n      name?: string\n      version?: string\n      dependencies?: Record<string, string | { version?: string }>\n    }\n  }\n}\n\nfunction depsFromPyProject(pyproject: PyProjectFile): Record<string, string> {\n  const out: Record<string, string> = {}\n\n  // PEP 621 — [project] dependencies = [\"psycopg2==2.7.0\", \"requests\"]\n  for (const entry of pyproject.project?.dependencies ?? []) {\n    const match = REQUIREMENT_LINE.exec(entry)\n    if (!match) continue\n    out[match[1]!.toLowerCase()] = match[3] ?? ''\n  }\n\n  // Poetry — [tool.poetry.dependencies] psycopg2 = \"2.7.0\"\n  const poetryDeps = pyproject.tool?.poetry?.dependencies ?? {}\n  for (const [name, value] of Object.entries(poetryDeps)) {\n    if (name.toLowerCase() === 'python') continue\n    const raw = typeof value === 'string' ? value : (value?.version ?? '')\n    out[name.toLowerCase()] = raw.replace(/^[\\^~><=v\\s]+/, '')\n  }\n  return out\n}\n\nexport interface PythonService {\n  name: string\n  version?: string\n  dependencies: Record<string, string>\n}\n\n// Detect a Python service by the conventional manifest files. We try\n// pyproject.toml first because it can name the package; fallback to the\n// directory name when only requirements.txt or setup.py is present.\nexport async function discoverPythonService(serviceDir: string): Promise<PythonService | null> {\n  const pyprojectPath = path.join(serviceDir, 'pyproject.toml')\n  const requirementsPath = path.join(serviceDir, 'requirements.txt')\n  const setupPath = path.join(serviceDir, 'setup.py')\n\n  const hasPyproject = await exists(pyprojectPath)\n  const hasRequirements = await exists(requirementsPath)\n  const hasSetup = await exists(setupPath)\n  if (!hasPyproject && !hasRequirements && !hasSetup) return null\n\n  let name = path.basename(serviceDir)\n  let version: string | undefined\n  const dependencies: Record<string, string> = {}\n\n  if (hasPyproject) {\n    const raw = await fs.readFile(pyprojectPath, 'utf8')\n    const pyproject = parseToml(raw) as PyProjectFile\n    name = pyproject.project?.name ?? pyproject.tool?.poetry?.name ?? name\n    version = pyproject.project?.version ?? pyproject.tool?.poetry?.version ?? undefined\n    Object.assign(dependencies, depsFromPyProject(pyproject))\n  }\n\n  if (hasRequirements) {\n    const raw = await fs.readFile(requirementsPath, 'utf8')\n    Object.assign(dependencies, parseRequirementsTxt(raw))\n  }\n\n  return { name, version, dependencies }\n}\n\n// Build the same `pkg`-shaped shim the JS path uses so downstream phases\n// (databases, calls, etc.) can keep reading service.pkg.dependencies and\n// service.pkg.name without caring which language produced the service.\nexport function pythonToPackage(service: PythonService): PackageJson {\n  return {\n    name: service.name,\n    version: service.version,\n    dependencies: service.dependencies,\n  }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { serviceId } from '@neat.is/types'\nimport type { DiscoveredService } from './shared.js'\nimport { IGNORED_DIRS } from './shared.js'\nimport { goImports, readGoModule } from './go.js'\n\n// ADR-255 — one Go module, several binaries. A repository like DeathStarBench's\n// hotelReservation is a single go.mod with one `cmd/<name>/main.go` per deployed\n// service, and its packages under `services/<name>/`. Discovery keys a Go service\n// on go.mod, so the whole repository was one service named after the module,\n// while each binary reports its own `service.name` at runtime (`frontend`, `geo`).\n//\n// When a module has two or more `cmd/<name>/main.go`, each becomes a service named\n// `<name>`. A Go package is a directory, so ownership is per package directory:\n// - a package reachable from exactly one binary's import closure (imports inside\n//   this module only) belongs to that binary's service;\n// - a package reachable from several binaries, or from none, stays on the module\n//   service as shared code, never duplicated;\n// - a directory with no Go package of its own (static assets, a config dir)\n//   follows its nearest ancestor package directory, else the module.\n// Every binary service and the module service keep the module root as `dir`, so\n// file ids stay module-relative; each one excludes the files it doesn't own.\n// A module with one main (or none) is returned unchanged, so existing repos don't\n// move.\n\ninterface GoFile {\n  abs: string\n  dir: string\n}\n\nasync function listModuleFiles(moduleDir: string): Promise<string[]> {\n  const out: string[] = []\n  async function walk(current: string, isRoot: boolean): Promise<void> {\n    const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n    // A nested go.mod or Gopkg.toml is another module; its files are not this module's.\n    if (!isRoot && entries.some((e) => e.isFile() && (e.name === 'go.mod' || e.name === 'Gopkg.toml'))) return\n    for (const entry of entries) {\n      const full = path.join(current, entry.name)\n      if (entry.isDirectory()) {\n        if (IGNORED_DIRS.has(entry.name) || entry.name.startsWith('.')) continue\n        await walk(full, false)\n      } else if (entry.isFile()) {\n        out.push(full)\n      }\n    }\n  }\n  await walk(moduleDir, true)\n  return out\n}\n\nexport async function splitGoBinaries(module: DiscoveredService): Promise<DiscoveredService[]> {\n  if (module.node.language !== 'go') return []\n  const root = path.resolve(module.dir)\n  const mod = await readGoModule(root)\n  if (!mod) return []\n  const modulePath = mod.module\n  const cmdDir = path.join(root, 'cmd')\n  const cmdEntries = await fs.readdir(cmdDir, { withFileTypes: true }).catch(() => [])\n  const binaries: string[] = []\n  for (const e of cmdEntries) {\n    if (!e.isDirectory()) continue\n    const main = path.join(cmdDir, e.name, 'main.go')\n    if (await fs.stat(main).then((s) => s.isFile()).catch(() => false)) binaries.push(e.name)\n  }\n  if (binaries.length < 2) return []\n  binaries.sort()\n\n  const files = await listModuleFiles(root)\n  const goFiles: GoFile[] = files\n    .filter((f) => f.endsWith('.go') && !f.endsWith('_test.go'))\n    .map((abs) => ({ abs, dir: path.dirname(abs) }))\n  const packageDirs = new Set(goFiles.map((f) => f.dir))\n\n  // package dir → the in-module package dirs it imports.\n  const importsOf = new Map<string, Set<string>>()\n  const prefix = modulePath + '/'\n  for (const f of goFiles) {\n    const src = await fs.readFile(f.abs, 'utf8').catch(() => '')\n    const set = importsOf.get(f.dir) ?? new Set<string>()\n    for (const imp of goImports(src)) {\n      if (!imp.startsWith(prefix)) continue\n      const dir = path.join(root, ...imp.slice(prefix.length).split('/'))\n      if (packageDirs.has(dir)) set.add(dir)\n    }\n    importsOf.set(f.dir, set)\n  }\n\n  // Which binaries reach each package.\n  const reachedBy = new Map<string, Set<string>>()\n  for (const bin of binaries) {\n    const start = path.join(cmdDir, bin)\n    const seen = new Set<string>([start])\n    const queue = [start]\n    while (queue.length > 0) {\n      const dir = queue.shift()!\n      for (const next of importsOf.get(dir) ?? []) {\n        if (!seen.has(next)) {\n          seen.add(next)\n          queue.push(next)\n        }\n      }\n    }\n    for (const dir of seen) {\n      const set = reachedBy.get(dir) ?? new Set<string>()\n      set.add(bin)\n      reachedBy.set(dir, set)\n    }\n  }\n\n  // The owning binary of a directory, or null for the module (shared).\n  const ownerCache = new Map<string, string | null>()\n  function ownerOf(dir: string): string | null {\n    const cached = ownerCache.get(dir)\n    if (cached !== undefined) return cached\n    let owner: string | null\n    if (packageDirs.has(dir)) {\n      const bins = reachedBy.get(dir)\n      owner = bins && bins.size === 1 ? [...bins][0]! : null\n    } else if (dir === root || !dir.startsWith(root + path.sep)) {\n      owner = null\n    } else {\n      owner = ownerOf(path.dirname(dir))\n    }\n    ownerCache.set(dir, owner)\n    return owner\n  }\n\n  const ownedBy = new Map<string | null, string[]>()\n  for (const f of files) {\n    const owner = ownerOf(path.dirname(f))\n    const list = ownedBy.get(owner) ?? []\n    list.push(f)\n    ownedBy.set(owner, list)\n  }\n  const notOwnedBy = (owner: string | null): string[] =>\n    [...ownedBy.entries()].filter(([o]) => o !== owner).flatMap(([, fs]) => fs)\n\n  // The module service keeps the shared code; it excludes what a binary owns.\n  module.excludeDirs = [...(module.excludeDirs ?? []), ...notOwnedBy(null)]\n\n  return binaries.map((bin) => {\n    const node: ServiceNode = { ...module.node, id: serviceId(bin), name: bin }\n    return {\n      pkg: { ...module.pkg, name: bin },\n      dir: module.dir,\n      node,\n      excludeDirs: notOwnedBy(bin),\n    }\n  })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport type { DiscoveredService, PackageJson } from './shared.js'\n\n// Ruby service discovery (ADR-173), the Gemfile analog of extract/go.ts's\n// `go.mod` reader. A Gemfile names no project, so the service takes its\n// directory's basename; the `gem` lines become dependency gates the way a\n// `go.mod` `require` block does, so the route producer can gate on `rails`.\n\nexport interface Gemfile {\n  dependencies: Record<string, string>\n}\n\n// Read the gems a Gemfile declares. `gem 'rails', '~> 7.1'` → { rails: '~> 7.1' }.\n// A version is optional (`gem 'puma'` → ''); a gem with only non-version options\n// (`gem 'pg', require: false`) still registers, at ''. Commented lines are\n// skipped. This is a line scan, not a Ruby parse — the same discipline go.ts's\n// `go.mod` reader and proto.ts's `.proto` scan use for polyglot manifest data.\nexport function parseGemfile(source: string): Gemfile {\n  const dependencies: Record<string, string> = {}\n  for (const raw of source.split(/\\r?\\n/)) {\n    const line = raw.replace(/#.*$/, '').trim()\n    const m = line.match(/^gem\\s+(['\"])([^'\"]+)\\1\\s*(?:,\\s*(['\"])([^'\"]+)\\3)?/)\n    if (!m) continue\n    const name = m[2]!\n    const version = m[4] && /\\d/.test(m[4]) ? m[4] : ''\n    dependencies[name] = version\n  }\n  return { dependencies }\n}\n\nexport async function discoverRubyService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  let raw: string\n  try {\n    raw = await fs.readFile(path.join(dir, 'Gemfile'), 'utf8')\n  } catch {\n    return null\n  }\n  const gemfile = parseGemfile(raw)\n  const name = path.basename(dir)\n  const pkg: PackageJson = { name, dependencies: gemfile.dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'ruby',\n    dependencies: gemfile.dependencies,\n    repoPath: path.relative(scanPath, dir),\n    ...(gemfile.dependencies['rails'] !== undefined ? { framework: 'rails' } : {}),\n  }\n  return { pkg, dir, node }\n}\n","import path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport { readJson, type DiscoveredService, type PackageJson } from './shared.js'\n\n// PHP service discovery (ADR-177), the `composer.json` analog of extract/ruby.ts's\n// Gemfile reader and extract/go.ts's `go.mod` reader. A composer.json does name a\n// project (`vendor/package`), but we keep the basename-as-service-name convention\n// the Gemfile/go.mod readers use so a PHP service sits next to the others without\n// a vendor slash in its id; the `require` block becomes the dependency gates the\n// route producer reads, so it can gate on `laravel/framework`.\n\ninterface ComposerJson {\n  name?: string\n  require?: Record<string, string>\n  'require-dev'?: Record<string, string>\n}\n\nexport interface Composer {\n  dependencies: Record<string, string>\n}\n\n// Read the packages a composer.json declares, merging `require` and\n// `require-dev` the way the JS reader merges dependencies and devDependencies.\n// `laravel/framework` in `require` is the gate the Laravel route recognizer uses.\nexport function parseComposerJson(composer: ComposerJson): Composer {\n  return {\n    dependencies: {\n      ...(composer.require ?? {}),\n      ...(composer['require-dev'] ?? {}),\n    },\n  }\n}\n\nexport async function discoverPhpService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  let composer: ComposerJson\n  try {\n    composer = await readJson<ComposerJson>(path.join(dir, 'composer.json'))\n  } catch {\n    return null\n  }\n  const { dependencies } = parseComposerJson(composer)\n  const name = path.basename(dir)\n  const pkg: PackageJson = { name, dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'php',\n    dependencies,\n    repoPath: path.relative(scanPath, dir),\n    ...(dependencies['laravel/framework'] !== undefined ? { framework: 'laravel' } : {}),\n  }\n  return { pkg, dir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport type { DiscoveredService, PackageJson } from './shared.js'\n\n// C#/.NET service discovery (ADR-196), the MSBuild-project analog of\n// extract/ruby.ts's Gemfile reader, extract/php.ts's composer.json reader, and\n// extract/go.ts's go.mod reader. A .NET service is a directory that ships an\n// MSBuild project — a `*.csproj` — or a solution — a `*.sln`. Unlike the other\n// language manifests, the marker is a glob, not a fixed filename: the file is\n// named after the assembly (`Cart.csproj`, `Accounting.csproj`), so a directory\n// is a service when it holds *any* `.csproj` / `.sln`. The `.csproj` names the\n// service (its basename, the assembly name convention); a `.sln`-only directory\n// falls back to the directory basename. `PackageReference` items become the\n// dependency gates a later route / EF Core recognizer keys on, the way a go.mod\n// `require` block or a composer.json `require` does.\n//\n// The project can sit at the service-root directory (`accounting/Accounting.csproj`,\n// the flat layout, `.cs` beside it) or one level down in the conventional `src/`\n// subdirectory (`cart/src/cart.csproj`, the nested layout the otel-demo `cart`\n// service uses). Both are real .NET service shapes, so the lookup checks the\n// directory itself first, then its `src/` child. The top level wins on a tie, and\n// the nested case anchors on the `src/` directory that actually holds the project —\n// the same directory the recursive discovery walk reaches on its own, so a\n// whole-repo scan and a scan pointed straight at the service root land the same\n// node (the discovery loop collapses the two candidates on that shared directory).\n\nexport interface Csproj {\n  dependencies: Record<string, string>\n}\n\n// The MSBuild project extensions that mark a .NET service directory. A `.csproj`\n// is a single project; a `.sln` aggregates projects. Either is an explicit\n// \"this is a .NET service\" marker.\nconst CSHARP_PROJECT_EXTS = new Set(['.csproj', '.sln'])\n\n// List the .NET project markers at the top level of `dir`, sorted so discovery\n// picks the same one on every pass (idempotency). One readdir; the glob shape\n// (any `*.csproj` / `*.sln`) is why C# can't ride the fixed-filename `exists`\n// checks the other manifests use.\nasync function projectFiles(dir: string): Promise<string[]> {\n  const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])\n  const out: string[] = []\n  for (const entry of entries) {\n    if (!entry.isFile()) continue\n    if (CSHARP_PROJECT_EXTS.has(path.extname(entry.name).toLowerCase())) out.push(entry.name)\n  }\n  return out.sort()\n}\n\n// The conventional subdirectory a .NET service keeps its project in when it isn't\n// flat at the root. Kept to the single `src/` convention — not an open recursive\n// hunt — so discovery stays precise: a directory becomes a service only on an\n// actual `.csproj` / `.sln`, at the root or exactly one `src/` level down.\nconst NESTED_PROJECT_DIR = 'src'\n\n// Conventional subdirectories whose own basename is not a service name — a nested\n// project's `src/`, a test project's `tests/` / `test/`. When a candidate dir IS one\n// of these, the service is named from its parent, so the root/subdir candidates fold\n// onto one service via the duplicate-name dedup rather than minting a bogus `src` /\n// `tests` service (ADR-252).\nconst NAMING_SUBDIRS = new Set([NESTED_PROJECT_DIR, 'tests', 'test'])\n\n// Resolve the directory that actually holds `dir`'s MSBuild project: `dir` itself\n// when it carries a top-level `.csproj` / `.sln` (the flat layout, top level wins),\n// else its `src/` child when that carries one (the nested layout), else null when\n// neither does. This is the one place the flat-vs-nested choice is made; every\n// other function reads through it.\nasync function resolveProjectDir(dir: string): Promise<string | null> {\n  if ((await projectFiles(dir)).length > 0) return dir\n  const nested = path.join(dir, NESTED_PROJECT_DIR)\n  if ((await projectFiles(nested)).length > 0) return nested\n  return null\n}\n\n// Cheap predicate the discovery walk and the Dockerfile fallback share: does this\n// directory carry a `.csproj` or `.sln` — at its root or one `src/` level down?\n// Keyed on the glob, so it can't be an `exists(path.join(dir, 'X'))` the way\n// `hasGoManifest` is.\nexport async function hasCsharpProject(dir: string): Promise<boolean> {\n  return (await resolveProjectDir(dir)) !== null\n}\n\n// Read the `PackageReference` items a `.csproj` declares. A line/regex scan, the\n// same discipline go.ts's go.mod reader and ruby.ts's Gemfile reader use for\n// polyglot manifest data — not a full MSBuild parse. The version is optional\n// (Central Package Management moves it to `Directory.Packages.props`), so a\n// reference with only an `Include` registers at ''. `Microsoft.AspNetCore.*` in\n// the set is the gate a later ASP.NET route recognizer reads.\nexport function parseCsproj(source: string): Csproj {\n  const dependencies: Record<string, string> = {}\n  const re = /<PackageReference\\b([^>]*?)\\/?>/g\n  let m: RegExpExecArray | null\n  while ((m = re.exec(source)) !== null) {\n    const attrs = m[1] ?? ''\n    const include = attrs.match(/\\bInclude\\s*=\\s*\"([^\"]+)\"/)?.[1]\n    if (!include) continue\n    const version = attrs.match(/\\bVersion\\s*=\\s*\"([^\"]+)\"/)?.[1]\n    dependencies[include] = version ?? ''\n  }\n  return { dependencies }\n}\n\nexport async function discoverCsharpService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  // Flat (`dir/X.csproj`) or nested (`dir/src/X.csproj`) — `projectDir` is\n  // whichever actually holds the project; null when neither does.\n  const projectDir = await resolveProjectDir(dir)\n  if (projectDir === null) return null\n  const projects = await projectFiles(projectDir)\n\n  // The service is named from its directory, matching every other manifest reader\n  // (Go module basename, Ruby / PHP / Rust / C++ / Gradle-Java dir basename) and the\n  // deployed OTEL_SERVICE_NAME / k8s convention. A `.csproj` basename is the PascalCase\n  // assembly name (`Accounting.csproj`), which doesn't fuse with the lowercase runtime\n  // `service.name` (`accounting`) — the directory is the stable, deploy-matching\n  // identity (ADR-252). A candidate that IS a nested `src/` / `tests/` subdir takes its\n  // parent's name, so the root/subdir pair folds onto one service. The `.csproj` is\n  // still read below for its PackageReference dependencies.\n  const csproj = projects.find((p) => p.toLowerCase().endsWith('.csproj'))\n  const base = path.basename(dir)\n  const name = NAMING_SUBDIRS.has(base) ? path.basename(path.dirname(dir)) : base\n\n  let dependencies: Record<string, string> = {}\n  if (csproj) {\n    const raw = await fs.readFile(path.join(projectDir, csproj), 'utf8').catch(() => '')\n    dependencies = parseCsproj(raw).dependencies\n  }\n\n  const pkg: PackageJson = { name, dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'csharp',\n    dependencies,\n    // Anchor on the directory that holds the project and its `.cs` files, so file\n    // attribution reaches the source whether it sits at the root or under `src/`.\n    repoPath: path.relative(scanPath, projectDir),\n  }\n  return { pkg, dir: projectDir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport { exists, type DiscoveredService, type PackageJson } from './shared.js'\n\n// Java service discovery (ADR-197), the build-manifest analog of extract/ruby.ts's\n// Gemfile reader, extract/php.ts's composer.json reader, and extract/go.ts's go.mod\n// reader. A Java service is a directory that ships a build manifest — a Maven\n// `pom.xml` or a Gradle `build.gradle` / `build.gradle.kts`. Unlike C# (ADR-196),\n// the marker is a fixed filename, so it rides the same `exists` predicate the\n// Ruby/PHP/Go readers use rather than a directory glob. Maven's `pom.xml` names the\n// project (its `<artifactId>`); a Gradle build has no name in `build.gradle` (the\n// canonical `rootProject.name` lives in `settings.gradle`), so it falls back to the\n// directory basename — the same basename-as-service-name convention the Gemfile and\n// go.mod readers use. Declared dependencies (`groupId:artifactId`) become the gates\n// a later Spring / JPA recognizer keys on, the way a go.mod `require` block does.\n\n// The build manifests that mark a Java service directory. Maven keys on `pom.xml`;\n// Gradle on `build.gradle` (Groovy DSL) or `build.gradle.kts` (Kotlin DSL). Any one\n// is an explicit \"this is a Java service\" marker, a fixed filename, not a glob.\nexport const JAVA_MANIFESTS = ['pom.xml', 'build.gradle', 'build.gradle.kts'] as const\n\nexport interface JavaManifest {\n  // The project name a Maven `pom.xml` declares (`<artifactId>`), if any. Gradle\n  // builds carry no name here, so this is undefined and discovery uses the dir.\n  name?: string\n  dependencies: Record<string, string>\n}\n\n// Cheap predicate the discovery walk and the Dockerfile fallback share: does this\n// directory carry a Maven or Gradle build manifest? A fixed-filename `exists`\n// check, the same shape `hasGoManifest` uses (extract/services.ts) — the Java\n// marker is a filename, not the directory glob C# needs (ADR-196).\nexport async function hasJavaManifest(dir: string): Promise<boolean> {\n  for (const manifest of JAVA_MANIFESTS) {\n    if (await exists(path.join(dir, manifest))) return true\n  }\n  return false\n}\n\n// Read a Maven `pom.xml`. A line/regex scan for the project `<artifactId>` and the\n// `<dependency>` coordinates, the same discipline go.ts's go.mod reader and ruby.ts's\n// Gemfile reader use for polyglot manifest data — not a full POM model with property\n// or parent-inheritance resolution. The project name is the first `<artifactId>`\n// once `<parent>` / `<dependencyManagement>` / `<dependencies>` / `<build>` blocks\n// are stripped, so the parent's or a dependency's artifactId can't be mistaken for\n// it. Each `<dependency>` registers as `groupId:artifactId` → version (version is\n// optional under a managed BOM, so it falls back to ''); `org.springframework.boot:*`\n// in the map is the gate a later Spring route recognizer reads.\nexport function parsePomXml(source: string): JavaManifest {\n  const dependencies: Record<string, string> = {}\n  const depBlock = /<dependency\\b[^>]*>([\\s\\S]*?)<\\/dependency>/g\n  let d: RegExpExecArray | null\n  while ((d = depBlock.exec(source)) !== null) {\n    const body = d[1] ?? ''\n    const groupId = body.match(/<groupId>\\s*([^<]+?)\\s*<\\/groupId>/)?.[1]\n    const artifactId = body.match(/<artifactId>\\s*([^<]+?)\\s*<\\/artifactId>/)?.[1]\n    if (!groupId || !artifactId) continue\n    const version = body.match(/<version>\\s*([^<]+?)\\s*<\\/version>/)?.[1]\n    dependencies[`${groupId}:${artifactId}`] = version ?? ''\n  }\n\n  const withoutBlocks = source\n    .replace(/<parent\\b[^>]*>[\\s\\S]*?<\\/parent>/g, '')\n    .replace(/<dependencyManagement\\b[^>]*>[\\s\\S]*?<\\/dependencyManagement>/g, '')\n    .replace(/<dependencies\\b[^>]*>[\\s\\S]*?<\\/dependencies>/g, '')\n    .replace(/<build\\b[^>]*>[\\s\\S]*?<\\/build>/g, '')\n  const name = withoutBlocks.match(/<artifactId>\\s*([^<]+?)\\s*<\\/artifactId>/)?.[1]\n  return { name, dependencies }\n}\n\n// The Gradle configurations that declare a runtime/compile dependency. A `gem`-line\n// equivalent for `build.gradle` — the string-notation coordinate is what a later\n// recognizer gates on, so the map form (`group:`, `name:`, `version:`) is out of\n// scope for a v1 line scan, the same way ruby.ts skips option-only `gem` forms.\nconst GRADLE_CONFIGS =\n  'implementation|api|compileOnly|runtimeOnly|compileOnlyApi|testImplementation|testRuntimeOnly|testCompileOnly|annotationProcessor|developmentOnly|runtimeClasspath'\n\n// Read a Gradle `build.gradle` / `build.gradle.kts`. A line scan for\n// `implementation 'group:artifact:version'` (and the Kotlin-DSL `implementation(\"…\")`\n// form) — the same discipline the Gemfile reader uses. The coordinate's first two\n// `:`-separated segments are the `groupId:artifactId` key; the remainder (version,\n// or version+classifier) is the value, '' when the coordinate names no version.\nexport function parseGradle(source: string): JavaManifest {\n  const dependencies: Record<string, string> = {}\n  const re = new RegExp(`\\\\b(?:${GRADLE_CONFIGS})\\\\s*\\\\(?\\\\s*(['\"])([^'\"]+)\\\\1`, 'g')\n  let m: RegExpExecArray | null\n  while ((m = re.exec(source)) !== null) {\n    const coord = m[2] ?? ''\n    const parts = coord.split(':')\n    if (parts.length < 2 || !parts[0] || !parts[1]) continue\n    const key = `${parts[0]}:${parts[1]}`\n    dependencies[key] = parts.slice(2).join(':')\n  }\n  return { dependencies }\n}\n\nexport async function discoverJavaService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  // Maven wins on a mixed dir (a `pom.xml` next to a `build.gradle` is a Maven\n  // project with a Gradle wrapper checked in), then Gradle Groovy, then Kotlin DSL.\n  const pomPath = path.join(dir, 'pom.xml')\n  const gradlePath = path.join(dir, 'build.gradle')\n  const gradleKtsPath = path.join(dir, 'build.gradle.kts')\n\n  let manifest: JavaManifest | null = null\n  if (await exists(pomPath)) {\n    manifest = parsePomXml(await fs.readFile(pomPath, 'utf8').catch(() => ''))\n  } else if (await exists(gradlePath)) {\n    manifest = parseGradle(await fs.readFile(gradlePath, 'utf8').catch(() => ''))\n  } else if (await exists(gradleKtsPath)) {\n    manifest = parseGradle(await fs.readFile(gradleKtsPath, 'utf8').catch(() => ''))\n  }\n  if (!manifest) return null\n\n  // The Maven `<artifactId>` names the service; a Gradle build has no name here, so\n  // it takes the directory basename the Go/Ruby/PHP readers use for name-less\n  // manifests.\n  const name = manifest.name?.trim() || path.basename(dir)\n  const dependencies = manifest.dependencies\n\n  const pkg: PackageJson = { name, dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'java',\n    dependencies,\n    repoPath: path.relative(scanPath, dir),\n  }\n  return { pkg, dir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport { exists, IGNORED_DIRS, type DiscoveredService, type PackageJson } from './shared.js'\nimport {\n  JAVA_MANIFESTS,\n  parseGradle,\n  parsePomXml,\n  hasJavaManifest,\n  type JavaManifest,\n} from './java.js'\n\n// Kotlin service discovery (ADR-199). Kotlin is the JVM sibling of Java (ADR-197)\n// and shares its entire build toolchain: a Kotlin service is a directory with the\n// *same* Maven `pom.xml` or Gradle `build.gradle` / `build.gradle.kts` a Java\n// service carries — the manifest alone can't tell the two apart. So the marker is\n// the source, not the manifest: a JVM manifest directory whose source is `.kt` is\n// Kotlin, one whose source is `.java` is Java. This reader keys on that\n// discriminator, running ahead of `discoverJavaService` in the chain so a\n// `.kt`-dominant Gradle directory (the otel-demo `fraud-detection` shape —\n// `build.gradle.kts` plus `src/main/kotlin/frauddetection/*.kt`) mints a **kotlin**\n// ServiceNode, while a `.java`-dominant one falls through untouched and Java claims\n// it exactly as before. The manifest parsing (POM `<artifactId>` naming, Gradle\n// basename fallback, `groupId:artifactId` dependency gates) is reused verbatim from\n// `extract/java.ts` — only the language label and the source-based discriminator\n// differ.\n\n// Kotlin source files. A `.kt` under the service tree is what tells a JVM-manifest\n// directory apart from a Java one; the Gradle Kotlin-DSL build script is `.kts`\n// (a manifest, not service source), so it never counts here.\nexport const KOTLIN_SOURCE_EXT = '.kt'\nconst JAVA_SOURCE_EXT = '.java'\n\n// How deep to look for source under a service directory when deciding Kotlin vs\n// Java. Kotlin conventionally lives at `src/main/kotlin/<pkg>/…`, several levels\n// below the manifest, so a top-level-only look (the Dockerfile fallback's precision\n// knob) would miss it — the discriminator has to descend, but bounded so a large\n// tree doesn't turn discovery into a full walk.\nconst SOURCE_PROBE_MAX_DEPTH = 8\n\n// The JVM source language a manifest directory actually holds. A bounded recursive\n// count of `.kt` vs `.java` files under the directory (`IGNORED_DIRS` skipped, so\n// `build/` output and vendored trees don't sway it): Kotlin wins when it is present\n// and at least ties Java, so a pure-Kotlin service resolves to `kotlin`, a pure-Java\n// one to `java`, and a mixed tree to whichever source dominates (ties to Kotlin,\n// the more specific case). `undefined` when the directory carries neither, which\n// leaves the JVM readers to fall through on a manifest with no JVM source yet.\nexport async function dominantJvmSourceLanguage(\n  dir: string,\n): Promise<'kotlin' | 'java' | undefined> {\n  let kt = 0\n  let java = 0\n\n  async function recurse(current: string, depth: number): Promise<void> {\n    if (depth > SOURCE_PROBE_MAX_DEPTH) return\n    const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n    for (const entry of entries) {\n      if (entry.isDirectory()) {\n        if (IGNORED_DIRS.has(entry.name)) continue\n        await recurse(path.join(current, entry.name), depth + 1)\n        continue\n      }\n      if (!entry.isFile()) continue\n      const ext = path.extname(entry.name).toLowerCase()\n      if (ext === KOTLIN_SOURCE_EXT) kt++\n      else if (ext === JAVA_SOURCE_EXT) java++\n    }\n  }\n  await recurse(dir, 0)\n\n  if (kt > 0 && kt >= java) return 'kotlin'\n  if (java > 0) return 'java'\n  return undefined\n}\n\n// Read the JVM build manifest a directory ships, with the same precedence\n// `discoverJavaService` uses (a `pom.xml` next to a `build.gradle` is a Maven\n// project with a Gradle wrapper checked in, so Maven wins; then Gradle Groovy, then\n// the Kotlin DSL). Reused so a Kotlin service is named and gated the same way its\n// Java sibling is.\nasync function readJvmManifest(dir: string): Promise<JavaManifest | null> {\n  const pomPath = path.join(dir, JAVA_MANIFESTS[0])\n  const gradlePath = path.join(dir, JAVA_MANIFESTS[1])\n  const gradleKtsPath = path.join(dir, JAVA_MANIFESTS[2])\n  if (await exists(pomPath)) {\n    return parsePomXml(await fs.readFile(pomPath, 'utf8').catch(() => ''))\n  }\n  if (await exists(gradlePath)) {\n    return parseGradle(await fs.readFile(gradlePath, 'utf8').catch(() => ''))\n  }\n  if (await exists(gradleKtsPath)) {\n    return parseGradle(await fs.readFile(gradleKtsPath, 'utf8').catch(() => ''))\n  }\n  return null\n}\n\nexport async function discoverKotlinService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  // Kotlin and Java both mark a service with a Maven/Gradle manifest — the source\n  // decides which. Only claim the directory when a JVM manifest is present *and*\n  // Kotlin is the dominant source; otherwise fall through so `discoverJavaService`\n  // handles a Java (or source-less) manifest directory exactly as it did before.\n  if (!(await hasJavaManifest(dir))) return null\n  if ((await dominantJvmSourceLanguage(dir)) !== 'kotlin') return null\n\n  const manifest = await readJvmManifest(dir)\n  if (!manifest) return null\n\n  // A Maven `<artifactId>` names the service; a Gradle build carries no name here,\n  // so it takes the directory basename the Go/Ruby/PHP readers use.\n  const name = manifest.name?.trim() || path.basename(dir)\n  const dependencies = manifest.dependencies\n\n  const pkg: PackageJson = { name, dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'kotlin',\n    dependencies,\n    repoPath: path.relative(scanPath, dir),\n  }\n  return { pkg, dir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport { exists, type DiscoveredService, type PackageJson } from './shared.js'\n\n// Rust service discovery (ADR-201), the Cargo analog of extract/go.ts's go.mod\n// reader and extract/java.ts's Maven/Gradle reader. A Rust service is a directory\n// that ships a `Cargo.toml` — a fixed filename, so it rides the same `exists`\n// predicate the Go/Ruby/PHP/Java readers use rather than a directory glob. Cargo's\n// `[package] name` names the service; a virtual-workspace manifest (a `[workspace]`\n// with no `[package]`) carries no name here, so it falls back to the directory\n// basename — the same basename-as-service-name convention the Gemfile and go.mod\n// readers use. Declared `[dependencies]` (crate → version) become the gates a later\n// Axum / Actix / SQLx recognizer would key on, the way a go.mod `require` block does.\n//\n// TOML is parsed with `smol-toml`, the same parser extract/python.ts reads\n// `pyproject.toml` with and the infra readers read `wrangler.toml` / `railway.toml`\n// with — the established manifest-parser for this repo, already a dependency, so no\n// hand-rolled scan and no new package (unlike java.ts, which regex-scans XML/Gradle\n// because no lightweight parser for those was on hand).\n\n// The build manifest that marks a Rust service directory. Cargo keys on a fixed\n// `Cargo.toml`, an explicit \"this is a Rust crate\" marker — a filename, not a glob.\nexport const CARGO_MANIFEST = 'Cargo.toml'\n\nexport interface CargoManifest {\n  // The crate name a `[package] name` declares, if any. A virtual-workspace\n  // manifest carries no `[package]`, so this is undefined and discovery uses the dir.\n  name?: string\n  dependencies: Record<string, string>\n}\n\n// The `Cargo.toml` shape this reader looks at — `[package] name` and the flat\n// `[dependencies]` table. A dependency's value is either a bare version string\n// (`serde = \"1.0\"`) or an inline table (`tokio = { version = \"1\", … }`); anything\n// else is a path / git source with no version.\ninterface CargoToml {\n  package?: { name?: unknown }\n  dependencies?: Record<string, unknown>\n}\n\n// Cheap predicate the discovery walk and the Dockerfile fallback share: does this\n// directory carry a `Cargo.toml`? A fixed-filename `exists` check, the same shape\n// `hasGoManifest` uses (extract/services.ts) — the Rust marker is a filename, not\n// the directory glob C# needs (ADR-196).\nexport async function hasRustManifest(dir: string): Promise<boolean> {\n  return exists(path.join(dir, CARGO_MANIFEST))\n}\n\n// Read a `Cargo.toml` into the crate name and its declared dependency gates. Each\n// `[dependencies]` entry registers as `crate` → version, whether it takes the string\n// form or the inline-table form (version '' when the table names a path / git source\n// with no version) — the same \"which packages does this service pull in\" gate a\n// go.mod `require` or a composer.json `require` provides. A malformed manifest is\n// swallowed to an empty result rather than thrown, so one bad `Cargo.toml` can't\n// abort a whole-repo discovery walk (java.ts's `.catch(() => '')` read discipline).\nexport function parseCargoToml(source: string): CargoManifest {\n  const dependencies: Record<string, string> = {}\n  let name: string | undefined\n\n  let parsed: CargoToml\n  try {\n    parsed = parseToml(source) as CargoToml\n  } catch {\n    return { dependencies }\n  }\n\n  if (typeof parsed.package?.name === 'string') name = parsed.package.name\n\n  for (const [crate, spec] of Object.entries(parsed.dependencies ?? {})) {\n    if (typeof spec === 'string') {\n      dependencies[crate] = spec\n    } else if (spec && typeof spec === 'object') {\n      const version = (spec as { version?: unknown }).version\n      dependencies[crate] = typeof version === 'string' ? version : ''\n    } else {\n      dependencies[crate] = ''\n    }\n  }\n\n  return { name, dependencies }\n}\n\nexport async function discoverRustService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  const cargoPath = path.join(dir, CARGO_MANIFEST)\n  if (!(await exists(cargoPath))) return null\n\n  const manifest = parseCargoToml(await fs.readFile(cargoPath, 'utf8').catch(() => ''))\n\n  // The `[package] name` names the service; a virtual-workspace manifest carries no\n  // name here, so it takes the directory basename the Go/Ruby/Java readers use for\n  // name-less manifests.\n  const name = manifest.name?.trim() || path.basename(dir)\n  const dependencies = manifest.dependencies\n\n  const pkg: PackageJson = { name, dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'rust',\n    dependencies,\n    repoPath: path.relative(scanPath, dir),\n  }\n  return { pkg, dir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport { exists, type DiscoveredService, type PackageJson } from './shared.js'\n\n// C++ service discovery (ADR-202), the last of the OpenTelemetry Demo languages.\n// Unlike Go/Ruby/Java/Rust, C++ has no single clean dependency manifest that also\n// names the service — a directory can build with plain `g++`, a Makefile, Bazel,\n// or CMake, and only some of those carry a service name at all. The primary marker\n// this reader keys on is CMake's `CMakeLists.txt`: a fixed filename, so it rides the\n// same `exists` predicate the Go/Ruby/Java/Rust readers use (not the directory glob\n// C# needs, ADR-196), and its `project(<name> …)` directive names the service. The\n// otel-demo `currency` service is exactly this shape — a `CMakeLists.txt` with\n// `project(currency)` plus `src/server.cpp`.\n//\n// There is no crate/gem/composer dependency table to lift into the ServiceNode's\n// `dependencies` gates — CMake's `find_package` / `target_link_libraries` are the\n// nearest analog, but they name build targets, not the versioned packages a route /\n// data recognizer would gate on — so `dependencies` is left empty here, the way the\n// Dockerfile-declared reader (ADR-194) leaves it empty. A `currency` discovered\n// instead via that Dockerfile path still reaches symbol grain: the symbol grain keys\n// off the file extension (`.cpp`), not the discovery route.\n\n// The build manifest that marks a C++ service directory. CMake keys on a fixed\n// `CMakeLists.txt`, an explicit \"this is a buildable project\" marker — a filename,\n// not a glob.\nexport const CMAKE_MANIFEST = 'CMakeLists.txt'\n\n// Cheap predicate the discovery walk and the Dockerfile fallback share: does this\n// directory carry a `CMakeLists.txt`? A fixed-filename `exists` check, the same\n// shape `hasRustManifest` / `hasJavaManifest` use — the C++ marker is a filename,\n// not the directory glob C# needs (ADR-196).\nexport async function hasCppManifest(dir: string): Promise<boolean> {\n  return exists(path.join(dir, CMAKE_MANIFEST))\n}\n\n// Read the service name out of a `CMakeLists.txt`'s `project(<name> …)` directive.\n// CMake's `project()` command always takes the project name as its first argument;\n// every optional keyword (`VERSION`, `DESCRIPTION`, `LANGUAGES`, `HOMEPAGE_URL`)\n// follows it, so the first token after `project(` is always the name. `#`-to-end-of-\n// line comments are stripped first so a commented-out `project()` can't win, and the\n// name is matched against a plain identifier character class — a computed name like\n// `project(${APP_NAME})` matches nothing and the caller falls back to the directory\n// basename. A targeted regex read, not a CMake parser: there is no TOML/JSON to lift,\n// and the name is the only field this reader needs.\nexport function parseCMakeProjectName(source: string): string | undefined {\n  const withoutComments = source.replace(/#.*$/gm, '')\n  // `project` `(` then optional whitespace/newlines, an optional quote, then the\n  // name token. `\\s` spans newlines, so a multi-line `project(\\n  currency\\n …)`\n  // still resolves. The character class is CMake's identifier shape plus the `.`/`+`\n  // /`-` that appear in real project names; `$`/`{` are excluded so a variable\n  // reference fails to match rather than capturing a bogus name.\n  const m = withoutComments.match(/\\bproject\\s*\\(\\s*\"?([A-Za-z0-9_.+-]+)\"?/i)\n  return m?.[1]\n}\n\nexport async function discoverCppService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  const cmakePath = path.join(dir, CMAKE_MANIFEST)\n  if (!(await exists(cmakePath))) return null\n\n  const source = await fs.readFile(cmakePath, 'utf8').catch(() => '')\n  // The `project()` name names the service; a manifest with no usable `project()`\n  // name takes the directory basename the Go/Ruby/Java/Rust readers use for\n  // name-less manifests.\n  const name = parseCMakeProjectName(source)?.trim() || path.basename(dir)\n\n  // No dependency-manifest analog to parse — CMake names build targets, not the\n  // versioned packages a later route / data recognizer would gate on.\n  const dependencies: Record<string, string> = {}\n\n  const pkg: PackageJson = { name, dependencies }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language: 'cpp',\n    dependencies,\n    repoPath: path.relative(scanPath, dir),\n  }\n  return { pkg, dir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType, serviceId } from '@neat.is/types'\nimport {\n  SERVICE_FILE_EXTENSIONS,\n  exists,\n  isNeatAuthoredSourceFile,\n  type DiscoveredService,\n  type PackageJson,\n} from './shared.js'\nimport { hasCsharpProject } from './csharp.js'\nimport { hasJavaManifest } from './java.js'\nimport { hasRustManifest } from './rust.js'\nimport { hasCppManifest } from './cpp.js'\n\n// Dockerfile-declared service discovery (ADR-194). Every other `discoverXService`\n// keys on a language manifest — package.json, pyproject.toml/requirements.txt,\n// go.mod, Gemfile, composer.json. A containerized service that ships none of them\n// (a k6 load generator is `Dockerfile` + `script.js` and nothing else) is\n// invisible to all of them, so it never becomes a ServiceNode and never reaches\n// symbol grain. The Dockerfile is the missing signal: it's an explicit \"this\n// directory is a deployable service\" marker, which is exactly what lets us mint\n// here without over-minting on any stray script.\n//\n// The precision boundary is three ANDs — a Dockerfile, AND top-level source, AND\n// no language manifest:\n//   - Dockerfile alone (no source)      → not a service. The Dockerfile could be\n//                                          a base image or a tooling container.\n//   - source alone (no Dockerfile)      → not a service. A loose script isn't a\n//                                          deployable unit; the manifest paths\n//                                          already cover real projects.\n//   - a manifest is present             → the manifest path owns the dir. This\n//                                          fallback bails so nothing double-mints.\n// Directories the walk already skips (`IGNORED_DIRS`, `.gitignore`) never reach\n// this function, so vendored / build-output dirs can't mint either.\n\n// Extension → language tag for a manifest-less service's `language` field. Only\n// the extensions the source walker actually reads (`SERVICE_FILE_EXTENSIONS`) map\n// to a language; anything else returns null so a `.sh` entrypoint or a `.json`\n// data file never counts as source.\nfunction languageForSourceExt(ext: string): string | null {\n  switch (ext) {\n    case '.py':\n      return 'python'\n    case '.go':\n      return 'go'\n    case '.rb':\n      return 'ruby'\n    case '.php':\n      return 'php'\n    case '.cs':\n      return 'csharp'\n    case '.java':\n      return 'java'\n    case '.kt':\n      return 'kotlin'\n    case '.rs':\n      return 'rust'\n    case '.cpp':\n    case '.cc':\n    case '.cxx':\n    case '.c++':\n    case '.hpp':\n    case '.hh':\n    case '.hxx':\n    case '.h++':\n      return 'cpp'\n    case '.ts':\n    case '.tsx':\n      return 'typescript'\n    case '.js':\n    case '.mjs':\n    case '.cjs':\n      return 'javascript'\n    default:\n      return null\n  }\n}\n\n// Detection precedence when a dir mixes languages at the top level — the winner\n// is the language with the most top-level source files, ties broken by this fixed\n// order so a mixed dir resolves to the same language on every pass (idempotency).\nconst LANGUAGE_PRECEDENCE = ['typescript', 'javascript', 'python', 'go', 'ruby', 'php', 'csharp', 'java', 'kotlin', 'rust', 'cpp']\n\n// Infer the service's language from the primary source at the *top level* of the\n// dir — not recursively. Top-level-only is the precision knob: it pins discovery\n// to a leaf service directory whose own files are the source (the load-generator\n// shape), so a repo root that merely has a Dockerfile and subdir services doesn't\n// mint a phantom root service off code that belongs to something else. Returns\n// null when the dir carries no recognized source, which is the \"Dockerfile alone\"\n// guardrail.\nasync function inferServiceLanguage(dir: string): Promise<string | null> {\n  const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])\n  const counts = new Map<string, number>()\n  for (const entry of entries) {\n    if (!entry.isFile()) continue\n    // NEAT's own generated bootstrap isn't the user's source.\n    if (isNeatAuthoredSourceFile(entry.name)) continue\n    const ext = path.extname(entry.name).toLowerCase()\n    if (!SERVICE_FILE_EXTENSIONS.has(ext)) continue\n    const lang = languageForSourceExt(ext)\n    if (!lang) continue\n    counts.set(lang, (counts.get(lang) ?? 0) + 1)\n  }\n  if (counts.size === 0) return null\n  let best: string | null = null\n  let bestCount = -1\n  for (const lang of LANGUAGE_PRECEDENCE) {\n    const c = counts.get(lang) ?? 0\n    if (c > bestCount) {\n      best = lang\n      bestCount = c\n    }\n  }\n  return best\n}\n\n// The language manifests every other discovery path keys on. A dir carrying any\n// of them is owned by that path, so the Dockerfile fallback stands down — even a\n// nameless package.json counts, so \"no language manifest\" is read strictly.\nasync function hasLanguageManifest(dir: string): Promise<boolean> {\n  return (\n    (await exists(path.join(dir, 'package.json'))) ||\n    (await exists(path.join(dir, 'pyproject.toml'))) ||\n    (await exists(path.join(dir, 'requirements.txt'))) ||\n    (await exists(path.join(dir, 'setup.py'))) ||\n    (await exists(path.join(dir, 'go.mod'))) ||\n    (await exists(path.join(dir, 'Gemfile'))) ||\n    (await exists(path.join(dir, 'composer.json'))) ||\n    // C#'s marker is a glob (`*.csproj` / `*.sln`), so it reads the directory\n    // rather than probing a fixed filename (ADR-196).\n    (await hasCsharpProject(dir)) ||\n    // Java (and its JVM sibling Kotlin, ADR-199) key on the same Maven / Gradle\n    // build manifest (ADR-197), so this one check stands the Dockerfile fallback\n    // down for both.\n    (await hasJavaManifest(dir)) ||\n    // Rust's marker is a fixed `Cargo.toml` (ADR-201).\n    (await hasRustManifest(dir)) ||\n    // C++'s marker is a fixed `CMakeLists.txt` (ADR-202).\n    (await hasCppManifest(dir))\n  )\n}\n\n// An nginx / OpenResty front end ships no source at all — a Dockerfile on an nginx\n// or OpenResty base image, its config, and static files — so the source-language\n// test above can't see it. It's still a deployable service: the Dockerfile's final\n// `FROM` (the runtime stage) names an nginx or OpenResty image AND the directory\n// carries an nginx config (`nginx.conf`, `conf/nginx.conf`, `conf.d/*.conf`). Both\n// are required, so a Dockerfile that merely mentions nginx, or a stray nginx.conf,\n// mints nothing. Its proxy_pass routes are read by infra/nginx.ts.\nconst NGINX_IMAGE = /^(?:[\\w.-]+\\/)*(?:nginx|openresty)(?:-[\\w.-]+)?(?::[\\w.-]+)?(?:@\\S+)?$/i\n\nasync function isNginxFrontend(dir: string): Promise<boolean> {\n  const dockerfile = await fs.readFile(path.join(dir, 'Dockerfile'), 'utf8').catch(() => '')\n  const froms = [...dockerfile.matchAll(/^\\s*FROM\\s+(?:--\\S+\\s+)*(\\S+)/gim)].map((m) => m[1]!)\n  const image = froms[froms.length - 1]\n  if (!image || !NGINX_IMAGE.test(image)) return false\n  if (await exists(path.join(dir, 'nginx.conf'))) return true\n  if (await exists(path.join(dir, 'conf', 'nginx.conf'))) return true\n  const confd = await fs.readdir(path.join(dir, 'conf.d')).catch(() => [] as string[])\n  return confd.some((n) => n.endsWith('.conf'))\n}\n\n// Cheap predicate the discovery walk uses to decide whether a manifest-less dir\n// is a candidate at all. The `Dockerfile` `exists` check gates the readdir, so a\n// dir without one pays a single `fs.access` and stops.\nexport async function hasDockerfileDeclaredService(dir: string): Promise<boolean> {\n  if (!(await exists(path.join(dir, 'Dockerfile')))) return false\n  return (await inferServiceLanguage(dir)) !== null || (await isNginxFrontend(dir))\n}\n\nexport async function discoverDockerfileService(\n  scanPath: string,\n  dir: string,\n): Promise<DiscoveredService | null> {\n  if (!(await exists(path.join(dir, 'Dockerfile')))) return null\n  // Manifest wins — the manifest-based paths run before this one in the discovery\n  // chain, but bail here too so the rule holds no matter the call order.\n  if (await hasLanguageManifest(dir)) return null\n  const language = (await inferServiceLanguage(dir)) ?? ((await isNginxFrontend(dir)) ? 'nginx' : null)\n  if (!language) return null\n  const name = path.basename(dir)\n  const pkg: PackageJson = { name, dependencies: {} }\n  const node: ServiceNode = {\n    id: serviceId(name),\n    type: NodeType.ServiceNode,\n    name,\n    language,\n    dependencies: {},\n    repoPath: path.relative(scanPath, dir),\n  }\n  return { pkg, dir, node }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { minimatch } from 'minimatch'\nimport { exists, readJson } from './shared.js'\n\nexport interface CodeownersRule {\n  pattern: string\n  owners: string\n}\n\nexport interface CodeownersFile {\n  rules: CodeownersRule[]\n}\n\ninterface PackageJsonAuthor {\n  author?: string | { name?: string }\n}\n\n// Read CODEOWNERS at <scanPath>/CODEOWNERS first, then <scanPath>/.github/CODEOWNERS.\n// Returns null when neither exists. ADR-054 #2.1.\nexport async function loadCodeowners(scanPath: string): Promise<CodeownersFile | null> {\n  const candidates = [\n    path.join(scanPath, 'CODEOWNERS'),\n    path.join(scanPath, '.github', 'CODEOWNERS'),\n  ]\n  for (const file of candidates) {\n    if (await exists(file)) {\n      const raw = await fs.readFile(file, 'utf8')\n      return parseCodeowners(raw)\n    }\n  }\n  return null\n}\n\nfunction parseCodeowners(raw: string): CodeownersFile {\n  const rules: CodeownersRule[] = []\n  for (const line of raw.split('\\n')) {\n    const trimmed = line.trim()\n    if (!trimmed || trimmed.startsWith('#')) continue\n    const match = /^(\\S+)\\s+(.+)$/.exec(trimmed)\n    if (!match) continue\n    rules.push({ pattern: match[1]!, owners: match[2]!.trim() })\n  }\n  return { rules }\n}\n\n// First matching pattern wins; returns the literal RHS or null. ADR-054 #2.1.\n// Pattern matcher is minimal per ADR-054 #6 — handles `*`, `**`, and exact\n// paths; not a full gitignore-style parser.\nexport function matchOwner(file: CodeownersFile, repoPath: string): string | null {\n  const normalized = repoPath.split(path.sep).join('/')\n  for (const rule of file.rules) {\n    if (matchesPattern(rule.pattern, normalized)) return rule.owners\n  }\n  return null\n}\n\nfunction matchesPattern(rawPattern: string, repoPath: string): boolean {\n  let pattern = rawPattern.startsWith('/') ? rawPattern.slice(1) : rawPattern\n  if (pattern === '*') return !repoPath.includes('/')\n  if (pattern === '**' || pattern === '') return true\n  // Trailing slash means \"everything in this directory\".\n  if (pattern.endsWith('/')) pattern = pattern + '**'\n  if (minimatch(repoPath, pattern, { dot: true })) return true\n  // A pattern that names a directory should match files beneath it too.\n  if (!pattern.includes('*') && minimatch(repoPath, pattern + '/**', { dot: true })) return true\n  return false\n}\n\n// Read <serviceDir>/package.json and return the `author` field as a literal\n// string. Accepts either string form (\"Cem D <cem@example.com>\") or object\n// form ({ name: 'Cem D' }). Returns null when missing or unparseable.\n// ADR-054 #2.2.\nexport async function readPackageJsonAuthor(serviceDir: string): Promise<string | null> {\n  const pkgPath = path.join(serviceDir, 'package.json')\n  if (!(await exists(pkgPath))) return null\n  try {\n    const pkg = await readJson<PackageJsonAuthor>(pkgPath)\n    if (!pkg.author) return null\n    if (typeof pkg.author === 'string') return pkg.author\n    if (typeof pkg.author === 'object' && typeof pkg.author.name === 'string') return pkg.author.name\n    return null\n  } catch {\n    return null\n  }\n}\n\n// Compute owner per ADR-054 priority: CODEOWNERS first, package.json `author`\n// fallback, undefined otherwise. Literal source value, no normalization (#3).\nexport async function computeServiceOwner(\n  codeowners: CodeownersFile | null,\n  repoPath: string | undefined,\n  serviceDir: string,\n): Promise<string | undefined> {\n  if (codeowners && repoPath !== undefined) {\n    const owner = matchOwner(codeowners, repoPath)\n    if (owner) return owner\n  }\n  const author = await readPackageJsonAuthor(serviceDir)\n  return author ?? undefined\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport { parseAllDocuments } from 'yaml'\nimport type { ServiceNode } from '@neat.is/types'\nimport { NodeType } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { recordExtractionError } from './errors.js'\nimport {\n  CONFIG_FILE_EXTENSIONS,\n  IGNORED_DIRS,\n  exists,\n  isPythonVenvDir,\n  readYaml,\n  type DiscoveredService,\n} from './shared.js'\n\n// Populate ServiceNode.aliases from sources that the OTel layer is likely to\n// see in span attributes:\n//\n//   - docker-compose service names (compose-DNS).\n//   - Dockerfile LABEL values that name the service.\n//   - k8s metadata.name (and the cluster-DNS variants) for Service /\n//     Deployment / StatefulSet whose name matches a known service.\n//\n// resolveServiceId in ingest.ts checks aliases before falling back to a\n// FRONTIER placeholder; promoteFrontierNodes uses them to retire stale\n// placeholders once they map to a real service.\n\ninterface ComposeService {\n  container_name?: string\n  hostname?: string\n  networks?: string[] | Record<string, unknown>\n}\n\ninterface ComposeFile {\n  services?: Record<string, ComposeService>\n}\n\ninterface K8sDoc {\n  kind?: string\n  metadata?: {\n    name?: string\n    namespace?: string\n    labels?: Record<string, string>\n  }\n  spec?: {\n    selector?: {\n      app?: string\n      matchLabels?: Record<string, string>\n    }\n  }\n}\n\nconst K8S_KINDS_WITH_HOSTNAMES = new Set([\n  'Service',\n  'Deployment',\n  'StatefulSet',\n  'DaemonSet',\n])\n\nfunction addAliases(graph: NeatGraph, serviceId: string, candidates: Iterable<string>): void {\n  if (!graph.hasNode(serviceId)) return\n  const node = graph.getNodeAttributes(serviceId) as ServiceNode & { type?: string }\n  if (node.type !== NodeType.ServiceNode) return\n  const set = new Set(node.aliases ?? [])\n  for (const c of candidates) {\n    if (!c) continue\n    if (c === node.name) continue\n    set.add(c)\n  }\n  if (set.size === 0) return\n  const updated: ServiceNode = { ...node, aliases: [...set].sort() }\n  graph.replaceNodeAttributes(serviceId, updated)\n}\n\nfunction indexServicesByName(services: DiscoveredService[]): Map<string, string> {\n  const map = new Map<string, string>()\n  for (const s of services) {\n    map.set(s.node.name, s.node.id)\n    map.set(path.basename(s.dir), s.node.id)\n  }\n  return map\n}\n\nasync function collectComposeAliases(\n  graph: NeatGraph,\n  scanPath: string,\n  serviceIndex: Map<string, string>,\n): Promise<void> {\n  let composePath: string | null = null\n  for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n    const abs = path.join(scanPath, name)\n    if (await exists(abs)) {\n      composePath = abs\n      break\n    }\n  }\n  if (!composePath) return\n\n  let compose: ComposeFile\n  try {\n    compose = await readYaml<ComposeFile>(composePath)\n  } catch (err) {\n    recordExtractionError(\n      'aliases compose',\n      path.relative(scanPath, composePath),\n      err,\n    )\n    return\n  }\n  if (!compose?.services) return\n\n  for (const [composeName, svc] of Object.entries(compose.services)) {\n    const serviceId = serviceIndex.get(composeName)\n    if (!serviceId) continue\n    const aliases = new Set<string>([composeName])\n    if (svc.container_name) aliases.add(svc.container_name)\n    if (svc.hostname) aliases.add(svc.hostname)\n    addAliases(graph, serviceId, aliases)\n  }\n}\n\nconst LABEL_KEYS = new Set([\n  'service',\n  'service.name',\n  'app',\n  'app.name',\n  'com.docker.compose.service',\n  'org.opencontainers.image.title',\n])\n\nfunction parseDockerfileLabels(content: string): string[] {\n  const out: string[] = []\n  // Support `LABEL key=value`, `LABEL key=\"value with spaces\"`, and the\n  // multi-pair form `LABEL k1=v1 k2=v2`. We don't try to honour line\n  // continuations — the common single-line form is enough.\n  const lineRegex = /^\\s*label\\s+(.+)$/i\n  for (const raw of content.split('\\n')) {\n    const m = lineRegex.exec(raw)\n    if (!m) continue\n    const rest = m[1]!\n    const pairRegex = /([\\w.-]+)\\s*=\\s*(\"([^\"]*)\"|'([^']*)'|([^\\s]+))/g\n    let pair: RegExpExecArray | null\n    while ((pair = pairRegex.exec(rest)) !== null) {\n      const key = pair[1]!.toLowerCase()\n      if (!LABEL_KEYS.has(key)) continue\n      const value = pair[3] ?? pair[4] ?? pair[5] ?? ''\n      if (value) out.push(value)\n    }\n  }\n  return out\n}\n\nasync function collectDockerfileAliases(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<void> {\n  for (const service of services) {\n    const dockerfilePath = path.join(service.dir, 'Dockerfile')\n    if (!(await exists(dockerfilePath))) continue\n    let content: string\n    try {\n      content = await fs.readFile(dockerfilePath, 'utf8')\n    } catch (err) {\n      recordExtractionError('aliases dockerfile', dockerfilePath, err)\n      continue\n    }\n    const aliases = parseDockerfileLabels(content)\n    if (aliases.length > 0) addAliases(graph, service.node.id, aliases)\n  }\n}\n\nasync function walkYamlFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n  if (depth > max) return []\n  const out: string[] = []\n  const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n  for (const entry of entries) {\n    if (entry.isDirectory()) {\n      if (IGNORED_DIRS.has(entry.name)) continue\n      const child = path.join(start, entry.name)\n      if (await isPythonVenvDir(child)) continue\n      out.push(...(await walkYamlFiles(child, depth + 1, max)))\n    } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n      out.push(path.join(start, entry.name))\n    }\n  }\n  return out\n}\n\nfunction k8sHostnames(name: string, namespace: string | undefined): string[] {\n  const ns = namespace ?? 'default'\n  return [\n    name,\n    `${name}.${ns}`,\n    `${name}.${ns}.svc`,\n    `${name}.${ns}.svc.cluster.local`,\n  ]\n}\n\nfunction k8sServiceTarget(\n  doc: K8sDoc,\n  byName: Map<string, string>,\n): string | null {\n  // For `Service` resources, the target is whatever app the spec selects, not\n  // necessarily the Service's own metadata.name. We prefer that mapping; if no\n  // selector, fall back to the metadata.name match.\n  const selector = doc.spec?.selector\n  const selectorApp = selector?.app ?? selector?.matchLabels?.app\n  if (selectorApp && byName.has(selectorApp)) return byName.get(selectorApp)!\n\n  const labelApp = doc.metadata?.labels?.app\n  if (labelApp && byName.has(labelApp)) return byName.get(labelApp)!\n\n  const metaName = doc.metadata?.name\n  if (metaName && byName.has(metaName)) return byName.get(metaName)!\n\n  return null\n}\n\nasync function collectK8sAliases(\n  graph: NeatGraph,\n  scanPath: string,\n  serviceIndex: Map<string, string>,\n): Promise<void> {\n  const files = await walkYamlFiles(scanPath)\n  for (const file of files) {\n    const content = await fs.readFile(file, 'utf8')\n    let docs: K8sDoc[]\n    try {\n      docs = parseAllDocuments(content).map((d) => d.toJSON() as K8sDoc)\n    } catch {\n      continue\n    }\n    for (const doc of docs) {\n      if (!doc?.kind || !doc.metadata?.name) continue\n      if (!K8S_KINDS_WITH_HOSTNAMES.has(doc.kind)) continue\n      const target = k8sServiceTarget(doc, serviceIndex)\n      if (!target) continue\n      addAliases(graph, target, k8sHostnames(doc.metadata.name, doc.metadata.namespace))\n    }\n  }\n}\n\nexport async function addServiceAliases(\n  graph: NeatGraph,\n  scanPath: string,\n  services: DiscoveredService[],\n): Promise<void> {\n  const byName = indexServicesByName(services)\n  await collectComposeAliases(graph, scanPath, byName)\n  await collectDockerfileAliases(graph, services)\n  await collectK8sAliases(graph, scanPath, byName)\n}\n","import type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { ensureFileNode, walkSourceFiles, toPosix } from './calls/shared.js'\nimport path from 'node:path'\n\n// Phase 1 — unconditional file enumeration (ADR-092, file-awareness.md §1).\n// Walks every source file matching SERVICE_FILE_EXTENSIONS within each service\n// and emits a FileNode + service ──CONTAINS──▶ file edge, regardless of whether\n// any call pattern fires from the file later.\nexport async function addFiles(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const filePaths = await walkSourceFiles(service.dir, service.excludeDirs)\n    for (const filePath of filePaths) {\n      const relPath = toPosix(path.relative(service.dir, filePath))\n      const { nodesAdded: n, edgesAdded: e } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        relPath,\n      )\n      nodesAdded += n\n      edgesAdded += e\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport TypeScript from 'tree-sitter-typescript'\nimport Python from 'tree-sitter-python'\nimport Go from 'tree-sitter-go'\nimport Ruby from 'tree-sitter-ruby'\nimport Php from 'tree-sitter-php'\nimport CSharp from 'tree-sitter-c-sharp'\nimport Java from 'tree-sitter-java'\nimport Kotlin from 'tree-sitter-kotlin'\nimport Rust from 'tree-sitter-rust'\nimport Cpp from 'tree-sitter-cpp'\nimport type { GraphEdge, SymbolKind, SymbolNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  symbolId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { ensureFileNode, loadSourceFiles, snippet, toPosix } from './calls/shared.js'\n\n// Static symbol-node extraction (ADR-158 wired JS/TS; ADR-192 added Python and\n// Go; ADR-193 added Ruby; ADR-195 added PHP; ADR-196 added C#/.NET; ADR-197 added Java;\n// ADR-199 added Kotlin; ADR-201 added Rust; ADR-202 added C++). Parses each source file with the grammar that understands it and mints a\n// SymbolNode per function / method / constructor / class *definition*, owned by\n// its file through a `file ──CONTAINS──▶ symbol` edge — the same containment\n// spine files use under services (file-awareness.md §2), one level deeper.\n// Static-first: a symbol exists in the inventory whether or not runtime ever\n// exercised it, and it carries its `{ startLine, endLine }` definition span,\n// which is the fusion key ingest joins a span's `code.line` against to land an\n// OBSERVED edge on the calling symbol (observed-first edges, ingest.ts). The node\n// is language-neutral — `symbolId` carries no language token — so the per-language\n// walker below is the only adapter, and a Python or Go symbol fuses with an\n// observed span exactly as a JS/TS one does: line-in-span primary, `code.function`\n// (the qualname's terminal name) the tiebreaker. The span alone earns the node;\n// fusion also needs the observed span to carry the `code.*` anchor, which is a\n// property of the instrumentation, not of this extractor (ADR-192 consequences).\n//\n// Scope is definitions only — no CALLS/INHERITS symbol edges (that stays Phase 2 /\n// symbol-edges.ts, JS/TS). Each file is parsed with the grammar that understands\n// it: `.ts` / `.tsx` through tree-sitter-typescript, `.js` / `.jsx` / `.mjs` /\n// `.cjs` through tree-sitter-javascript, `.py` through tree-sitter-python, `.go`\n// through tree-sitter-go, `.rb` through tree-sitter-ruby, `.php` through\n// tree-sitter-php (the `php_only` variant, matching extract/routes.ts and\n// calls/eloquent.ts). Those grammars extract/routes.ts and the call producers\n// already load, so they added no dependency; C#, Java, Kotlin, and Rust are the\n// symbol-grain languages with no route / call producer yet, so `.cs` through\n// tree-sitter-c-sharp, `.java` through tree-sitter-java, `.kt` through\n// tree-sitter-kotlin, `.rs` through tree-sitter-rust, and the C++ extensions through\n// tree-sitter-cpp are the new grammar dependencies (each pinned at the ABI-14\n// ceiling, see SYMBOL_GRAMMAR_BY_EXT below).\n// The JS grammar cannot parse\n// TypeScript type annotations — it produces ERROR nodes that swallow most\n// definitions (an all-`.ts` core file yields 4 of 27 functions under the JS\n// grammar, 27 of 27 under the TS one) — and symbol extraction, unlike the string /\n// route matchers that survive a partial parse, needs a correct AST, so the grammar\n// is chosen per extension. `collectSymbolDefsForExt` dispatches to the JS/TS,\n// Python, Go, Ruby, PHP, C#, Java, Kotlin, or Rust walker on the extension. Evidence carries the real `file:line`,\n// never fabricated (file-awareness.md §6).\n\nconst PARSE_CHUNK = 16384\n\n// The grammar for the JS/TS extensions NEAT symbol-extracts. tree-sitter-\n// typescript is a superset grammar sharing the same definition node types\n// (function_declaration / class_declaration / method_definition /\n// variable_declarator), so `collectSymbolDefs` walks TS and JS trees identically.\n// This map stays JS/TS-only because the other AST producers that import it\n// (symbol-edges.ts, actions.ts, zod-shapes.ts, calls/drizzle.ts,\n// calls/firestore.ts) are JS/TS-scoped; symbol extraction extends the set to\n// Python, Go, Ruby, and PHP through `SYMBOL_GRAMMAR_BY_EXT` below without pulling\n// those producers onto languages they don't parse.\nexport const GRAMMAR_BY_EXT: Record<string, typeof JavaScript> = {\n  '.ts': TypeScript.typescript,\n  '.tsx': TypeScript.tsx,\n  '.js': JavaScript,\n  '.jsx': JavaScript,\n  '.mjs': JavaScript,\n  '.cjs': JavaScript,\n}\n\n// Symbol extraction alone reaches Python, Go, Ruby, PHP, C#, Java, Kotlin, and Rust\n// (ADR-192, ADR-193, ADR-195, ADR-196, ADR-197, ADR-199, ADR-201): `.py` →\n// tree-sitter-python, `.go` → tree-sitter-go, `.rb` → tree-sitter-ruby, `.php` →\n// tree-sitter-php's `php_only` variant (the same one extract/routes.ts and\n// calls/eloquent.ts parse Laravel with), `.cs` → tree-sitter-c-sharp, `.java` →\n// tree-sitter-java, `.kt` → tree-sitter-kotlin, `.rs` → tree-sitter-rust, layered\n// over the JS/TS set so the shared `GRAMMAR_BY_EXT` its sibling producers import\n// stays untouched. C#, Java, Kotlin, and Rust are the symbol-grain languages with no\n// route / call producer yet, so each brings its own grammar dependency pinned at the\n// ABI-14 ceiling: tree-sitter-c-sharp at 0.21.3 (its 0.23 line jumps to ABI-15 + an\n// ESM-top-level-await binding the CJS extractor can't `require()`), tree-sitter-java\n// at 0.21.0, tree-sitter-kotlin at 0.3.8, and tree-sitter-rust at 0.21.0. The Kotlin\n// grammar is the fwcd community grammar, whose versioning tracks its own line rather\n// than the official grammars, so its ABI was checked empirically rather than inferred\n// from the sibling pins: 0.3.8 generates a `LANGUAGE_VERSION 14` parser and ships a\n// `require()`-able node-addon-api binding — it was loaded against the pinned\n// tree-sitter@^0.21 runtime and parsed a `.kt` file with zero ERROR nodes before the\n// walker was written (ADR-199), the same ABI-14 discipline that pins tree-sitter-ruby\n// at 0.21.0 and tree-sitter-php at 0.22.8. tree-sitter-rust jumps from its lone\n// 0.21.0 release straight to the 0.23 (ABI-15, ESM-top-level-await) line with no\n// 0.22.x between, so 0.21.0 is the one release that both generates a\n// `LANGUAGE_VERSION 14` parser and `require()`s under the pinned runtime — verified\n// by loading it and parsing a `.rs` file with zero ERROR nodes before the walker was\n// written (ADR-201), the same exact-pin discipline the sibling grammars follow.\n// tree-sitter-cpp is pinned at 0.22.3 (ADR-202): unlike the sibling grammars whose\n// next line jumps to an ESM-top-level-await binding, tree-sitter-cpp keeps a\n// `require()`-able CJS `node-gyp-build` binding even on its 0.23.x line, but 0.22.3 is\n// chosen as the newest 0.22.x for parity with the tree-sitter-php@0.22.8 pin and to\n// stay on one ABI-14 generation — it generates a `LANGUAGE_VERSION 14` parser and,\n// loaded against the pinned runtime, parsed a `.cpp` file with zero ERROR nodes\n// (resolving function_definition / class_specifier / struct_specifier /\n// namespace_definition / template_declaration) before the walker was written. Only\n// the unambiguous C++ extensions map to it — `.h` / `.c` stay out (shared with C).\nexport const SYMBOL_GRAMMAR_BY_EXT: Record<string, typeof JavaScript> = {\n  ...GRAMMAR_BY_EXT,\n  '.py': Python,\n  '.go': Go,\n  '.rb': Ruby,\n  '.php': Php.php_only,\n  '.cs': CSharp,\n  '.java': Java,\n  '.kt': Kotlin,\n  '.rs': Rust,\n  // C++ (ADR-202) — only the UNAMBIGUOUS extensions. `.cpp` / `.cc` / `.cxx` /\n  // `.c++` are implementation files; `.hpp` / `.hh` / `.hxx` / `.h++` are C++-only\n  // headers. `.h` and `.c` are deliberately absent: they are shared with C (a\n  // language NEAT does not add), and this map is global — the symbol grain\n  // dispatches on extension, not on the owning service's language — so claiming\n  // `.h` would parse every pure-C header in any repo with the C++ grammar and\n  // mislabel it. The otel-demo `currency` target's executable code lives in a\n  // `.cpp`, so nothing is lost.\n  '.cpp': Cpp,\n  '.cc': Cpp,\n  '.cxx': Cpp,\n  '.c++': Cpp,\n  '.hpp': Cpp,\n  '.hh': Cpp,\n  '.hxx': Cpp,\n  '.h++': Cpp,\n}\n\nexport function parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\n// A parsed definition, pre-identity. `qualname` is the source-declared name\n// (`OrderService.create`, `merge`); `node` carries the definition span.\nexport interface SymbolDef {\n  kind: SymbolKind\n  qualname: string\n  startLine: number\n  endLine: number\n  startIndex: number\n  endIndex: number\n}\n\nfunction methodName(node: Parser.SyntaxNode): string | null {\n  const name = node.childForFieldName('name')\n  return name ? name.text : null\n}\n\n// Walk the AST once, emitting one SymbolDef per definition. A class carries its\n// method context so a method's qualname is `Class.method`; a plain (including\n// nested) function keeps its bare declared name. Anonymous definitions with no\n// declared name are skipped rather than given a fabricated one (§6).\nexport function collectSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  const visit = (node: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    switch (node.type) {\n      case 'function_declaration':\n      case 'generator_function_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('function', name, node)\n        break\n      }\n      case 'class_declaration':\n      case 'abstract_class_declaration':\n      case 'class': {\n        // `abstract class Foo` parses as its own node type in the TS grammar,\n        // not `class_declaration` — miss it and every INHERITS/IMPLEMENTS to an\n        // abstract base (the most common heritage target) has no symbol to land\n        // on. It carries the same `name` / `body` fields, so it mints identically.\n        const name = node.childForFieldName('name')?.text\n        if (name) push('class', name, node)\n        const body = node.childForFieldName('body')\n        if (body) {\n          for (let i = 0; i < body.namedChildCount; i++) {\n            const child = body.namedChild(i)\n            if (child) visit(child, name ?? classCtx)\n          }\n        }\n        // Class children were walked with the class context above; skip the\n        // generic recurse so its body isn't visited twice.\n        return\n      }\n      case 'method_definition': {\n        const name = methodName(node)\n        if (name) {\n          const kind: SymbolKind = name === 'constructor' ? 'constructor' : 'method'\n          push(kind, classCtx ? `${classCtx}.${name}` : name, node)\n        }\n        break\n      }\n      case 'variable_declarator': {\n        // `const foo = () => {}` / `const foo = function () {}` — the common\n        // arrow/function-expression definition form. Only a plain identifier\n        // name yields a symbol; a destructuring pattern names no single symbol.\n        const value = node.childForFieldName('value')\n        if (\n          value &&\n          (value.type === 'arrow_function' ||\n            value.type === 'function' ||\n            value.type === 'function_expression' ||\n            value.type === 'generator_function')\n        ) {\n          const nameNode = node.childForFieldName('name')\n          if (nameNode && nameNode.type === 'identifier') {\n            push('function', nameNode.text, node)\n          }\n        }\n        break\n      }\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child, classCtx)\n    }\n  }\n\n  visit(root, undefined)\n  return out\n}\n\n// Python: `def` is `function_definition`, `class` is `class_definition`, and a\n// decorated form wraps either in `decorated_definition`. A `function_definition`\n// whose direct owner is a class body is a method (its `__init__` the constructor,\n// the qualname `Class.__init__` so the terminal name still matches the runtime\n// `code.function`); a top-level or nested `def` is a plain function. Method-ness\n// comes from direct class-body membership, not ambient scope — a `def` nested in a\n// method is a function, mirroring the JS/TS walker where the node type decides.\n// `async def` is the same node type, so it needs no separate case.\nexport function collectPythonSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  const visit = (node: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    switch (node.type) {\n      case 'function_definition': {\n        const name = node.childForFieldName('name')?.text\n        if (name) {\n          if (classCtx) {\n            const kind: SymbolKind = name === '__init__' ? 'constructor' : 'method'\n            push(kind, `${classCtx}.${name}`, node)\n          } else {\n            push('function', name, node)\n          }\n        }\n        // The body is walked with no class context: a `def` inside this function\n        // is a plain function, never a method of the enclosing class.\n        const body = node.childForFieldName('body')\n        if (body) {\n          for (let i = 0; i < body.namedChildCount; i++) {\n            const child = body.namedChild(i)\n            if (child) visit(child, undefined)\n          }\n        }\n        return\n      }\n      case 'class_definition': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('class', name, node)\n        const body = node.childForFieldName('body')\n        if (body) {\n          for (let i = 0; i < body.namedChildCount; i++) {\n            const child = body.namedChild(i)\n            if (child) visit(child, name ?? classCtx)\n          }\n        }\n        return\n      }\n      case 'decorated_definition': {\n        // `@app.get(...)` etc. wrap the def/class in a `decorated_definition`;\n        // unwrap to the inner definition, keeping the class context so a decorated\n        // method in a class body still mints as a method.\n        const def = node.childForFieldName('definition')\n        if (def) visit(def, classCtx)\n        return\n      }\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child, classCtx)\n    }\n  }\n\n  visit(root, undefined)\n  return out\n}\n\n// Go: a `function_declaration` is a free function; a `method_declaration` carries\n// a receiver, so its qualname is `Receiver.method` — the terminal name matches the\n// runtime `code.function` whether the instrumentation stamps the bare method name\n// or a package-qualified `main.(*Server).Handle` (both reduce to `Handle` under\n// `terminalName`). The receiver type is read off the receiver parameter, unwrapping\n// a `*T` pointer and a `T[U]` generic to the base `type_identifier`. Go has no\n// classes; struct types are not symbols in this rung (mirrors the JS/TS scope of\n// callable-and-class definitions, without a Go analog for the class).\nfunction goReceiverType(node: Parser.SyntaxNode): string | undefined {\n  const receiver = node.childForFieldName('receiver')\n  if (!receiver) return undefined\n  for (let i = 0; i < receiver.namedChildCount; i++) {\n    const param = receiver.namedChild(i)\n    if (param?.type !== 'parameter_declaration') continue\n    let typeNode = param.childForFieldName('type')\n    if (typeNode?.type === 'pointer_type') typeNode = typeNode.namedChild(0) ?? typeNode\n    if (typeNode?.type === 'generic_type') {\n      typeNode = typeNode.childForFieldName('type') ?? typeNode.namedChild(0) ?? typeNode\n    }\n    if (typeNode?.type === 'type_identifier') return typeNode.text\n    return typeNode?.text\n  }\n  return undefined\n}\n\nexport function collectGoSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  const visit = (node: Parser.SyntaxNode): void => {\n    switch (node.type) {\n      case 'function_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('function', name, node)\n        break\n      }\n      case 'method_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) {\n          const recv = goReceiverType(node)\n          push('method', recv ? `${recv}.${name}` : name, node)\n        }\n        break\n      }\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child)\n    }\n  }\n\n  visit(root)\n  return out\n}\n\n// Ruby: `method` is an instance method, `singleton_method` a class method\n// (`def self.x`), `class` a class, `module` a namespace. A `method` / `singleton_method`\n// inside a class or module body is a method (an instance `initialize` the\n// constructor, its qualname `Class.initialize` so the terminal name still matches\n// the runtime `code.function`); a top-level `def` is a plain function. Method-ness\n// comes from direct class/module-body membership, not ambient scope — a `def`\n// nested in a method is a function, mirroring the Python and JS/TS walkers where\n// the node type and its owner decide. Ruby writes a method as `Class#method` and a\n// namespace with `::` (`Shop::OrderMailer`); the qualname joins the nesting with a\n// plain `.` so it reduces under `terminalName` (last-`.` split) to the bare method\n// name — a runtime `OrderMailer#deliver` or a bare `deliver` both land via the\n// line-in-span primary, and the bare form also matches the `code.function`\n// tiebreaker. A class/module declared with a `::` scope-resolution name\n// (`class Shop::OrderMailer`) is normalized to the same dotted form.\nexport function collectRubySymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  // The declared name of a class/module, dot-joined so a `Shop::OrderMailer`\n  // scope-resolution name reduces cleanly under `terminalName`.\n  const nameText = (node: Parser.SyntaxNode): string | undefined =>\n    node.childForFieldName('name')?.text.replace(/::/g, '.')\n\n  const walkBody = (node: Parser.SyntaxNode, ctx: string | undefined): void => {\n    const body = node.childForFieldName('body')\n    if (!body) return\n    for (let i = 0; i < body.namedChildCount; i++) {\n      const child = body.namedChild(i)\n      if (child) visit(child, ctx)\n    }\n  }\n\n  const visit = (node: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    switch (node.type) {\n      case 'method':\n      case 'singleton_method': {\n        const name = node.childForFieldName('name')?.text\n        if (name) {\n          if (classCtx) {\n            const kind: SymbolKind =\n              node.type === 'method' && name === 'initialize' ? 'constructor' : 'method'\n            push(kind, `${classCtx}.${name}`, node)\n          } else {\n            push('function', name, node)\n          }\n        }\n        // The body is walked with no class context: a `def` inside this method is a\n        // plain function, never a method of the enclosing class.\n        walkBody(node, undefined)\n        return\n      }\n      case 'class':\n      case 'module': {\n        const name = nameText(node)\n        if (name) push('class', classCtx ? `${classCtx}.${name}` : name, node)\n        walkBody(node, name ? (classCtx ? `${classCtx}.${name}` : name) : classCtx)\n        return\n      }\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child, classCtx)\n    }\n  }\n\n  visit(root, undefined)\n  return out\n}\n\n// PHP: a top-level `function_definition` is a plain (possibly namespaced)\n// function; a `method_declaration` inside a class / trait / interface body is a\n// method (its `__construct` the constructor); `class_declaration`,\n// `trait_declaration`, and `interface_declaration` all mint as `class`-kind nodes\n// (a trait and an interface are class-shaped heritage targets, so an INHERITS /\n// IMPLEMENTS to either has a symbol to land on). PHP writes namespaces with `\\`\n// (`App\\Quote`) and static members with `::` (`QuoteService::calculate`); the\n// qualname joins the namespace and class nesting with a plain `.`\n// (`App.Quote.QuoteService.calculate`) so it reduces under ingest's `terminalName`\n// (last-`.` split) to the bare method name (`calculate`) — a runtime\n// `App\\Quote\\QuoteService::calculate` or a bare `calculate` both land via the\n// line-in-span primary, and the bare form also matches the `code.function`\n// tiebreaker. A semicolon-form `namespace App\\Quote;` sets the ambient namespace\n// for every sibling that follows it; a braced `namespace App\\Quote { … }` scopes\n// it to its body — the walker threads both. Method-ness comes from direct\n// class-body membership, mirroring the Python and Ruby walkers.\nexport function collectPhpSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  // PHP's `\\` namespace separator and `::` member separator both normalize to the\n  // `.` the qualname joins on, so a declared `App\\Quote` or `Billing::Invoice`\n  // reduces cleanly under `terminalName`; a leading separator (`\\App`) is dropped.\n  const dot = (s: string): string => s.replace(/\\\\/g, '.').replace(/::/g, '.').replace(/^\\.+/, '')\n  const join = (prefix: string | undefined, name: string): string =>\n    prefix ? `${prefix}.${name}` : name\n\n  // Walk a container's named children in order, threading the ambient namespace a\n  // semicolon-form `namespace X;` sets for every sibling after it.\n  const walkChildren = (\n    container: Parser.SyntaxNode,\n    nsCtx: string | undefined,\n    classCtx: string | undefined,\n  ): void => {\n    let ns = nsCtx\n    for (let i = 0; i < container.namedChildCount; i++) {\n      const child = container.namedChild(i)\n      if (!child) continue\n      if (child.type === 'namespace_definition' && !child.childForFieldName('body')) {\n        const nameNode = child.childForFieldName('name')\n        if (nameNode) ns = dot(nameNode.text)\n        continue\n      }\n      visit(child, ns, classCtx)\n    }\n  }\n\n  const walkBody = (\n    node: Parser.SyntaxNode,\n    nsCtx: string | undefined,\n    classCtx: string | undefined,\n  ): void => {\n    const body = node.childForFieldName('body')\n    if (body) walkChildren(body, nsCtx, classCtx)\n  }\n\n  const visit = (\n    node: Parser.SyntaxNode,\n    nsCtx: string | undefined,\n    classCtx: string | undefined,\n  ): void => {\n    switch (node.type) {\n      case 'function_definition': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('function', join(nsCtx, name), node)\n        // A function nested in a function is still a plain function, never a method.\n        walkBody(node, nsCtx, undefined)\n        return\n      }\n      case 'class_declaration':\n      case 'trait_declaration':\n      case 'interface_declaration': {\n        const name = node.childForFieldName('name')?.text\n        const full = name ? join(nsCtx, name) : classCtx\n        if (name) push('class', full!, node)\n        walkBody(node, nsCtx, full)\n        return\n      }\n      case 'method_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) {\n          const kind: SymbolKind = name === '__construct' ? 'constructor' : 'method'\n          push(kind, join(classCtx ?? nsCtx, name), node)\n        }\n        return\n      }\n      case 'namespace_definition': {\n        // A braced `namespace App\\Quote { … }`: scoped to its body. The\n        // semicolon form carries no body and is handled by walkChildren above.\n        const nameNode = node.childForFieldName('name')\n        const ns = nameNode ? dot(nameNode.text) : nsCtx\n        walkBody(node, ns, classCtx)\n        return\n      }\n    }\n    walkChildren(node, nsCtx, classCtx)\n  }\n\n  walkChildren(root, undefined, undefined)\n  return out\n}\n\n// C#/.NET: a `method_declaration` inside a type body is a method and a\n// `constructor_declaration` its constructor (the declared name of a C#\n// constructor is the type name); `class_declaration`, `interface_declaration`,\n// `struct_declaration`, and `record_declaration` all mint as `class`-kind nodes —\n// an interface, struct, or record is a class-shaped definition / heritage target,\n// so an INHERITS / IMPLEMENTS to any of them has a symbol to land on. C# already\n// writes namespaces and members with `.` (`Cart.Services.CartService.AddItem`), so\n// the qualname joins the namespace and type nesting with a plain `.` and reduces\n// under ingest's `terminalName` (last-`.` split) to the bare method name\n// (`AddItem`) — normalization is minimal, since there's no `::` or `\\` to rewrite.\n// A runtime `code.function` of `AddItem` matches the tiebreaker; a namespace- or\n// type-qualified form still lands via the line-in-span primary — the same keying\n// ADR-192 relies on for Go's package-qualified names. A block\n// `namespace Cart.Services { … }` scopes its name to its body; a C# 10 file-scoped\n// `namespace Cart.Services;` carries no body and threads its ambient namespace onto\n// every sibling that follows it — the same two forms PHP's braced / semicolon\n// namespaces take, threaded the same way (extract/symbols.ts collectPhpSymbolDefs).\n// Method-ness comes from direct type-body membership, mirroring the Python, Ruby,\n// and PHP walkers.\nexport function collectCsharpSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  const join = (prefix: string | undefined, name: string): string =>\n    prefix ? `${prefix}.${name}` : name\n\n  // Walk a container's named children in order, threading the ambient namespace a\n  // file-scoped `namespace X;` (which carries no body) sets for every sibling after\n  // it — the C# analog of PHP's semicolon-form namespace.\n  const walkChildren = (\n    container: Parser.SyntaxNode,\n    nsCtx: string | undefined,\n    classCtx: string | undefined,\n  ): void => {\n    let ns = nsCtx\n    for (let i = 0; i < container.namedChildCount; i++) {\n      const child = container.namedChild(i)\n      if (!child) continue\n      if (child.type === 'file_scoped_namespace_declaration') {\n        const nameNode = child.childForFieldName('name')\n        if (nameNode) ns = join(nsCtx, nameNode.text)\n        continue\n      }\n      visit(child, ns, classCtx)\n    }\n  }\n\n  const walkBody = (\n    node: Parser.SyntaxNode,\n    nsCtx: string | undefined,\n    classCtx: string | undefined,\n  ): void => {\n    const body = node.childForFieldName('body')\n    if (body) walkChildren(body, nsCtx, classCtx)\n  }\n\n  const visit = (\n    node: Parser.SyntaxNode,\n    nsCtx: string | undefined,\n    classCtx: string | undefined,\n  ): void => {\n    switch (node.type) {\n      case 'namespace_declaration': {\n        // Block form `namespace Cart.Services { … }`: scoped to its body. The name\n        // is already dotted; nested block namespaces join with `.`.\n        const nameNode = node.childForFieldName('name')\n        const ns = nameNode ? join(nsCtx, nameNode.text) : nsCtx\n        walkBody(node, ns, classCtx)\n        return\n      }\n      case 'class_declaration':\n      case 'interface_declaration':\n      case 'struct_declaration':\n      case 'record_declaration': {\n        const name = node.childForFieldName('name')?.text\n        const full = name ? join(classCtx ?? nsCtx, name) : classCtx\n        if (name) push('class', full!, node)\n        // Members carry the full type path as their class context, so a nested\n        // type reads `Outer.Inner` and a method reads `Type.method`.\n        walkBody(node, nsCtx, full)\n        return\n      }\n      case 'method_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('method', join(classCtx ?? nsCtx, name), node)\n        // No descent into the method body: a local function is out of scope, the\n        // same boundary the JS/TS, Python, Ruby, and PHP walkers hold.\n        return\n      }\n      case 'constructor_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('constructor', join(classCtx ?? nsCtx, name), node)\n        return\n      }\n    }\n    walkChildren(node, nsCtx, classCtx)\n  }\n\n  walkChildren(root, undefined, undefined)\n  return out\n}\n\n// Java: a `method_declaration` inside a type body is a method and a\n// `constructor_declaration` its constructor (a Java constructor's declared name is\n// the type name); `class_declaration`, `interface_declaration`, `enum_declaration`,\n// and `record_declaration` all mint as `class`-kind nodes — an interface, enum, or\n// record is a class-shaped definition / heritage target, so an INHERITS / IMPLEMENTS\n// to any of them has a symbol to land on. Java's scoping is simpler than C#'s: a\n// file has at most one file-level `package com.a.b;` that prefixes every top-level\n// type, with no nested or block namespaces, so the package is read once from the\n// root and there is nothing to thread through siblings. The qualname joins that\n// package and the type nesting with `.` (`com.example.cart.CartService.addItem`) —\n// Java already writes packages and members with `.`, so normalization is minimal (no\n// `::` or `\\` to rewrite) and it reduces under ingest's `terminalName` (last-`.`\n// split) to the bare method name (`addItem`). A runtime `code.function` of `addItem`\n// matches the tiebreaker; a package- or type-qualified form still lands via the\n// line-in-span primary — the same keying ADR-192 relies on for Go's\n// package-qualified names. Method-ness comes from direct type-body membership,\n// mirroring the Python, Ruby, PHP, and C# walkers; a method body is not descended\n// into, so a local class is out of scope — the same boundary those walkers hold.\nexport function collectJavaSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  const join = (prefix: string | undefined, name: string): string =>\n    prefix ? `${prefix}.${name}` : name\n\n  // Java allows at most one file-level `package com.a.b;`, and it applies to the\n  // whole compilation unit — no nesting, no scoping blocks. Read it once from the\n  // root; its name node is a `scoped_identifier` (or bare `identifier`) that already\n  // carries the dotted form.\n  let pkg: string | undefined\n  for (let i = 0; i < root.namedChildCount; i++) {\n    const child = root.namedChild(i)\n    if (child?.type === 'package_declaration') {\n      pkg = child.namedChild(0)?.text\n      break\n    }\n  }\n\n  const walkChildren = (container: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    for (let i = 0; i < container.namedChildCount; i++) {\n      const child = container.namedChild(i)\n      if (child) visit(child, classCtx)\n    }\n  }\n\n  const walkBody = (node: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    // `class_body` / `interface_body` / `enum_body` all sit under the `body` field.\n    const body = node.childForFieldName('body')\n    if (body) walkChildren(body, classCtx)\n  }\n\n  const visit = (node: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    switch (node.type) {\n      case 'class_declaration':\n      case 'interface_declaration':\n      case 'enum_declaration':\n      case 'record_declaration': {\n        const name = node.childForFieldName('name')?.text\n        const full = name ? join(classCtx ?? pkg, name) : classCtx\n        if (name) push('class', full!, node)\n        // Members carry the full type path as their class context, so a nested type\n        // reads `Outer.Inner` and a method reads `Type.method`.\n        walkBody(node, full)\n        return\n      }\n      case 'method_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('method', join(classCtx ?? pkg, name), node)\n        return\n      }\n      case 'constructor_declaration': {\n        const name = node.childForFieldName('name')?.text\n        if (name) push('constructor', join(classCtx ?? pkg, name), node)\n        return\n      }\n    }\n    walkChildren(node, classCtx)\n  }\n\n  walkChildren(root, undefined)\n  return out\n}\n\n// Kotlin (ADR-199), the JVM sibling of Java. The fwcd tree-sitter-kotlin grammar\n// folds every type-shaped definition into `class_declaration` — a plain `class`, an\n// `interface`, an `enum class`, a `data class`, and a `sealed class` are all\n// `class_declaration` nodes, distinguished only by an anonymous keyword child — so\n// one case covers them all and each mints as a `class`-kind node (a heritage /\n// definition target an INHERITS/IMPLEMENTS can land on). `object_declaration`\n// (Kotlin's singleton) mints as `class` too, and a `companion_object` is descended\n// into without adding a name segment when anonymous, so its members read as members\n// of the enclosing type — `FraudService.threshold`, the shape Kotlin itself exposes\n// (`FraudService.threshold()`). A `function_declaration` is a `method` inside a type\n// body and a `function` at file scope — unlike Java, Kotlin has real top-level\n// functions, so method-ness is decided by the class context, mirroring the\n// Python/JS walkers rather than Java's always-a-method rule. A `secondary_constructor`\n// (`constructor(…)`) mints as a `constructor` named for its enclosing type, the way\n// a Java constructor's declared name is its type; the primary constructor is part of\n// the class header and carries no independent body, so it is left to the class node.\n//\n// The grammar exposes no `name` / `body` fields (unlike Java's), so navigation is by\n// child node type: a type's name is its `type_identifier`, a function's its\n// `simple_identifier`, and the body is the `class_body` / `enum_class_body` child.\n// Kotlin's scoping is Java-simple: at most one file-level `package a.b.c` prefixes\n// every top-level type — the `package_header`'s `identifier` child already carries\n// the dotted form — with no nested or block namespaces to thread. The qualname joins\n// that package and the type nesting with `.` (`com.example.fraud.FraudService.check`),\n// so it reduces under ingest's `terminalName` (last-`.` split) to the bare function\n// name (`check`) a runtime `code.function` matches, the same key the Java/C# walkers\n// rely on. A function body is not descended into, so a local function is out of\n// scope — the same boundary the sibling walkers hold.\nexport function collectKotlinSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  const join = (prefix: string | undefined, name: string): string =>\n    prefix ? `${prefix}.${name}` : name\n\n  // The first named child of `node` whose type is one of `types`. The grammar has no\n  // field names, so a definition's name and body are found by type, not `childForFieldName`.\n  const firstChildOfType = (\n    node: Parser.SyntaxNode,\n    types: readonly string[],\n  ): Parser.SyntaxNode | undefined => {\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child && types.includes(child.type)) return child\n    }\n    return undefined\n  }\n  const nameOf = (node: Parser.SyntaxNode, ...types: string[]): string | undefined =>\n    firstChildOfType(node, types)?.text\n  const bodyOf = (node: Parser.SyntaxNode): Parser.SyntaxNode | undefined =>\n    firstChildOfType(node, ['class_body', 'enum_class_body'])\n\n  // At most one file-level `package a.b.c` prefixes every top-level type; its\n  // `identifier` child already carries the dotted form. Read once from the root.\n  let pkg: string | undefined\n  for (let i = 0; i < root.namedChildCount; i++) {\n    const child = root.namedChild(i)\n    if (child?.type === 'package_header') {\n      pkg = child.namedChild(0)?.text\n      break\n    }\n  }\n\n  const walkChildren = (container: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    for (let i = 0; i < container.namedChildCount; i++) {\n      const child = container.namedChild(i)\n      if (child) visit(child, classCtx)\n    }\n  }\n\n  const visit = (node: Parser.SyntaxNode, classCtx: string | undefined): void => {\n    switch (node.type) {\n      case 'class_declaration':\n      case 'object_declaration': {\n        // class / interface / enum class / data class / sealed class all parse as\n        // class_declaration; object is object_declaration. All mint as class-kind.\n        const name = nameOf(node, 'type_identifier')\n        const full = name ? join(classCtx ?? pkg, name) : classCtx\n        if (name) push('class', full!, node)\n        const body = bodyOf(node)\n        // Members carry the full type path as their class context, so a nested type\n        // reads `Outer.Inner` and a method reads `Type.method`.\n        if (body) walkChildren(body, full)\n        return\n      }\n      case 'companion_object': {\n        // `companion object` — anonymous by default, so it adds no name segment and\n        // its members read as members of the enclosing type (`FraudService.threshold`).\n        // A named companion (`companion object Factory`) threads its name.\n        const name = nameOf(node, 'type_identifier')\n        const full = name ? join(classCtx ?? pkg, name) : (classCtx ?? pkg)\n        const body = bodyOf(node)\n        if (body) walkChildren(body, full)\n        return\n      }\n      case 'function_declaration': {\n        // A method in a type body, a top-level function at file scope.\n        const name = nameOf(node, 'simple_identifier')\n        if (name) push(classCtx ? 'method' : 'function', join(classCtx ?? pkg, name), node)\n        return\n      }\n      case 'secondary_constructor': {\n        // `constructor(…)` — its name is the enclosing type's, the last segment of\n        // the class context, matching how a Java constructor's declared name is its type.\n        if (classCtx) {\n          const typeName = classCtx.slice(classCtx.lastIndexOf('.') + 1)\n          push('constructor', join(classCtx, typeName), node)\n        }\n        return\n      }\n    }\n    walkChildren(node, classCtx)\n  }\n\n  walkChildren(root, undefined)\n  return out\n}\n\n// Rust (ADR-201). A `function_item` is a `function` at module/file scope and a\n// `method` inside an `impl_item` (or a `trait_item` — a trait's `function_item`\n// default methods and its `function_signature_item` abstract declarations both mint\n// as `method`, the way Kotlin's abstract interface method does). `struct_item`,\n// `enum_item`, and `trait_item` mint as `class`-kind nodes — a struct, an enum, and\n// a trait are the class-shaped definition / heritage targets Rust has, mirroring how\n// Java maps interface/enum/record and C# maps struct/record/interface all to `class`.\n// Rust has no constructor keyword: an associated `fn new()` is just an associated\n// function, so everything inside an `impl` mints as `method` with no `constructor`\n// case (the SymbolKind vocabulary is reused, not extended).\n//\n// Rust addresses definitions with `::` path separators, and this walker keeps that\n// native form rather than rewriting it to `.` the way the Ruby/PHP walkers normalize\n// their separators: a module's items read `module::item`, an impl's methods read\n// `module::Type::method` (keyed on the impl's target type, not the file), and a\n// nested module threads `outer::inner::item`. A `mod_item` is a namespace only — it\n// scopes the qualname but is not itself a symbol, the way a Java `package` or a C#\n// `namespace` scopes without minting. Because the qualname carries `::`, ingest's\n// `terminalName` (a last-`.` split) does not reduce it to the bare function name, so\n// the `code.function` tiebreaker won't match a `::`-addressed Rust span — but that is\n// only the tiebreaker: fusion's primary key is line-in-span (the observed\n// `code.lineno` falling inside a SymbolNode's definition span), which is\n// language-agnostic and lands a Rust span on its symbol regardless of separator\n// (landObservedSymbol, ingest.ts — unchanged). A method body is not descended into,\n// so a local `fn` or item is out of scope — the same boundary the sibling walkers hold.\nexport function collectRustSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  // Rust joins path segments with `::`, kept verbatim so a qualname reads the way\n  // Rust itself addresses the item (`shipping::Quote::price`).\n  const join = (prefix: string | undefined, name: string): string =>\n    prefix ? `${prefix}::${name}` : name\n\n  // Emit each `fn` in a type body (an `impl` or a `trait` `declaration_list`) as a\n  // method under the type: a `function_item` is a concrete method / associated\n  // function, a `function_signature_item` a trait's abstract method (no body — the\n  // node itself carries the span). Nested items other than functions (associated\n  // types, consts) are not symbols and are skipped.\n  const walkTypeBody = (body: Parser.SyntaxNode, typeCtx: string): void => {\n    for (let i = 0; i < body.namedChildCount; i++) {\n      const child = body.namedChild(i)\n      if (!child) continue\n      if (child.type === 'function_item' || child.type === 'function_signature_item') {\n        const name = child.childForFieldName('name')?.text\n        if (name) push('method', join(typeCtx, name), child)\n      }\n    }\n  }\n\n  const walkChildren = (container: Parser.SyntaxNode, modCtx: string | undefined): void => {\n    for (let i = 0; i < container.namedChildCount; i++) {\n      const child = container.namedChild(i)\n      if (child) visit(child, modCtx)\n    }\n  }\n\n  const visit = (node: Parser.SyntaxNode, modCtx: string | undefined): void => {\n    switch (node.type) {\n      case 'mod_item': {\n        // A module scopes the qualname but is not itself a symbol. An inline\n        // `mod name { … }` carries a `declaration_list` body its items nest under; a\n        // bare `mod name;` (the file-as-module declaration) has no body here.\n        const name = node.childForFieldName('name')?.text\n        const full = name ? join(modCtx, name) : modCtx\n        const body = node.childForFieldName('body')\n        if (body) walkChildren(body, full)\n        return\n      }\n      case 'struct_item':\n      case 'enum_item': {\n        // A struct / enum is a class-kind definition; its fields / variants are not\n        // symbols, and Rust methods live in separate `impl` blocks, so there is no\n        // body to descend for members.\n        const name = node.childForFieldName('name')?.text\n        if (name) push('class', join(modCtx, name), node)\n        return\n      }\n      case 'trait_item': {\n        // A trait is a class-kind heritage target; its body holds the method\n        // signatures / default methods that mint under it.\n        const name = node.childForFieldName('name')?.text\n        const full = name ? join(modCtx, name) : modCtx\n        if (name) push('class', full!, node)\n        const body = node.childForFieldName('body')\n        if (body && full) walkTypeBody(body, full)\n        return\n      }\n      case 'impl_item': {\n        // An `impl Type { … }` / `impl Trait for Type { … }` block is not a symbol;\n        // its methods mint under the target type, keyed on the impl's `type` field so\n        // `impl Priced for Quote` and the inherent `impl Quote` both address `Quote`.\n        const typeName = node.childForFieldName('type')?.text\n        const full = typeName ? join(modCtx, typeName) : modCtx\n        const body = node.childForFieldName('body')\n        if (body && full) walkTypeBody(body, full)\n        return\n      }\n      case 'function_item': {\n        // A free function at module / file scope. A `fn` inside an `impl` / `trait`\n        // is reached through `walkTypeBody` above, never here, so this is always a\n        // plain function. Its body is not descended — a local item is out of scope.\n        const name = node.childForFieldName('name')?.text\n        if (name) push('function', join(modCtx, name), node)\n        return\n      }\n    }\n    walkChildren(node, modCtx)\n  }\n\n  walkChildren(root, undefined)\n  return out\n}\n\n// C++ (ADR-202), the last OpenTelemetry-Demo language. A `function_definition` is a\n// `function` at namespace/file scope and a `method` inside a `class_specifier` /\n// `struct_specifier` body; a `function_definition` whose declarator name equals its\n// enclosing class name is a `constructor`, and a destructor (`~Name`) maps to\n// `method` (the SymbolKind vocabulary is reused, not extended). `class_specifier` and\n// `struct_specifier` mint as `class`-kind nodes — the class-shaped definition /\n// heritage targets, mirroring how Java maps interface/enum/record and Rust maps\n// struct/enum/trait. A `namespace_definition` is a namespace only — it scopes the\n// qualname but is not itself a symbol, the way a Rust `mod_item` scopes without\n// minting — and a `template_declaration` wraps a function/class, so the walker\n// descends to the inner definition (the generic recursion visits it with the same\n// context).\n//\n// C++'s shape is unlike the sibling walkers in two ways. First, a `function_definition`\n// carries NO `name` field — the name lives inside its `function_declarator`'s\n// `declarator` field, reached by unwrapping a `pointer_declarator` / `reference_declarator`\n// return type (`Money* clone()`). That name node is an `identifier` (free fn / in-class\n// ctor), a `field_identifier` (in-class method), a `destructor_name` (`~Money`), an\n// `operator_name` (`operator==`), or a `qualified_identifier`. Second, an OUT-OF-LINE\n// member definition at file/namespace scope (`Money Money::add(…) { … }`) carries a\n// `qualified_identifier` declarator (`Money::add`), so the class is read from the\n// qualified path itself and the method keys onto that class (`Money::Money` out-of-line\n// is still a constructor, `Money::~Money` a method).\n//\n// Like the Rust walker, this one KEEPS the native `::` in the qualname rather than\n// rewriting it to `.`: a namespace's items read `ns::item`, a class's methods read\n// `ns::Class::method`, a nested namespace threads `outer::inner::item`. Because the\n// qualname carries `::`, ingest's `terminalName` (a last-`.` split) leaves it whole,\n// so a `::`-addressed `code.function` misses the tiebreaker and the observed span\n// lands on line-in-span alone — the primary key (landObservedSymbol, ingest.ts —\n// unchanged), the same case Rust proved. A method/function body is not descended\n// into, so a local class or lambda is out of scope — the boundary the sibling walkers\n// hold.\nexport function collectCppSymbolDefs(root: Parser.SyntaxNode): SymbolDef[] {\n  const out: SymbolDef[] = []\n\n  const push = (kind: SymbolKind, qualname: string, node: Parser.SyntaxNode): void => {\n    out.push({\n      kind,\n      qualname,\n      startLine: node.startPosition.row + 1,\n      endLine: node.endPosition.row + 1,\n      startIndex: node.startIndex,\n      endIndex: node.endIndex,\n    })\n  }\n\n  // C++ joins path segments with `::`, kept verbatim so a qualname reads the way C++\n  // itself addresses the item (`shop::Money::add`).\n  const join = (prefix: string | undefined, name: string): string =>\n    prefix ? `${prefix}::${name}` : name\n\n  // A `function_definition`'s declarator field is the `function_declarator` carrying\n  // the name, but a pointer/reference return type wraps it first (`T* f()` →\n  // pointer_declarator; `const T& f()` → reference_declarator). Descend through those\n  // wrappers to the `function_declarator`, then return its own `declarator` (the name\n  // node). The inner declarator is exposed as the `declarator` field on a\n  // pointer_declarator but only as a plain named child on a reference_declarator, so\n  // the descent looks for the next declarator wrapper among named children by type\n  // rather than by field — stopping at the function_declarator so a function-pointer\n  // parameter (which lives under the parameter list) is never mistaken for the name.\n  const DECLARATOR_WRAPPERS = new Set([\n    'function_declarator',\n    'pointer_declarator',\n    'reference_declarator',\n    'parenthesized_declarator',\n  ])\n  const functionNameNode = (node: Parser.SyntaxNode): Parser.SyntaxNode | undefined => {\n    let decl: Parser.SyntaxNode | null | undefined = node.childForFieldName('declarator')\n    for (let guard = 0; decl && guard < 8; guard++) {\n      if (decl.type === 'function_declarator') {\n        return decl.childForFieldName('declarator') ?? undefined\n      }\n      let next: Parser.SyntaxNode | undefined\n      for (let i = 0; i < decl.namedChildCount; i++) {\n        const child = decl.namedChild(i)\n        if (child && DECLARATOR_WRAPPERS.has(child.type)) {\n          next = child\n          break\n        }\n      }\n      decl = next\n    }\n    return undefined\n  }\n\n  // Classify a definition from its declared name text and the enclosing class's\n  // simple name (undefined at namespace/file scope). The name text keeps `::`: an\n  // out-of-line `Money::add` names its own class in the segment before the last, so\n  // its class is read from the name rather than the enclosing scope; a bare `cents`\n  // takes the enclosing class. A member whose name equals the class name is a\n  // constructor; a destructor (`~Name`) differs from the class name, so it stays a\n  // method; anything at namespace scope with no class is a plain function.\n  const classify = (\n    nameText: string,\n    prefix: string | undefined,\n    enclosingClass: string | undefined,\n  ): { kind: SymbolKind; qualname: string } => {\n    const qualname = join(prefix, nameText)\n    let className: string | undefined\n    let memberName: string\n    const idx = nameText.lastIndexOf('::')\n    if (idx >= 0) {\n      memberName = nameText.slice(idx + 2)\n      const before = nameText.slice(0, idx)\n      const j = before.lastIndexOf('::')\n      className = j >= 0 ? before.slice(j + 2) : before\n    } else {\n      memberName = nameText\n      className = enclosingClass\n    }\n    let kind: SymbolKind\n    if (className && memberName === className) kind = 'constructor'\n    else if (className) kind = 'method'\n    else kind = 'function'\n    return { kind, qualname }\n  }\n\n  const walkChildren = (\n    container: Parser.SyntaxNode,\n    prefix: string | undefined,\n    enclosingClass: string | undefined,\n  ): void => {\n    for (let i = 0; i < container.namedChildCount; i++) {\n      const child = container.namedChild(i)\n      if (child) visit(child, prefix, enclosingClass)\n    }\n  }\n\n  const visit = (\n    node: Parser.SyntaxNode,\n    prefix: string | undefined,\n    enclosingClass: string | undefined,\n  ): void => {\n    switch (node.type) {\n      case 'namespace_definition': {\n        // A namespace scopes the qualname but is not itself a symbol. An anonymous\n        // namespace (`namespace { … }`) carries no name and leaves the prefix as-is.\n        const name = node.childForFieldName('name')?.text\n        const newPrefix = name ? join(prefix, name) : prefix\n        const body = node.childForFieldName('body')\n        // Inside a namespace the enclosing class resets to undefined.\n        if (body) walkChildren(body, newPrefix, undefined)\n        return\n      }\n      case 'class_specifier':\n      case 'struct_specifier': {\n        // A class / struct is a class-kind definition. An anonymous one (no `name`)\n        // is not minted and its members are not descended — there is no stable path\n        // to key them on.\n        const name = node.childForFieldName('name')?.text\n        const full = name ? join(prefix, name) : prefix\n        if (name) push('class', full!, node)\n        const body = node.childForFieldName('body')\n        // Members carry the full class path as their prefix and the simple class name\n        // as their enclosing class, so a method reads `ns::Class::method` and a\n        // constructor is recognized by name equality.\n        if (body && name) walkChildren(body, full, name)\n        return\n      }\n      case 'function_definition': {\n        const nameNode = functionNameNode(node)\n        if (nameNode) {\n          const { kind, qualname } = classify(nameNode.text, prefix, enclosingClass)\n          push(kind, qualname, node)\n        }\n        // The body is not descended into — a local definition is out of scope.\n        return\n      }\n    }\n    // Generic descent covers `translation_unit`, `template_declaration` (whose inner\n    // function/class definition is minted here with the same context),\n    // `linkage_specification` (`extern \"C\" { … }`), and preprocessor blocks. A\n    // `field_declaration` (a member declaration without a body) has no\n    // `function_definition` child, so a declaration-only method is correctly skipped.\n    walkChildren(node, prefix, enclosingClass)\n  }\n\n  walkChildren(root, undefined, undefined)\n  return out\n}\n\n// Dispatch to the walker that reads the file's language. `.py`, `.go`, `.rb`,\n// `.php`, `.cs`, `.java`, `.kt`, `.rs`, and the C++ extensions map to their own\n// definition node types; every other mapped extension is JS/TS and rides the shared\n// walker.\nexport function collectSymbolDefsForExt(ext: string, root: Parser.SyntaxNode): SymbolDef[] {\n  switch (ext) {\n    case '.py':\n      return collectPythonSymbolDefs(root)\n    case '.go':\n      return collectGoSymbolDefs(root)\n    case '.rb':\n      return collectRubySymbolDefs(root)\n    case '.php':\n      return collectPhpSymbolDefs(root)\n    case '.cs':\n      return collectCsharpSymbolDefs(root)\n    case '.java':\n      return collectJavaSymbolDefs(root)\n    case '.kt':\n      return collectKotlinSymbolDefs(root)\n    case '.rs':\n      return collectRustSymbolDefs(root)\n    case '.cpp':\n    case '.cc':\n    case '.cxx':\n    case '.c++':\n    case '.hpp':\n    case '.hh':\n    case '.hxx':\n    case '.h++':\n      return collectCppSymbolDefs(root)\n    default:\n      return collectSymbolDefs(root)\n  }\n}\n\n// Same-named siblings in one file (overloads, repeated anonymous-arrow names)\n// get an ordinal disambiguator in source order so the id stays collision-free\n// without inventing a name (ADR-158). A qualname that appears once keeps the\n// clean, disambiguator-free id.\nexport function disambiguate(defs: SymbolDef[]): { def: SymbolDef; disambiguator?: number }[] {\n  const counts = new Map<string, number>()\n  for (const def of defs) counts.set(def.qualname, (counts.get(def.qualname) ?? 0) + 1)\n  const seen = new Map<string, number>()\n  return defs.map((def) => {\n    if ((counts.get(def.qualname) ?? 0) <= 1) return { def }\n    const ordinal = seen.get(def.qualname) ?? 0\n    seen.set(def.qualname, ordinal + 1)\n    return { def, disambiguator: ordinal }\n  })\n}\n\nfunction utf8Offsets(content: string, defs: SymbolDef[]): Map<number, number> {\n  if (content.includes('\\uFFFD')) return new Map()\n  const indices = [...new Set(defs.flatMap(({ startIndex, endIndex }) => [startIndex, endIndex]))].sort(\n    (a, b) => a - b,\n  )\n  const offsets = new Map<number, number>()\n  let cursor = 0\n  let bytes = 0\n  for (const index of indices) {\n    if (index < cursor || index > content.length) return new Map()\n    bytes += Buffer.byteLength(content.slice(cursor, index), 'utf8')\n    offsets.set(index, bytes)\n    cursor = index\n  }\n  return offsets\n}\n\nexport async function addSymbols(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const parsers = new Map<string, Parser>()\n  const parserForExt = (ext: string): Parser | null => {\n    const grammar = SYMBOL_GRAMMAR_BY_EXT[ext]\n    if (!grammar) return null\n    let parser = parsers.get(ext)\n    if (!parser) {\n      parser = new Parser()\n      parser.setLanguage(grammar)\n      parsers.set(ext, parser)\n    }\n    return parser\n  }\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    for (const file of files) {\n      const ext = path.extname(file.path)\n      const parser = parserForExt(ext)\n      if (!parser) continue\n      const relPath = toPosix(path.relative(service.dir, file.path))\n\n      let defs: SymbolDef[]\n      let completeParse: boolean\n      try {\n        const tree = parseSource(parser, file.content)\n        defs = collectSymbolDefsForExt(ext, tree.rootNode)\n        completeParse = !tree.rootNode.hasError\n      } catch (err) {\n        recordExtractionError('symbol extraction', file.path, err)\n        continue\n      }\n      if (defs.length === 0) continue\n      const offsets = completeParse ? utf8Offsets(file.content, defs) : new Map<number, number>()\n\n      // The file owns its symbols; ensure the FileNode (and the owning\n      // `service ──CONTAINS──▶ file` edge) exists before a symbol hangs off it.\n      // Idempotent — addFiles already minted it on this pass.\n      const {\n        fileNodeId,\n        nodesAdded: fn,\n        edgesAdded: fe,\n      } = ensureFileNode(graph, service.pkg.name, service.node.id, relPath)\n      nodesAdded += fn\n      edgesAdded += fe\n\n      for (const { def, disambiguator } of disambiguate(defs)) {\n        const sid = symbolId(service.pkg.name, relPath, def.qualname, disambiguator)\n        // tree-sitter's JavaScript indices count UTF-16 code units. Convert the\n        // parsed definition's boundaries to byte positions in the UTF-8 file.\n        // Replacement characters may stand for undecodable input, so such files\n        // retain their line span but never claim edit-safe byte positions.\n        const startByte = offsets.get(def.startIndex)\n        const endByte = offsets.get(def.endIndex)\n        const precise =\n          startByte !== undefined && endByte !== undefined && endByte > startByte\n            ? { startByte, endByte }\n            : {}\n        const node: SymbolNode = {\n          id: sid,\n          type: NodeType.SymbolNode,\n          kind: def.kind,\n          qualname: def.qualname,\n          span: { startLine: def.startLine, endLine: def.endLine, ...precise },\n          service: service.pkg.name,\n          relPath,\n          discoveredVia: 'static',\n        }\n        if (!graph.hasNode(sid)) {\n          graph.addNode(sid, node)\n          nodesAdded++\n        } else {\n          const previous = graph.getNodeAttributes(sid) as SymbolNode\n          const discoveredVia =\n            previous.discoveredVia === 'otel' || previous.discoveredVia === 'merged'\n              ? 'merged'\n              : 'static'\n          const moved = previous.span.startLine !== node.span.startLine ||\n            previous.span.endLine !== node.span.endLine ||\n            previous.span.startByte !== node.span.startByte ||\n            previous.span.endByte !== node.span.endByte\n          if (moved || previous.kind !== node.kind || previous.qualname !== node.qualname ||\n            previous.discoveredVia !== discoveredVia || previous.service !== node.service ||\n            previous.relPath !== node.relPath) {\n            graph.replaceNodeAttributes(sid, { ...previous, ...node, discoveredVia })\n          }\n        }\n        // `file ──CONTAINS──▶ symbol` — structural ownership, the same tier and\n        // shape as `service ──CONTAINS──▶ file` (file-awareness.md §2), evidence\n        // pinned to the definition's file:line.\n        const containsId = extractedEdgeId(fileNodeId, sid, EdgeType.CONTAINS)\n        if (!graph.hasEdge(containsId)) {\n          const edge: GraphEdge = {\n            id: containsId,\n            source: fileNodeId,\n            target: sid,\n            type: EdgeType.CONTAINS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: {\n              file: relPath,\n              line: def.startLine,\n              snippet: snippet(file.content, def.startLine),\n            },\n          }\n          graph.addEdgeWithKey(containsId, fileNodeId, sid, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport type { GraphEdge, SymbolKind, SymbolNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  symbolId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, snippet, toPosix } from './calls/shared.js'\nimport {\n  GRAMMAR_BY_EXT,\n  collectSymbolDefs,\n  disambiguate,\n  parseSource,\n} from './symbols.js'\nimport { loadTsPathConfig, resolveJsImport, type TsPathConfig } from './imports.js'\n\n// Static symbol *edges* (ADR-158 §3, Phase 2). Builds on the Phase-1 SymbolNode\n// inventory: for every class it mints `INHERITS` / `IMPLEMENTS` from the parsed\n// heritage clause, and for every call expression a symbol→symbol `CALLS` from the\n// enclosing caller symbol to the callee — but only the confident ones. The\n// load-bearing discipline (ADR-158 §3, file-awareness.md §6): an edge is emitted\n// only when its target resolves to exactly one known SymbolNode without guessing —\n// a same-file definition, or an imported binding resolved through the import graph\n// to the exact exported symbol. A callee that needs a type or a runtime value to\n// resolve (method dispatch on a receiver, a dynamic/computed call, an unresolvable\n// or re-exported import, a default/namespace import) is left unclaimed rather than\n// fuzzy-matched. A guessed symbol edge poisons the determinism the graph sells.\n//\n// Runs after `addSymbols` (the inventory it resolves against) and `addImports`\n// (so the import graph is in place), reusing the same tree-sitter grammars and\n// the `resolveJsImport` specifier→file resolver rather than reimplementing them.\n// JS/TS only, matching Phase-1 node grain; Python/Go heritage and calls are a\n// follow-on rung. Every edge grades EXTRACTED with `evidence.file`/`line` pinned\n// to the real heritage clause / call site (never fabricated, §6).\n\n// A Phase-1 symbol as this producer needs it: the id plus the definition span it\n// was minted with, so a call line can be attributed to its enclosing symbol.\ninterface LocalSymbol {\n  sid: string\n  qualname: string\n  kind: SymbolKind\n  startLine: number\n  endLine: number\n}\n\n// A named import binding resolved to the intra-service file that defines it and\n// the exported name to match there. `import { Base } from './base'` →\n// `Base → { targetRelPath: 'base.ts', importedName: 'Base' }`; an alias keeps the\n// source-declared export name (`import { Shape as S }` → `S → …importedName:'Shape'`).\ninterface ResolvedImport {\n  targetRelPath: string\n  importedName: string\n}\n\n// The bare superclass name of a class's heritage, when it is a plain identifier\n// this producer can resolve — handling both grammar shapes: the TS grammar wraps\n// the superclass in an `extends_clause` (its `value` field), the JS grammar puts\n// the identifier directly under `class_heritage`. A qualified superclass\n// (`mod.Base`, a mixin call `mixin(Base)`) is not a bare identifier, so it returns\n// null and no INHERITS edge is guessed.\nfunction extendsInfo(\n  classHeritage: Parser.SyntaxNode,\n): { name: string; line: number } | null {\n  for (let i = 0; i < classHeritage.namedChildCount; i++) {\n    const child = classHeritage.namedChild(i)\n    if (!child) continue\n    if (child.type === 'extends_clause') {\n      const value = child.childForFieldName('value')\n      if (value && value.type === 'identifier') {\n        return { name: value.text, line: value.startPosition.row + 1 }\n      }\n      return null\n    }\n    // JS grammar: the superclass identifier hangs directly off class_heritage.\n    if (child.type === 'identifier') {\n      return { name: child.text, line: child.startPosition.row + 1 }\n    }\n  }\n  return null\n}\n\n// The bare implemented-type names of a class's `implements` clause (TS only).\n// Each entry is a `type_identifier` (`implements Shape`) or a `generic_type`\n// (`implements Comparable<number>`); a qualified `nested_type_identifier`\n// (`ns.Shape`) is skipped rather than guessed. Note: an interface is not a\n// SymbolNode (ADR-158 §2 fixes the kind set to function/method/constructor/class),\n// so an IMPLEMENTS edge lands only when the implemented name resolves to a known\n// *class* symbol (TS permits `implements <class>`); an `implements <interface>`\n// resolves to nothing and emits no edge, honestly, until interface symbols exist.\nfunction implementsInfo(\n  classHeritage: Parser.SyntaxNode,\n): { name: string; line: number }[] {\n  const out: { name: string; line: number }[] = []\n  for (let i = 0; i < classHeritage.namedChildCount; i++) {\n    const clause = classHeritage.namedChild(i)\n    if (!clause || clause.type !== 'implements_clause') continue\n    for (let j = 0; j < clause.namedChildCount; j++) {\n      const t = clause.namedChild(j)\n      if (!t) continue\n      if (t.type === 'type_identifier') {\n        out.push({ name: t.text, line: t.startPosition.row + 1 })\n      } else if (t.type === 'generic_type') {\n        const nameNode = t.childForFieldName('name')\n        if (nameNode && nameNode.type === 'type_identifier') {\n          out.push({ name: nameNode.text, line: nameNode.startPosition.row + 1 })\n        }\n      }\n    }\n  }\n  return out\n}\n\n// Collect the ES-import bindings of a file: local name → { specifier, importedName }.\n// Only named imports (including `as`-aliased) are collected — the binding names the\n// exported symbol exactly. Default imports (`import X from`) and namespace imports\n// (`import * as ns`) are skipped: resolving the former needs the target's\n// export-default declaration and the latter is member access, both deferred rather\n// than guessed. CommonJS `require` destructuring is likewise out of this slice.\nfunction collectImportBindings(\n  root: Parser.SyntaxNode,\n): Map<string, { specifier: string; importedName: string }> {\n  const out = new Map<string, { specifier: string; importedName: string }>()\n  const visit = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'import_statement') {\n      const source = node.childForFieldName('source')\n      const specifier = source ? stringInner(source) : null\n      if (specifier) {\n        for (let i = 0; i < node.namedChildCount; i++) {\n          const clause = node.namedChild(i)\n          if (clause?.type === 'import_clause') collectClause(clause, specifier, out)\n        }\n      }\n      return\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child)\n    }\n  }\n  visit(root)\n  return out\n}\n\nfunction collectClause(\n  clause: Parser.SyntaxNode,\n  specifier: string,\n  out: Map<string, { specifier: string; importedName: string }>,\n): void {\n  for (let i = 0; i < clause.namedChildCount; i++) {\n    const child = clause.namedChild(i)\n    if (!child) continue\n    if (child.type === 'named_imports') {\n      for (let j = 0; j < child.namedChildCount; j++) {\n        const spec = child.namedChild(j)\n        if (spec?.type !== 'import_specifier') continue\n        const nameNode = spec.childForFieldName('name')\n        const aliasNode = spec.childForFieldName('alias')\n        if (!nameNode) continue\n        const importedName = nameNode.text\n        const localName = aliasNode ? aliasNode.text : importedName\n        out.set(localName, { specifier, importedName })\n      }\n    }\n    // `identifier` (default import) and `namespace_import` are intentionally\n    // skipped — see collectImportBindings.\n  }\n}\n\n// The interior text of a string literal node (its `string_fragment` child), or a\n// quote-stripped fallback. Mirrors imports.ts's `stringLiteralText`.\nfunction stringInner(node: Parser.SyntaxNode): string | null {\n  for (let i = 0; i < node.childCount; i++) {\n    const child = node.child(i)\n    if (child?.type === 'string_fragment') return child.text\n  }\n  const raw = node.text\n  return raw.length >= 2 ? raw.slice(1, -1) : null\n}\n\n// A heritage or call edge to emit once its target resolves.\ninterface EdgeRequest {\n  sourceSid: string\n  targetName: string\n  wantKind: SymbolKind\n  edgeType: typeof EdgeType.INHERITS | typeof EdgeType.IMPLEMENTS | typeof EdgeType.CALLS\n  line: number\n}\n\nexport async function addSymbolEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const parsers = new Map<string, Parser>()\n  const parserForExt = (ext: string): Parser | null => {\n    const grammar = GRAMMAR_BY_EXT[ext]\n    if (!grammar) return null\n    let parser = parsers.get(ext)\n    if (!parser) {\n      parser = new Parser()\n      parser.setLanguage(grammar)\n      parsers.set(ext, parser)\n    }\n    return parser\n  }\n\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const serviceName = service.pkg.name\n    const tsPaths: TsPathConfig | null = await loadTsPathConfig(service.dir)\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n\n    for (const file of files) {\n      const parser = parserForExt(path.extname(file.path))\n      if (!parser) continue\n      const relPath = toPosix(path.relative(service.dir, file.path))\n      const fileDir = path.dirname(file.path)\n\n      let root: Parser.SyntaxNode\n      try {\n        root = parseSource(parser, file.content).rootNode\n      } catch (err) {\n        recordExtractionError('symbol edge extraction', file.path, err)\n        continue\n      }\n\n      // Rebuild this file's symbol table (spans + ids) from the same collector\n      // the node producer used, so ids and spans line up exactly.\n      const disambiguated = disambiguate(collectSymbolDefs(root))\n      const locals: LocalSymbol[] = disambiguated.map(({ def, disambiguator }) => ({\n        sid: symbolId(serviceName, relPath, def.qualname, disambiguator),\n        qualname: def.qualname,\n        kind: def.kind,\n        startLine: def.startLine,\n        endLine: def.endLine,\n      }))\n      if (locals.length === 0) continue\n\n      // A bare (dot-free) qualname that appears exactly once in the file — the\n      // clean, disambiguator-free id. Same-name siblings (overloads, a module and\n      // a nested definition sharing a name) are all disambiguated, so none lands\n      // here: existence in this map *is* the \"resolves to exactly one\" test.\n      const uniqueByBareName = new Map<string, LocalSymbol>()\n      for (const { def, disambiguator } of disambiguated) {\n        if (disambiguator !== undefined) continue\n        if (def.qualname.includes('.')) continue // a method, not a callable bare name\n        const local = locals.find((l) => l.qualname === def.qualname && l.startLine === def.startLine)\n        if (local) uniqueByBareName.set(def.qualname, local)\n      }\n\n      // The symbol a definition span identifies exactly (used to find a class's own\n      // node from its class_declaration span).\n      const localBySpan = new Map<string, LocalSymbol>()\n      for (const l of locals) localBySpan.set(`${l.startLine}:${l.endLine}`, l)\n\n      // Resolve every named-import binding's specifier to its intra-service file\n      // once, so target resolution during the walk stays a pure map lookup.\n      const bindings = collectImportBindings(root)\n      const resolvedImports = new Map<string, ResolvedImport>()\n      for (const [localName, binding] of bindings) {\n        const targetRelPath = await resolveJsImport(binding.specifier, fileDir, service.dir, tsPaths)\n        if (targetRelPath) {\n          resolvedImports.set(localName, { targetRelPath, importedName: binding.importedName })\n        }\n      }\n\n      // Resolve a used name to exactly one SymbolNode of the wanted kind, or null.\n      // Same-file first (a unique bare definition), then a resolved named import\n      // whose exported symbol exists in the target file at the wanted kind.\n      const resolveTarget = (name: string, wantKind: SymbolKind): string | null => {\n        const local = uniqueByBareName.get(name)\n        if (local) return local.kind === wantKind ? local.sid : null\n\n        const imp = resolvedImports.get(name)\n        if (imp) {\n          const candidate = symbolId(serviceName, imp.targetRelPath, imp.importedName)\n          if (graph.hasNode(candidate)) {\n            const node = graph.getNodeAttributes(candidate) as SymbolNode\n            if (node.type === NodeType.SymbolNode && node.kind === wantKind) return candidate\n          }\n        }\n        return null\n      }\n\n      // Innermost symbol whose span contains `line` — the enclosing caller of a\n      // call site. Smallest containing span wins (a call inside a method belongs to\n      // the method, not the class), matching ingest's observed-landing choice.\n      const enclosingSymbol = (line: number): LocalSymbol | null => {\n        let best: LocalSymbol | null = null\n        for (const l of locals) {\n          if (line < l.startLine || line > l.endLine) continue\n          if (!best || l.endLine - l.startLine < best.endLine - best.startLine) best = l\n        }\n        return best\n      }\n\n      // Walk once, collecting the confident edge requests.\n      const requests: EdgeRequest[] = []\n      const walk = (node: Parser.SyntaxNode): void => {\n        if (\n          node.type === 'class_declaration' ||\n          node.type === 'abstract_class_declaration' ||\n          node.type === 'class'\n        ) {\n          const self = localBySpan.get(`${node.startPosition.row + 1}:${node.endPosition.row + 1}`)\n          if (self && self.kind === 'class') {\n            for (let i = 0; i < node.namedChildCount; i++) {\n              const child = node.namedChild(i)\n              if (!child || child.type !== 'class_heritage') continue\n              const ext = extendsInfo(child)\n              if (ext) {\n                requests.push({\n                  sourceSid: self.sid,\n                  targetName: ext.name,\n                  wantKind: 'class',\n                  edgeType: EdgeType.INHERITS,\n                  line: ext.line,\n                })\n              }\n              for (const impl of implementsInfo(child)) {\n                requests.push({\n                  sourceSid: self.sid,\n                  targetName: impl.name,\n                  wantKind: 'class',\n                  edgeType: EdgeType.IMPLEMENTS,\n                  line: impl.line,\n                })\n              }\n            }\n          }\n        } else if (node.type === 'call_expression') {\n          const fn = node.childForFieldName('function')\n          // Only a bare identifier callee is resolvable without a receiver type —\n          // `obj.foo()` (member_expression), `arr[k]()` (subscript), and dynamic\n          // callees are left to observed / SCIP (ADR-158 §3).\n          if (fn && fn.type === 'identifier') {\n            const line = node.startPosition.row + 1\n            const caller = enclosingSymbol(line)\n            if (caller) {\n              requests.push({\n                sourceSid: caller.sid,\n                targetName: fn.text,\n                wantKind: 'function',\n                edgeType: EdgeType.CALLS,\n                line,\n              })\n            }\n          }\n        }\n        for (let i = 0; i < node.namedChildCount; i++) {\n          const child = node.namedChild(i)\n          if (child) walk(child)\n        }\n      }\n      walk(root)\n\n      for (const req of requests) {\n        const targetSid = resolveTarget(req.targetName, req.wantKind)\n        if (!targetSid) continue\n        if (targetSid === req.sourceSid) continue // no self-loop (recursion / self-reference)\n\n        const edgeId = extractedEdgeId(req.sourceSid, targetSid, req.edgeType)\n        if (graph.hasEdge(edgeId)) continue\n        const edge: GraphEdge = {\n          id: edgeId,\n          source: req.sourceSid,\n          target: targetSid,\n          type: req.edgeType,\n          provenance: Provenance.EXTRACTED,\n          confidence: confidenceForExtracted('structural'),\n          evidence: {\n            file: relPath,\n            line: req.line,\n            snippet: snippet(file.content, req.line),\n          },\n        }\n        graph.addEdgeWithKey(edgeId, req.sourceSid, targetSid, edge)\n        edgesAdded++\n      }\n    }\n  }\n\n  return { nodesAdded: 0, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport type { GraphEdge, SymbolKind } from '@neat.is/types'\nimport {\n  EdgeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  symbolId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, snippet, toPosix } from './calls/shared.js'\nimport { SYMBOL_GRAMMAR_BY_EXT, collectGoSymbolDefs, disambiguate, parseSource } from './symbols.js'\n\n// Static Go symbol *edges* — the \"Python/Go calls\" follow-on rung `symbol-edges.ts`\n// names (ADR-158 §3). symbol-edges.ts mints JS/TS symbol→symbol CALLS; Go can't ride\n// it (its AST node types differ and it has no ES-import resolver), so Go gets its own\n// producer here holding the SAME precision discipline: a CALLS edge is emitted only\n// when the callee is a bare identifier resolving to exactly one known same-file\n// top-level function SymbolNode. A method/selector call (`s.Render()`, `fmt.Println()`),\n// a builtin (`len`, `make` — an identifier resolving to no in-file symbol), a\n// package-qualified call, and a same-package call to a function defined in another\n// file are all left unclaimed rather than guessed — a guessed symbol edge poisons the\n// determinism the graph sells (file-awareness.md §6).\n//\n// Deferred to later rungs, deliberately: same-package cross-file resolution (Go has no\n// per-file import map naming the exact callee the way `resolveJsImport` does, so it\n// needs a package symbol index), cross-package resolution, and method-dispatch edges\n// (which need receiver typing). Runs after `addSymbols`, reusing `collectGoSymbolDefs`\n// so ids and spans line up exactly with the SymbolNodes that producer minted. Every\n// edge grades EXTRACTED with evidence.file/line pinned to the real call site.\n\n// A Phase-1 Go symbol as this producer needs it: the id plus the definition span it\n// was minted with, so a call line can be attributed to its enclosing symbol.\ninterface LocalSymbol {\n  sid: string\n  qualname: string\n  kind: SymbolKind\n  startLine: number\n  endLine: number\n}\n\nexport async function addGoSymbolEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const grammar = SYMBOL_GRAMMAR_BY_EXT['.go']\n  if (!grammar) return { nodesAdded: 0, edgesAdded: 0 }\n  const parser = new Parser()\n  parser.setLanguage(grammar)\n\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const serviceName = service.pkg.name\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n\n    for (const file of files) {\n      if (path.extname(file.path) !== '.go') continue\n      const relPath = toPosix(path.relative(service.dir, file.path))\n\n      let root: Parser.SyntaxNode\n      try {\n        root = parseSource(parser, file.content).rootNode\n      } catch (err) {\n        recordExtractionError('go symbol edge extraction', file.path, err)\n        continue\n      }\n\n      // Rebuild this file's symbol inventory from the same collector the node\n      // producer used, so ids and spans match the minted SymbolNodes exactly.\n      const disambiguated = disambiguate(collectGoSymbolDefs(root))\n      const locals: LocalSymbol[] = disambiguated.map(({ def, disambiguator }) => ({\n        sid: symbolId(serviceName, relPath, def.qualname, disambiguator),\n        qualname: def.qualname,\n        kind: def.kind,\n        startLine: def.startLine,\n        endLine: def.endLine,\n      }))\n      if (locals.length === 0) continue\n\n      // A bare (dot-free) function name that appears exactly once in the file — the\n      // clean, disambiguator-free id. A method qualname (`Receiver.method`) carries a\n      // dot and is excluded: a Go method is only ever reached through a selector\n      // (`s.Render()`), never a bare-identifier callee. Existence in this map IS the\n      // \"resolves to exactly one same-file function\" test (Go forbids two top-level\n      // funcs sharing a name, so a bare function name is unique by the language rule).\n      const uniqueFnByName = new Map<string, LocalSymbol>()\n      for (const { def, disambiguator } of disambiguated) {\n        if (disambiguator !== undefined) continue\n        if (def.kind !== 'function') continue\n        if (def.qualname.includes('.')) continue\n        const local = locals.find(\n          (l) => l.qualname === def.qualname && l.startLine === def.startLine,\n        )\n        if (local) uniqueFnByName.set(def.qualname, local)\n      }\n\n      // Innermost symbol whose span contains `line` — the enclosing caller of a call\n      // site; smallest containing span wins (a call inside a method belongs to the\n      // method), matching ingest's observed-landing choice.\n      const enclosingSymbol = (line: number): LocalSymbol | null => {\n        let best: LocalSymbol | null = null\n        for (const l of locals) {\n          if (line < l.startLine || line > l.endLine) continue\n          if (!best || l.endLine - l.startLine < best.endLine - best.startLine) best = l\n        }\n        return best\n      }\n\n      // Walk once, minting a CALLS for each confident bare-function call site.\n      const walk = (node: Parser.SyntaxNode): void => {\n        if (node.type === 'call_expression') {\n          const fn = node.childForFieldName('function')\n          // Only a bare identifier callee is a same-file free-function call. A\n          // `selector_expression` callee (`s.Render()`, `fmt.Println()`) needs a\n          // receiver type or a package to resolve and is left to observed / a later rung.\n          if (fn && fn.type === 'identifier') {\n            const line = node.startPosition.row + 1\n            const caller = enclosingSymbol(line)\n            const target = uniqueFnByName.get(fn.text)\n            if (caller && target && caller.sid !== target.sid) {\n              const edgeId = extractedEdgeId(caller.sid, target.sid, EdgeType.CALLS)\n              if (!graph.hasEdge(edgeId)) {\n                const edge: GraphEdge = {\n                  id: edgeId,\n                  source: caller.sid,\n                  target: target.sid,\n                  type: EdgeType.CALLS,\n                  provenance: Provenance.EXTRACTED,\n                  confidence: confidenceForExtracted('structural'),\n                  evidence: {\n                    file: relPath,\n                    line,\n                    snippet: snippet(file.content, line),\n                  },\n                }\n                graph.addEdgeWithKey(edgeId, caller.sid, target.sid, edge)\n                edgesAdded++\n              }\n            }\n          }\n        }\n        for (let i = 0; i < node.namedChildCount; i++) {\n          const child = node.namedChild(i)\n          if (child) walk(child)\n        }\n      }\n      walk(root)\n    }\n  }\n\n  return { nodesAdded: 0, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport type { ExtractedConfidenceKind, GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted, extractedEdgeId, symbolId } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, snippet, toPosix, type SourceFile } from './calls/shared.js'\nimport { SYMBOL_GRAMMAR_BY_EXT, collectJavaSymbolDefs, disambiguate, parseSource } from './symbols.js'\n\n// Static Java symbol edges — the Java rung of ADR-158 §3, beside go-symbol-edges.ts\n// and holding its precision rule: a CALLS edge only where the callee resolves to\n// exactly one method SymbolNode, never a guess. Three tiers, all inside one\n// service directory, never across services:\n//\n//   1. Same file (#1442). An unqualified call or `this.m(…)` resolves to the one\n//      method the innermost named class declares under that name; `Type.m(…)` to\n//      the one such method of a same-file class.\n//   2. Typed receiver (ADR-257). `x.m(…)` / `this.x.m(…)` where `x` is a local, a\n//      parameter or a field (innermost scope first) resolves through `x`'s\n//      declared type: the type name goes through the file's single-type imports,\n//      then its own package, then its wildcard imports, to a class in the same\n//      service, and the callee is the one method that class declares by that name.\n//   3. Interface → implementation (ADR-257). When that declared type is an\n//      interface, the call lands on the implementing class's method, but only when\n//      the service's own source has exactly one class implementing it — the single\n//      candidate that lets Spring wire the bean without a @Qualifier.\n//\n// Left unclaimed: an overloaded name (the argument types would have to pick), an\n// inherited or outer-class method, a call inside an anonymous or local class\n// (its own methods would shadow), a receiver typed `var`, generic-only or by a\n// type outside the service, an interface with zero or several implementors in the\n// service, and any receiver that isn't a plain name (`a.b().m()`). One case the\n// rules can't see: a superclass declaring an overload of the same name, which a\n// call could bind to instead; the class hierarchy isn't read beyond `implements`.\n// Runs after `addSymbols`, reusing its collector so ids and spans match the minted\n// SymbolNodes exactly.\n\ninterface Def {\n  sid: string\n  qualname: string\n  kind: string\n  startIndex: number\n  ambiguous: boolean\n}\n\ninterface FileInfo {\n  file: SourceFile\n  relPath: string\n  root: Parser.SyntaxNode\n  pkg: string | undefined\n  singleImports: Map<string, string> // simple name → qualified\n  wildcardImports: string[] // package prefixes\n  defs: Def[]\n  byStart: Map<number, Def>\n}\n\ninterface TypeInfo {\n  qualname: string\n  isInterface: boolean\n  implementsNames: string[] // as written, resolved against `file`\n  file: FileInfo\n}\n\nconst TYPE_DECLS = new Set(['class_declaration', 'interface_declaration', 'enum_declaration', 'record_declaration'])\n\nfunction readImports(root: Parser.SyntaxNode): { single: Map<string, string>; wildcard: string[] } {\n  const single = new Map<string, string>()\n  const wildcard: string[] = []\n  for (const c of root.namedChildren) {\n    if (c.type !== 'import_declaration') continue\n    const m = /^import\\s+(static\\s+)?([\\w.]+?)(\\.\\*)?\\s*;/.exec(c.text)\n    if (!m || m[1]) continue\n    if (m[3]) wildcard.push(m[2]!)\n    else single.set(m[2]!.slice(m[2]!.lastIndexOf('.') + 1), m[2]!)\n  }\n  return { single, wildcard }\n}\n\n// A declared type as a name to resolve; generics, arrays and `var` → null.\nfunction declaredTypeName(typeNode: Parser.SyntaxNode | null): string | null {\n  if (!typeNode) return null\n  if (typeNode.type === 'type_identifier') return typeNode.text === 'var' ? null : typeNode.text\n  if (typeNode.type === 'scoped_type_identifier') return typeNode.text\n  return null\n}\n\n// A field's declared type in a class body; undefined when the class has no such field.\nfunction fieldType(name: string, classNode: Parser.SyntaxNode): string | null | undefined {\n  for (const f of classNode.childForFieldName('body')?.namedChildren ?? []) {\n    if (f.type !== 'field_declaration') continue\n    for (const d of f.namedChildren) {\n      if (d.type === 'variable_declarator' && d.childForFieldName('name')?.text === name) {\n        return declaredTypeName(f.childForFieldName('type'))\n      }\n    }\n  }\n  return undefined\n}\n\n// The declared type of `name` at `call`: a local or parameter of an enclosing\n// scope (innermost first), else a field of the innermost class. null when it's\n// declared but untyped for our purposes (var, generic); undefined when not found.\nfunction declaredType(name: string, call: Parser.SyntaxNode, classNode: Parser.SyntaxNode): string | null | undefined {\n  for (let n: Parser.SyntaxNode | null = call.parent; n && n !== classNode; n = n.parent) {\n    let found: string | null | undefined\n    for (const c of n.namedChildren) {\n      if (c.startIndex >= call.startIndex) break\n      if (c.type !== 'local_variable_declaration') continue\n      for (const d of c.namedChildren) {\n        if (d.type === 'variable_declarator' && d.childForFieldName('name')?.text === name) {\n          found = declaredTypeName(c.childForFieldName('type'))\n        }\n      }\n    }\n    if (found !== undefined) return found\n    if (n.type === 'enhanced_for_statement' && n.childForFieldName('name')?.text === name) {\n      return declaredTypeName(n.childForFieldName('type'))\n    }\n    if (n.type === 'method_declaration' || n.type === 'constructor_declaration' || n.type === 'lambda_expression') {\n      const params = n.childForFieldName('parameters')\n      if (params?.type === 'identifier' && params.text === name) return null // `x -> …`\n      for (const p of params?.namedChildren ?? []) {\n        if (p.type === 'formal_parameter' && p.childForFieldName('name')?.text === name) {\n          return declaredTypeName(p.childForFieldName('type'))\n        }\n        if ((p.type === 'identifier' || p.type === 'spread_parameter') && p.text.endsWith(name)) return null\n      }\n    }\n  }\n  return fieldType(name, classNode)\n}\n\nexport async function addJavaSymbolEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const grammar = SYMBOL_GRAMMAR_BY_EXT['.java']\n  if (!grammar) return { nodesAdded: 0, edgesAdded: 0 }\n  const parser = new Parser()\n  parser.setLanguage(grammar)\n  let edgesAdded = 0\n\n  for (const service of services) {\n    if (service.node.language !== 'java') continue\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n\n    // Pass 1: every file's symbols, package, imports and declared types.\n    const infos: FileInfo[] = []\n    const types = new Map<string, TypeInfo | null>() // null: qualname declared twice\n    for (const file of files) {\n      if (path.extname(file.path) !== '.java') continue\n      let root: Parser.SyntaxNode\n      try {\n        root = parseSource(parser, file.content).rootNode\n      } catch (err) {\n        recordExtractionError('java symbol edge extraction', file.path, err)\n        continue\n      }\n      const relPath = toPosix(path.relative(service.dir, file.path))\n      const defs: Def[] = disambiguate(collectJavaSymbolDefs(root)).map(({ def, disambiguator }) => ({\n        sid: symbolId(service.pkg.name, relPath, def.qualname, disambiguator),\n        qualname: def.qualname,\n        kind: def.kind,\n        startIndex: def.startIndex,\n        ambiguous: disambiguator !== undefined,\n      }))\n      const byStart = new Map<number, Def>()\n      for (const d of defs) byStart.set(d.startIndex, d)\n      const { single, wildcard } = readImports(root)\n      const info: FileInfo = {\n        file,\n        relPath,\n        root,\n        pkg: root.namedChildren.find((c) => c.type === 'package_declaration')?.namedChildren[0]?.text,\n        singleImports: single,\n        wildcardImports: wildcard,\n        defs,\n        byStart,\n      }\n      infos.push(info)\n      const visitTypes = (n: Parser.SyntaxNode): void => {\n        if (TYPE_DECLS.has(n.type)) {\n          const def = byStart.get(n.startIndex)\n          if (def) {\n            const names: string[] = []\n            const ifaces = n.type === 'class_declaration' ? n.childForFieldName('interfaces') : null\n            for (const t of ifaces?.descendantsOfType(['type_identifier', 'scoped_type_identifier']) ?? []) {\n              if (t.parent?.type === 'type_list') names.push(t.text)\n            }\n            types.set(\n              def.qualname,\n              types.has(def.qualname)\n                ? null\n                : { qualname: def.qualname, isInterface: n.type === 'interface_declaration', implementsNames: names, file: info },\n            )\n          }\n        }\n        for (const c of n.namedChildren) visitTypes(c)\n      }\n      visitTypes(root)\n    }\n    if (infos.length === 0) continue\n\n    // A type name as written in `info` → a type declared in this service.\n    const resolveType = (name: string, info: FileInfo): TypeInfo | null => {\n      if (name.includes('.')) return types.get(name) ?? null\n      const imported = info.singleImports.get(name)\n      if (imported) return types.get(imported) ?? null\n      const local = types.get(info.pkg ? `${info.pkg}.${name}` : name)\n      if (local) return local\n      const viaWildcard = info.wildcardImports\n        .map((p) => types.get(`${p}.${name}`))\n        .filter((t): t is TypeInfo => !!t)\n      return viaWildcard.length === 1 ? viaWildcard[0]! : null\n    }\n\n    // Methods by owner + name across the service; more than one means overloads.\n    const methods = new Map<string, Def[]>()\n    for (const info of infos) {\n      for (const d of info.defs) {\n        if (d.kind === 'method') methods.set(d.qualname, [...(methods.get(d.qualname) ?? []), d])\n      }\n    }\n    const uniqueMethod = (owner: string, name: string): Def | null => {\n      const found = methods.get(`${owner}.${name}`)\n      return found && found.length === 1 && !found[0]!.ambiguous ? found[0]! : null\n    }\n\n    // Interface → the classes in this service that implement it directly.\n    const implementors = new Map<string, string[]>()\n    for (const t of types.values()) {\n      if (!t || t.isInterface) continue\n      for (const n of t.implementsNames) {\n        const iface = resolveType(n, t.file)\n        if (iface?.isInterface) implementors.set(iface.qualname, [...(implementors.get(iface.qualname) ?? []), t.qualname])\n      }\n    }\n\n    const addEdge = (caller: Def, target: Def, kind: ExtractedConfidenceKind, info: FileInfo, line: number): void => {\n      if (caller.sid === target.sid) return\n      const edgeId = extractedEdgeId(caller.sid, target.sid, EdgeType.CALLS)\n      if (graph.hasEdge(edgeId) || !graph.hasNode(caller.sid) || !graph.hasNode(target.sid)) return\n      const edge: GraphEdge = {\n        id: edgeId,\n        source: caller.sid,\n        target: target.sid,\n        type: EdgeType.CALLS,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted(kind),\n        evidence: { file: info.relPath, line, snippet: snippet(info.file.content, line) },\n      }\n      graph.addEdgeWithKey(edgeId, caller.sid, target.sid, edge)\n      edgesAdded++\n    }\n\n    // A typed receiver's call: tier 2 on a class, tier 3 through an interface.\n    const viaType = (typeName: string, name: string, info: FileInfo): { target: Def; kind: ExtractedConfidenceKind } | null => {\n      const type = resolveType(typeName, info)\n      if (!type) return null\n      if (!type.isInterface) {\n        const t = uniqueMethod(type.qualname, name)\n        return t ? { target: t, kind: 'structural' } : null\n      }\n      const impls = implementors.get(type.qualname) ?? []\n      if (impls.length !== 1) return null\n      const t = uniqueMethod(impls[0]!, name)\n      return t ? { target: t, kind: 'verified-call-site' } : null\n    }\n\n    // Pass 2: resolve each call site.\n    for (const info of infos) {\n      const classBySimple = new Map<string, string | null>()\n      for (const d of info.defs) {\n        if (d.kind !== 'class') continue\n        const simple = d.qualname.slice(d.qualname.lastIndexOf('.') + 1)\n        classBySimple.set(simple, classBySimple.has(simple) ? null : d.qualname)\n      }\n\n      // The caller and the innermost named class, or null when an anonymous or\n      // local class sits in between.\n      const context = (call: Parser.SyntaxNode): { caller: Def; classNode: Parser.SyntaxNode; classQual: string } | null => {\n        let caller: Def | null = null\n        for (let n = call.parent; n; n = n.parent) {\n          if (n.type === 'class_body' && n.parent?.type === 'object_creation_expression') return null\n          if (!caller && (n.type === 'method_declaration' || n.type === 'constructor_declaration')) {\n            caller = info.byStart.get(n.startIndex) ?? null\n            if (!caller) return null\n          }\n          if (TYPE_DECLS.has(n.type)) {\n            const cls = info.byStart.get(n.startIndex)\n            if (!caller || !cls || cls.kind !== 'class') return null\n            return { caller, classNode: n, classQual: cls.qualname }\n          }\n        }\n        return null\n      }\n\n      const visit = (node: Parser.SyntaxNode): void => {\n        if (node.type === 'method_invocation') {\n          const name = node.childForFieldName('name')?.text\n          const obj = node.childForFieldName('object')\n          const ctx = name ? context(node) : null\n          if (ctx && name) {\n            const line = node.startPosition.row + 1\n            let hit: { target: Def; kind: ExtractedConfidenceKind } | null = null\n            if (!obj || obj.type === 'this') {\n              // Tier 1: the enclosing class's own method.\n              const t = uniqueMethod(ctx.classQual, name)\n              if (t && info.defs.includes(t)) hit = { target: t, kind: 'structural' }\n            } else if (obj.type === 'identifier') {\n              const typeName = declaredType(obj.text, node, ctx.classNode)\n              if (typeName) hit = viaType(typeName, name, info)\n              else if (typeName === undefined) {\n                // Tier 1: `Type.m()` on a same-file class.\n                const cls = classBySimple.get(obj.text)\n                const t = cls ? uniqueMethod(cls, name) : null\n                if (t) hit = { target: t, kind: 'structural' }\n              }\n            } else if (obj.type === 'field_access' && obj.childForFieldName('object')?.type === 'this') {\n              const field = obj.childForFieldName('field')?.text\n              const typeName = field ? fieldType(field, ctx.classNode) : null\n              if (typeName) hit = viaType(typeName, name, info)\n            }\n            if (hit) addEdge(ctx.caller, hit.target, hit.kind, info, line)\n          }\n        }\n        for (const c of node.namedChildren) visit(c)\n      }\n      visit(info.root)\n    }\n  }\n  return { nodesAdded: 0, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport type { GraphEdge, ServerActionNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  serverActionId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { ensureFileNode, loadSourceFiles, snippet, toPosix } from './calls/shared.js'\nimport { GRAMMAR_BY_EXT, parseSource } from './symbols.js'\nimport { loadTsPathConfig, resolveJsImport, type TsPathConfig } from './imports.js'\n\n// Next.js Server Action extraction (ADR-168). A Server Action is the mutation\n// boundary of a modern App Router app: an exported async function marked\n// `\"use server\"`, either by a module-level directive (every exported async\n// function in the file is an action) or an in-body directive (that one\n// function). The client references the imported action binding — a call, an\n// `action={fn}` JSX attribute, a `useActionState(fn)` / `fn.bind(...)` argument —\n// and Next posts to it, serialising the call to an opaque `Next-Action` hash. At\n// HTTP grain the whole surface collapses onto one POST edge, so this producer\n// mints a ServerActionNode per exported action to recover the per-action\n// topology, owned by its file through `file ──CONTAINS──▶ action`, and stitches\n// `file ──CALLS──▶ action` on any client reference resolved through the import\n// graph.\n//\n// EXTRACTED-first: OBSERVED fusion is deferred (the `Next-Action` hash carries no\n// action name), the same posture GraphQLOperationNode took before its static\n// extractor. Scope is gated by the `next` manifest dependency, JS/TS only,\n// matching the SymbolNode grain the client-stitch resolves against. The\n// load-bearing discipline (file-awareness.md §6): the client-stitch fires only\n// when the imported binding resolves through `resolveJsImport` to exactly one\n// known ServerActionNode — never fuzzy-matched — so the edge is deterministic.\n\n// The interior text of a JS/TS string literal node (its `string_fragment`\n// child), quote-stripped. Mirrors imports.ts's `stringLiteralText`.\nfunction stringLiteralText(node: Parser.SyntaxNode): string | null {\n  for (let i = 0; i < node.childCount; i++) {\n    const child = node.child(i)\n    if (child?.type === 'string_fragment') return child.text\n  }\n  const raw = node.text\n  return raw.length >= 2 ? raw.slice(1, -1) : null\n}\n\n// A `\"use server\"` directive is a leading string-literal expression statement in\n// a module body or a function's statement block. Scan only the leading run of\n// string-literal statements (the directive prologue): a `\"use strict\"` /\n// `\"use client\"` before it is skipped, and the first non-directive statement ends\n// the prologue. Returns true when one of the leading directives is `use server`.\nfunction hasUseServerDirective(container: Parser.SyntaxNode): boolean {\n  for (let i = 0; i < container.namedChildCount; i++) {\n    const stmt = container.namedChild(i)\n    if (!stmt || stmt.type !== 'expression_statement') break\n    const expr = stmt.namedChild(0)\n    if (!expr || expr.type !== 'string') break\n    if (stringLiteralText(expr) === 'use server') return true\n    // Another leading directive (`use strict` / `use client`) — keep scanning.\n  }\n  return false\n}\n\n// A function node is async when it carries the `async` keyword token. tree-sitter\n// exposes it as an anonymous child of the function / arrow node.\nfunction isAsyncFunction(node: Parser.SyntaxNode): boolean {\n  for (let i = 0; i < node.childCount; i++) {\n    if (node.child(i)?.type === 'async') return true\n  }\n  return false\n}\n\n// One exported async function the file declares — the unit a `\"use server\"`\n// directive promotes to an action. `bodyNode` is the function's statement block\n// (for the in-body directive test) or null for a concise-body arrow.\ninterface ExportedAsyncFn {\n  exportName: string\n  fnNode: Parser.SyntaxNode\n  bodyNode: Parser.SyntaxNode | null\n  line: number\n}\n\n// Collect the file's directly-exported async functions: `export async function\n// f(){}` and `export const f = async () => {}` / `= async function(){}`. A\n// destructuring export, a re-export clause (`export { f }`), and a default export\n// are out of this slice — the direct-declaration forms are the idiomatic action\n// shape. Sync exports are skipped (a Server Action must be async).\nfunction collectExportedAsyncFns(root: Parser.SyntaxNode): ExportedAsyncFn[] {\n  const out: ExportedAsyncFn[] = []\n  const visit = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'export_statement') {\n      const decl = node.childForFieldName('declaration')\n      const line = node.startPosition.row + 1\n      if (decl?.type === 'function_declaration') {\n        const name = decl.childForFieldName('name')?.text\n        if (name && isAsyncFunction(decl)) {\n          out.push({ exportName: name, fnNode: decl, bodyNode: decl.childForFieldName('body'), line })\n        }\n      } else if (decl?.type === 'lexical_declaration' || decl?.type === 'variable_declaration') {\n        for (let i = 0; i < decl.namedChildCount; i++) {\n          const d = decl.namedChild(i)\n          if (d?.type !== 'variable_declarator') continue\n          const nameNode = d.childForFieldName('name')\n          const value = d.childForFieldName('value')\n          if (nameNode?.type !== 'identifier' || !value) continue\n          if (\n            (value.type === 'arrow_function' ||\n              value.type === 'function' ||\n              value.type === 'function_expression' ||\n              value.type === 'generator_function') &&\n            isAsyncFunction(value)\n          ) {\n            out.push({\n              exportName: nameNode.text,\n              fnNode: value,\n              bodyNode: value.childForFieldName('body'),\n              line,\n            })\n          }\n        }\n      }\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child)\n    }\n  }\n  visit(root)\n  return out\n}\n\n// The named-import bindings of a file: local name → the exported name it names in\n// its source module. Only named imports (including `as`-aliased) are collected —\n// a Server Action is a named export, so a default / namespace import can't name\n// one. `import type` is skipped (a type reference is not a value call path).\nfunction collectNamedImports(\n  root: Parser.SyntaxNode,\n): Map<string, { specifier: string; importedName: string }> {\n  const out = new Map<string, { specifier: string; importedName: string }>()\n  const visit = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'import_statement') {\n      // `import type { … }` — skip the whole statement.\n      for (let i = 0; i < node.childCount; i++) {\n        if (node.child(i)?.type === 'type') return\n      }\n      const source = node.childForFieldName('source')\n      const specifier = source ? stringLiteralText(source) : null\n      if (specifier) {\n        for (let i = 0; i < node.namedChildCount; i++) {\n          const clause = node.namedChild(i)\n          if (clause?.type !== 'import_clause') continue\n          for (let j = 0; j < clause.namedChildCount; j++) {\n            const named = clause.namedChild(j)\n            if (named?.type !== 'named_imports') continue\n            for (let k = 0; k < named.namedChildCount; k++) {\n              const spec = named.namedChild(k)\n              if (spec?.type !== 'import_specifier') continue\n              // A per-specifier `import { type Foo }` marks a type-only binding.\n              let isType = false\n              for (let t = 0; t < spec.childCount; t++) {\n                if (spec.child(t)?.type === 'type') isType = true\n              }\n              if (isType) continue\n              const nameNode = spec.childForFieldName('name')\n              if (!nameNode) continue\n              const importedName = nameNode.text\n              const localName = spec.childForFieldName('alias')?.text ?? importedName\n              out.set(localName, { specifier, importedName })\n            }\n          }\n        }\n      }\n      return\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child)\n    }\n  }\n  visit(root)\n  return out\n}\n\n// First reference line for each name in `wanted`, walking value-position\n// `identifier` uses and skipping the import declarations themselves. A call\n// (`fn()`), a JSX attribute (`action={fn}`), a `useActionState(fn)` argument, and\n// a `fn.bind(...)` receiver are all plain `identifier` nodes — property keys and\n// shorthand are their own node types, so they never match — which is what closes\n// the form-action gap: referenced, not only called.\nfunction firstReferenceLines(\n  root: Parser.SyntaxNode,\n  wanted: Set<string>,\n): Map<string, number> {\n  const lines = new Map<string, number>()\n  const visit = (node: Parser.SyntaxNode): void => {\n    // Don't descend into the import that declares the binding — the import\n    // specifier is not a usage reference.\n    if (node.type === 'import_statement') return\n    if (node.type === 'identifier' && wanted.has(node.text) && !lines.has(node.text)) {\n      lines.set(node.text, node.startPosition.row + 1)\n    }\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child) visit(child)\n    }\n  }\n  visit(root)\n  return lines\n}\n\nexport async function addServerActions(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const parsers = new Map<string, Parser>()\n  const parserForExt = (ext: string): Parser | null => {\n    const grammar = GRAMMAR_BY_EXT[ext]\n    if (!grammar) return null\n    let parser = parsers.get(ext)\n    if (!parser) {\n      parser = new Parser()\n      parser.setLanguage(grammar)\n      parsers.set(ext, parser)\n    }\n    return parser\n  }\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const deps = {\n      ...(service.pkg.dependencies ?? {}),\n      ...(service.pkg.devDependencies ?? {}),\n    }\n    // Gated on the `next` dependency, the same registry discipline addRoutes\n    // uses — a service that isn't a Next.js app declares no Server Actions.\n    if (deps['next'] === undefined) continue\n\n    const tsPaths: TsPathConfig | null = await loadTsPathConfig(service.dir)\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n\n    // ── Pass 1: mint an action node per exported `\"use server\"` function. ──\n    for (const file of files) {\n      if (isTestPath(file.path)) continue\n      const parser = parserForExt(path.extname(file.path))\n      if (!parser) continue\n      const relPath = toPosix(path.relative(service.dir, file.path))\n\n      let root: Parser.SyntaxNode\n      try {\n        root = parseSource(parser, file.content).rootNode\n      } catch (err) {\n        recordExtractionError('server action extraction', file.path, err)\n        continue\n      }\n\n      const moduleDirective = hasUseServerDirective(root)\n      const exported = collectExportedAsyncFns(root)\n      const actions = exported.filter(\n        (fn) => moduleDirective || (fn.bodyNode ? hasUseServerDirective(fn.bodyNode) : false),\n      )\n      if (actions.length === 0) continue\n\n      // The file owns its actions; ensure its FileNode (and the owning\n      // `service ──CONTAINS──▶ file` edge) exists before an action hangs off it.\n      const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        relPath,\n      )\n      nodesAdded += fn\n      edgesAdded += fe\n\n      for (const action of actions) {\n        const aid = serverActionId(service.pkg.name, relPath, action.exportName)\n        if (!graph.hasNode(aid)) {\n          const node: ServerActionNode = {\n            id: aid,\n            type: NodeType.ServerActionNode,\n            name: action.exportName,\n            service: service.pkg.name,\n            module: relPath,\n            exportName: action.exportName,\n            path: relPath,\n            line: action.line,\n            discoveredVia: 'static',\n          }\n          graph.addNode(aid, node)\n          nodesAdded++\n        }\n        // `file ──CONTAINS──▶ action` — structural ownership, the same tier and\n        // shape as `file ──CONTAINS──▶ symbol` (file-awareness.md §2), evidence\n        // pinned to the action's declaration file:line.\n        const containsId = extractedEdgeId(fileNodeId, aid, EdgeType.CONTAINS)\n        if (!graph.hasEdge(containsId)) {\n          const edge: GraphEdge = {\n            id: containsId,\n            source: fileNodeId,\n            target: aid,\n            type: EdgeType.CONTAINS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: {\n              file: relPath,\n              line: action.line,\n              snippet: snippet(file.content, action.line),\n            },\n          }\n          graph.addEdgeWithKey(containsId, fileNodeId, aid, edge)\n          edgesAdded++\n        }\n      }\n    }\n\n    // ── Pass 2: client-stitch `file ──CALLS──▶ action` on any reference to an ──\n    //    imported action binding, resolved through the import graph.\n    for (const file of files) {\n      if (isTestPath(file.path)) continue\n      const parser = parserForExt(path.extname(file.path))\n      if (!parser) continue\n      const relPath = toPosix(path.relative(service.dir, file.path))\n      const fileDir = path.dirname(file.path)\n\n      let root: Parser.SyntaxNode\n      try {\n        root = parseSource(parser, file.content).rootNode\n      } catch (err) {\n        recordExtractionError('server action stitch', file.path, err)\n        continue\n      }\n\n      // Resolve each named import to a known ServerActionNode; a local binding\n      // that resolves to one is an action reference in this file.\n      const bindings = collectNamedImports(root)\n      const actionBindings = new Map<string, string>() // local name → action id\n      for (const [local, binding] of bindings) {\n        const target = await resolveJsImport(binding.specifier, fileDir, service.dir, tsPaths)\n        if (!target) continue\n        const aid = serverActionId(service.pkg.name, target, binding.importedName)\n        if (graph.hasNode(aid)) actionBindings.set(local, aid)\n      }\n      if (actionBindings.size === 0) continue\n\n      const refLines = firstReferenceLines(root, new Set(actionBindings.keys()))\n\n      let clientFileId: string | null = null\n      for (const [local, aid] of actionBindings) {\n        const line = refLines.get(local)\n        if (line === undefined) continue // imported but never referenced — no edge, honestly.\n        if (clientFileId === null) {\n          const ensured = ensureFileNode(graph, service.pkg.name, service.node.id, relPath)\n          clientFileId = ensured.fileNodeId\n          nodesAdded += ensured.nodesAdded\n          edgesAdded += ensured.edgesAdded\n        }\n        // `file ──CALLS──▶ action` — a client reference to the action, resolved\n        // through the import graph to exactly one known node. Reuses CALLS; no new\n        // edge type (ADR-168). Deduped by the deterministic edge id, so multiple\n        // references (a call and a JSX `action={fn}`) land one edge.\n        const callsId = extractedEdgeId(clientFileId, aid, EdgeType.CALLS)\n        if (graph.hasEdge(callsId)) continue\n        const edge: GraphEdge = {\n          id: callsId,\n          source: clientFileId,\n          target: aid,\n          type: EdgeType.CALLS,\n          provenance: Provenance.EXTRACTED,\n          confidence: confidenceForExtracted('structural'),\n          evidence: {\n            file: relPath,\n            line,\n            snippet: snippet(file.content, line),\n          },\n        }\n        graph.addEdgeWithKey(callsId, clientFileId, aid, edge)\n        edgesAdded++\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport type {\n  CompatibleDriver,\n  ConfigNode,\n  DatabaseNode,\n  GraphEdge,\n  GraphNode,\n  ServiceNode,\n} from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  configId,\n  databaseId,\n  confidenceForExtracted,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n  checkCompatibility,\n  checkDeprecatedApi,\n  checkNodeEngineConstraint,\n  checkPackageConflict,\n  compatPairs,\n  deprecatedApis,\n  nodeEngineConstraints,\n  packageConflicts,\n} from '../../compat.js'\nimport {\n  cleanVersion,\n  isConfigFile,\n  makeEdgeId,\n  type DiscoveredService,\n} from '../shared.js'\nimport { ensureFileNode, toPosix } from '../calls/shared.js'\nimport { dbConfigYamlParser } from './db-config-yaml.js'\nimport { dotenvParser } from './dotenv.js'\nimport { prismaParser } from './prisma.js'\nimport { drizzleParser } from './drizzle.js'\nimport { knexParser } from './knex.js'\nimport { ormconfigParser } from './ormconfig.js'\nimport { typeormParser } from './typeorm.js'\nimport { sequelizeParser } from './sequelize.js'\nimport { csharpParser } from './csharp.js'\nimport { springDatasourceParser } from './spring.js'\nimport { dockerComposeParser } from './docker-compose.js'\nimport type { DbConfig } from './shared.js'\n\nexport type { DbConfig } from './shared.js'\n\nexport interface DbParser {\n  name: string\n  parse(serviceDir: string): Promise<DbConfig[]>\n}\n\n// Registry — order is for tie-breaking only (first wins on identical host).\n// db-config.yaml stays first so the canonical demo behaviour matches today's\n// extraction byte-for-byte.\nexport const DB_PARSERS: DbParser[] = [\n  dbConfigYamlParser,\n  dotenvParser,\n  prismaParser,\n  drizzleParser,\n  knexParser,\n  ormconfigParser,\n  typeormParser,\n  sequelizeParser,\n  csharpParser,\n  springDatasourceParser,\n  dockerComposeParser,\n]\n\nfunction compatibleDriversFor(engine: string): CompatibleDriver[] {\n  return compatPairs()\n    .filter((p) => p.engine === engine)\n    .map((p) => ({ name: p.driver, minVersion: p.minDriverVersion }))\n}\n\nfunction toDatabaseNode(config: DbConfig): DatabaseNode {\n  return {\n    id: databaseId(config.host),\n    type: NodeType.DatabaseNode,\n    name: config.database || config.host,\n    engine: config.engine,\n    engineVersion: config.engineVersion,\n    compatibleDrivers: compatibleDriversFor(config.engine),\n    host: config.host,\n    port: config.port,\n  }\n}\n\nexport function attachIncompatibilities(\n  service: DiscoveredService,\n  configs: DbConfig[],\n): void {\n  const deps = { ...(service.pkg.dependencies ?? {}), ...(service.pkg.devDependencies ?? {}) }\n  const incompatibilities: NonNullable<ServiceNode['incompatibilities']> = []\n  const seen = new Set<string>()\n\n  // 1. driver-engine — original behaviour. Per (db config, configured driver\n  // pair) check that the declared driver version meets the engine threshold.\n  for (const config of configs) {\n    for (const pair of compatPairs()) {\n      if (pair.engine !== config.engine) continue\n      const declaredVersion = cleanVersion(deps[pair.driver])\n      if (!declaredVersion) continue\n      const result = checkCompatibility(\n        pair.driver,\n        declaredVersion,\n        config.engine,\n        config.engineVersion,\n      )\n      if (!result.compatible && result.reason) {\n        const key = `driver-engine|${pair.driver}@${declaredVersion}|${config.engine}@${config.engineVersion}`\n        if (seen.has(key)) continue\n        seen.add(key)\n        incompatibilities.push({\n          kind: 'driver-engine',\n          driver: pair.driver,\n          driverVersion: declaredVersion,\n          engine: config.engine,\n          engineVersion: config.engineVersion,\n          reason: result.reason,\n        })\n      }\n    }\n  }\n\n  // 2. node-engine — service's `engines.node` vs each declared dep that has a\n  // matrix-recorded minimum.\n  const serviceNodeEngine = service.node.nodeEngine ?? service.pkg.engines?.node\n  for (const constraint of nodeEngineConstraints()) {\n    const declared = cleanVersion(deps[constraint.package])\n    if (!declared) continue\n    const result = checkNodeEngineConstraint(constraint, declared, serviceNodeEngine)\n    if (!result.compatible && result.reason) {\n      const key = `node-engine|${constraint.package}@${declared}|${serviceNodeEngine ?? ''}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      incompatibilities.push({\n        kind: 'node-engine',\n        package: constraint.package,\n        packageVersion: declared,\n        requiredNodeVersion: result.requiredNodeVersion ?? constraint.minNodeVersion,\n        ...(serviceNodeEngine ? { declaredNodeEngine: serviceNodeEngine } : {}),\n        reason: result.reason,\n      })\n    }\n  }\n\n  // 3. package-conflict — pair like react-query 5+ requiring react 18+.\n  for (const conflict of packageConflicts()) {\n    const declared = cleanVersion(deps[conflict.package])\n    if (!declared) continue\n    const requiredVersion = cleanVersion(deps[conflict.requires.name])\n    const result = checkPackageConflict(conflict, declared, requiredVersion)\n    if (!result.compatible && result.reason) {\n      const key = `package-conflict|${conflict.package}@${declared}|${conflict.requires.name}@${requiredVersion ?? 'missing'}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      incompatibilities.push({\n        kind: 'package-conflict',\n        package: conflict.package,\n        packageVersion: declared,\n        requires: conflict.requires,\n        ...(requiredVersion ? { foundVersion: requiredVersion } : {}),\n        reason: result.reason,\n      })\n    }\n  }\n\n  // 4. deprecated-api — flag presence of a known-deprecated package.\n  for (const rule of deprecatedApis()) {\n    const declared = cleanVersion(deps[rule.package])\n    if (declared === undefined) continue\n    const result = checkDeprecatedApi(rule, declared)\n    if (!result.compatible && result.reason) {\n      const key = `deprecated-api|${rule.package}@${declared}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      incompatibilities.push({\n        kind: 'deprecated-api',\n        package: rule.package,\n        packageVersion: declared,\n        reason: result.reason,\n      })\n    }\n  }\n\n  if (incompatibilities.length > 0) service.node.incompatibilities = incompatibilities\n}\n\n// Phase 2 — for each service, run every parser and merge their DbConfigs by\n// host. Each unique host produces one DatabaseNode + CONNECTS_TO edge from the\n// service. The parser registry decides priority on tie; the demo's\n// db-config.yaml stays first so its `engineVersion: 15` continues to win.\nexport async function addDatabasesAndCompat(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const merged = new Map<string, DbConfig>()\n    for (const parser of DB_PARSERS) {\n      let configs: DbConfig[]\n      try {\n        configs = await parser.parse(service.dir)\n      } catch (err) {\n        console.warn(\n          `[neat] ${parser.name} parser failed on ${service.node.name}: ${(err as Error).message}`,\n        )\n        continue\n      }\n      for (const config of configs) {\n        if (!config.host) continue\n        if (!merged.has(config.host)) merged.set(config.host, config)\n      }\n    }\n\n    const allConfigs = [...merged.values()]\n    for (const config of allConfigs) {\n      const dbNode = toDatabaseNode(config)\n      if (!graph.hasNode(dbNode.id)) {\n        graph.addNode(dbNode.id, { ...dbNode, discoveredVia: 'static' })\n        nodesAdded++\n      } else {\n        // OTel ingest may have auto-created a minimal node at this id. Merge\n        // per ADR-033: static fields override OTel-derived fields, discoveredVia\n        // flips to 'merged' when both layers contributed.\n        const existing = graph.getNodeAttributes(dbNode.id) as DatabaseNode\n        const mergedDiscoveredVia: 'static' | 'otel' | 'merged' =\n          existing.discoveredVia === 'otel' ? 'merged' : 'static'\n        graph.replaceNodeAttributes(dbNode.id, {\n          ...existing,\n          ...dbNode,\n          discoveredVia: mergedDiscoveredVia,\n        })\n      }\n      // file-awareness §1 — the connection is declared in a config file; that\n      // file is the relationship origin. ensureFileNode creates the FileNode +\n      // CONTAINS edge so the CONNECTS_TO lands file-grained, not service-level.\n      const relConfigFile = toPosix(path.relative(service.dir, config.sourceFile))\n      const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        relConfigFile,\n      )\n      nodesAdded += fn\n      edgesAdded += fe\n      const evidenceFile = toPosix(path.relative(scanPath, config.sourceFile))\n      const edge: GraphEdge = {\n        id: makeEdgeId(fileNodeId, dbNode.id, EdgeType.CONNECTS_TO),\n        source: fileNodeId,\n        target: dbNode.id,\n        type: EdgeType.CONNECTS_TO,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        // Carry how the host was recovered (ADR-213) so the divergence ranker\n        // can tell a real declared store from a hardcoded fault-injection /\n        // flag-gated probe. Only set when the parser distinguished the two.\n        evidence: config.hostSource\n          ? { file: evidenceFile, hostSource: config.hostSource }\n          : { file: evidenceFile },\n      }\n      if (!graph.hasEdge(edge.id)) {\n        graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n        edgesAdded++\n      }\n    }\n\n    // Service-level declared DB target. When a service declares exactly one DB\n    // connection in config — a `postgres://…` string in .env, a db-config.yaml,\n    // a prisma/drizzle/knex datasource — record where it's pointed on the\n    // ServiceNode as `dbConnectionTarget` (host[:port]) and link the service to\n    // the config that declared it with an EXTRACTED CONFIGURED_BY edge. This is\n    // the service-grained declared intent the host-mismatch divergence compares\n    // against the service-grained OBSERVED CONNECTS_TO (file-awareness §7 —\n    // compare at the shared grain; a DB OTel span carries no call site, so the\n    // comparison is service-level). Without this, `declaredHostFor` reads an\n    // unpopulated field and host-mismatch never fires.\n    //\n    // We hold to a *single* declared target: with two or more distinct hosts\n    // the single-target model is ambiguous and would flag every observed host\n    // but one as a false mismatch, so we decline rather than guess.\n    if (allConfigs.length === 1) {\n      const primary = allConfigs[0]!\n      service.node.dbConnectionTarget = primary.port\n        ? `${primary.host}:${primary.port}`\n        : primary.host\n\n      // Link to the config file that declared the connection. Mirror configs.ts's\n      // ConfigNode id (Phase 3 runs after this and is idempotent on the node);\n      // the CONFIGURED_BY edge is service-grained here, matching the grain of\n      // the declared target it backs.\n      const relPath = path.relative(scanPath, primary.sourceFile)\n      const cfgId = configId(relPath)\n      if (!graph.hasNode(cfgId)) {\n        const cfgNode: ConfigNode = {\n          id: cfgId,\n          type: NodeType.ConfigNode,\n          name: path.basename(primary.sourceFile),\n          path: relPath,\n          fileType: isConfigFile(path.basename(primary.sourceFile)).fileType || 'config',\n        }\n        graph.addNode(cfgId, cfgNode)\n        nodesAdded++\n      }\n      const cfgEdge: GraphEdge = {\n        id: makeEdgeId(service.node.id, cfgId, EdgeType.CONFIGURED_BY),\n        source: service.node.id,\n        target: cfgId,\n        type: EdgeType.CONFIGURED_BY,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: { file: toPosix(relPath) },\n      }\n      if (!graph.hasEdge(cfgEdge.id)) {\n        graph.addEdgeWithKey(cfgEdge.id, cfgEdge.source, cfgEdge.target, cfgEdge)\n        edgesAdded++\n      }\n    }\n\n    // Run all kinds of incompat checks even for services with no db connection\n    // — node-engine / package-conflict / deprecated-api don't depend on db.\n    attachIncompatibilities(service, allConfigs)\n    if (graph.hasNode(service.node.id)) {\n      // Merge with whatever's on the node already (aliases from γ #75 land\n      // before this phase), so the writeback doesn't drop fields populated by\n      // earlier passes.\n      const current = graph.getNodeAttributes(service.node.id) as ServiceNode\n      const updated: ServiceNode = {\n        ...current,\n        ...(service.node as ServiceNode),\n        ...(current.aliases ? { aliases: current.aliases } : {}),\n      }\n      // attachIncompatibilities only sets the field when there's something to\n      // flag. On a re-extract (`neat watch`, `POST /graph/scan`), a stale\n      // entry on `current` would otherwise survive the spread and leave the\n      // graph reporting a problem the new manifest no longer has.\n      if (!service.node.incompatibilities || service.node.incompatibilities.length === 0) {\n        delete (updated as { incompatibilities?: unknown }).incompatibilities\n      }\n      // Same stale-survivor guard for the declared DB target: if this pass found\n      // no single declared connection, a value left on `current` from a prior\n      // extract would otherwise survive the spread.\n      if (!service.node.dbConnectionTarget) {\n        delete (updated as { dbConnectionTarget?: unknown }).dbConnectionTarget\n      }\n      graph.replaceNodeAttributes(service.node.id, updated as unknown as GraphNode)\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { exists, readYaml } from '../shared.js'\nimport type { DbConfig } from './shared.js'\n\ninterface DbConfigYaml {\n  host: string\n  port?: number\n  database: string\n  engine: string\n  engineVersion?: string | number\n}\n\n// The original db-config.yaml format, kept as a parser so the demo continues\n// to work. Engine + version are explicit here, so this is the one source that\n// can produce a real engineVersion without inference.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const yamlPath = path.join(serviceDir, 'db-config.yaml')\n  if (!(await exists(yamlPath))) return []\n  const raw = await readYaml<DbConfigYaml>(yamlPath)\n  return [\n    {\n      host: raw.host,\n      port: raw.port,\n      database: raw.database,\n      engine: raw.engine,\n      engineVersion: raw.engineVersion !== undefined ? String(raw.engineVersion) : 'unknown',\n      sourceFile: yamlPath,\n    },\n  ]\n}\n\nexport const dbConfigYamlParser = { name: 'db-config.yaml', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { isConfigFile } from '../shared.js'\nimport { parseConnectionString, type DbConfig } from './shared.js'\n\n// Both the `_URL` and `_URI` spellings for every engine — apps split roughly\n// evenly between them and the two are interchangeable. `MONGODB_URL` in\n// particular is the single most common Mongo env-var name (the Mongoose docs\n// and most boilerplates use it), and its earlier absence meant an app's own\n// database connection went unextracted, so the runtime span had nothing to fuse\n// onto and minted a standalone `database:<host>` node instead (#832).\nconst CONNECTION_KEYS = new Set([\n  'DATABASE_URL',\n  'DATABASE_URI',\n  'DB_URL',\n  'DB_URI',\n  'POSTGRES_URL',\n  'POSTGRES_URI',\n  'POSTGRESQL_URL',\n  'POSTGRESQL_URI',\n  'MYSQL_URL',\n  'MYSQL_URI',\n  'MONGODB_URL',\n  'MONGODB_URI',\n  'MONGO_URL',\n  'MONGO_URI',\n  'REDIS_URL',\n  'REDIS_URI',\n])\n\n// Per ADR-016, .env contents do not land in any snapshot. We read them here\n// only to derive a transient DbConfig — the value never reaches a ConfigNode.\nfunction parseDotenvLine(line: string): { key: string; value: string } | null {\n  const trimmed = line.trim()\n  if (!trimmed || trimmed.startsWith('#')) return null\n  const eq = trimmed.indexOf('=')\n  if (eq < 0) return null\n  const key = trimmed.slice(0, eq).trim()\n  let value = trimmed.slice(eq + 1).trim()\n  if (\n    (value.startsWith('\"') && value.endsWith('\"')) ||\n    (value.startsWith(\"'\") && value.endsWith(\"'\"))\n  ) {\n    value = value.slice(1, -1)\n  }\n  return { key, value }\n}\n\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const entries = await fs.readdir(serviceDir, { withFileTypes: true }).catch(() => [])\n  const configs: DbConfig[] = []\n  const seen = new Set<string>()\n\n  for (const entry of entries) {\n    if (!entry.isFile()) continue\n    const match = isConfigFile(entry.name)\n    if (!match.match || match.fileType !== 'env') continue\n\n    const filePath = path.join(serviceDir, entry.name)\n    const content = await fs.readFile(filePath, 'utf8')\n    for (const line of content.split('\\n')) {\n      const parsed = parseDotenvLine(line)\n      if (!parsed) continue\n      if (!CONNECTION_KEYS.has(parsed.key.toUpperCase())) continue\n      const config = parseConnectionString(parsed.value)\n      if (!config) continue\n      const key = `${config.engine}://${config.host}:${config.port ?? ''}/${config.database}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      configs.push({ ...config, sourceFile: filePath })\n    }\n  }\n  return configs\n}\n\nexport const dotenvParser = { name: '.env', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport interface DbConfig {\n  host: string\n  port?: number\n  database: string\n  engine: string\n  engineVersion: string // \"unknown\" when not statically determinable\n  // Absolute path to the file the parser read this config from. Required —\n  // ghost-edge cleanup keys CONNECTS_TO retirement on `evidence.file` per\n  // ADR-032 / #140. Parsers that synthesize a DbConfig from a partial\n  // source still set this to the file the partial came from.\n  sourceFile: string\n  // How the host was recovered (ADR-213): `config` when resolved from an env\n  // var / IConfiguration key / config file — the deployment's real target —\n  // and `literal` when read from a hardcoded string literal in source. Threaded\n  // onto the CONNECTS_TO edge's evidence so the divergence ranker can tell a\n  // real declared store from a hardcoded fault-injection / flag-gated probe.\n  // Optional — a parser that doesn't distinguish the two leaves it unset, and\n  // the ranker then treats the host as a normal declaration.\n  hostSource?: 'literal' | 'config'\n}\n\n// Map a connection-string scheme to the engine name our compat matrix uses.\n// Schemes like \"postgres+asyncpg\" are normalised by stripping the dialect\n// suffix; anything we don't recognise returns null so the parser can decline.\nexport function schemeToEngine(scheme: string): string | null {\n  const s = scheme.toLowerCase().split('+')[0]\n  switch (s) {\n    case 'postgres':\n    case 'postgresql':\n      return 'postgresql'\n    case 'mysql':\n    case 'mariadb':\n      return 'mysql'\n    case 'mongodb':\n    case 'mongodb+srv':\n      return 'mongodb'\n    case 'redis':\n    case 'rediss':\n      return 'redis'\n    case 'sqlite':\n      return 'sqlite'\n    default:\n      return null\n  }\n}\n\n// Returns the inner DbConfig fields without sourceFile — every caller spreads\n// the parser's own file path on top. Type makes that contract explicit.\nexport type ParsedConnectionConfig = Omit<DbConfig, 'sourceFile'>\n\nexport function parseConnectionString(url: string): ParsedConnectionConfig | null {\n  const m = url.match(\n    /^(?<scheme>[a-z][a-z+]*):\\/\\/(?:[^@/]+(?::[^@]*)?@)?(?<host>[^:/?]+)(?::(?<port>\\d+))?(?:\\/(?<db>[^?#]*))?/i,\n  )\n  if (!m || !m.groups) return null\n  const engine = schemeToEngine(m.groups.scheme!)\n  if (!engine) return null\n  return {\n    host: m.groups.host!,\n    port: m.groups.port ? Number(m.groups.port) : undefined,\n    database: m.groups.db ?? '',\n    engine,\n    engineVersion: 'unknown',\n  }\n}\n\nexport async function readIfExists(filePath: string): Promise<string | null> {\n  try {\n    return await fs.readFile(filePath, 'utf8')\n  } catch {\n    return null\n  }\n}\n\n// Resolve an env variable an ORM datasource references indirectly — Prisma's\n// `url = env(\"DATABASE_URL\")`, Drizzle/Knex reading `process.env.DATABASE_URL`\n// — from the service's `.env` files, so the parser can recover the real host\n// instead of falling back to a placeholder (ADR-141). Precedence follows the\n// dotenv convention: `.env.local` overrides `.env`, then any other `.env.*`.\n// Per ADR-016 the value is transient — it only derives the DatabaseNode host and\n// never lands in a ConfigNode or the snapshot.\nexport async function resolveEnvVar(serviceDir: string, name: string): Promise<string | null> {\n  const entries = await fs.readdir(serviceDir, { withFileTypes: true }).catch(() => [])\n  const envNames = entries\n    .filter((e) => e.isFile() && (e.name === '.env' || e.name.startsWith('.env.')))\n    .map((e) => e.name)\n  const rank = (n: string): number => (n === '.env.local' ? 0 : n === '.env' ? 1 : 2)\n  envNames.sort((a, b) => rank(a) - rank(b) || a.localeCompare(b))\n  for (const fileName of envNames) {\n    const content = await readIfExists(path.join(serviceDir, fileName))\n    if (!content) continue\n    for (const line of content.split('\\n')) {\n      const trimmed = line.trim()\n      if (!trimmed || trimmed.startsWith('#')) continue\n      const eq = trimmed.indexOf('=')\n      if (eq < 0) continue\n      if (trimmed.slice(0, eq).trim() !== name) continue\n      let value = trimmed.slice(eq + 1).trim()\n      if (\n        (value.startsWith('\"') && value.endsWith('\"')) ||\n        (value.startsWith(\"'\") && value.endsWith(\"'\"))\n      ) {\n        value = value.slice(1, -1)\n      }\n      return value || null\n    }\n  }\n  return null\n}\n\nexport async function findFirst(\n  serviceDir: string,\n  candidates: string[],\n): Promise<string | null> {\n  for (const rel of candidates) {\n    const abs = path.join(serviceDir, rel)\n    const content = await readIfExists(abs)\n    if (content !== null) return abs\n  }\n  return null\n}\n\n// Engine name from a docker-compose `image:` value like \"postgres:15-alpine\"\n// or \"mysql/mysql-server:8.0\". Returns the engine + version when both are\n// resolvable, or null if the image isn't one we recognise.\nexport function engineFromImage(\n  image: string,\n): { engine: string; engineVersion: string } | null {\n  const lower = image.toLowerCase()\n  const colon = lower.lastIndexOf(':')\n  const repo = colon >= 0 ? lower.slice(0, colon) : lower\n  const tag = colon >= 0 ? lower.slice(colon + 1) : 'latest'\n  const last = repo.split('/').pop() ?? repo\n  let engine: string | null = null\n  if (last.startsWith('postgres')) engine = 'postgresql'\n  else if (last.startsWith('mysql') || last.startsWith('mariadb')) engine = 'mysql'\n  else if (last.startsWith('mongo')) engine = 'mongodb'\n  else if (last.startsWith('redis')) engine = 'redis'\n  else if (last.startsWith('sqlite')) engine = 'sqlite'\n  if (!engine) return null\n  // Strip everything after the major version digit run; \"15-alpine\" -> \"15\".\n  const versionMatch = tag.match(/^(\\d+(?:\\.\\d+){0,2})/)\n  return {\n    engine,\n    engineVersion: versionMatch ? versionMatch[1]! : 'unknown',\n  }\n}\n","import path from 'node:path'\nimport {\n  readIfExists,\n  parseConnectionString,\n  resolveEnvVar,\n  schemeToEngine,\n  type DbConfig,\n} from './shared.js'\n\n// Prisma's schema file declares datasources of the form:\n//\n//   datasource db {\n//     provider = \"postgresql\"\n//     url      = env(\"DATABASE_URL\")\n//   }\n//\n// We match the provider directly. The url is almost always an env() indirection,\n// so we resolve the referenced variable from the service's .env to recover the\n// real host — that keys the DatabaseNode on the same host the dotenv parser\n// mints, so the two fuse to one declared node instead of a placeholder twin\n// (ADR-141). Only when the url is a literal, or the env var is absent, do we\n// fall back (literal parse, then a deterministic per-service placeholder).\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const schemaPath = path.join(serviceDir, 'prisma', 'schema.prisma')\n  const content = await readIfExists(schemaPath)\n  if (!content) return []\n\n  const block = content.match(/datasource\\s+\\w+\\s*\\{([^}]*)\\}/s)\n  if (!block) return []\n  const body = block[1] ?? ''\n\n  const providerMatch = body.match(/provider\\s*=\\s*\"([^\"]+)\"/)\n  if (!providerMatch) return []\n  const engine = schemeToEngine(providerMatch[1]!)\n  if (!engine) return []\n\n  const urlMatch = body.match(/url\\s*=\\s*\"([^\"]+)\"/)\n  if (urlMatch) {\n    const config = parseConnectionString(urlMatch[1]!)\n    if (config) return [{ ...config, sourceFile: schemaPath }]\n  }\n\n  const envMatch = body.match(/url\\s*=\\s*env\\(\\s*\"([^\"]+)\"\\s*\\)/)\n  if (envMatch) {\n    const resolved = await resolveEnvVar(serviceDir, envMatch[1]!)\n    if (resolved) {\n      const config = parseConnectionString(resolved)\n      if (config) return [{ ...config, sourceFile: schemaPath }]\n    }\n  }\n\n  return [\n    {\n      host: `${engine}-prisma`,\n      database: '',\n      engine,\n      engineVersion: 'unknown',\n      sourceFile: schemaPath,\n    },\n  ]\n}\n\nexport const prismaParser = { name: 'prisma', parse }\n","import {\n  findFirst,\n  readIfExists,\n  parseConnectionString,\n  resolveEnvVar,\n  schemeToEngine,\n  type DbConfig,\n} from './shared.js'\n\nconst DIALECT_TO_ENGINE: Record<string, string> = {\n  postgresql: 'postgresql',\n  postgres: 'postgresql',\n  pg: 'postgresql',\n  mysql: 'mysql',\n  mysql2: 'mysql',\n  sqlite: 'sqlite',\n  'better-sqlite': 'sqlite',\n}\n\n// Drizzle's drizzle.config.{ts,js,mjs} declares a `dialect` plus credentials.\n// We can't safely eval the file, but the relevant bits are simple key/value\n// expressions — regex-extracted to stay sandbox-clean and dep-free.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const filePath = await findFirst(serviceDir, [\n    'drizzle.config.ts',\n    'drizzle.config.js',\n    'drizzle.config.mjs',\n  ])\n  if (!filePath) return []\n  const content = await readIfExists(filePath)\n  if (!content) return []\n\n  const dialectMatch = content.match(/dialect\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n  if (!dialectMatch) return []\n  const engine =\n    DIALECT_TO_ENGINE[dialectMatch[1]!.toLowerCase()] ?? schemeToEngine(dialectMatch[1]!)\n  if (!engine) return []\n\n  const urlMatch = content.match(\n    /(?:url|connectionString)\\s*:\\s*['\"`]([a-z][a-z+]*:\\/\\/[^'\"`]+)['\"`]/i,\n  )\n  if (urlMatch) {\n    const config = parseConnectionString(urlMatch[1]!)\n    if (config) return [{ ...config, sourceFile: filePath }]\n  }\n  // `url: process.env.DATABASE_URL` (or `connectionString:`, bracket form) — the\n  // common env-driven shape. Resolve it from the service's .env so the node keys\n  // on the real host and dedups with the dotenv parser instead of a placeholder\n  // (ADR-141, #807).\n  const urlEnvMatch = content.match(\n    /(?:url|connectionString)\\s*:\\s*process\\.env(?:\\.([A-Za-z_$][\\w$]*)|\\[\\s*['\"]([^'\"]+)['\"]\\s*\\])/,\n  )\n  if (urlEnvMatch) {\n    const varName = urlEnvMatch[1] ?? urlEnvMatch[2]\n    const resolved = varName ? await resolveEnvVar(serviceDir, varName) : null\n    const config = resolved ? parseConnectionString(resolved) : null\n    if (config) return [{ ...config, sourceFile: filePath }]\n  }\n  const hostMatch = content.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n  if (hostMatch) {\n    const portMatch = content.match(/port\\s*:\\s*(\\d+)/)\n    const dbMatch = content.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n    return [\n      {\n        host: hostMatch[1]!,\n        port: portMatch ? Number(portMatch[1]) : undefined,\n        database: dbMatch?.[1] ?? '',\n        engine,\n        engineVersion: 'unknown',\n        sourceFile: filePath,\n      },\n    ]\n  }\n  return [\n    { host: `${engine}-drizzle`, database: '', engine, engineVersion: 'unknown', sourceFile: filePath },\n  ]\n}\n\nexport const drizzleParser = { name: 'drizzle', parse }\n","import {\n  findFirst,\n  readIfExists,\n  parseConnectionString,\n  resolveEnvVar,\n  type DbConfig,\n} from './shared.js'\n\nconst CLIENT_TO_ENGINE: Record<string, string> = {\n  pg: 'postgresql',\n  postgres: 'postgresql',\n  postgresql: 'postgresql',\n  mysql: 'mysql',\n  mysql2: 'mysql',\n  sqlite3: 'sqlite',\n  'better-sqlite3': 'sqlite',\n}\n\n// knexfile.{js,ts} declares a client (one of pg/mysql/sqlite/...) plus a\n// connection string or host/port object. We pick whichever shape is in the\n// file and ignore environment-driven values we can't resolve statically.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const filePath = await findFirst(serviceDir, [\n    'knexfile.js',\n    'knexfile.ts',\n    'knexfile.cjs',\n    'knexfile.mjs',\n  ])\n  if (!filePath) return []\n  const content = await readIfExists(filePath)\n  if (!content) return []\n\n  const clientMatch = content.match(/client\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n  if (!clientMatch) return []\n  const engine = CLIENT_TO_ENGINE[clientMatch[1]!.toLowerCase()]\n  if (!engine) return []\n\n  const urlMatch = content.match(\n    /connection\\s*:\\s*['\"`]([a-z][a-z+]*:\\/\\/[^'\"`]+)['\"`]/i,\n  )\n  if (urlMatch) {\n    const config = parseConnectionString(urlMatch[1]!)\n    if (config) return [{ ...config, sourceFile: filePath }]\n  }\n\n  // `connection: process.env.DATABASE_URL` (bracket form too) — the whole\n  // connection is a URL from env. Resolve it from the service's .env so the node\n  // keys on the real host and dedups instead of a placeholder (ADR-141, #807).\n  // `connection: { host: process.env.DB_HOST }` deliberately does not match — an\n  // object of env fields keeps the placeholder rather than a fabricated URL.\n  const urlEnvMatch = content.match(\n    /connection\\s*:\\s*process\\.env(?:\\.([A-Za-z_$][\\w$]*)|\\[\\s*['\"]([^'\"]+)['\"]\\s*\\])/,\n  )\n  if (urlEnvMatch) {\n    const varName = urlEnvMatch[1] ?? urlEnvMatch[2]\n    const resolved = varName ? await resolveEnvVar(serviceDir, varName) : null\n    const config = resolved ? parseConnectionString(resolved) : null\n    if (config) return [{ ...config, sourceFile: filePath }]\n  }\n\n  const host = content.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1]\n  if (host) {\n    const port = content.match(/port\\s*:\\s*(\\d+)/)?.[1]\n    const database = content.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1] ?? ''\n    return [\n      {\n        host,\n        port: port ? Number(port) : undefined,\n        database,\n        engine,\n        engineVersion: 'unknown',\n        sourceFile: filePath,\n      },\n    ]\n  }\n\n  return [{ host: `${engine}-knex`, database: '', engine, engineVersion: 'unknown', sourceFile: filePath }]\n}\n\nexport const knexParser = { name: 'knex', parse }\n","import path from 'node:path'\nimport { exists, readJson, readYaml } from '../shared.js'\nimport { schemeToEngine, type DbConfig } from './shared.js'\n\ninterface OrmConfigEntry {\n  type?: string\n  host?: string\n  port?: number\n  database?: string\n}\n\n// ormconfig.{json,yaml,yml} — TypeORM's legacy config file. Single object or\n// an array of named connections; we walk both.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  for (const candidate of ['ormconfig.json', 'ormconfig.yaml', 'ormconfig.yml']) {\n    const abs = path.join(serviceDir, candidate)\n    if (!(await exists(abs))) continue\n    const raw = candidate.endsWith('.json')\n      ? await readJson<OrmConfigEntry | OrmConfigEntry[]>(abs)\n      : await readYaml<OrmConfigEntry | OrmConfigEntry[]>(abs)\n    const entries = Array.isArray(raw) ? raw : [raw]\n\n    const out: DbConfig[] = []\n    for (const entry of entries) {\n      if (!entry?.type || !entry.host) continue\n      const engine = schemeToEngine(entry.type)\n      if (!engine) continue\n      out.push({\n        host: entry.host,\n        port: entry.port,\n        database: entry.database ?? '',\n        engine,\n        engineVersion: 'unknown',\n        sourceFile: abs,\n      })\n    }\n    if (out.length > 0) return out\n  }\n  return []\n}\n\nexport const ormconfigParser = { name: 'ormconfig', parse }\n","import { findFirst, readIfExists, schemeToEngine, type DbConfig } from './shared.js'\n\n// TypeORM's modern shape: `new DataSource({ type: 'postgres', host, port, ... })`\n// in a data-source.ts (or .js). We regex for the type/host/port/database keys\n// in the first DataSource literal we find.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const filePath = await findFirst(serviceDir, [\n    'data-source.ts',\n    'data-source.js',\n    'src/data-source.ts',\n    'src/data-source.js',\n  ])\n  if (!filePath) return []\n  const content = await readIfExists(filePath)\n  if (!content) return []\n\n  const block = content.match(/new\\s+DataSource\\s*\\(\\s*\\{([\\s\\S]*?)\\}\\s*\\)/)\n  const body = block ? block[1]! : content\n\n  const typeMatch = body.match(/type\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)\n  const host = body.match(/host\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1]\n  if (!typeMatch || !host) return []\n\n  const engine = schemeToEngine(typeMatch[1]!)\n  if (!engine) return []\n\n  const port = body.match(/port\\s*:\\s*(\\d+)/)?.[1]\n  const database = body.match(/database\\s*:\\s*['\"`]([^'\"`]+)['\"`]/)?.[1] ?? ''\n\n  return [\n    {\n      host,\n      port: port ? Number(port) : undefined,\n      database,\n      engine,\n      engineVersion: 'unknown',\n      sourceFile: filePath,\n    },\n  ]\n}\n\nexport const typeormParser = { name: 'typeorm', parse }\n","import path from 'node:path'\nimport { exists, readJson } from '../shared.js'\nimport { schemeToEngine, type DbConfig } from './shared.js'\n\ninterface SequelizeConfigEntry {\n  dialect?: string\n  host?: string\n  port?: number\n  database?: string\n}\n\ntype SequelizeConfig = Record<string, SequelizeConfigEntry>\n\n// Sequelize stores per-environment configs under config/config.json. We read\n// every named environment so a service that declares production + staging\n// surfaces both DB targets.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const configPath = path.join(serviceDir, 'config', 'config.json')\n  if (!(await exists(configPath))) return []\n  const raw = await readJson<SequelizeConfig>(configPath)\n\n  const out: DbConfig[] = []\n  const seen = new Set<string>()\n  for (const entry of Object.values(raw)) {\n    if (!entry?.dialect || !entry.host) continue\n    const engine = schemeToEngine(entry.dialect)\n    if (!engine) continue\n    const key = `${engine}://${entry.host}:${entry.port ?? ''}/${entry.database ?? ''}`\n    if (seen.has(key)) continue\n    seen.add(key)\n    out.push({\n      host: entry.host,\n      port: entry.port,\n      database: entry.database ?? '',\n      engine,\n      engineVersion: 'unknown',\n      sourceFile: configPath,\n    })\n  }\n  return out\n}\n\nexport const sequelizeParser = { name: 'sequelize', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { maskCommentsInSource } from '../shared.js'\nimport { walkSourceFiles } from '../calls/shared.js'\nimport {\n  parseConnectionString,\n  resolveEnvVar,\n  type DbConfig,\n  type ParsedConnectionConfig,\n} from './shared.js'\n\n// C# datastore clients (ADR-205; id scheme refined by ADR-207) — the connection axis of C#/.NET, the sibling\n// of prisma.ts / drizzle.ts here and of calls/efcore.ts (the table axis). Two\n// client shapes, both producing a `DatabaseNode` keyed on the resolved peer host\n// so the EXTRACTED twin lands on the same `database:<host>` id an OBSERVED\n// CONNECTS_TO span already minted (ingest keys a db span on server.address /\n// net.peer.name via `databaseId`, ingest.ts) — the whole point being that the\n// two layers fuse instead of twinning:\n//\n//   1. EF Core / Npgsql -> Postgres. A `DbContext.OnConfiguring` (or a DI\n//      `AddDbContext`/`AddNpgsql*`) calls `UseNpgsql(<conn>)`. The connection is\n//      an ADO.NET keyword string — `Host=postgresql;Username=...;Database=otel`\n//      — either a literal or read from an env var / `IConfiguration` key, so the\n//      host is recovered by parsing the `Host=` keyword (resolving the env var\n//      from the service's `.env`, walking up to the repo root, when it's\n//      indirected — the otel-demo puts `DB_CONNECTION_STRING` and `VALKEY_ADDR`\n//      in a root `.env`/compose, above each service dir).\n//\n//   2. StackExchange.Redis -> Redis/Valkey. `ConnectionMultiplexer.Connect(...)`\n//      / `ConfigurationOptions.Parse(\"host:port,opts\")` names the endpoint; the\n//      host is the token before the first `:` / `,`. Valkey is Redis-wire\n//      compatible, so `db.system` is `redis` and the store keys on its own host\n//      (`valkey-cart`) exactly like any Redis peer — engine `redis`.\n//\n// Precision & identity (ADR-207): a config is emitted only when a real client\n// call is present AND a host resolves to a plain string (no unresolved `${VAR}`\n// left in it). The `DatabaseNode` is keyed on that resolved host ALONE — the\n// engine (`postgres`/`redis`) is a node ATTRIBUTE, never part of the id — so the\n// id equals the `database:<host>` an OBSERVED span already minted from\n// `server.address` (no `-npgsql`/`-stackexchange` driver suffix, which would key\n// the twin off the observed peer and never fuse). Every genuinely declared host\n// is extracted, config-driven addresses first: the otel-demo cart declares both\n// the `VALKEY_ADDR` peer (`valkey-cart`, which fuses) AND a hardcoded\n// `\"badhost:1234\"` fault-probe store, so both mint — `badhost` is a real declared\n// connection that simply has no OBSERVED twin (an honest divergence), not a\n// phantom to drop. What is NEVER minted is a fabricated placeholder host for a\n// client whose connection can't be resolved at all: a made-up host looks fusable\n// but isn't, so an unresolvable connection is left as an honest gap. Comment\n// bodies are masked before scanning so a connection string inside a `//` / `/* */`\n// comment never mints a node (the ADR-065 #2 discipline the regex extractors\n// share).\n\nconst CS_EXT = '.cs'\n\n// Cheap per-file gates — skip a `.cs` file that names neither client before the\n// heavier scan runs, the import-gate discipline the data-axis readers follow.\nconst NPGSQL_GATE = /\\bUseNpgsql\\b|\\bNpgsql\\b/\nconst REDIS_GATE = /\\bConnectionMultiplexer\\b|\\bStackExchange\\.Redis\\b|\\bConfigurationOptions\\.Parse\\b|\\bAddStackExchangeRedisCache\\b/\n\n// An `IConfiguration` / environment read that yields a connection string:\n//   Environment.GetEnvironmentVariable(\"NAME\")\n//   Configuration[\"NAME\"] / builder.Configuration[\"NAME\"]\n//   Configuration.GetConnectionString(\"NAME\")\nconst ENV_READ_RE =\n  /(?:GetEnvironmentVariable|GetConnectionString)\\(\\s*\"([^\"]+)\"\\s*\\)|Configuration\\s*\\[\\s*\"([^\"]+)\"\\s*\\]/g\n\n// A double-quoted string literal (C# `\"...\"` or verbatim `@\"...\"`; interpolated\n// `$\"...\"` is skipped by the caller since its host is a runtime value).\nconst STRING_LITERAL_RE = /@?\"([^\"\\\\]*(?:\\\\.[^\"\\\\]*)*)\"/g\n\n// A host token still carrying an interpolation hole (`${VAR}`, `$(cmd)`, a C#\n// `{expr}`, or a bare `$`) never resolved to a real peer — reject it so a\n// runtime-computed host falls through to the placeholder instead of minting a\n// node id with braces in it.\nfunction hostIsUnresolved(host: string): boolean {\n  return host === '' || /[${}]/.test(host)\n}\n\n// Does a string look like a Postgres keyword / URL connection string?\nfunction looksLikePostgres(s: string): boolean {\n  return /(?:^|;)\\s*(?:host|server|data\\s*source)\\s*=/i.test(s) || /^postgres(?:ql)?:\\/\\//i.test(s)\n}\n\n// Does a string look like a StackExchange.Redis endpoint? A bare word is too\n// ambiguous (any string literal in the file would match) — require a `host:port`\n// pair, a redis option token (`,ssl=`, `,abortConnect=`, …), or a `redis://` URL,\n// so a log message or a schema name is never mistaken for a Redis host.\nfunction looksLikeRedis(s: string): boolean {\n  return (\n    /^rediss?:\\/\\//i.test(s) ||\n    /^[A-Za-z0-9_.-]+:\\d+(?:$|,)/.test(s) ||\n    /,\\s*(?:ssl|abortconnect|allowadmin|connecttimeout|password|user)\\s*=/i.test(s)\n  )\n}\n\n// Host / port / database out of an ADO.NET keyword connection string\n// (`Host=postgresql;Port=5432;Database=otel;Username=...`) or a `postgres://` URL.\n// Case-insensitive keys, first host of a comma-separated multi-host list, null\n// when no host key is present or the host is still an unresolved `${VAR}`.\nfunction parsePostgresConnection(raw: string): ParsedConnectionConfig | null {\n  const s = raw.trim()\n  if (/^postgres(?:ql)?:\\/\\//i.test(s)) return parseConnectionString(s)\n\n  const fields = new Map<string, string>()\n  for (const part of s.split(';')) {\n    const eq = part.indexOf('=')\n    if (eq < 0) continue\n    const key = part.slice(0, eq).trim().toLowerCase().replace(/\\s+/g, ' ')\n    const value = part.slice(eq + 1).trim()\n    if (value && !fields.has(key)) fields.set(key, value)\n  }\n  const hostRaw = fields.get('host') ?? fields.get('server') ?? fields.get('data source')\n  if (!hostRaw) return null\n  const host = hostRaw.split(',')[0]!.trim()\n  if (hostIsUnresolved(host)) return null\n  const portRaw = fields.get('port')\n  const port = portRaw && /^\\d+$/.test(portRaw) ? Number(portRaw) : undefined\n  const database = fields.get('database') ?? fields.get('db') ?? ''\n  return { host, port, database, engine: 'postgresql', engineVersion: 'unknown' }\n}\n\n// Host / port out of a StackExchange.Redis endpoint string\n// (`valkey-cart:6379,ssl=false,abortConnect=false`) or a `redis://` URL. The\n// endpoint is the first comma-separated token; the host is the part before the\n// last `:` (an option token like `ssl=false` has no bare host shape and is\n// rejected). Null when the leading token is not a host[:port].\nfunction parseRedisEndpoint(raw: string): ParsedConnectionConfig | null {\n  const s = raw.trim()\n  if (/^rediss?:\\/\\//i.test(s)) return parseConnectionString(s)\n\n  const first = s.split(',')[0]!.trim()\n  const m = first.match(/^([A-Za-z0-9_.-]+)(?::(\\d+))?$/)\n  if (!m) return null\n  const host = m[1]!\n  if (hostIsUnresolved(host) || host.includes('=')) return null\n  const port = m[2] ? Number(m[2]) : undefined\n  return { host, port, database: '', engine: 'redis', engineVersion: 'unknown' }\n}\n\n// Resolve an env var / IConfiguration key the way .NET layers configuration:\n// the value most often lives in a `.env` at the repo root, ABOVE the service\n// dir (the otel-demo keeps `DB_CONNECTION_STRING` / `VALKEY_ADDR` there), so this\n// walks up from the service dir checking each level's `.env*` (via the shared\n// dotenv reader) and stops at the repo root — a directory holding `.git`. Bounded\n// so a detached service dir can't walk the whole filesystem.\nasync function resolveEnvUpTree(startDir: string, name: string): Promise<string | null> {\n  let dir = path.resolve(startDir)\n  for (let depth = 0; depth < 12; depth++) {\n    const value = await resolveEnvVar(dir, name)\n    if (value !== null) return value\n    const atRepoRoot = await fs\n      .access(path.join(dir, '.git'))\n      .then(() => true)\n      .catch(() => false)\n    const parent = path.dirname(dir)\n    if (atRepoRoot || parent === dir) break\n    dir = parent\n  }\n  return null\n}\n\n// Replace `${VAR}` / `$VAR` references in an env value with their own resolved\n// values (one pass), so `Host=${POSTGRES_HOST}` recovers the real host when the\n// referenced var is declared in a reachable `.env`. An unresolved reference is\n// left verbatim; a host that still carries `${` is treated as unresolved by the\n// parsers above and falls back to the placeholder.\nasync function interpolateEnvRefs(value: string, dir: string): Promise<string> {\n  const refs = new Set<string>()\n  for (const m of value.matchAll(/\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}|\\$([A-Za-z_][A-Za-z0-9_]*)/g)) {\n    refs.add(m[1] ?? m[2]!)\n  }\n  let out = value\n  for (const name of refs) {\n    const resolved = await resolveEnvUpTree(dir, name)\n    if (resolved === null) continue\n    out = out\n      .split(`\\${${name}}`)\n      .join(resolved)\n      .replace(new RegExp(`\\\\$${name}\\\\b`, 'g'), resolved)\n  }\n  return out\n}\n\n// Every double-quoted string literal in the (comment-masked) source.\nfunction stringLiterals(masked: string): string[] {\n  const out: string[] = []\n  STRING_LITERAL_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = STRING_LITERAL_RE.exec(masked)) !== null) out.push(m[1]!)\n  return out\n}\n\n// Every env-var / config key referenced in the (comment-masked) source.\nfunction envKeys(masked: string): string[] {\n  const out: string[] = []\n  ENV_READ_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = ENV_READ_RE.exec(masked)) !== null) {\n    const key = m[1] ?? m[2]\n    if (key) out.push(key)\n  }\n  return out\n}\n\n// Resolve EVERY host a client declares in the service — a service can genuinely\n// name more than one peer of an engine, and each real declaration is extracted\n// rather than one silently winning. The otel-demo cart is the shape: it connects\n// to the config-driven `VALKEY_ADDR` (`valkey-cart`) AND constructs a second store\n// against a hardcoded `\"badhost:1234\"` fault-probe, so both are declared and both\n// mint — `valkey-cart` fuses with the OBSERVED peer, `badhost` stands as a\n// declared-but-unobserved connection (the honest divergence, not a node to drop).\n// Config/env-referenced hosts are listed first (the deployment's real target),\n// then matching literals. A host is only skipped when it doesn't parse to a plain\n// string; a caller that gets an empty array mints no node (no fabricated\n// placeholder). De-dup by `engine:host` is the caller's job (`push`).\nasync function resolveConfigs(\n  literals: string[],\n  keys: string[],\n  serviceDir: string,\n  looksLike: (s: string) => boolean,\n  parse: (s: string) => ParsedConnectionConfig | null,\n): Promise<ParsedConnectionConfig[]> {\n  const out: ParsedConnectionConfig[] = []\n  for (const key of keys) {\n    const raw = await resolveEnvUpTree(serviceDir, key)\n    if (raw === null) continue\n    const value = await interpolateEnvRefs(raw, serviceDir)\n    if (!looksLike(value)) continue\n    const parsed = parse(value)\n    // An env var / IConfiguration key is the deployment's real target — mark it\n    // `config` so the divergence ranker never mistakes it for a dead-code probe\n    // (ADR-213).\n    if (parsed) out.push({ ...parsed, hostSource: 'config' })\n  }\n  for (const lit of literals) {\n    if (!looksLike(lit)) continue\n    const parsed = parse(lit)\n    // A hardcoded string literal — mark it `literal`. The cart's `\"badhost:1234\"`\n    // fault-probe lands here; the ranker dampens its missing-observed when it has\n    // never been observed and a config-driven store of the same engine has\n    // (ADR-213).\n    if (parsed) out.push({ ...parsed, hostSource: 'literal' })\n  }\n  return out\n}\n\n// The connection string and the client call can live in different files — cart\n// reads `VALKEY_ADDR` in Program.cs but calls `ConnectionMultiplexer.Connect` in\n// cartstore/ValkeyCartStore.cs — so scanning is service-wide: literals and config\n// keys are pooled across every `.cs` file, and the file holding the client call is\n// remembered as the connection's origin (the CONNECTS_TO source, ADR-205). The\n// shape gates (`looksLikePostgres` / `looksLikeRedis`) keep the two engines'\n// pools disjoint even though they share one literal/key pool.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const files = (await walkSourceFiles(serviceDir).catch(() => [])).filter(\n    (f) => path.extname(f) === CS_EXT,\n  )\n  if (files.length === 0) return []\n\n  const sources: Array<{ file: string; content: string }> = []\n  for (const file of files) {\n    const content = await fs.readFile(file, 'utf8').catch(() => null)\n    if (content !== null) sources.push({ file, content })\n  }\n\n  // First locate the client calls; the file holding one is the connection origin.\n  let pgGateFile: string | null = null\n  let redisGateFile: string | null = null\n  for (const { file, content } of sources) {\n    if (pgGateFile === null && NPGSQL_GATE.test(content)) pgGateFile = file\n    if (redisGateFile === null && REDIS_GATE.test(content)) redisGateFile = file\n  }\n  if (!pgGateFile && !redisGateFile) return []\n\n  // Pool literals and config keys from EVERY `.cs` file, not only the ones holding\n  // the client call — the connection string / address is often read in a different\n  // file (cart reads `VALKEY_ADDR` in Program.cs, connects in the store). The shape\n  // gates keep the two engines' pools disjoint despite the shared pool.\n  const literals: string[] = []\n  const keys: string[] = []\n  for (const { content } of sources) {\n    const masked = maskCommentsInSource(content)\n    literals.push(...stringLiterals(masked))\n    keys.push(...envKeys(masked))\n  }\n\n  const out: DbConfig[] = []\n  const seenHosts = new Set<string>()\n  const push = (config: ParsedConnectionConfig, sourceFile: string): void => {\n    const dedupe = `${config.engine}:${config.host}`\n    if (seenHosts.has(dedupe)) return\n    seenHosts.add(dedupe)\n    out.push({ ...config, sourceFile })\n  }\n\n  // Every genuinely declared host mints a node; a host that can't be resolved to a\n  // real peer mints nothing. The key discipline (ADR-207): never fabricate a\n  // placeholder host — a made-up `database:<host>` shares the shape an OBSERVED span\n  // carries but never fuses, so an unresolvable connection is an honest gap, not a\n  // twin. A host that IS declared but simply doesn't fuse is still real and is kept\n  // (the cart's `badhost:1234` fault-probe stands as a declared-but-unobserved edge).\n  if (pgGateFile) {\n    for (const pg of await resolveConfigs(literals, keys, serviceDir, looksLikePostgres, parsePostgresConnection)) {\n      push(pg, pgGateFile)\n    }\n  }\n\n  if (redisGateFile) {\n    for (const redis of await resolveConfigs(literals, keys, serviceDir, looksLikeRedis, parseRedisEndpoint)) {\n      push(redis, redisGateFile)\n    }\n  }\n\n  return out\n}\n\nexport const csharpParser = { name: 'csharp', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parseAllDocuments } from 'yaml'\nimport { parseConnectionString, resolveEnvVar, type DbConfig } from './shared.js'\n\n// Spring Boot datasources — the connection axis of Java, the sibling of\n// csharp.ts here and of calls/jpa.ts (the table axis). A Spring service names\n// its store in `application.yml` / `application.properties`:\n//\n//   spring:\n//     datasource:\n//       url: jdbc:mysql://${ORDER_MYSQL_HOST:ts-order-mysql}:${ORDER_MYSQL_PORT:3306}/ts\n//\n// The keys read are `spring.datasource.url` and `spring.r2dbc.url` (a JDBC /\n// R2DBC URL, whose `jdbc:` / `r2dbc:` prefix is dropped before the usual\n// connection-string parse) and `spring.data.mongodb.uri`. A `${NAME:default}`\n// placeholder resolves from the service's `.env` when it sets NAME, else to its\n// default — the value the app runs with when the deployment sets nothing. A\n// placeholder with neither leaves the URL unresolved, and nothing is minted.\n//\n// Only the default profile is read: a document activated by a profile\n// (`spring.config.activate.on-profile`, or the older `spring.profiles`) says\n// where the app points under that profile, not by default.\n\nconst CONFIG_FILES = ['application.yml', 'application.yaml', 'application.properties']\nconst URL_KEYS = ['spring.datasource.url', 'spring.r2dbc.url', 'spring.data.mongodb.uri']\n\n// A key from a YAML document, nested (`spring: datasource: url:`) or written\n// flat (`spring.datasource.url:`), or any mix of the two.\nfunction yamlValue(doc: unknown, key: string): unknown {\n  if (!doc || typeof doc !== 'object') return undefined\n  const obj = doc as Record<string, unknown>\n  if (key in obj) return obj[key]\n  const parts = key.split('.')\n  for (let i = 1; i < parts.length; i++) {\n    const head = parts.slice(0, i).join('.')\n    if (head in obj) {\n      const v = yamlValue(obj[head], parts.slice(i).join('.'))\n      if (v !== undefined) return v\n    }\n  }\n  return undefined\n}\n\nfunction isProfileDocument(doc: unknown): boolean {\n  return (\n    yamlValue(doc, 'spring.config.activate.on-profile') !== undefined ||\n    yamlValue(doc, 'spring.profiles') !== undefined\n  )\n}\n\nfunction urlsFromYaml(text: string): string[] {\n  const out: string[] = []\n  for (const d of parseAllDocuments(text)) {\n    if (d.errors.length > 0) continue\n    const doc = d.toJS() as unknown\n    if (isProfileDocument(doc)) continue\n    for (const key of URL_KEYS) {\n      const v = yamlValue(doc, key)\n      if (typeof v === 'string' && v.trim()) out.push(v.trim())\n    }\n  }\n  return out\n}\n\nfunction urlsFromProperties(text: string): string[] {\n  const out: string[] = []\n  for (const raw of text.split('\\n')) {\n    const line = raw.trim()\n    if (!line || line.startsWith('#') || line.startsWith('!')) continue\n    const m = /^([^=:\\s]+)\\s*[=:]\\s*(.*)$/.exec(line)\n    if (m && URL_KEYS.includes(m[1]!) && m[2]!.trim()) out.push(m[2]!.trim())\n  }\n  return out\n}\n\n// `${NAME:default}` / `${NAME}` → the .env value, else the default; null when a\n// placeholder has neither.\nasync function resolvePlaceholders(serviceDir: string, value: string): Promise<string | null> {\n  let out = ''\n  let last = 0\n  const re = /\\$\\{([^}:]+)(?::([^}]*))?\\}/g\n  let m: RegExpExecArray | null\n  while ((m = re.exec(value)) !== null) {\n    out += value.slice(last, m.index)\n    const fromEnv = await resolveEnvVar(serviceDir, m[1]!)\n    const resolved = fromEnv ?? m[2]\n    if (resolved === undefined) return null\n    out += resolved\n    last = m.index + m[0].length\n  }\n  return out + value.slice(last)\n}\n\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  const out: DbConfig[] = []\n  for (const dir of [path.join(serviceDir, 'src', 'main', 'resources'), serviceDir]) {\n    for (const name of CONFIG_FILES) {\n      const file = path.join(dir, name)\n      const text = await fs.readFile(file, 'utf8').catch(() => null)\n      if (text === null) continue\n      // A malformed config file yields nothing rather than failing the pass (ADR-055).\n      try {\n        const urls = name.endsWith('.properties') ? urlsFromProperties(text) : urlsFromYaml(text)\n        for (const raw of urls) {\n          const resolved = await resolvePlaceholders(serviceDir, raw)\n          if (!resolved) continue\n          const parsed = parseConnectionString(resolved.replace(/^(?:jdbc|r2dbc):/i, ''))\n          if (!parsed || !parsed.host) continue\n          out.push({ ...parsed, sourceFile: file, hostSource: 'config' })\n        }\n      } catch {\n        continue\n      }\n    }\n  }\n  return out\n}\n\nexport const springDatasourceParser = { name: 'spring-datasource', parse }\n","import path from 'node:path'\nimport { exists, readYaml } from '../shared.js'\nimport { engineFromImage, type DbConfig } from './shared.js'\n\ninterface ComposeService {\n  image?: string\n  ports?: (string | number)[]\n  environment?: Record<string, string> | string[]\n}\n\ninterface ComposeFile {\n  services?: Record<string, ComposeService>\n}\n\nfunction portFromService(svc: ComposeService): number | undefined {\n  for (const raw of svc.ports ?? []) {\n    const str = String(raw)\n    // \"5432:5432\", \"5432\", or \"host:5432\" → take the trailing port.\n    const last = str.split(':').pop()\n    const n = Number(last)\n    if (Number.isFinite(n) && n > 0) return n\n  }\n  return undefined\n}\n\nfunction databaseFromEnv(svc: ComposeService): string {\n  const env = svc.environment\n  const get = (key: string): string | undefined => {\n    if (!env) return undefined\n    if (Array.isArray(env)) {\n      for (const line of env) {\n        const [k, v] = line.split('=')\n        if (k === key) return v\n      }\n      return undefined\n    }\n    return env[key]\n  }\n  return get('POSTGRES_DB') ?? get('MYSQL_DATABASE') ?? get('MONGO_INITDB_DATABASE') ?? ''\n}\n\n// Service-local docker-compose.yml — every service whose image we recognise\n// becomes a candidate DB. The compose service name doubles as the host since\n// that's how peer services on the same compose network reach it.\nexport async function parse(serviceDir: string): Promise<DbConfig[]> {\n  for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n    const abs = path.join(serviceDir, name)\n    if (!(await exists(abs))) continue\n    const raw = await readYaml<ComposeFile>(abs)\n    if (!raw?.services) return []\n\n    const out: DbConfig[] = []\n    for (const [serviceName, svc] of Object.entries(raw.services)) {\n      if (!svc.image) continue\n      const meta = engineFromImage(svc.image)\n      if (!meta) continue\n      out.push({\n        host: serviceName,\n        port: portFromService(svc),\n        database: databaseFromEnv(svc),\n        engine: meta.engine,\n        engineVersion: meta.engineVersion,\n        sourceFile: abs,\n      })\n    }\n    return out\n  }\n  return []\n}\n\nexport const dockerComposeParser = { name: 'docker-compose', parse }\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ConfigNode, GraphEdge } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  configId,\n  confidenceForExtracted,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n  IGNORED_DIRS,\n  isConfigFile,\n  isPythonVenvDir,\n  makeEdgeId,\n  type DiscoveredService,\n} from './shared.js'\nimport { ensureFileNode, toPosix } from './calls/shared.js'\n\n// Walk a service directory and collect every config file path\n// (yaml/yml + .env-shaped). We deliberately stop at file paths here so nothing\n// in this module reads file contents — .env files routinely carry secrets\n// (ADR-016).\nexport async function walkConfigFiles(dir: string, excludeDirs: string[] = []): Promise<string[]> {\n  // ADR-200 — skip nested discovered services' subtrees so an ancestor doesn't\n  // re-mint their ConfigNodes under itself.\n  const excluded = new Set(excludeDirs.map((d) => path.resolve(d)))\n  const out: string[] = []\n  async function walk(current: string): Promise<void> {\n    const entries = await fs.readdir(current, { withFileTypes: true })\n    for (const entry of entries) {\n      const full = path.join(current, entry.name)\n      if (entry.isDirectory()) {\n        if (IGNORED_DIRS.has(entry.name)) continue\n        if (excluded.has(path.resolve(full))) continue\n        if (await isPythonVenvDir(full)) continue\n        await walk(full)\n      } else if (entry.isFile() && isConfigFile(entry.name).match && !excluded.has(path.resolve(full))) {\n        out.push(full)\n      }\n    }\n  }\n  await walk(dir)\n  return out\n}\n\n// Phase 3 — turn each config file into a ConfigNode with a CONFIGURED_BY edge\n// from its owning service.\nexport async function addConfigNodes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  for (const service of services) {\n    const configFiles = await walkConfigFiles(service.dir, service.excludeDirs)\n    for (const file of configFiles) {\n      const relPath = path.relative(scanPath, file)\n      const node: ConfigNode = {\n        id: configId(relPath),\n        type: NodeType.ConfigNode,\n        name: path.basename(file),\n        path: relPath,\n        fileType: isConfigFile(path.basename(file)).fileType,\n      }\n      if (!graph.hasNode(node.id)) {\n        graph.addNode(node.id, node)\n        nodesAdded++\n      }\n      // file-awareness §1 — the config file IS the relationship origin.\n      // ensureFileNode creates the FileNode + CONTAINS edge so CONFIGURED_BY\n      // lands file-grained rather than service-level.\n      const relToService = toPosix(path.relative(service.dir, file))\n      const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        relToService,\n      )\n      nodesAdded += fn\n      edgesAdded += fe\n      const edge: GraphEdge = {\n        id: makeEdgeId(fileNodeId, node.id, EdgeType.CONFIGURED_BY),\n        source: fileNodeId,\n        target: node.id,\n        type: EdgeType.CONFIGURED_BY,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: { file: relPath.split(path.sep).join('/') },\n      }\n      if (!graph.hasEdge(edge.id)) {\n        graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n        edgesAdded++\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { GraphEdge, InfraNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  infraId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { flagStoreProviders } from '../compat.js'\nimport { FLAG_STORE_KIND, foldDeclaredFlags, parseFlagDocument, type DeclaredFlag } from '../flags.js'\nimport type { FlagDefinition } from '@neat.is/types'\nimport { isTestPath, makeEdgeId, maskCommentsInSource, type DiscoveredService } from './shared.js'\nimport { ensureFileNode, isMinifiedSource, toPosix, walkSourceFiles } from './calls/shared.js'\nimport { configMapFlagsFromYaml } from './flags-configmap.js'\n\n// Flag grain, EXTRACTED side (ADR-242). Two reads:\n//\n// 1. The committed definitions. A flag file is any `.json` under the scan root\n//    whose top level holds a `flags` object of flag definitions and whose\n//    `$schema` names a flag-store provider listed in compat.json. Each provider\n//    becomes one `flag-store` InfraNode; each flag a grain entry on it carrying\n//    its canonical definition. Only the `flags` object is read.\n// 2. The code that reads each key. A source file holding a string literal exactly\n//    equal to a declared key reads that flag. The match is on the literal, not on\n//    any SDK call shape, so it holds in every language the walk covers and through\n//    a wrapper or a constant: the literal is still in the service's own tree. The\n//    file gets an EXTRACTED CONNECTS_TO to the store (the dependency, evidence at\n//    the literal's line), and the flag records the file as a reader.\n//\n// A key built at runtime holds no literal and gets no reader: nothing is guessed.\n//\n// The committed definitions have a second source (#1454): a Kubernetes ConfigMap\n// manifest, plain or Helm template, whose data holds a flag document. See\n// flags-configmap.ts.\n\nconst JSON_EXTENSIONS: ReadonlySet<string> = new Set(['.json'])\nconst YAML_EXTENSIONS: ReadonlySet<string> = new Set(['.yaml', '.yml'])\n// A flag file is small. Anything past this is data, not a flag file.\nconst MAX_FLAG_FILE_BYTES = 1_000_000\n// One string literal on one line, in any of the three quote styles the walked\n// languages use. Comments are masked first, so a key named in a comment is not a\n// reader.\nconst STRING_LITERAL_RE = /([\"'`])((?:\\\\.|(?!\\1)[^\\\\\\n])*)\\1/g\n\nfunction providerFor(doc: unknown): string | null {\n  if (typeof doc !== 'object' || doc === null) return null\n  const schema = (doc as Record<string, unknown>)['$schema']\n  if (typeof schema !== 'string') return null\n  for (const p of flagStoreProviders()) {\n    if (schema.includes(p.schemaPattern)) return p.provider\n  }\n  return null\n}\n\ninterface FlagFile {\n  provider: string\n  relPath: string\n  flags: Map<string, FlagDefinition>\n}\n\nasync function findFlagFiles(scanPath: string): Promise<FlagFile[]> {\n  const out: FlagFile[] = []\n  const files = (await walkSourceFiles(scanPath, [], JSON_EXTENSIONS)).sort()\n  for (const file of files) {\n    const relPath = toPosix(path.relative(scanPath, file))\n    if (isTestPath(relPath)) continue\n    let text: string\n    try {\n      const stat = await fs.stat(file)\n      if (stat.size > MAX_FLAG_FILE_BYTES) continue\n      text = await fs.readFile(file, 'utf8')\n    } catch {\n      continue\n    }\n    // Cheap gate before a parse: every flag file names both words.\n    if (!text.includes('\"flags\"') || !text.includes('\"variants\"')) continue\n    let doc: unknown\n    try {\n      doc = JSON.parse(text)\n    } catch {\n      continue\n    }\n    const provider = providerFor(doc)\n    if (!provider) continue\n    const flags = parseFlagDocument(doc)\n    if (flags) out.push({ provider, relPath, flags })\n  }\n  return out.concat(await findConfigMapFlagFiles(scanPath))\n}\n\n// Flag documents embedded in ConfigMap manifests (#1454).\nasync function findConfigMapFlagFiles(scanPath: string): Promise<FlagFile[]> {\n  const out: FlagFile[] = []\n  const providers = flagStoreProviders().map((p) => p.provider)\n  const files = (await walkSourceFiles(scanPath, [], YAML_EXTENSIONS)).sort()\n  for (const file of files) {\n    const relPath = toPosix(path.relative(scanPath, file))\n    if (isTestPath(relPath)) continue\n    let text: string\n    try {\n      const stat = await fs.stat(file)\n      if (stat.size > MAX_FLAG_FILE_BYTES) continue\n      text = await fs.readFile(file, 'utf8')\n    } catch {\n      continue\n    }\n    // Cheap gate before a parse: a ConfigMap holding flag definitions.\n    if (!text.includes('ConfigMap') || !text.includes('flags') || !text.includes('variants')) continue\n    for (const found of configMapFlagsFromYaml(text, providers)) {\n      out.push({ provider: found.provider, relPath, flags: found.flags })\n    }\n  }\n  return out\n}\n\ninterface Reader {\n  file: string\n  service: string\n  line: number\n}\n\n// Every (key → first literal line) in one source file, for the keys asked about.\nfunction literalKeyLines(src: string, keys: ReadonlySet<string>): Map<string, number> {\n  const masked = maskCommentsInSource(src)\n  const out = new Map<string, number>()\n  STRING_LITERAL_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = STRING_LITERAL_RE.exec(masked)) !== null) {\n    const value = m[2]!\n    if (!keys.has(value) || out.has(value)) continue\n    let line = 1\n    for (let i = 0; i < m.index; i++) if (masked.charCodeAt(i) === 10) line++\n    out.set(value, line)\n  }\n  return out\n}\n\nexport async function addFlagStores(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  const flagFiles = await findFlagFiles(scanPath)\n  if (flagFiles.length === 0) return { nodesAdded, edgesAdded }\n\n  // provider → key → declaration. The first file (sorted path) to declare a key\n  // for a provider wins, so the result is stable across runs.\n  const byProvider = new Map<string, Map<string, { definition: FlagDefinition; declaredIn: string }>>()\n  for (const ff of flagFiles) {\n    const keys = byProvider.get(ff.provider) ?? new Map()\n    for (const [key, definition] of ff.flags) {\n      if (!keys.has(key)) keys.set(key, { definition, declaredIn: ff.relPath })\n    }\n    byProvider.set(ff.provider, keys)\n  }\n\n  for (const [provider, declarations] of byProvider) {\n    const storeId = infraId(FLAG_STORE_KIND, provider)\n    if (!graph.hasNode(storeId)) {\n      const node: InfraNode = {\n        id: storeId,\n        type: NodeType.InfraNode,\n        name: provider,\n        provider,\n        kind: FLAG_STORE_KIND,\n      }\n      graph.addNode(storeId, node)\n      nodesAdded++\n    }\n\n    const keys = new Set(declarations.keys())\n    const readers = new Map<string, Reader[]>()\n    for (const service of services) {\n      const files = await walkSourceFiles(service.dir, service.excludeDirs)\n      for (const file of files) {\n        const relToService = toPosix(path.relative(service.dir, file))\n        if (isTestPath(relToService)) continue\n        let src: string\n        try {\n          src = await fs.readFile(file, 'utf8')\n        } catch {\n          continue\n        }\n        if (isMinifiedSource(file, src).minified) continue\n        const hits = literalKeyLines(src, keys)\n        if (hits.size === 0) continue\n        const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n          graph,\n          service.pkg.name,\n          service.node.id,\n          relToService,\n        )\n        nodesAdded += fn\n        edgesAdded += fe\n        let firstLine = Number.POSITIVE_INFINITY\n        for (const [key, line] of hits) {\n          const list = readers.get(key) ?? []\n          list.push({ file: fileNodeId, service: service.node.id, line })\n          readers.set(key, list)\n          firstLine = Math.min(firstLine, line)\n        }\n        const edge: GraphEdge = {\n          id: makeEdgeId(fileNodeId, storeId, EdgeType.CONNECTS_TO),\n          source: fileNodeId,\n          target: storeId,\n          type: EdgeType.CONNECTS_TO,\n          provenance: Provenance.EXTRACTED,\n          confidence: confidenceForExtracted('structural'),\n          evidence: { file: toPosix(path.relative(scanPath, file)), line: firstLine },\n        }\n        if (!graph.hasEdge(edge.id)) {\n          graph.addEdgeWithKey(edge.id, edge.source, edge.target, edge)\n          edgesAdded++\n        }\n      }\n    }\n\n    const declared: DeclaredFlag[] = [...declarations].map(([key, d]) => ({\n      key,\n      definition: d.definition,\n      declaredIn: d.declaredIn,\n      readers: readers.get(key) ?? [],\n    }))\n    const node = graph.getNodeAttributes(storeId) as InfraNode\n    graph.mergeNodeAttributes(storeId, { flags: foldDeclaredFlags(node.flags, declared) })\n  }\n  return { nodesAdded, edgesAdded }\n}\n","import { parseAllDocuments, parse as parseYaml } from 'yaml'\nimport type { FlagDefinition } from '@neat.is/types'\nimport { parseFlagDocument } from '../flags.js'\n\n// Flag grain, EXTRACTED side, second source (ADR-242 amendment, #1454): flag\n// definitions embedded in a Kubernetes ConfigMap.\n//\n//   kind: ConfigMap\n//   metadata:\n//     name: flagd-config\n//   data:\n//     flags.yaml: |\n//       flags:\n//         tt-feat-01:\n//           state: ENABLED\n//           variants: { \"on\": true, \"off\": false }\n//           defaultVariant: \"off\"\n//\n// A data value is read as YAML (which also reads JSON) and is a flag document\n// when it holds a `flags` map of definitions, the same shape a flag file holds.\n// A ConfigMap carries no `$schema`, so the provider is the one whose name (from\n// compat.json's flag-store list) appears in the ConfigMap's name or the data key.\n//\n// Helm templates are read as text and never rendered. A `{{ … }}` expression is\n// swapped for a marker before the parse, and a line holding only a template\n// action (`{{- if … }}`) is dropped. A flag whose definition still holds the\n// marker came from a template value and stays unclaimed; the rest of the file\n// is read. A file that won't parse yields nothing.\n\nconst MARKER = '__neat_helm_expr__'\n\nexport interface ConfigMapFlags {\n  provider: string\n  flags: Map<string, FlagDefinition>\n}\n\nfunction untemplate(text: string): string {\n  return text\n    .split('\\n')\n    .filter((line) => !/^\\s*\\{\\{-?[^}]*-?\\}\\}\\s*$/.test(line))\n    .join('\\n')\n    .replace(/\\{\\{-?[^}]*?-?\\}\\}/g, MARKER)\n}\n\nfunction isRecord(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}\n\n/** Flag documents in one YAML manifest's ConfigMaps, by provider. */\nexport function configMapFlagsFromYaml(text: string, providers: readonly string[]): ConfigMapFlags[] {\n  const out: ConfigMapFlags[] = []\n  let docs\n  try {\n    docs = parseAllDocuments(untemplate(text))\n  } catch {\n    return out\n  }\n  for (const d of docs) {\n    if (d.errors.length > 0) continue\n    const doc = d.toJS() as unknown\n    if (!isRecord(doc) || doc['kind'] !== 'ConfigMap' || !isRecord(doc['data'])) continue\n    const name = isRecord(doc['metadata']) && typeof doc['metadata']['name'] === 'string' ? doc['metadata']['name'] : ''\n    for (const [key, value] of Object.entries(doc['data'])) {\n      if (typeof value !== 'string' || !value.includes('flags')) continue\n      const provider = providers.find((p) => name.includes(p) || key.includes(p))\n      if (!provider) continue\n      let inner: unknown\n      try {\n        inner = parseYaml(value)\n      } catch {\n        continue\n      }\n      // A flag whose raw definition came from a template value is left out.\n      if (isRecord(inner) && isRecord(inner['flags'])) {\n        const flagsObj = inner['flags']\n        for (const k of Object.keys(flagsObj)) {\n          if (k.includes(MARKER) || JSON.stringify(flagsObj[k]).includes(MARKER)) delete flagsObj[k]\n        }\n      }\n      const flags = parseFlagDocument(inner)\n      if (flags) out.push({ provider, flags })\n    }\n  }\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Java from 'tree-sitter-java'\nimport type { GraphEdge, RouteNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  routeId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, snippet, toPosix } from './calls/shared.js'\nimport { canonicalizeTemplate, type ExtractedRoute } from './routes.js'\n\n// Spring MVC route extraction. A Java service's HTTP surface is declared in\n// annotations: a controller class may carry a `@RequestMapping(\"/prefix\")`, and\n// each handler method a `@GetMapping` / `@PostMapping` / `@PutMapping` /\n// `@DeleteMapping` / `@PatchMapping`, or a `@RequestMapping(method = …)`. Each\n// (method, path) pair becomes a RouteNode owned by its service through\n// `service ──CONTAINS──▶ route`, the same shape addRoutes mints for every other\n// router (ADR-119), so a Spring server span's `http.route` fuses onto it.\n//\n// The gate is the source, not the manifest. A Spring service usually inherits\n// `spring-boot-starter-web` from a parent POM (train-ticket's 41 services all\n// do), and java.ts reads each module's own POM, so the dependency isn't there to\n// gate on. A file is read when it imports `org.springframework.web.bind.annotation`\n// (or names an annotation fully qualified), the per-file self-gate Sinatra and\n// Slim use (ADR-206).\n//\n// Only classes Spring treats as handlers are read: a `@RestController` /\n// `@Controller`, or a class carrying `@RequestMapping` itself. A `@FeignClient`\n// interface declares the same annotations for the *client* side and is never a\n// route. A path that isn't a literal, or a concatenation of literals and same-file\n// `static final String` constants, stays unclaimed rather than guessed.\n\nconst PARSE_CHUNK = 16384\nconst SPRING_WEB = 'org.springframework.web.bind.annotation'\n\nconst VERB_ANNOTATIONS: Record<string, string> = {\n  GetMapping: 'GET',\n  PostMapping: 'POST',\n  PutMapping: 'PUT',\n  DeleteMapping: 'DELETE',\n  PatchMapping: 'PATCH',\n}\nconst HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS', 'TRACE'])\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nexport function makeJavaParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Java)\n  return p\n}\n\n// The annotation's simple name and whether it was written fully qualified under\n// Spring's web package.\nfunction annotationName(node: Parser.SyntaxNode): { name: string; qualified: boolean } | null {\n  const n = node.childForFieldName('name')\n  if (!n) return null\n  const text = n.text\n  const dot = text.lastIndexOf('.')\n  return dot === -1\n    ? { name: text, qualified: false }\n    : { name: text.slice(dot + 1), qualified: text.slice(0, dot) === SPRING_WEB }\n}\n\nfunction annotationsOf(decl: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const mods = decl.namedChildren.find((c) => c.type === 'modifiers')\n  if (!mods) return []\n  return mods.namedChildren.filter((c) => c.type === 'annotation' || c.type === 'marker_annotation')\n}\n\nfunction javaStringLiteral(node: Parser.SyntaxNode): string | null {\n  if (node.type !== 'string_literal') return null\n  // A plain literal's fragments; an escape sequence makes it not worth guessing.\n  let out = ''\n  for (const c of node.namedChildren) {\n    if (c.type === 'string_fragment') out += c.text\n    else return null\n  }\n  return out\n}\n\n// `static final String NAME = \"literal\"` fields anywhere in the file.\nfunction stringConstants(root: Parser.SyntaxNode): Map<string, string> {\n  const out = new Map<string, string>()\n  const visit = (n: Parser.SyntaxNode): void => {\n    if (n.type === 'field_declaration') {\n      const mods = n.namedChildren.find((c) => c.type === 'modifiers')?.text ?? ''\n      if (/\\bstatic\\b/.test(mods) && /\\bfinal\\b/.test(mods)) {\n        for (const d of n.namedChildren) {\n          if (d.type !== 'variable_declarator') continue\n          const name = d.childForFieldName('name')?.text\n          const value = d.childForFieldName('value')\n          const lit = value ? constantString(value, out) : null\n          if (name && lit !== null) out.set(name, lit)\n        }\n      }\n    }\n    for (const c of n.namedChildren) visit(c)\n  }\n  visit(root)\n  return out\n}\n\n// A string built only from literals and known constants; null otherwise.\nfunction constantString(node: Parser.SyntaxNode, consts: Map<string, string>): string | null {\n  if (node.type === 'string_literal') return javaStringLiteral(node)\n  if (node.type === 'identifier') return consts.get(node.text) ?? null\n  if (node.type === 'parenthesized_expression' && node.namedChildren[0]) {\n    return constantString(node.namedChildren[0], consts)\n  }\n  if (node.type === 'binary_expression' && node.childForFieldName('operator')?.text === '+') {\n    const l = node.childForFieldName('left')\n    const r = node.childForFieldName('right')\n    const ls = l ? constantString(l, consts) : null\n    const rs = r ? constantString(r, consts) : null\n    return ls !== null && rs !== null ? ls + rs : null\n  }\n  return null\n}\n\n// The value nodes for `key` (or the lone positional value, which Spring binds to\n// `value`), unwrapping an `{a, b}` array.\nfunction annotationValues(ann: Parser.SyntaxNode, keys: string[]): Parser.SyntaxNode[] | null {\n  const args = ann.childForFieldName('arguments')\n  if (!args) return null\n  let value: Parser.SyntaxNode | null = null\n  for (const c of args.namedChildren) {\n    if (c.type === 'element_value_pair') {\n      if (keys.includes(c.childForFieldName('key')?.text ?? '')) value = c.childForFieldName('value')\n    } else if (keys.includes('value')) {\n      value = c\n    }\n  }\n  if (!value) return null\n  return value.type === 'element_value_array_initializer' ? value.namedChildren : [value]\n}\n\n// The paths an annotation declares: [''] when it names none (the handler sits at\n// the prefix), null when one isn't a resolvable constant (skip, don't guess).\nfunction annotationPaths(ann: Parser.SyntaxNode, consts: Map<string, string>): string[] | null {\n  const values = annotationValues(ann, ['value', 'path'])\n  if (!values || values.length === 0) return ['']\n  const out: string[] = []\n  for (const v of values) {\n    const s = constantString(v, consts)\n    if (s === null) return null\n    out.push(s)\n  }\n  return out\n}\n\n// `method = RequestMethod.GET` / `{GET, POST}`; ['ALL'] when none is named.\nfunction requestMappingMethods(ann: Parser.SyntaxNode): string[] | null {\n  const values = annotationValues(ann, ['method'])\n  if (!values || values.length === 0) return ['ALL']\n  const out: string[] = []\n  for (const v of values) {\n    const name = (v.type === 'field_access' ? v.childForFieldName('field')?.text : v.text) ?? ''\n    if (!HTTP_METHODS.has(name)) return null\n    out.push(name)\n  }\n  return out\n}\n\nfunction joinPath(prefix: string, leaf: string): string {\n  if (!prefix) return canonicalizeTemplate(leaf || '/')\n  if (!leaf) return canonicalizeTemplate(prefix)\n  return canonicalizeTemplate(prefix.replace(/\\/+$/, '') + '/' + leaf.replace(/^\\/+/, ''))\n}\n\nfunction importsSpringWeb(root: Parser.SyntaxNode): boolean {\n  return root.namedChildren.some(\n    (c) => c.type === 'import_declaration' && c.text.includes(SPRING_WEB),\n  )\n}\n\n/** Spring MVC routes declared in one Java source file. */\nexport function springRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const root = parseSource(parser, source).rootNode\n  const imported = importsSpringWeb(root)\n  const consts = stringConstants(root)\n  const out: ExtractedRoute[] = []\n  const isSpring = (a: { qualified: boolean }): boolean => imported || a.qualified\n\n  const visitClass = (cls: Parser.SyntaxNode): void => {\n    const anns = annotationsOf(cls)\n    let isHandler = false\n    let prefixes: string[] | null = ['']\n    for (const a of anns) {\n      const n = annotationName(a)\n      if (!n) continue\n      if (n.name === 'RestController' || n.name === 'Controller') isHandler = true\n      if (n.name === 'RequestMapping' && isSpring(n)) {\n        isHandler = true\n        prefixes = annotationPaths(a, consts)\n      }\n    }\n    const body = cls.childForFieldName('body')\n    if (isHandler && prefixes && body) {\n      for (const m of body.namedChildren) {\n        if (m.type !== 'method_declaration') continue\n        for (const a of annotationsOf(m)) {\n          const n = annotationName(a)\n          if (!n || !isSpring(n)) continue\n          const verb = VERB_ANNOTATIONS[n.name]\n          const methods = verb ? [verb] : n.name === 'RequestMapping' ? requestMappingMethods(a) : null\n          if (!methods) continue\n          const leaves = annotationPaths(a, consts)\n          if (!leaves) continue\n          for (const prefix of prefixes) {\n            for (const leaf of leaves) {\n              for (const method of methods) {\n                out.push({\n                  method,\n                  pathTemplate: joinPath(prefix, leaf),\n                  line: a.startPosition.row + 1,\n                  framework: 'spring',\n                })\n              }\n            }\n          }\n        }\n      }\n    }\n    // Nested classes declare their own mappings, with their own prefix.\n    if (body) for (const c of body.namedChildren) if (c.type === 'class_declaration') visitClass(c)\n  }\n\n  for (const c of root.namedChildren) if (c.type === 'class_declaration') visitClass(c)\n  return out\n}\n\n/** Mint Spring MVC RouteNodes for every Java service. */\nexport async function addJavaRoutes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const parser = makeJavaParser()\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    if (service.node.language !== 'java') continue\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    for (const file of files) {\n      if (path.extname(file.path) !== '.java' || isTestPath(file.path)) continue\n      // Cheap pre-check before parsing: a file with no Spring web reference\n      // can't declare a route.\n      if (!file.content.includes(SPRING_WEB)) continue\n      let routes: ExtractedRoute[]\n      try {\n        routes = springRoutesFromSource(file.content, parser)\n      } catch (err) {\n        recordExtractionError('route extraction', file.path, err)\n        continue\n      }\n      const relFile = toPosix(path.relative(service.dir, file.path))\n      for (const route of routes) {\n        const rid = routeId(service.pkg.name, route.method, route.pathTemplate)\n        if (!graph.hasNode(rid)) {\n          const node: RouteNode = {\n            id: rid,\n            type: NodeType.RouteNode,\n            name: `${route.method} ${route.pathTemplate}`,\n            service: service.pkg.name,\n            method: route.method,\n            pathTemplate: route.pathTemplate,\n            path: relFile,\n            line: route.line,\n            framework: route.framework,\n            discoveredVia: 'static',\n          }\n          graph.addNode(rid, node)\n          nodesAdded++\n        }\n        const containsId = extractedEdgeId(service.node.id, rid, EdgeType.CONTAINS)\n        if (!graph.hasEdge(containsId)) {\n          const edge: GraphEdge = {\n            id: containsId,\n            source: service.node.id,\n            target: rid,\n            type: EdgeType.CONTAINS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: { file: relFile, line: route.line, snippet: snippet(file.content, route.line) },\n          }\n          graph.addEdgeWithKey(containsId, service.node.id, rid, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Python from 'tree-sitter-python'\nimport type { GraphEdge, RouteNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  routeId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, snippet, toPosix } from './calls/shared.js'\nimport { canonicalizeTemplate, type ExtractedRoute } from './routes.js'\n\n// Tornado route extraction. A Tornado app declares its routes as a literal\n// handler table passed to `Application`:\n//\n//   tornado.web.Application([\n//       (r\"/getVoucher\", GetVoucherHandler),\n//       url(r\"/orders/(?P<id>[0-9]+)\", OrderHandler, name=\"order\"),\n//   ])\n//\n// Each entry's path pattern becomes a RouteNode, with one route per HTTP verb\n// method (`get`, `post`, …) the handler class defines in the same file; a\n// handler defined elsewhere gives one `ALL` route. The table may be inline,\n// passed as `handlers=[…]`, or a same-file list variable.\n//\n// A pattern is a regex. Each capture group becomes a param segment (`:id` for a\n// named group, `:param` otherwise), a leading `^` and trailing `$` or `/?` are\n// dropped, and a pattern that still carries regex syntax after that is left\n// unclaimed rather than guessed. Gated on the service's `tornado` dependency.\n\nconst PARSE_CHUNK = 16384\nconst VERBS = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options']\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of node.namedChildren) walk(c, visit)\n}\n\n// A plain (raw or not) string literal's text; null for an f-string or a\n// concatenation.\nfunction pyString(node: Parser.SyntaxNode | undefined): string | null {\n  if (!node || node.type !== 'string') return null\n  let out = ''\n  for (const c of node.namedChildren) {\n    if (c.type === 'string_content') out += c.text\n    else if (c.type === 'interpolation') return null\n  }\n  return out\n}\n\n/** A Tornado URL regex as a path template; null when it isn't one. */\nexport function tornadoPathTemplate(pattern: string): string | null {\n  let p = pattern.replace(/^\\^/, '').replace(/\\$$/, '').replace(/\\/\\?$/, '')\n  p = p.replace(/\\(\\?P<([A-Za-z_][A-Za-z0-9_]*)>[^()]*\\)/g, ':$1')\n  p = p.replace(/\\((?!\\?)[^()]*\\)/g, ':param')\n  if (/[\\\\()[\\]{}*+?|^$]/.test(p)) return null\n  return canonicalizeTemplate(p || '/')\n}\n\n// The verb methods each same-file class defines.\nfunction handlerVerbs(root: Parser.SyntaxNode): Map<string, string[]> {\n  const out = new Map<string, string[]>()\n  for (const c of root.namedChildren) {\n    const cls = c.type === 'decorated_definition' ? c.childForFieldName('definition') : c\n    if (cls?.type !== 'class_definition') continue\n    const name = cls.childForFieldName('name')?.text\n    const body = cls.childForFieldName('body')\n    if (!name || !body) continue\n    const verbs: string[] = []\n    for (const m of body.namedChildren) {\n      const fn = m.type === 'decorated_definition' ? m.childForFieldName('definition') : m\n      const fname = fn?.type === 'function_definition' ? fn.childForFieldName('name')?.text : undefined\n      if (fname && VERBS.includes(fname)) verbs.push(fname.toUpperCase())\n    }\n    out.set(name, verbs)\n  }\n  return out\n}\n\n// Same-file `name = [...]` list assignments, for a handler table passed by name.\nfunction listVariables(root: Parser.SyntaxNode): Map<string, Parser.SyntaxNode | null> {\n  const out = new Map<string, Parser.SyntaxNode | null>()\n  walk(root, (n) => {\n    if (n.type !== 'assignment') return\n    const left = n.childForFieldName('left')\n    const right = n.childForFieldName('right')\n    if (left?.type !== 'identifier') return\n    out.set(left.text, out.has(left.text) ? null : right?.type === 'list' ? right : null)\n  })\n  return out\n}\n\nfunction isApplicationCall(call: Parser.SyntaxNode): boolean {\n  const fn = call.childForFieldName('function')\n  const name = fn?.type === 'attribute' ? fn.childForFieldName('attribute')?.text : fn?.text\n  return name === 'Application'\n}\n\n/** Tornado routes declared in one Python source file. */\nexport function tornadoRoutesFromSource(source: string, parser: Parser): ExtractedRoute[] {\n  const root = parseSource(parser, source).rootNode\n  const verbs = handlerVerbs(root)\n  const lists = listVariables(root)\n  const out: ExtractedRoute[] = []\n\n  walk(root, (call) => {\n    if (call.type !== 'call' || !isApplicationCall(call)) return\n    const args = call.childForFieldName('arguments')?.namedChildren ?? []\n    let table: Parser.SyntaxNode | null | undefined = args.find((a) => a.type !== 'keyword_argument')\n    for (const a of args) {\n      if (a.type === 'keyword_argument' && a.childForFieldName('name')?.text === 'handlers') {\n        table = a.childForFieldName('value')\n      }\n    }\n    if (table?.type === 'identifier') table = lists.get(table.text) ?? null\n    if (!table || table.type !== 'list') return\n\n    for (const entry of table.namedChildren) {\n      // `(pattern, Handler, …)` or `url(pattern, Handler, …)` / `URLSpec(…)`.\n      let parts: Parser.SyntaxNode[] = []\n      if (entry.type === 'tuple') parts = entry.namedChildren\n      else if (entry.type === 'call') {\n        const fn = entry.childForFieldName('function')\n        const fname = fn?.type === 'attribute' ? fn.childForFieldName('attribute')?.text : fn?.text\n        if (fname !== 'url' && fname !== 'URLSpec') continue\n        parts = (entry.childForFieldName('arguments')?.namedChildren ?? []).filter((a) => a.type !== 'keyword_argument')\n      } else continue\n      const pattern = pyString(parts[0])\n      const handler = parts[1]\n      if (pattern === null || !handler) continue\n      const pathTemplate = tornadoPathTemplate(pattern)\n      if (!pathTemplate) continue\n      const handlerName = handler.type === 'attribute' ? handler.childForFieldName('attribute')?.text : handler.text\n      const methods = (handlerName && verbs.get(handlerName)?.length ? verbs.get(handlerName)! : ['ALL'])\n      for (const method of methods) {\n        out.push({ method, pathTemplate, line: entry.startPosition.row + 1, framework: 'tornado' })\n      }\n    }\n  })\n  return out\n}\n\n/** Mint Tornado RouteNodes for every service that depends on tornado. */\nexport async function addTornadoRoutes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let parser: Parser | null = null\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const deps = { ...(service.pkg.dependencies ?? {}), ...(service.pkg.devDependencies ?? {}) }\n    if (deps['tornado'] === undefined) continue\n    parser ??= (() => {\n      const p = new Parser()\n      p.setLanguage(Python)\n      return p\n    })()\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    for (const file of files) {\n      if (path.extname(file.path) !== '.py' || isTestPath(file.path)) continue\n      if (!file.content.includes('Application')) continue\n      let routes: ExtractedRoute[]\n      try {\n        routes = tornadoRoutesFromSource(file.content, parser)\n      } catch (err) {\n        recordExtractionError('route extraction', file.path, err)\n        continue\n      }\n      const relFile = toPosix(path.relative(service.dir, file.path))\n      for (const route of routes) {\n        const rid = routeId(service.pkg.name, route.method, route.pathTemplate)\n        if (!graph.hasNode(rid)) {\n          const node: RouteNode = {\n            id: rid,\n            type: NodeType.RouteNode,\n            name: `${route.method} ${route.pathTemplate}`,\n            service: service.pkg.name,\n            method: route.method,\n            pathTemplate: route.pathTemplate,\n            path: relFile,\n            line: route.line,\n            framework: route.framework,\n            discoveredVia: 'static',\n          }\n          graph.addNode(rid, node)\n          nodesAdded++\n        }\n        const containsId = extractedEdgeId(service.node.id, rid, EdgeType.CONTAINS)\n        if (!graph.hasEdge(containsId)) {\n          const edge: GraphEdge = {\n            id: containsId,\n            source: service.node.id,\n            target: rid,\n            type: EdgeType.CONTAINS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: { file: relFile, line: route.line, snippet: snippet(file.content, route.line) },\n          }\n          graph.addEdgeWithKey(containsId, service.node.id, rid, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parseAllDocuments, isMap, isSeq, isScalar, type Node as YamlNode } from 'yaml'\nimport type { GraphEdge, RouteNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  routeId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { makeEdgeId, type DiscoveredService } from './shared.js'\nimport { recordExtractionError, noteExtractedDropped } from './errors.js'\nimport { resolveEnvVar } from './databases/shared.js'\nimport { buildServiceHostIndex, ensureFileNode, snippet, toPosix } from './calls/shared.js'\n\n// Spring Cloud Gateway routes — config as a source. A gateway service declares\n// its whole routing table in application.yml:\n//\n//   spring:\n//     cloud:\n//       gateway:\n//         routes:\n//           - id: order\n//             uri: lb://${ORDER_SERVICE_HOST:ts-order-service}\n//             predicates:\n//               - Path=/api/v1/orderservice/**\n//\n// Each route's Path patterns become RouteNodes on the gateway (method from a\n// `Method=` predicate, else ALL), owned through `service ──CONTAINS──▶ route`\n// like any other route, and the config file gets `file ──CALLS──▶ service` to\n// the service the `uri` names. That is the hop every request takes from the\n// front door, declared in config rather than code.\n//\n// Read from `spring.cloud.gateway.routes` and the newer\n// `spring.cloud.gateway.server.webflux.routes`, default profile only, in either\n// predicate form: the shortcut string (`Path=/a/**,/b/**`) or the expanded map\n// (`name: Path`, `args: { patterns: … }`). A `${NAME:default}` in the uri\n// resolves from the service's `.env`, else to its default. A uri with no\n// resolvable host, or whose host names no service in the graph, gets no CALLS\n// edge; an unresolved one is recorded as a drop with its reason.\n\nconst CONFIG_FILES = ['application.yml', 'application.yaml']\nconst ROUTE_KEYS = ['spring.cloud.gateway.routes', 'spring.cloud.gateway.server.webflux.routes']\nconst HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'])\n\nexport interface GatewayRoute {\n  id?: string\n  // The uri as written, and its host once placeholders resolve (null when they\n  // can't be).\n  uri: string\n  host: string | null\n  paths: string[]\n  methods: string[]\n  line: number\n}\n\n// A key from a YAML map node, nested or written flat (`spring.cloud.gateway:`).\nfunction mapGet(node: unknown, key: string): unknown {\n  if (!isMap(node)) return undefined\n  for (const pair of node.items) {\n    const k = isScalar(pair.key) ? String(pair.key.value) : undefined\n    if (k === undefined) continue\n    if (k === key) return pair.value\n    if (key.startsWith(k + '.')) {\n      const v = mapGet(pair.value, key.slice(k.length + 1))\n      if (v !== undefined) return v\n    }\n  }\n  return undefined\n}\n\nfunction scalarString(node: unknown): string | undefined {\n  return isScalar(node) && node.value !== null && node.value !== undefined ? String(node.value) : undefined\n}\n\nfunction lineAt(text: string, offset: number): number {\n  return text.slice(0, offset).split('\\n').length\n}\n\n// A predicate as (name, values): `Path=/a/**,/b/**` or the expanded map form.\nfunction predicate(node: unknown): { name: string; values: string[]; offset: number } | null {\n  const offset = (node as YamlNode | undefined)?.range?.[0] ?? 0\n  const s = scalarString(node)\n  if (s !== undefined) {\n    const eq = s.indexOf('=')\n    if (eq <= 0) return null\n    return { name: s.slice(0, eq).trim(), values: s.slice(eq + 1).split(',').map((v) => v.trim()).filter(Boolean), offset }\n  }\n  if (!isMap(node)) return null\n  const name = scalarString(mapGet(node, 'name'))\n  if (!name) return null\n  const args = mapGet(node, 'args')\n  const values: string[] = []\n  if (isMap(args)) {\n    for (const pair of args.items) {\n      const v = pair.value\n      if (isSeq(v)) for (const item of v.items) {\n        const t = scalarString(item)\n        if (t) values.push(...t.split(',').map((x) => x.trim()).filter(Boolean))\n      }\n      else {\n        const t = scalarString(v)\n        if (t) values.push(...t.split(',').map((x) => x.trim()).filter(Boolean))\n      }\n    }\n  }\n  return { name, values, offset }\n}\n\nasync function resolvePlaceholders(serviceDir: string, value: string): Promise<string | null> {\n  let out = ''\n  let last = 0\n  const re = /\\$\\{([^}:]+)(?::([^}]*))?\\}/g\n  let m: RegExpExecArray | null\n  while ((m = re.exec(value)) !== null) {\n    out += value.slice(last, m.index)\n    const resolved = (await resolveEnvVar(serviceDir, m[1]!)) ?? m[2]\n    if (resolved === undefined) return null\n    out += resolved\n    last = m.index + m[0].length\n  }\n  return out + value.slice(last)\n}\n\n// `lb://name`, `http://host:port/x`, `ws://…` → host; null otherwise.\nfunction hostOf(uri: string): string | null {\n  const m = /^[a-z][a-z0-9+.-]*:\\/\\/([^/:?#]+)/i.exec(uri)\n  return m ? m[1]! : null\n}\n\n/** The Spring Cloud Gateway routes one application.yml declares (default profile). */\nexport async function gatewayRoutesFromYaml(text: string, serviceDir: string): Promise<GatewayRoute[]> {\n  const out: GatewayRoute[] = []\n  for (const doc of parseAllDocuments(text)) {\n    if (doc.errors.length > 0) continue\n    const root = doc.contents\n    if (mapGet(root, 'spring.config.activate.on-profile') !== undefined || mapGet(root, 'spring.profiles') !== undefined) {\n      continue\n    }\n    for (const key of ROUTE_KEYS) {\n      const routes = mapGet(root, key)\n      if (!isSeq(routes)) continue\n      for (const r of routes.items) {\n        const uri = scalarString(mapGet(r, 'uri'))\n        const preds = mapGet(r, 'predicates')\n        if (!uri || !isSeq(preds)) continue\n        const paths: string[] = []\n        let methods: string[] = ['ALL']\n        let line = lineAt(text, (r as YamlNode).range?.[0] ?? 0)\n        for (const p of preds.items) {\n          const pred = predicate(p)\n          if (!pred) continue\n          if (pred.name === 'Path') {\n            paths.push(...pred.values)\n            line = lineAt(text, pred.offset)\n          } else if (pred.name === 'Method') {\n            const ms = pred.values.map((v) => v.toUpperCase()).filter((v) => HTTP_METHODS.has(v))\n            if (ms.length > 0) methods = ms\n          }\n        }\n        if (paths.length === 0) continue\n        const resolved = await resolvePlaceholders(serviceDir, uri)\n        out.push({\n          id: scalarString(mapGet(r, 'id')),\n          uri,\n          host: resolved ? hostOf(resolved) : null,\n          paths,\n          methods,\n          line,\n        })\n      }\n    }\n  }\n  return out\n}\n\n/** Gateway RouteNodes and the config file's CALLS to each routed service. */\nexport async function addGatewayRoutes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const { hostToNodeId } = buildServiceHostIndex(services)\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    if (service.node.language !== 'java') continue\n    for (const dir of [path.join(service.dir, 'src', 'main', 'resources'), service.dir]) {\n      for (const name of CONFIG_FILES) {\n        const abs = path.join(dir, name)\n        const text = await fs.readFile(abs, 'utf8').catch(() => null)\n        if (text === null || !text.includes('gateway')) continue\n        let routes: GatewayRoute[]\n        try {\n          routes = await gatewayRoutesFromYaml(text, service.dir)\n        } catch (err) {\n          recordExtractionError('gateway route extraction', abs, err)\n          continue\n        }\n        if (routes.length === 0) continue\n        const relFile = toPosix(path.relative(service.dir, abs))\n        const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n          graph,\n          service.pkg.name,\n          service.node.id,\n          relFile,\n        )\n        nodesAdded += n\n        edgesAdded += e\n\n        for (const r of routes) {\n          const ev = { file: relFile, line: r.line, snippet: snippet(text, r.line) }\n          for (const p of r.paths) {\n            const pathTemplate = p.startsWith('/') ? p : '/' + p\n            for (const method of r.methods) {\n              const rid = routeId(service.pkg.name, method, pathTemplate)\n              if (!graph.hasNode(rid)) {\n                const node: RouteNode = {\n                  id: rid,\n                  type: NodeType.RouteNode,\n                  name: `${method} ${pathTemplate}`,\n                  service: service.pkg.name,\n                  method,\n                  pathTemplate,\n                  path: relFile,\n                  line: r.line,\n                  framework: 'spring-cloud-gateway',\n                  discoveredVia: 'static',\n                }\n                graph.addNode(rid, node)\n                nodesAdded++\n              }\n              const containsId = extractedEdgeId(service.node.id, rid, EdgeType.CONTAINS)\n              if (!graph.hasEdge(containsId)) {\n                const edge: GraphEdge = {\n                  id: containsId,\n                  source: service.node.id,\n                  target: rid,\n                  type: EdgeType.CONTAINS,\n                  provenance: Provenance.EXTRACTED,\n                  confidence: confidenceForExtracted('structural'),\n                  evidence: ev,\n                }\n                graph.addEdgeWithKey(containsId, service.node.id, rid, edge)\n                edgesAdded++\n              }\n            }\n          }\n\n          if (r.host === null) {\n            noteExtractedDropped({\n              source: fileNodeId,\n              target: 'service:unresolved',\n              type: EdgeType.CALLS,\n              confidence: confidenceForExtracted('reconstructed-approximate'),\n              confidenceKind: 'reconstructed-approximate',\n              evidence: { ...ev, approximate: true, reason: `the route's uri host doesn't resolve: ${r.uri}` },\n            })\n            continue\n          }\n          const target = hostToNodeId.get(r.host)\n          if (!target || target === service.node.id) continue\n          const edgeId = makeEdgeId(fileNodeId, target, EdgeType.CALLS)\n          if (graph.hasEdge(edgeId)) continue\n          const edge: GraphEdge = {\n            id: edgeId,\n            source: fileNodeId,\n            target,\n            type: EdgeType.CALLS,\n            provenance: Provenance.EXTRACTED,\n            // A declared routing table: the gateway forwards these paths to this\n            // service by configuration, not by a guessed URL.\n            confidence: confidenceForExtracted('structural'),\n            evidence: { ...ev, pathTemplate: r.paths[0] },\n          }\n          graph.addEdgeWithKey(edgeId, fileNodeId, target, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { GraphEdge, GrpcMethodNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  grpcMethodId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { IGNORED_DIRS, isPythonVenvDir, isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { snippet, toPosix } from './calls/shared.js'\n\n// gRPC `.proto` service/method extraction (ADR-123). gRPC used to engage only at\n// service grain — the client-stub detector in calls/grpc.ts maps a\n// `new OrderServiceClient()` to one `infra:grpc-service:*` node, and nothing read\n// the method surface at all. This producer reads the `.proto` service contract\n// as DATA (a bounded line-scan, no tree-sitter grammar — polyglot files are read\n// as data, CLAUDE.md) and materialises each `rpc` as a `GrpcMethodNode`. A proto\n// under a service's dir is owned through a `service ──CONTAINS──▶ method` edge; a\n// centralized proto that sits outside every service dir (otel-demo's `pb/demo.proto`,\n// a sibling of `src/`) mints the node alone, the OBSERVED span supplying the\n// service link (ADR-123 scan scope, #1459).\n//\n// This is the static half of two-sided gRPC observation: the node is keyed on the\n// fully-qualified `<package>.<Service>` name — the exact `rpc.service` an OBSERVED\n// execution span carries — so a declared method and its observed counterpart fuse\n// onto one node into a method-grain divergence (docs/contracts/otel-ingest.md\n// §gRPC methods). Scope is the service/method definitions only; message/field\n// grain, `import` resolution across proto files, and error-detail enrichment are\n// out of scope for this slice.\n\nconst PROTO_EXTENSION = '.proto'\n\n// A `.proto` service/method definition parsed out of one file.\nexport interface ExtractedGrpcMethod {\n  rpcService: string // fully-qualified `<package>.<Service>` (or bare `<Service>` when the file declares no package)\n  rpcMethod: string // bare method name, e.g. `GetOrder`\n  line: number // 1-indexed line the `rpc` is declared on\n}\n\n// ── `.proto` parsing (data, not a grammar) ──────────────────────────────────\n\n// The file-level `package foo.bar;` declaration, if present. gRPC fully-qualifies\n// `rpc.service` as `<package>.<Service>`, so the package prefixes every service\n// name in the file. proto2/proto3 both use this single-line form.\nfunction packageOf(content: string): string | null {\n  const m = content.match(/^\\s*package\\s+([A-Za-z_][A-Za-z0-9_.]*)\\s*;/m)\n  return m ? m[1]! : null\n}\n\n// The 1-indexed line an absolute character offset falls on.\nfunction lineAt(content: string, offset: number): number {\n  return content.slice(0, offset).split('\\n').length\n}\n\n// Scan a `.proto` file's `service X { rpc M(Req) returns (Res); }` blocks and\n// emit one method per `rpc`. Brace-balanced so a service body is read to its\n// close; the `rpc` scan is confined to that body. Streaming qualifiers\n// (`rpc M(stream Req) returns (stream Res)`) don't change the method identity, so\n// they're accepted and ignored. Comment-only or option lines that merely mention\n// `rpc`/`service` don't match — both anchors require the keyword followed by an\n// identifier and the structural token (`{` for a service, `(` for an rpc).\nexport function grpcMethodsFromProto(content: string, fqPackage: string | null): ExtractedGrpcMethod[] {\n  const out: ExtractedGrpcMethod[] = []\n  const serviceRe = /\\bservice\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*\\{/g\n  let sm: RegExpExecArray | null\n  while ((sm = serviceRe.exec(content)) !== null) {\n    const serviceName = sm[1]!\n    const rpcService = fqPackage ? `${fqPackage}.${serviceName}` : serviceName\n    // Walk from the opening brace to its matching close, tracking depth so a\n    // nested block (an inline `option`/message) doesn't end the service early.\n    const bodyStart = serviceRe.lastIndex // index just past the `{`\n    let depth = 1\n    let i = bodyStart\n    for (; i < content.length && depth > 0; i++) {\n      const ch = content[i]\n      if (ch === '{') depth++\n      else if (ch === '}') depth--\n    }\n    const body = content.slice(bodyStart, i - 1)\n    const rpcRe = /\\brpc\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*\\(/g\n    let rm: RegExpExecArray | null\n    while ((rm = rpcRe.exec(body)) !== null) {\n      const rpcMethod = rm[1]!\n      const line = lineAt(content, bodyStart + rm.index)\n      out.push({ rpcService, rpcMethod, line })\n    }\n    // Continue the outer scan past this service body.\n    serviceRe.lastIndex = i\n  }\n  return out\n}\n\n// ── file discovery ──────────────────────────────────────────────────────────\n\n// Walk a service directory for `.proto` files, honouring the shared ignore set\n// (node_modules, .git, …) and Python venvs the same way walkSourceFiles does.\n// `.proto` isn't a SERVICE_FILE_EXTENSION, so the source-file walker skips it —\n// this is a dedicated pass over the proto contract surface.\nasync function walkProtoFiles(dir: string, excludeDirs: string[] = []): Promise<string[]> {\n  // ADR-200 — skip nested discovered services' subtrees so an ancestor doesn't\n  // re-mint their `.proto` methods under itself.\n  const excluded = new Set(excludeDirs.map((d) => path.resolve(d)))\n  const out: string[] = []\n  async function walk(current: string): Promise<void> {\n    const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])\n    for (const entry of entries) {\n      const full = path.join(current, entry.name)\n      if (entry.isDirectory()) {\n        if (IGNORED_DIRS.has(entry.name)) continue\n        if (excluded.has(path.resolve(full))) continue\n        if (await isPythonVenvDir(full)) continue\n        await walk(full)\n      } else if (entry.isFile() && path.extname(entry.name) === PROTO_EXTENSION && !excluded.has(path.resolve(full))) {\n        out.push(full)\n      }\n    }\n  }\n  await walk(dir)\n  return out\n}\n\n// ── producer ─────────────────────────────────────────────────────────────────\n\n// Read one `.proto`, parse its services/methods, and mint a `GrpcMethodNode` per\n// `rpc` (idempotent on the wire-canonical id). When `owner` is set — the proto sits\n// inside a discovered service's dir — also mint the static\n// `service ──CONTAINS──▶ method` edge. A centralized proto that no service owns\n// mints the node alone.\nasync function mintMethodsFromProto(\n  graph: NeatGraph,\n  protoPath: string,\n  relFile: string,\n  owner: DiscoveredService | null,\n  counters: { nodesAdded: number; edgesAdded: number },\n): Promise<void> {\n  let content: string\n  try {\n    content = await fs.readFile(protoPath, 'utf8')\n  } catch (err) {\n    recordExtractionError('proto extraction', protoPath, err)\n    return\n  }\n\n  let methods: ExtractedGrpcMethod[]\n  try {\n    methods = grpcMethodsFromProto(content, packageOf(content))\n  } catch (err) {\n    recordExtractionError('proto extraction', protoPath, err)\n    return\n  }\n  if (methods.length === 0) return\n\n  for (const method of methods) {\n    const mid = grpcMethodId(method.rpcService, method.rpcMethod)\n    if (!graph.hasNode(mid)) {\n      const node: GrpcMethodNode = {\n        id: mid,\n        type: NodeType.GrpcMethodNode,\n        name: `${method.rpcService}/${method.rpcMethod}`,\n        rpcService: method.rpcService,\n        rpcMethod: method.rpcMethod,\n        path: relFile,\n        line: method.line,\n        discoveredVia: 'static',\n      }\n      graph.addNode(mid, node)\n      counters.nodesAdded++\n    }\n    if (!owner) continue\n    // `service ──CONTAINS──▶ method` — the service owns the methods its `.proto`\n    // declares, the same structural verb it has over its routes (ADR-119) and\n    // files (file-awareness.md §2). Evidence pinned to the `rpc` line. The node id\n    // is the wire-canonical FQN, so an OBSERVED execution span lands on this same\n    // node — declared and observed fuse.\n    const containsId = extractedEdgeId(owner.node.id, mid, EdgeType.CONTAINS)\n    if (!graph.hasEdge(containsId)) {\n      const edge: GraphEdge = {\n        id: containsId,\n        source: owner.node.id,\n        target: mid,\n        type: EdgeType.CONTAINS,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: {\n          file: relFile,\n          line: method.line,\n          snippet: snippet(content, method.line),\n        },\n      }\n      graph.addEdgeWithKey(containsId, owner.node.id, mid, edge)\n      counters.edgesAdded++\n    }\n  }\n}\n\nexport async function addGrpcMethods(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const counters = { nodesAdded: 0, edgesAdded: 0 }\n  // Resolved paths of every `.proto` a per-service walk has already claimed, so the\n  // project-root pass doesn't re-read one or shadow its `CONTAINS`.\n  const claimed = new Set<string>()\n\n  // Pass 1 — per service. A `.proto` under a service's own dir is that service's\n  // declared contract: mint the methods and the `service ──CONTAINS──▶ method`\n  // edge. ADR-255 narrows a shared-module binary to its own files through\n  // `excludeDirs`, so each binary claims only the protos it owns.\n  for (const service of services) {\n    const protoPaths = await walkProtoFiles(service.dir, service.excludeDirs)\n    for (const protoPath of protoPaths) {\n      // ADR-065 #1 — test-scope exclusion. A `.proto` under a test tree isn't the\n      // service's declared contract surface.\n      if (isTestPath(protoPath)) continue\n      claimed.add(path.resolve(protoPath))\n      await mintMethodsFromProto(\n        graph,\n        protoPath,\n        toPosix(path.relative(service.dir, protoPath)),\n        service,\n        counters,\n      )\n    }\n  }\n\n  // Pass 2 — project root (ADR-123 scan scope, #1459). A centralized contract that\n  // sits outside every service dir never reaches a per-service walk: otel-demo keeps\n  // its whole gRPC surface in `pb/demo.proto`, a sibling of `src/`, so none of the\n  // `src/<service>` dirs contain it and the `oteldemo.*` methods had no static twin\n  // at all. Scan the whole project root and mint the method node for any `.proto` no\n  // service claimed. Node only — there is no owning service dir to attribute a static\n  // `CONTAINS` to, and the OBSERVED SERVER span already carries the emitting service,\n  // so the node alone makes the observed methods two-sided (declared + observed on\n  // one id).\n  const rootProtos = await walkProtoFiles(scanPath)\n  for (const protoPath of rootProtos) {\n    if (isTestPath(protoPath)) continue\n    if (claimed.has(path.resolve(protoPath))) continue\n    await mintMethodsFromProto(\n      graph,\n      protoPath,\n      toPosix(path.relative(scanPath, protoPath)),\n      null,\n      counters,\n    )\n  }\n\n  return counters\n}\n","import type { GraphEdge, InfraNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  passesExtractedFloor,\n} from '@neat.is/types'\nimport { noteExtractedDropped, recordExtractionError } from '../errors.js'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n  isTestPath,\n  makeEdgeId,\n  maskCommentsInSource,\n  type DiscoveredService,\n} from '../shared.js'\nimport { addHttpCallEdges } from './http.js'\nimport { addRouteCallEdges } from './route-match.js'\nimport { ensureFileNode, loadSourceFiles, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\nimport { kafkaEndpointsFromFile } from './kafka.js'\nimport { redisEndpointsFromFile } from './redis.js'\nimport { awsEndpointsFromFile } from './aws.js'\nimport { grpcEndpointsFromFile } from './grpc.js'\nimport { supabaseEndpointsFromFile } from './supabase.js'\nimport { firestoreEndpointsFromFile, firestoreCrossFileEndpoints } from './firestore.js'\nimport { mongooseEndpointsFromFile, mongooseCrossFileEndpoints } from './mongoose.js'\nimport { sqlalchemyEndpointsFromFile, pythonOrmCrossFileEndpoints } from './sqlalchemy.js'\nimport { socketEndpointsFromFile } from './socket.js'\nimport { djangoOrmEndpointsFromFile } from './django-orm.js'\nimport { drizzleEndpointsFromFile } from './drizzle.js'\nimport { prismaColumnEndpoints } from './prisma.js'\nimport { railsSchemaEndpointsFromFile, railsModelEndpointsFromFile } from './activerecord.js'\nimport { laravelMigrationEndpointsFromFile, laravelModelEndpointsFromFile } from './eloquent.js'\nimport { foldColumns, foldSdkWrites } from '../../columns.js'\nimport { goSqlEndpointsFromFile } from './go.js'\nimport { gormEndpointsFromFile } from './gorm.js'\nimport { efcoreEndpointsFromFile } from './efcore.js'\nimport { mysqlJsEndpointsFromFile } from './mysql-js.js'\nimport { pythonDbapiEndpointsFromFile } from './dbapi-python.js'\nimport { jpaEndpoints } from './jpa.js'\n\nexport interface CallExtractResult {\n  nodesAdded: number\n  edgesAdded: number\n}\n\nfunction edgeTypeFromEndpoint(ep: ExternalEndpoint): (typeof EdgeType)[keyof typeof EdgeType] {\n  switch (ep.edgeType) {\n    case 'PUBLISHES_TO':\n      return EdgeType.PUBLISHES_TO\n    case 'CONSUMES_FROM':\n      return EdgeType.CONSUMES_FROM\n    default:\n      return EdgeType.CALLS\n  }\n}\n\nfunction isAwsKind(kind: string): boolean {\n  return (\n    kind.startsWith('aws-') ||\n    kind.startsWith('s3') ||\n    kind.startsWith('dynamodb')\n  )\n}\n\nasync function addExternalEndpointEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<CallExtractResult> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    const endpoints: ExternalEndpoint[] = []\n    const maskedFiles: SourceFile[] = []\n    for (const file of files) {\n      // ADR-065 #1 — test-scope exclusion. Tests stay registered as\n      // service-internal (via the file walk earlier); only outbound\n      // endpoint inference from them is filtered.\n      if (isTestPath(file.path)) continue\n      // ADR-065 #2 — comment-body exclusion. The regex-based extractors\n      // (redis / kafka / aws / grpc) scan raw file.content; URLs inside\n      // JSDoc / line / block comments leaked through to the graph in the\n      // v0.3.0 medusa run. Mask comments while preserving line/column for\n      // evidence line-mapping.\n      const masked = maskCommentsInSource(file.content)\n      const maskedFile = { path: file.path, content: masked }\n      maskedFiles.push(maskedFile)\n      endpoints.push(...kafkaEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...redisEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...awsEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...grpcEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...supabaseEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...firestoreEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...mongooseEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...sqlalchemyEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...djangoOrmEndpointsFromFile(maskedFile, service.dir))\n      endpoints.push(...drizzleEndpointsFromFile(maskedFile, service.dir))\n      try {\n        endpoints.push(...goSqlEndpointsFromFile(maskedFile, service.dir))\n      } catch (err) {\n        recordExtractionError('go SQL call extraction', file.path, err)\n      }\n      // JS/TS raw-SQL data axis (#1432). `mysql`/`mysql2` `.query`/`.execute` with a\n      // literal (or literal-headed, variable-resolved) statement → `sql-table` nodes +\n      // touched columns, the JS sibling of the Go database/sql reader above. Runs on\n      // the comment-masked copy like the other JS recognizers; wrapped because\n      // tree-sitter is a native module — a per-file failure must not abort the phase.\n      try {\n        endpoints.push(...mysqlJsEndpointsFromFile(maskedFile, service.dir))\n      } catch (err) {\n        recordExtractionError('mysql/mysql2 SQL call extraction', file.path, err)\n      }\n      // Go/GORM data axis (ADR-180). Model structs → `sql-table` nodes + literal\n      // columns. Parsed via tree-sitter-go from the raw file (not the JS-comment-\n      // masked copy), so Go `//` comments are excluded structurally as `comment`\n      // nodes. Wrapped because tree-sitter-go is a native module — a per-file\n      // failure must not abort the phase (ADR-055).\n      try {\n        endpoints.push(...gormEndpointsFromFile(file, service.dir))\n      } catch (err) {\n        recordExtractionError('gorm data-axis extraction', file.path, err)\n      }\n      // Rails ActiveRecord data axis (ADR-174). `db/schema.rb` tables + columns\n      // and the model→table link. Parsed via tree-sitter-ruby from the raw file\n      // (not the JS-comment-masked copy), so Ruby `#` comments are excluded\n      // structurally as `comment` nodes. Wrapped because tree-sitter-ruby is a\n      // native module — a per-file failure must not abort the phase (ADR-055).\n      try {\n        endpoints.push(...railsSchemaEndpointsFromFile(file, service.dir))\n        endpoints.push(...railsModelEndpointsFromFile(file, service.dir))\n      } catch (err) {\n        recordExtractionError('rails activerecord extraction', file.path, err)\n      }\n      // Laravel data axis (ADR-178). `database/migrations/*.php` Schema::create\n      // blueprints (tables + literal columns) and the `app/Models/*.php`\n      // Eloquent class→table link. Parsed via tree-sitter-php (`php_only`) from\n      // the raw file — PHP `//` / `#` comments are excluded structurally as\n      // `comment` nodes. Wrapped because tree-sitter-php is a native module — a\n      // per-file failure must not abort the phase (ADR-055).\n      try {\n        endpoints.push(...laravelMigrationEndpointsFromFile(file, service.dir))\n        endpoints.push(...laravelModelEndpointsFromFile(file, service.dir))\n      } catch (err) {\n        recordExtractionError('laravel eloquent extraction', file.path, err)\n      }\n      // C#/.NET EF Core data axis (ADR-203). `[Table(\"...\")]` annotations and\n      // `.ToTable(\"...\")` fluent calls → `sql-table` nodes. Parsed via\n      // tree-sitter-c-sharp from the raw file (not the JS-comment-masked copy), so\n      // C# `//` / `/* */` comments are excluded structurally as `comment` nodes.\n      // Wrapped because tree-sitter-c-sharp is a native module — a per-file failure\n      // must not abort the phase (ADR-055).\n      try {\n        endpoints.push(...efcoreEndpointsFromFile(file, service.dir))\n      } catch (err) {\n        recordExtractionError('efcore data-axis extraction', file.path, err)\n      }\n      // Python raw-socket dependencies. `socket.socket(...)` + `.connect((host, port))`\n      // → a `socket` endpoint — the bare-socket dependency the frameworked recognizers\n      // (grpc / redis / sqlalchemy) miss, so a custom line-protocol datastore call has a\n      // static twin its OBSERVED connection-refused can fuse onto. Parsed via\n      // tree-sitter-python from the raw file, so Python `#` comments are excluded\n      // structurally as `comment` nodes. Wrapped because tree-sitter-python is a native\n      // module — a per-file failure must not abort the phase (ADR-055).\n      try {\n        endpoints.push(...socketEndpointsFromFile(file, service.dir))\n      } catch (err) {\n        recordExtractionError('python socket call extraction', file.path, err)\n      }\n      // Python raw-SQL data axis (#1432). DB-API `cursor.execute`/`.executemany` with a\n      // literal (or literal-headed, variable-resolved) statement → `sql-table` nodes +\n      // touched columns, the Python sibling of the Go/JS raw-SQL readers. Parsed via\n      // tree-sitter-python from the raw file like the socket recognizer above (the\n      // JS-comment masker would corrupt Python `//` floor-division); wrapped because\n      // tree-sitter is a native module — a per-file failure must not abort the phase.\n      try {\n        endpoints.push(...pythonDbapiEndpointsFromFile(file, service.dir))\n      } catch (err) {\n        recordExtractionError('python dbapi SQL call extraction', file.path, err)\n      }\n    }\n    // Cross-file mongoose resolution (ADR-149) — a whole-program pass over the\n    // service's files, attributing a query in one file to a model defined in\n    // another via the import graph.\n    // Cross-file Firestore client resolution (#1223) — the near-universal Firebase\n    // layout exports one client (`export const db = getFirestore(app)`) and imports it\n    // everywhere else, so the per-file pass above claims none of those calls. Same\n    // whole-program shape as the mongoose pass below, applied to the client.\n    endpoints.push(...(await firestoreCrossFileEndpoints(maskedFiles, service.dir)))\n    endpoints.push(...(await mongooseCrossFileEndpoints(maskedFiles, service.dir)))\n    // Cross-file SQLAlchemy model→table query attribution (ADR-149 analog): a\n    // query file gets the table edge for a model imported from another file.\n    endpoints.push(...pythonOrmCrossFileEndpoints(maskedFiles, service.dir))\n    // JPA / Spring Data (Java): an entity's literal @Table name, attributed to the\n    // entity file and to each repository over it, across the service's files.\n    try {\n      endpoints.push(...jpaEndpoints(maskedFiles, service.dir))\n    } catch (err) {\n      recordExtractionError('jpa data-axis extraction', service.dir, err)\n    }\n    // Prisma declared columns (ADR-157 §3): `schema.prisma` is read as text —\n    // it isn't a source file the walker loads — so this runs once per service,\n    // reading each model's scalar fields as EXTRACTED columns at DB-name fidelity.\n    endpoints.push(...(await prismaColumnEndpoints(service.dir)))\n    if (endpoints.length === 0) continue\n\n    const seenEdges = new Set<string>()\n    for (const ep of endpoints) {\n      if (!graph.hasNode(ep.infraId)) {\n        const node: InfraNode = {\n          id: ep.infraId,\n          type: NodeType.InfraNode,\n          name: ep.name,\n          // #238 — `aws-*` covers AWS-SDK client kinds (aws-s3, aws-dynamodb,\n          // aws-cognito-identity-provider, …); `s3-` / `dynamodb-` cover the\n          // bucket / table kinds from aws.ts.\n          provider: isAwsKind(ep.kind) ? 'aws' : 'self',\n          kind: ep.kind,\n        }\n        graph.addNode(node.id, node)\n        nodesAdded++\n      }\n\n      // Column grain (ADR-157 §3): a schema-column producer (Drizzle) carries the\n      // declared columns at database-name fidelity. Fold them onto the table node\n      // with EXTRACTED provenance — whether the node was just minted here or\n      // already exists from an OBSERVED span, so the declared and observed columns\n      // fuse on one node and column-drift (§4) can read both sides. The\n      // definition's file:line rides the EXTRACTED edge minted below. Mutation is\n      // allowed here — extract/* is a lifecycle authority (lifecycle.md §3).\n      if (ep.columns && ep.columns.length > 0) {\n        const node = graph.getNodeAttributes(ep.infraId) as InfraNode\n        if (node.type === NodeType.InfraNode) {\n          graph.replaceNodeAttributes(ep.infraId, {\n            ...node,\n            columns: foldColumns(\n              node.columns,\n              ep.columns,\n              Provenance.EXTRACTED,\n              confidenceForExtracted(ep.confidenceKind),\n            ),\n          })\n        }\n      }\n\n      // Firestore write-SDK tags (ADR-167). A `firestore-collection` endpoint\n      // carries, per written field, which SDK wrote it (client vs admin) — the\n      // seam the field-guard policy (ADR-169) joins on. Fold it onto the columns\n      // the block above just landed, via the parallel `foldSdkWrites` — a separate\n      // firestore-gated pass so `foldColumns` and its fold block stay untouched.\n      // Gated on `ep.sdkWrites`, which only calls/firestore.ts populates.\n      if (ep.sdkWrites && Object.keys(ep.sdkWrites).length > 0) {\n        const node = graph.getNodeAttributes(ep.infraId) as InfraNode\n        if (node.type === NodeType.InfraNode) {\n          graph.replaceNodeAttributes(ep.infraId, {\n            ...node,\n            columns: foldSdkWrites(node.columns, ep.sdkWrites),\n          })\n        }\n      }\n\n      const edgeType = edgeTypeFromEndpoint(ep)\n      const confidence = confidenceForExtracted(ep.confidenceKind)\n      // File-first (file-awareness.md §1): the endpoint relationship originates\n      // from the file the call site lives in, with the owning service\n      // ──CONTAINS──▶ file edge alongside it (§2). File-node existence is\n      // independent of edge-target precision (ADR-089 amendment) — a matched\n      // call site is a parsed fact, so the FileNode + CONTAINS materialize\n      // regardless of how confident we are about the resolved target.\n      const relFile = toPosix(ep.evidence.file)\n      const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        relFile,\n      )\n      nodesAdded += n\n      edgesAdded += e\n      // Precision floor (ADR-066 §3). Only the file→target edge is gated:\n      // sub-threshold candidates are recorded as drops (banner accounting) and\n      // never added to the graph; the file and its call site still surface.\n      if (!passesExtractedFloor(confidence)) {\n        noteExtractedDropped({\n          source: fileNodeId,\n          target: ep.infraId,\n          type: edgeType,\n          confidence,\n          confidenceKind: ep.confidenceKind,\n          evidence: ep.evidence,\n        })\n        continue\n      }\n      const edgeId = makeEdgeId(fileNodeId, ep.infraId, edgeType)\n      if (seenEdges.has(edgeId)) continue\n      seenEdges.add(edgeId)\n      if (!graph.hasEdge(edgeId)) {\n        const edge: GraphEdge = {\n          id: edgeId,\n          source: fileNodeId,\n          target: ep.infraId,\n          type: edgeType,\n          provenance: Provenance.EXTRACTED,\n          confidence,\n          evidence: ep.evidence,\n        }\n        graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n        edgesAdded++\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded }\n}\n\nexport async function addCallEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<CallExtractResult> {\n  const http = await addHttpCallEdges(graph, services)\n  const ext = await addExternalEndpointEdges(graph, services)\n  // Cross-service contract matching (ADR-119). Runs after the RouteNodes are in\n  // the graph (addRoutes, a prior phase) so client call sites can be matched\n  // against the full route table, minting route-grained CALLS edges.\n  const routes = await addRouteCallEdges(graph, services)\n  return {\n    nodesAdded: http.nodesAdded + ext.nodesAdded + routes.nodesAdded,\n    edgesAdded: http.edgesAdded + ext.edgesAdded + routes.edgesAdded,\n  }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport TypeScript from 'tree-sitter-typescript'\nimport Python from 'tree-sitter-python'\nimport type { GraphEdge } from '@neat.is/types'\nimport {\n  EdgeType,\n  Provenance,\n  confidenceForExtracted,\n  passesExtractedFloor,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport {\n  isTestPath,\n  makeEdgeId,\n  urlMatchesHost,\n  type DiscoveredService,\n} from '../shared.js'\nimport { recordExtractionError, noteExtractedDropped } from '../errors.js'\nimport {\n  buildServiceHostIndex,\n  ensureFileNode,\n  loadSourceFiles,\n  snippet,\n  toPosix,\n} from './shared.js'\n\n// JS uses `string_fragment` for the textual interior of a template/string;\n// Python uses `string_content` inside a `string` node. Either way we want the\n// raw textual content (no quotes), so we accept both.\nconst STRING_LITERAL_NODE_TYPES = new Set(['string_fragment', 'string_content'])\n\n// ADR-065 #3 — JSX external-link exclusion. Tags whose URL-attr strings are\n// user-clickable hyperlinks, not service-to-service calls.\nconst JSX_EXTERNAL_LINK_TAGS = new Set(['a', 'Link', 'NavLink', 'ExternalLink', 'Anchor'])\n\n// Walk upward from a string-literal node to detect whether it sits inside a\n// JSX attribute on an external-link element. Returns true if the literal\n// should be filtered.\nfunction isInsideJsxExternalLink(node: Parser.SyntaxNode): boolean {\n  let cursor: Parser.SyntaxNode | null = node.parent\n  // Step out of the string wrapper if needed (parent is `string` /\n  // `template_string`).\n  while (cursor) {\n    if (cursor.type === 'jsx_attribute') {\n      // The element that owns this attribute. jsx_attribute lives inside\n      // jsx_opening_element / jsx_self_closing_element.\n      let owner: Parser.SyntaxNode | null = cursor.parent\n      while (owner && owner.type !== 'jsx_opening_element' && owner.type !== 'jsx_self_closing_element') {\n        owner = owner.parent\n      }\n      if (!owner) return false\n      // First named child of an opening/self-closing element is the tag name\n      // (`identifier` or `member_expression`).\n      const tagNode = owner.namedChild(0)\n      const tagName = tagNode?.text ?? ''\n      // For `<Foo.Bar>` we just want the rightmost ident; pick after the\n      // last dot.\n      const right = tagName.includes('.') ? tagName.split('.').pop()! : tagName\n      return JSX_EXTERNAL_LINK_TAGS.has(right)\n    }\n    cursor = cursor.parent\n  }\n  return false\n}\n\n// Collect (literal text, ast-node) pairs so the JSX-context check has the\n// node available. Comment tokens have no string_fragment / string_content\n// children in tree-sitter — JSDoc text lives inside `comment` nodes — so\n// comment-body exclusion comes for free with this AST walk (ADR-065 #2).\nfunction collectStringLiterals(\n  node: Parser.SyntaxNode,\n  out: { text: string; node: Parser.SyntaxNode }[],\n): void {\n  if (STRING_LITERAL_NODE_TYPES.has(node.type)) out.push({ text: node.text, node })\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) collectStringLiterals(child, out)\n  }\n}\n\n// A matched outbound call: the host the URL literal names and the 1-indexed\n// line it sits on. File-first extraction (file-awareness.md §1) originates a\n// CALLS edge from the file the call site lives in, so the position travels with\n// the host rather than being recovered after the fact.\nexport interface HttpCallSite {\n  host: string\n  line: number\n}\n\n// tree-sitter's node binding copies a string handed to `parser.parse` into a\n// fixed scratch buffer of ~32K code units and throws a bare \"Invalid argument\"\n// once the source is larger — it never names the size as the cause. NEAT's own\n// `cli.ts`, `ingest.ts`, and `installers/javascript.ts` all clear 40K, so the\n// http-call extractor was quietly skipping the three most interesting files in\n// the repo while dogfooding NEAT-on-NEAT. The callback form sidesteps the\n// buffer entirely: tree-sitter pulls the text in chunks we keep well under the\n// limit, so a file of any length parses. Chunking is by `.length` (UTF-16 code\n// units), which is exactly what the buffer counts.\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nexport function callsFromSource(\n  source: string,\n  parser: Parser,\n  knownHosts: Set<string>,\n): HttpCallSite[] {\n  const tree = parseSource(parser, source)\n  const literals: { text: string; node: Parser.SyntaxNode }[] = []\n  collectStringLiterals(tree.rootNode, literals)\n  const out: HttpCallSite[] = []\n  for (const lit of literals) {\n    // ADR-065 #3 — JSX external-link exclusion. URL strings on <a>, <Link>,\n    // <NavLink>, <ExternalLink>, <Anchor> are user-clickable hyperlinks, not\n    // service calls.\n    if (isInsideJsxExternalLink(lit.node)) continue\n    for (const host of knownHosts) {\n      // ADR-065 #5 — exact hostname match (not substring containment).\n      // `medusa.cloud` no longer matches `@medusajs/medusa`.\n      if (urlMatchesHost(lit.text, host)) {\n        out.push({ host, line: lit.node.startPosition.row + 1 })\n      }\n    }\n  }\n  return out\n}\n\n// Grammar per source extension. `.ts` / `.tsx` parse through\n// tree-sitter-typescript so TypeScript-only syntax — a `<T>expr` type\n// assertion, a `const` type parameter — parses cleanly instead of collapsing\n// into an ERROR node that can swallow a nearby URL literal and undercount CALLS\n// (issue #883). The JS grammar survives *most* TypeScript files but not all;\n// symbols.ts (ADR-158), drizzle.ts, zod-shapes.ts, and actions.ts already pick\n// their grammar by extension for the same reason. `.py` stays on\n// tree-sitter-python; anything else falls back to JavaScript, matching the\n// prior behaviour for non-mapped extensions.\nconst GRAMMAR_BY_EXT: Record<string, typeof JavaScript> = {\n  '.ts': TypeScript.typescript,\n  '.tsx': TypeScript.tsx,\n  '.js': JavaScript,\n  '.jsx': JavaScript,\n  '.mjs': JavaScript,\n  '.cjs': JavaScript,\n  '.py': Python,\n}\n\n// One Parser per grammar, created on first use and reused across files — a\n// Parser is reusable once its language is set, so the cache keys on the grammar\n// object rather than re-instantiating per file.\nfunction parserForExt(ext: string, cache: Map<unknown, Parser>): Parser {\n  const grammar = GRAMMAR_BY_EXT[ext] ?? JavaScript\n  let parser = cache.get(grammar)\n  if (!parser) {\n    parser = new Parser()\n    parser.setLanguage(grammar)\n    cache.set(grammar, parser)\n  }\n  return parser\n}\n\n// HTTP CALLS via URL hostname match. Parser is picked per file extension:\n// .py uses tree-sitter-python; everything else uses tree-sitter-javascript.\n//\n// File-first (file-awareness.md §1): each matched call site originates a\n// `file:<svc>:<relPath> ──CALLS──▶ target` edge plus the owning service's\n// CONTAINS edge, rather than collapsing every call in a service to one\n// service-level edge.\n//\n// File-node existence is independent of edge-target precision (file-awareness.md\n// §1, ADR-089 amendment). A matched call site is a parsed fact — the file and\n// its `service ──CONTAINS──▶ file` edge are certain regardless of how confident\n// we are about *what* it calls. So the FileNode + CONTAINS materialize for every\n// matched site; only the file→target CALLS edge is subject to the precision\n// floor. A scheme-qualified URL literal to a registered service grades at the\n// floor (url-literal-service-target, 0.7) so the declared HTTP dependency enters\n// the graph; if the floor is raised past it for diagnostics the file and its\n// call site still surface, without claiming the resolved target.\nexport async function addHttpCallEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  // One reusable parser per grammar, picked by file extension (see\n  // GRAMMAR_BY_EXT). `.ts` / `.tsx` ride tree-sitter-typescript so TypeScript\n  // syntax doesn't drop URL literals (#883).\n  const parserCache = new Map<unknown, Parser>()\n\n  // Host → owning ServiceNode id (ADR-065 #5), shared with the route-matching\n  // producer so both resolve a URL's host to a service the same way.\n  const { knownHosts, hostToNodeId } = buildServiceHostIndex(services)\n\n  let nodesAdded = 0\n  let edgesAdded = 0\n  for (const service of services) {\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    // File grain: one file→target CALLS per (file, target) pair, even when a\n    // file names the same host on several lines (function-level is deferred).\n    const seen = new Set<string>()\n    for (const file of files) {\n      // ADR-065 #1 — test-scope exclusion.\n      if (isTestPath(file.path)) continue\n      const parser = parserForExt(path.extname(file.path), parserCache)\n      let sites: HttpCallSite[]\n      try {\n        sites = callsFromSource(file.content, parser, knownHosts)\n      } catch (err) {\n        recordExtractionError('http call extraction', file.path, err)\n        continue\n      }\n      if (sites.length === 0) continue\n      const relFile = toPosix(path.relative(service.dir, file.path))\n      for (const site of sites) {\n        const targetId = hostToNodeId.get(site.host)\n        if (!targetId || targetId === service.node.id) continue\n        const dedupKey = `${relFile}|${targetId}`\n        if (seen.has(dedupKey)) continue\n        seen.add(dedupKey)\n        // A scheme-qualified URL literal that resolves to a registered service\n        // is a declared HTTP dependency (static-extraction contract §5). It\n        // grades at the precision floor rather than below it, so the EXTRACTED\n        // CALLS edge enters the graph and missing-observed can flag a declared-\n        // but-never-driven upstream (issue #592). Still below structural /\n        // verified-call-site: no call expression wraps the literal.\n        const confidence = confidenceForExtracted('url-literal-service-target')\n        const ev = {\n          file: relFile,\n          line: site.line,\n          snippet: snippet(file.content, site.line),\n        }\n        // The matched call site is a parsed fact: materialize the FileNode and\n        // its `service ──CONTAINS──▶ file` edge regardless of target precision\n        // (file-awareness.md §1, ADR-089 amendment). The file surfaces even\n        // when the resolved target sits below the floor.\n        const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n          graph,\n          service.pkg.name,\n          service.node.id,\n          relFile,\n        )\n        nodesAdded += n\n        edgesAdded += e\n        // The file→target CALLS edge alone is subject to the precision floor.\n        // A sub-floor target is recorded as a drop (banner accounting) and not\n        // claimed as a resolved edge — the file and its call site still stand.\n        if (!passesExtractedFloor(confidence)) {\n          noteExtractedDropped({\n            source: fileNodeId,\n            target: targetId,\n            type: EdgeType.CALLS,\n            confidence,\n            confidenceKind: 'url-literal-service-target',\n            evidence: ev,\n          })\n          continue\n        }\n        const edgeId = makeEdgeId(fileNodeId, targetId, EdgeType.CALLS)\n        if (!graph.hasEdge(edgeId)) {\n          const edge: GraphEdge = {\n            id: edgeId,\n            source: fileNodeId,\n            target: targetId,\n            type: EdgeType.CALLS,\n            provenance: Provenance.EXTRACTED,\n            confidence,\n            evidence: ev,\n          }\n          graph.addEdgeWithKey(edgeId, fileNodeId, targetId, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport type { ExtractedConfidenceKind, GraphEdge, RouteNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  passesExtractedFloor,\n  serviceId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { isTestPath, makeEdgeId, urlMatchesHost, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError, noteExtractedDropped } from '../errors.js'\nimport { normalizePathTemplate } from '../routes.js'\nimport {\n  buildServiceHostIndex,\n  ensureFileNode,\n  loadSourceFiles,\n  snippet,\n  toPosix,\n} from './shared.js'\n\n// Cross-service contract matching (ADR-119). This is the bridge between the two\n// static islands: a client call site names a URL (host + method + path); a\n// server RouteNode (extracted by routes.ts) declares (method, path-template).\n// When a client call's (host→service, method, normalised path) resolves to a\n// server route, this producer mints a route-grained EXTRACTED CALLS edge from\n// the client's FileNode to the server's RouteNode. It reuses the host→service\n// resolution the HTTP producers share (buildServiceHostIndex / urlMatchesHost),\n// adding path-template matching for the route half.\n//\n// The edge pairs with the OBSERVED server-span edge landing on the same\n// RouteNode (#576), giving get_divergences a file-precise, two-sided comparison\n// at route grain instead of only at service grain.\n//\n// Mainstream clients only: `fetch`, `axios` (default instance + method calls),\n// and node `http`/`https` `.request`/`.get`. The host and path must sit in the\n// same URL literal (or template literal) for a match — split base-URL + path\n// across variables is out of scope for this slice.\n\nconst PARSE_CHUNK = 16384\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction makeJsParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(JavaScript)\n  return p\n}\n\nconst JS_CLIENT_EXTENSIONS = new Set(['.js', '.jsx', '.mjs', '.cjs', '.ts', '.tsx'])\nconst AXIOS_METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'request'])\n\nexport interface ClientCallSite {\n  // The known host the URL named (basename or pkg name), or null when the base\n  // URL was an interpolation we couldn't resolve — an approximate call site with\n  // no resolvable target (ADR-219).\n  host: string | null\n  method?: string // upper-cased; undefined when not statically determinable\n  pathTemplate: string // the URL path, with `:param` for unresolved interpolations; '' when the host is unresolved\n  line: number\n  snippet: string\n  // Reconstruction fidelity (ADR-219). True when a load-bearing interpolation in\n  // the URL couldn't be resolved statically, so any match rests on shape rather\n  // than literal evidence.\n  approximate: boolean\n  reason?: string // why the reconstruction was approximated (diagnostic)\n}\n\n// ── AST helpers ─────────────────────────────────────────────────────────────\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) walk(child, visit)\n  }\n}\n\n// Resolve an expression node to a static string when the file alone determines\n// it: a string / no-substitution template literal, an identifier bound to one\n// earlier in the file, or the literal side of a `||` / `??` default (the\n// `process.env.X || 'http://localhost'` shape). Returns null for anything\n// computed at runtime. This is what turns an interpolated base URL held in a\n// `const` back into a real host instead of a `:param` (ADR-219).\nfunction resolveStaticString(\n  node: Parser.SyntaxNode | null,\n  constMap: Map<string, string>,\n  depth = 0,\n): string | null {\n  if (!node || depth > 4) return null\n  if (node.type === 'string') return stringText(node)\n  if (node.type === 'template_string') {\n    let out = ''\n    let sawSub = false\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (!child) continue\n      if (child.type === 'string_fragment') out += child.text\n      else if (child.type === 'template_substitution') sawSub = true\n    }\n    return sawSub ? null : out\n  }\n  if (node.type === 'identifier') return constMap.get(node.text) ?? null\n  if (node.type === 'binary_expression') {\n    // `a || b` / `a ?? b` — take whichever side resolves. Covers an env read\n    // with a literal dev default, where the literal is the statically-known value.\n    const left = resolveStaticString(node.childForFieldName('left'), constMap, depth + 1)\n    if (left !== null) return left\n    return resolveStaticString(node.childForFieldName('right'), constMap, depth + 1)\n  }\n  if (node.type === 'parenthesized_expression') {\n    return resolveStaticString(node.namedChild(0), constMap, depth + 1)\n  }\n  return null\n}\n\n// Build identifier → static-string bindings from the file's declarations, so an\n// interpolated base URL held in a variable (`const API_BASE = 'http://api'`) can\n// be substituted back into the URL. Document-order pass; later writes win. This\n// deliberately doesn't model block scope or reassignment — the target is the\n// common module-level base-URL const, not a general dataflow.\nfunction collectStaticStringBindings(root: Parser.SyntaxNode): Map<string, string> {\n  const map = new Map<string, string>()\n  walk(root, (node) => {\n    if (node.type !== 'variable_declarator') return\n    const name = node.childForFieldName('name')\n    if (!name || name.type !== 'identifier') return\n    const resolved = resolveStaticString(node.childForFieldName('value'), map)\n    if (resolved !== null) map.set(name.text, resolved)\n  })\n  return map\n}\n\n// Reconstruct the URL text a string / template-string argument names, resolving\n// interpolations back to their static values where the file determines them (a\n// base URL held in a const, ADR-219). A substitution that stays unresolvable\n// becomes `:param` and marks the result approximate: `/users/${id}` →\n// `/users/:param` (approximate), `${API_BASE}/x` with `API_BASE` a const → the\n// real base + `/x` (exact). Returns null for anything that isn't a string-ish\n// literal.\nfunction reconstructUrl(\n  node: Parser.SyntaxNode,\n  constMap: Map<string, string>,\n): { url: string; approximate: boolean } | null {\n  if (node.type === 'string') {\n    const s = stringText(node)\n    return s === null ? null : { url: s, approximate: false }\n  }\n  if (node.type === 'template_string') {\n    let out = ''\n    let approximate = false\n    let sawPart = false\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (!child) continue\n      if (child.type === 'string_fragment') {\n        out += child.text\n        sawPart = true\n      } else if (child.type === 'template_substitution') {\n        sawPart = true\n        const resolved = resolveStaticString(child.namedChild(0), constMap)\n        if (resolved !== null) out += resolved\n        else {\n          out += ':param'\n          approximate = true\n        }\n      }\n    }\n    // A template with no fragments/subs (empty) — fall back to stripped text.\n    if (!sawPart) {\n      const raw = node.text\n      return { url: raw.length >= 2 ? raw.slice(1, -1) : '', approximate: false }\n    }\n    return { url: out, approximate }\n  }\n  return null\n}\n\n// Read the `method` string off an options / config object (`{ method: 'POST' }`).\nfunction methodFromOptions(objNode: Parser.SyntaxNode): string | undefined {\n  for (let i = 0; i < objNode.namedChildCount; i++) {\n    const pair = objNode.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    const kText = k ? (k.type === 'string' ? stringText(k) : k.text) : null\n    if (kText !== 'method') continue\n    const v = pair.childForFieldName('value')\n    if (v && (v.type === 'string' || v.type === 'template_string')) {\n      const s = stringText(v)\n      return s ? s.toUpperCase() : undefined\n    }\n  }\n  return undefined\n}\n\nfunction stringText(node: Parser.SyntaxNode): string | null {\n  if (node.type === 'string') {\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (child?.type === 'string_fragment') return child.text\n    }\n    return ''\n  }\n  return null\n}\n\n// The URL string a config object names (`axios({ url: '…', method })`).\nfunction urlNodeFromConfig(objNode: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  for (let i = 0; i < objNode.namedChildCount; i++) {\n    const pair = objNode.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    const kText = k ? (k.type === 'string' ? stringText(k) : k.text) : null\n    if (kText === 'url') return pair.childForFieldName('value')\n  }\n  return null\n}\n\n// Parse the path out of a reconstructed URL string. Returns null when the string\n// isn't URL-shaped (no scheme + host). `:param` in the path survives parsing.\nfunction pathOf(urlStr: string): string | null {\n  try {\n    const candidate = urlStr.startsWith('//') ? `http:${urlStr}` : urlStr\n    const parsed = new URL(candidate)\n    return parsed.pathname || '/'\n  } catch {\n    return null\n  }\n}\n\n// Resolve which known host a reconstructed URL names (ADR-065 #5 — scheme +\n// exact hostname). Returns the host token or null.\nfunction matchHost(urlStr: string, knownHosts: Set<string>): string | null {\n  for (const host of knownHosts) {\n    if (urlMatchesHost(urlStr, host)) return host\n  }\n  return null\n}\n\n// Whether the authority (host[:port]) slot of a reconstructed URL is an\n// unresolved interpolation rather than a literal host. Distinguishes a base URL\n// that couldn't be resolved (`:param/charges`, `${base}` unresolved) — which we\n// surface as an approximate diagnostic — from a literal external host that\n// simply isn't one of our services (`https://stripe.com/${id}`), which stays a\n// silent skip (ADR-219).\nfunction hostSlotUnresolved(url: string): boolean {\n  const schemeRel = url.indexOf('//')\n  let authority: string\n  if (schemeRel >= 0) {\n    const rest = url.slice(schemeRel + 2)\n    const slash = rest.indexOf('/')\n    authority = slash >= 0 ? rest.slice(0, slash) : rest\n  } else {\n    const slash = url.indexOf('/')\n    authority = slash >= 0 ? url.slice(0, slash) : url\n  }\n  return authority.length === 0 || authority.includes(':param')\n}\n\n// Whether a reconstructed path carries at least one literal segment to anchor\n// which route it names. A path that is entirely dynamic once normalised — a lone\n// `/:param` from a computed first segment — matches any same-arity `/:id` route\n// with no literal evidence, so it must not mint a confident edge (ADR-219). A\n// literal segment (`/charges/:param`) pins the match to a specific route family.\nfunction pathHasLiteralAnchor(pathTemplate: string): boolean {\n  const segs = normalizePathTemplate(pathTemplate)\n    .split('/')\n    .filter((s) => s.length > 0)\n  if (segs.length === 0) return false\n  return segs.some((s) => s !== ':param')\n}\n\n// ── client call-site recognition ────────────────────────────────────────────\n\n// Extract every recognised HTTP client call site whose URL literal names a\n// known host. Each site carries the method (when statically determinable) and\n// the path-template, ready to be matched against the server route table.\nexport function clientCallSitesFromSource(\n  source: string,\n  parser: Parser,\n  knownHosts: Set<string>,\n): ClientCallSite[] {\n  const tree = parseSource(parser, source)\n  const out: ClientCallSite[] = []\n  // File-level static bindings, so an interpolated base URL held in a const\n  // resolves back to its real host instead of collapsing to `:param` (ADR-219).\n  const constMap = collectStaticStringBindings(tree.rootNode)\n\n  const push = (\n    urlNode: Parser.SyntaxNode,\n    method: string | undefined,\n    callNode: Parser.SyntaxNode,\n  ): void => {\n    const rec = reconstructUrl(urlNode, constMap)\n    if (!rec) return\n    const line = callNode.startPosition.row + 1\n    const host = matchHost(rec.url, knownHosts)\n    if (host === null) {\n      // No known host resolved. When the authority itself was an unresolved\n      // interpolation, surface it as an approximate call site — never a silent\n      // drop (ADR-219). A literal external host that just isn't one of our\n      // services stays a silent skip.\n      if (rec.approximate && hostSlotUnresolved(rec.url)) {\n        out.push({\n          host: null,\n          method,\n          pathTemplate: '',\n          line,\n          snippet: snippet(source, line),\n          approximate: true,\n          reason: 'base URL interpolation could not be resolved statically',\n        })\n      }\n      return\n    }\n    const p = pathOf(rec.url)\n    if (p === null) return\n    out.push({\n      host,\n      method,\n      pathTemplate: p,\n      line,\n      snippet: snippet(source, line),\n      approximate: rec.approximate,\n      reason: rec.approximate\n        ? 'path segment interpolation could not be resolved statically'\n        : undefined,\n    })\n  }\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call_expression') return\n    const fn = node.childForFieldName('function')\n    if (!fn) return\n    const args = node.childForFieldName('arguments')\n    const first = args?.namedChild(0)\n    if (!first) return\n\n    // fetch(url, opts?) — global or member (globalThis.fetch).\n    const fnName =\n      fn.type === 'identifier'\n        ? fn.text\n        : fn.type === 'member_expression'\n          ? (fn.childForFieldName('property')?.text ?? '')\n          : ''\n\n    if (fn.type === 'identifier' && fnName === 'fetch') {\n      const opts = args?.namedChild(1)\n      const method = opts && opts.type === 'object' ? (methodFromOptions(opts) ?? 'GET') : 'GET'\n      push(first, method, node)\n      return\n    }\n\n    // axios(url | config) — default instance called directly.\n    if (fn.type === 'identifier' && fnName === 'axios') {\n      if (first.type === 'object') {\n        const urlNode = urlNodeFromConfig(first)\n        if (urlNode) push(urlNode, methodFromOptions(first) ?? 'GET', node)\n      } else {\n        const opts = args?.namedChild(1)\n        const method = opts && opts.type === 'object' ? (methodFromOptions(opts) ?? 'GET') : 'GET'\n        push(first, method, node)\n      }\n      return\n    }\n\n    if (fn.type === 'member_expression') {\n      const obj = fn.childForFieldName('object')\n      const objName = obj?.text ?? ''\n\n      // axios.get('/x') / axios.post('/x', body) / axios.request({ url, method }).\n      if (objName === 'axios' && AXIOS_METHODS.has(fnName)) {\n        if (fnName === 'request' && first.type === 'object') {\n          const urlNode = urlNodeFromConfig(first)\n          if (urlNode) push(urlNode, methodFromOptions(first) ?? 'GET', node)\n        } else {\n          push(first, fnName.toUpperCase(), node)\n        }\n        return\n      }\n\n      // node http/https .request(url, …) / .get(url, …).\n      if ((objName === 'http' || objName === 'https') && (fnName === 'request' || fnName === 'get')) {\n        const opts = args?.namedChild(1)\n        const method =\n          opts && opts.type === 'object'\n            ? (methodFromOptions(opts) ?? (fnName === 'get' ? 'GET' : 'GET'))\n            : 'GET'\n        push(first, method, node)\n        return\n      }\n    }\n  })\n\n  return out\n}\n\n// ── route index + matching ──────────────────────────────────────────────────\n\ninterface RouteEntry {\n  method: string // upper, or 'ALL'\n  normalizedPath: string\n  routeNodeId: string\n}\n\n// Group every RouteNode in the graph by its owning ServiceNode id, keyed for\n// (method, normalised-path) lookup. Built once per pass so client matching is a\n// map read, not a graph scan per call site.\nfunction buildRouteIndex(graph: NeatGraph): Map<string, RouteEntry[]> {\n  const index = new Map<string, RouteEntry[]>()\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as unknown as { type?: string }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    const owner = serviceId(route.service)\n    const entry: RouteEntry = {\n      method: route.method.toUpperCase(),\n      normalizedPath: normalizePathTemplate(route.pathTemplate),\n      routeNodeId: route.id,\n    }\n    const list = index.get(owner)\n    if (list) list.push(entry)\n    else index.set(owner, [entry])\n  })\n  return index\n}\n\n// A client call matches a route when the normalised paths agree and the methods\n// are compatible: exact, or the route is method-agnostic (`ALL`), or the client\n// method couldn't be read statically.\nfunction findRoute(\n  entries: RouteEntry[],\n  method: string | undefined,\n  normalizedPath: string,\n): RouteEntry | undefined {\n  return entries.find(\n    (e) =>\n      e.normalizedPath === normalizedPath &&\n      (e.method === 'ALL' || method === undefined || e.method === method),\n  )\n}\n\nexport async function addRouteCallEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const jsParser = makeJsParser()\n  const { knownHosts, hostToNodeId } = buildServiceHostIndex(services)\n  const routeIndex = buildRouteIndex(graph)\n  if (routeIndex.size === 0) return { nodesAdded: 0, edgesAdded: 0 }\n\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    // One edge per (client file, route) pair even if a file calls the route on\n    // several lines (function grain is deferred, matching http.ts).\n    const seen = new Set<string>()\n    for (const file of files) {\n      // ADR-065 #1 — test-scope exclusion.\n      if (isTestPath(file.path)) continue\n      if (!JS_CLIENT_EXTENSIONS.has(path.extname(file.path))) continue\n\n      let sites: ClientCallSite[]\n      try {\n        sites = clientCallSitesFromSource(file.content, jsParser, knownHosts)\n      } catch (err) {\n        recordExtractionError('route-match call extraction', file.path, err)\n        continue\n      }\n      if (sites.length === 0) continue\n\n      const relFile = toPosix(path.relative(service.dir, file.path))\n      for (const site of sites) {\n        // An unresolved base URL has no host to attribute the call to. It is\n        // still a recognised call site (file-awareness §1), so materialise the\n        // file and record an approximate drop — visible under the rejected log /\n        // diagnostic floor, never a silent miss (ADR-219).\n        if (site.host === null) {\n          const dedupKey = `${relFile}|unresolved-host`\n          if (seen.has(dedupKey)) continue\n          seen.add(dedupKey)\n          const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n            graph,\n            service.pkg.name,\n            service.node.id,\n            relFile,\n          )\n          nodesAdded += n\n          edgesAdded += e\n          noteExtractedDropped({\n            source: fileNodeId,\n            target: 'route:unresolved',\n            type: EdgeType.CALLS,\n            confidence: confidenceForExtracted('reconstructed-approximate'),\n            confidenceKind: 'reconstructed-approximate',\n            evidence: {\n              file: relFile,\n              line: site.line,\n              snippet: site.snippet,\n              method: site.method,\n              approximate: true,\n              reason: site.reason,\n            },\n          })\n          continue\n        }\n\n        const serverServiceId = hostToNodeId.get(site.host)\n        // Skip a self-call (intra-service — no cross-service contract to match,\n        // mirroring http.ts).\n        if (!serverServiceId || serverServiceId === service.node.id) continue\n        const entries = routeIndex.get(serverServiceId)\n        if (!entries) continue\n        const normalizedPath = normalizePathTemplate(site.pathTemplate)\n        const match = findRoute(entries, site.method, normalizedPath)\n        if (!match) continue\n\n        const dedupKey = `${relFile}|${match.routeNodeId}`\n        if (seen.has(dedupKey)) continue\n        seen.add(dedupKey)\n\n        // The matched call site is a parsed fact — the client FileNode and its\n        // service ──CONTAINS──▶ file edge materialise regardless (file-awareness\n        // §1). Only the file→route edge is gated by the precision floor.\n        const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n          graph,\n          service.pkg.name,\n          service.node.id,\n          relFile,\n        )\n        nodesAdded += n\n        edgesAdded += e\n\n        // Reconstruction-fidelity grade (ADR-219). A fully-resolved URL — literal,\n        // or with every interpolation resolved from scope — grades\n        // verified-call-site (0.85): both endpoints are recognised and the client\n        // URL is faithful. A URL that stayed approximate keeps that grade only\n        // when a literal path segment anchors which route it names\n        // (`/charges/:param`); an all-dynamic path (`/:param` from a computed\n        // segment) has no literal evidence of the target and grades\n        // reconstructed-approximate, below the precision floor — refused under the\n        // default floor, visible with its reason when the floor is lowered.\n        const anchored = pathHasLiteralAnchor(site.pathTemplate)\n        const confidenceKind: ExtractedConfidenceKind =\n          site.approximate && !anchored ? 'reconstructed-approximate' : 'verified-call-site'\n        const confidence = confidenceForExtracted(confidenceKind)\n        const ev = {\n          file: relFile,\n          line: site.line,\n          snippet: site.snippet,\n          method: site.method ?? match.method,\n          pathTemplate: site.pathTemplate,\n          ...(confidenceKind === 'reconstructed-approximate'\n            ? { approximate: true, reason: site.reason }\n            : {}),\n        }\n        if (!passesExtractedFloor(confidence)) {\n          noteExtractedDropped({\n            source: fileNodeId,\n            target: match.routeNodeId,\n            type: EdgeType.CALLS,\n            confidence,\n            confidenceKind,\n            evidence: ev,\n          })\n          continue\n        }\n        const edgeId = makeEdgeId(fileNodeId, match.routeNodeId, EdgeType.CALLS)\n        if (!graph.hasEdge(edgeId)) {\n          const edge: GraphEdge = {\n            id: edgeId,\n            source: fileNodeId,\n            target: match.routeNodeId,\n            type: EdgeType.CALLS,\n            provenance: Provenance.EXTRACTED,\n            confidence,\n            evidence: ev,\n          }\n          graph.addEdgeWithKey(edgeId, fileNodeId, match.routeNodeId, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Match `producer.send({ topic: \"orders\" ... })` and `producer.send({\n// topic: 'orders' })` plus the two-arg form `producer.send(\"orders\", ...)`.\n// Kafka client libraries vary; these two forms cover kafkajs + node-rdkafka\n// well enough for static extraction. Same shape covers consumer.subscribe.\nconst PRODUCER_TOPIC_RE =\n  /(?:producer|kafkaProducer)[\\s\\S]{0,40}?\\.send\\s*\\(\\s*\\{[\\s\\S]{0,200}?topic\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\nconst CONSUMER_TOPIC_RE =\n  /(?:consumer|kafkaConsumer)[\\s\\S]{0,40}?\\.(?:subscribe|run)\\s*\\(\\s*\\{[\\s\\S]{0,200}?topic[s]?\\s*:\\s*(?:\\[\\s*)?['\"`]([^'\"`]+)['\"`]/g\n\n// --- Go (Sarama) ---\n//\n// The otel-demo `checkout` service is Go using IBM/Shopify Sarama; the JS regexes\n// above never match its `sarama.ProducerMessage{Topic: \"orders\"}` shape, so the\n// observed `PUBLISHES_TO infra:kafka-topic:orders` edge orphaned with no static\n// twin. These read the Go call sites as data — the same \"polyglot files are read,\n// the extractor stays TypeScript\" approach proto.ts uses — and mint the SAME\n// `infra:kafka-topic:<topic>` node the JS path and the OBSERVED span land on, so\n// declared and observed queue topology fuse on one node.\n//\n// Everything below is gated on a real Sarama import: without it an arbitrary Go\n// struct named `ProducerMessage` or any `.Consume(...)` method would mint a\n// phantom topic. This mirrors the import gate calls/go.ts and routes.ts use.\nconst SARAMA_IMPORT_RE = /\"[^\"]*\\/sarama\"/\n\n// Producer: `sarama.ProducerMessage{Topic: \"orders\"}` (sync SendMessage) and\n// `producer.Input() <- &sarama.ProducerMessage{Topic: topicVar}` (async). The\n// `Topic` field can sit anywhere in the struct literal, so scan a bounded window\n// for it and capture either a string literal (interpreted `\"x\"` or raw `` `x` ``)\n// or a bare identifier we resolve to an in-file literal below.\nconst GO_PRODUCER_RE =\n  /ProducerMessage\\s*\\{[\\s\\S]{0,300}?\\bTopic\\s*:\\s*(?:\"([^\"]+)\"|`([^`]+)`|([A-Za-z_]\\w*))/g\n\n// Consumer group: `consumerGroup.Consume(ctx, []string{\"orders\"}, handler)`. The\n// topic list is the `[]string{...}` argument; it may hold literals or identifiers.\nconst GO_CONSUMER_RE = /\\.Consume\\s*\\([\\s\\S]{0,120}?\\[\\]string\\s*\\{([^}]*)\\}/g\n\n// Every string literal (interpreted or raw) inside a captured `[]string{...}` body.\nconst GO_STRING_LITERAL_RE = /\"([^\"]+)\"|`([^`]+)`/g\n\n// A bare identifier — the fallback when the topic is a const/var rather than a\n// literal at the call site.\nconst GO_IDENT_RE = /[A-Za-z_]\\w*/g\n\nfunction findAll(re: RegExp, text: string): { topic: string; index: number }[] {\n  re.lastIndex = 0\n  const out: { topic: string; index: number }[] = []\n  let m: RegExpExecArray | null\n  while ((m = re.exec(text)) !== null) {\n    out.push({ topic: m[1]!, index: m.index })\n  }\n  return out\n}\n\n// Resolve a Go identifier to an in-file string literal — `topic := \"orders\"`,\n// `topic = \"orders\"`, `const KafkaTopic = \"orders\"` (const-block members read as\n// `KafkaTopic = \"orders\"`), and typed `var topic string = \"orders\"`. A value that\n// isn't an in-file literal — `topic := os.Getenv(\"KAFKA_TOPIC\")`, a computed\n// string — has no literal RHS and stays unresolved rather than guessed: NEAT would\n// be inventing a topic name it cannot see.\nfunction resolveGoLiteral(ident: string, text: string): string | undefined {\n  const esc = ident.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n  const re = new RegExp(\n    `\\\\b${esc}(?:\\\\s+\\\\w[\\\\w.\\\\[\\\\]*]*)?\\\\s*(?::=|=)\\\\s*(?:\"([^\"]+)\"|\\`([^\\`]+)\\`)`,\n  )\n  const m = re.exec(text)\n  if (!m) return undefined\n  return m[1] ?? m[2]\n}\n\n// Character offset of the topic token at the tail of a producer match, so evidence\n// points at the `Topic: \"orders\"` line rather than the head of the struct literal.\nfunction producerTopicAnchor(match: RegExpExecArray): number {\n  const [full] = match\n  const tokenLen = match[1]\n    ? match[1].length + 2 // \"x\"\n    : match[2]\n      ? match[2].length + 2 // `x`\n      : (match[3]?.length ?? 0) // ident\n  return match.index + full.length - tokenLen\n}\n\ntype Emit = (\n  topic: string,\n  edgeType: 'PUBLISHES_TO' | 'CONSUMES_FROM',\n  anchor: number,\n) => void\n\n// Walk a Go file's Sarama producer / consumer-group call sites, emitting a topic\n// per resolved site. No-op unless the file imports Sarama.\nfunction goSaramaEndpoints(text: string, emit: Emit): void {\n  if (!SARAMA_IMPORT_RE.test(text)) return\n\n  GO_PRODUCER_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = GO_PRODUCER_RE.exec(text)) !== null) {\n    const literal = m[1] ?? m[2]\n    const anchor = producerTopicAnchor(m)\n    if (literal) {\n      emit(literal, 'PUBLISHES_TO', anchor)\n    } else if (m[3]) {\n      const resolved = resolveGoLiteral(m[3], text)\n      if (resolved) emit(resolved, 'PUBLISHES_TO', anchor)\n    }\n  }\n\n  GO_CONSUMER_RE.lastIndex = 0\n  while ((m = GO_CONSUMER_RE.exec(text)) !== null) {\n    const inside = m[1] ?? ''\n    const anchor = m.index + Math.max(0, m[0].indexOf('[]string'))\n    let sawLiteral = false\n    GO_STRING_LITERAL_RE.lastIndex = 0\n    let s: RegExpExecArray | null\n    while ((s = GO_STRING_LITERAL_RE.exec(inside)) !== null) {\n      const topic = s[1] ?? s[2]\n      if (topic) {\n        emit(topic, 'CONSUMES_FROM', anchor)\n        sawLiteral = true\n      }\n    }\n    if (sawLiteral) continue\n    // `[]string{topicVar}` — resolve each identifier to an in-file literal.\n    GO_IDENT_RE.lastIndex = 0\n    let id: RegExpExecArray | null\n    while ((id = GO_IDENT_RE.exec(inside)) !== null) {\n      const resolved = resolveGoLiteral(id[0], text)\n      if (resolved) emit(resolved, 'CONSUMES_FROM', anchor)\n    }\n  }\n}\n\nexport function kafkaEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const make = (\n    topic: string,\n    edgeType: 'PUBLISHES_TO' | 'CONSUMES_FROM',\n    anchor?: number,\n  ): void => {\n    const key = `${edgeType}|${topic}`\n    if (seen.has(key)) return\n    seen.add(key)\n    // JS callers pass no anchor and fall back to finding the topic string. The Go\n    // path already knows the exact call-site offset (the topic may be a const, so\n    // its literal lives elsewhere in the file), so count newlines up to it.\n    const line =\n      anchor !== undefined\n        ? file.content.slice(0, anchor).split('\\n').length\n        : lineOf(file.content, topic)\n    out.push({\n      infraId: infraId('kafka-topic', topic),\n      name: topic,\n      kind: 'kafka-topic',\n      edgeType,\n      // JS: `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})`\n      // (kafkajs / node-rdkafka). Go: `sarama.ProducerMessage{Topic: 'x'}` /\n      // `consumerGroup.Consume(ctx, []string{'x'}, …)`. Both are framework-aware\n      // call sites — verified-call-site tier (ADR-066).\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  if (path.extname(file.path) === '.go') {\n    goSaramaEndpoints(file.content, make)\n  } else {\n    for (const { topic } of findAll(PRODUCER_TOPIC_RE, file.content)) make(topic, 'PUBLISHES_TO')\n    for (const { topic } of findAll(CONSUMER_TOPIC_RE, file.content)) make(topic, 'CONSUMES_FROM')\n  }\n  return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Redis URLs in source — `redis://host[:port]` or `rediss://...`. We only\n// catch literal strings; env-driven URLs go through the database parsers\n// (.env, ormconfig, etc.) and don't need a CALLS edge.\nconst REDIS_URL_RE = /redis(?:s)?:\\/\\/(?:[^@'\"`\\s]+@)?([^:/'\"`\\s]+)(?::(\\d+))?/g\n\nexport function redisEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  REDIS_URL_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = REDIS_URL_RE.exec(file.content)) !== null) {\n    const host = m[1]!\n    if (seen.has(host)) continue\n    seen.add(host)\n    const line = lineOf(file.content, host)\n    out.push({\n      infraId: infraId('redis', host),\n      name: host,\n      kind: 'redis',\n      edgeType: 'CALLS',\n      // `redis://host` URL literal — the scheme is structural support, but no\n      // call expression is verified to wire it through. URL-with-structural-\n      // support tier (ADR-066).\n      confidenceKind: 'url-with-structural-support',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n  return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// AWS SDK v3 calls. We catch S3 (`Bucket: \"x\"` near a `S3Client`-using\n// PutObjectCommand / GetObjectCommand / DeleteObjectCommand) and DynamoDB\n// (`TableName: \"x\"` near GetCommand / PutCommand / DynamoDBClient). The\n// pattern is intentionally permissive: a literal Bucket/TableName near an\n// SDK constant is good enough evidence; misses are fine because non-static\n// resources can't be catalogued anyway.\nconst S3_BUCKET_RE = /Bucket\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\nconst DYNAMO_TABLE_RE = /TableName\\s*:\\s*['\"`]([^'\"`]+)['\"`]/g\n\nfunction hasMarker(text: string, markers: string[]): boolean {\n  return markers.some((m) => text.includes(m))\n}\n\nfunction findAll(re: RegExp, text: string): { name: string; index: number }[] {\n  re.lastIndex = 0\n  const out: { name: string; index: number }[] = []\n  let m: RegExpExecArray | null\n  while ((m = re.exec(text)) !== null) {\n    out.push({ name: m[1]!, index: m.index })\n  }\n  return out\n}\n\nexport function awsEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const make = (kind: string, name: string): void => {\n    const key = `${kind}|${name}`\n    if (seen.has(key)) return\n    seen.add(key)\n    const line = lineOf(file.content, name)\n    out.push({\n      infraId: infraId(kind, name),\n      name,\n      kind,\n      edgeType: 'CALLS',\n      // SDK marker (S3Client, GetCommand, etc.) plus a Bucket/TableName\n      // literal — framework-aware recognizer, verified-call-site tier\n      // (ADR-066).\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  if (hasMarker(file.content, ['S3Client', 'PutObjectCommand', 'GetObjectCommand', 'DeleteObjectCommand'])) {\n    for (const { name } of findAll(S3_BUCKET_RE, file.content)) make('s3-bucket', name)\n  }\n  if (\n    hasMarker(file.content, [\n      'DynamoDBClient',\n      'DynamoDBDocumentClient',\n      'GetCommand',\n      'PutCommand',\n      'QueryCommand',\n      'UpdateCommand',\n      'DeleteCommand',\n    ])\n  ) {\n    for (const { name } of findAll(DYNAMO_TABLE_RE, file.content)) make('dynamodb-table', name)\n  }\n  return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Client-construction in JS/TS:\n//\n//   const client = new orders_proto.OrderService(...)\n//   const client = new OrdersClient('orders.internal:50051', ...)\n//   const client = new S3Client({ region: 'us-east-1' })\n//\n// The same `new <Name>Client(...)` shape is used by gRPC client stubs, AWS\n// SDK v3 service clients, and a long tail of other SDKs. v0.3.0 mapped every\n// `*Client(...)` to `infra:grpc-service:*`, which was true for the demo and\n// false for every AWS service medusa imported.\n//\n// Per ADR-065 / #238, classification is import-aware:\n//   1. file imports `@aws-sdk/client-<suffix>` and `<Name>` lowercases to the\n//      same alphanumeric tail (`S3Client` ↔ `client-s3`,\n//      `CognitoIdentityProviderClient` ↔ `client-cognito-identity-provider`)\n//      → kind `aws-<suffix>` (e.g. `infra:aws-s3:S3`).\n//   2. file imports `@grpc/grpc-js` or any `*_grpc_pb` generated stub\n//      → kind `grpc-service` (the legitimate gRPC path; demo unchanged).\n//   3. otherwise → kind `service` (the safe default — accurate but\n//      uninformative, the v0.3.0 grpc lie is removed).\nconst GRPC_CLIENT_RE = /new\\s+([A-Z][A-Za-z0-9_]*)Client\\s*\\(\\s*['\"`]?([^,'\"`)]+)?/g\nconst AWS_SDK_IMPORT_RE =\n  /(?:from\\s+['\"`]|require\\(\\s*['\"`])@aws-sdk\\/client-([a-z0-9-]+)['\"`]/g\nconst GRPC_IMPORT_RE =\n  /(?:from\\s+['\"`]|require\\(\\s*['\"`])@grpc\\/grpc-js['\"`]|_grpc_pb['\"`]/\n\nfunction isLikelyAddress(value: string | undefined): boolean {\n  if (!value) return false\n  // Reject code expressions: object literals, anything with whitespace.\n  // process.env.X contains dots and would otherwise pass the dot check.\n  if (/\\s/.test(value) || value.startsWith('{')) return false\n  return /:\\d{2,5}$/.test(value) || value.includes('.')\n}\n\nfunction normaliseForMatch(s: string): string {\n  return s.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n\ninterface ImportContext {\n  awsSdkSuffixes: Map<string, string>  // normalised → raw suffix (e.g. 's3' → 's3')\n  hasGrpcImport: boolean\n}\n\nfunction readImports(content: string): ImportContext {\n  const awsSdkSuffixes = new Map<string, string>()\n  AWS_SDK_IMPORT_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = AWS_SDK_IMPORT_RE.exec(content)) !== null) {\n    const raw = m[1]!\n    awsSdkSuffixes.set(normaliseForMatch(raw), raw)\n  }\n  return {\n    awsSdkSuffixes,\n    hasGrpcImport: GRPC_IMPORT_RE.test(content),\n  }\n}\n\nfunction classifyClient(\n  symbol: string,\n  ctx: ImportContext,\n): { kind: string } | null {\n  const key = normaliseForMatch(symbol)\n  const awsRaw = ctx.awsSdkSuffixes.get(key)\n  if (awsRaw) return { kind: `aws-${awsRaw}` }\n  if (ctx.hasGrpcImport) return { kind: 'grpc-service' }\n  // ADR-065 #5-adjacent — a bare `new <Name>Client()` with no AWS or gRPC\n  // import context is ambiguous; could be an in-process client object\n  // (`new QueryClient()` from @tanstack/react-query, `new PrismaClient()`,\n  // a domain Client class, etc.). Refuse to emit an edge rather than guess\n  // a `service` kind that produces false positives. v0.3.3 medusa run had\n  // a QueryClient false positive before this guard.\n  return null\n}\n\nexport function grpcEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const ctx = readImports(file.content)\n  GRPC_CLIENT_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = GRPC_CLIENT_RE.exec(file.content)) !== null) {\n    const symbol = m[1]!\n    const addr = m[2]?.trim()\n    const name = isLikelyAddress(addr) ? addr! : symbol\n    if (seen.has(name)) continue\n    const classified = classifyClient(symbol, ctx)\n    if (!classified) continue\n    seen.add(name)\n    const { kind } = classified\n    const line = lineOf(file.content, m[0])\n    out.push({\n      infraId: infraId(kind, name),\n      name,\n      kind,\n      edgeType: 'CALLS',\n      // `new <Name>Client(...)` with @aws-sdk/* or @grpc/grpc-js import\n      // context — import-aware classification per #238. Verified-call-site\n      // tier (ADR-066).\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n  return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { lineOf, snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Supabase clients in JS/TS:\n//\n//   import { createClient } from '@supabase/supabase-js'\n//   const supabase = createClient(process.env.SUPABASE_URL, key)\n//   const db = createClient('https://abc.supabase.co', key)\n//   supabase.from('orders').select()\n//   db.auth.getUser()\n//\n//   import { createServerClient } from '@supabase/ssr'\n//   const supabase = createServerClient(url, key, { cookies })\n//\n// Supabase apps talk to *.supabase.co exclusively through these client\n// constructors. The HTTP-call extractor never sees the host: it lives behind\n// `createClient`, and in the common case the URL is `process.env.SUPABASE_URL`\n// (or `EXPO_PUBLIC_SUPABASE_URL`), not a literal. So a production-observed\n// `service → *.supabase.co` CALLS edge arrives with no declared twin and shows\n// up as a false `missing-extracted` divergence. This extractor closes that gap.\n//\n// Classification is import-aware, the same discipline grpc.ts / aws.ts use\n// (#238): a bare `createClient(...)` is too common a name to claim without the\n// `@supabase/*` import in scope. The constructor names map to the package that\n// owns them:\n//   - `createClient`                       ← @supabase/supabase-js\n//   - `createServerClient` / `createBrowserClient` ← @supabase/ssr\nconst SUPABASE_JS_IMPORT_RE =\n  /(?:from\\s+['\"`]|require\\(\\s*['\"`])@supabase\\/supabase-js['\"`]/\nconst SUPABASE_SSR_IMPORT_RE =\n  /(?:from\\s+['\"`]|require\\(\\s*['\"`])@supabase\\/ssr['\"`]/\n\n// First argument of a Supabase client constructor. Group 1 is the constructor\n// name, group 2 (when present) is a string-literal URL. A non-literal first arg\n// (`process.env.SUPABASE_URL`, a config getter) leaves group 2 undefined — we\n// still match the construction, we just can't resolve the literal host.\nconst SUPABASE_CLIENT_RE =\n  /\\b(createClient|createServerClient|createBrowserClient)\\s*\\(\\s*(?:['\"`]([^'\"`]*)['\"`])?/g\n\n// A *.supabase.co host pulled out of a literal URL argument. We only treat the\n// constructor's URL as a resolvable host when the literal actually names a\n// supabase.co domain — anything else (a self-hosted Supabase behind a custom\n// domain, a placeholder) stays the unresolved env target rather than a guessed\n// host. Reading the literal is the only honest host source (file-awareness §6).\nfunction hostFromLiteral(literal: string | undefined): string | null {\n  if (!literal) return null\n  const m = /^https?:\\/\\/([^/:'\"`\\s]+)/.exec(literal.trim())\n  if (!m) return null\n  const host = m[1]!\n  if (!/\\.supabase\\.(co|in)$/i.test(host)) return null\n  return host\n}\n\ninterface ImportContext {\n  hasSupabaseJs: boolean\n  hasSupabaseSsr: boolean\n}\n\nfunction readImports(content: string): ImportContext {\n  return {\n    hasSupabaseJs: SUPABASE_JS_IMPORT_RE.test(content),\n    hasSupabaseSsr: SUPABASE_SSR_IMPORT_RE.test(content),\n  }\n}\n\n// A constructor name is only a Supabase client when the package that owns it is\n// imported in the same file. `createClient` needs @supabase/supabase-js;\n// `createServerClient` / `createBrowserClient` need @supabase/ssr. Without the\n// import in scope we refuse to emit — a bare `createClient` could be anything.\nfunction constructorMatchesImport(name: string, ctx: ImportContext): boolean {\n  if (name === 'createClient') return ctx.hasSupabaseJs\n  return ctx.hasSupabaseSsr\n}\n\n// Variables assigned from a Supabase client constructor in this file, e.g.\n// `const supabase = createClient(...)`. We scope `.from()` / `.rpc()` matching to\n// these so `supabase.from('orders')` (a table query) is recognized while\n// `Array.from(...)` or an unrelated `.from` never mints a phantom table node.\nconst SUPABASE_CLIENT_ASSIGN_RE =\n  /(?:const|let|var)\\s+(\\w+)\\s*=\\s*(?:await\\s+)?(createClient|createServerClient|createBrowserClient)\\s*\\(/g\n\nfunction supabaseClientVars(content: string, ctx: ImportContext): Set<string> {\n  const vars = new Set<string>()\n  SUPABASE_CLIENT_ASSIGN_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = SUPABASE_CLIENT_ASSIGN_RE.exec(content)) !== null) {\n    if (constructorMatchesImport(m[2]!, ctx)) vars.add(m[1]!)\n  }\n  return vars\n}\n\nexport function supabaseEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const ctx = readImports(file.content)\n  if (!ctx.hasSupabaseJs && !ctx.hasSupabaseSsr) return []\n\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  SUPABASE_CLIENT_RE.lastIndex = 0\n  let m: RegExpExecArray | null\n  while ((m = SUPABASE_CLIENT_RE.exec(file.content)) !== null) {\n    const ctor = m[1]!\n    if (!constructorMatchesImport(ctor, ctx)) continue\n\n    // When the first argument is a literal *.supabase.co URL we resolve the\n    // real host. Otherwise the URL is env-driven (`process.env.SUPABASE_URL`,\n    // a config getter) and unknowable statically — the edge still has to land,\n    // so it resolves to a stable `supabase:env` target. That target is honest:\n    // we read the @supabase import and the `createClient` call, but not a host,\n    // so we don't fabricate one (file-awareness §6).\n    const host = hostFromLiteral(m[2])\n    const name = host ?? 'env'\n    if (seen.has(name)) continue\n    seen.add(name)\n\n    const line = lineOf(file.content, m[0])\n    out.push({\n      infraId: infraId('supabase', name),\n      name,\n      kind: 'supabase',\n      edgeType: 'CALLS',\n      // `createClient(...)` from @supabase/supabase-js (or createServerClient /\n      // createBrowserClient from @supabase/ssr) with the import in scope — a\n      // framework-aware recognizer matched the SDK shape. Verified-call-site\n      // tier (ADR-066), the same grade aws.ts / grpc.ts emit at.\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  // `<client>.from('<table>')` / `<client>.rpc('<fn>')` — table/RPC-grained call\n  // sites (#803). These give a production-observed supabase-table access a\n  // file-grained static twin to fuse onto (the Supabase connector otherwise\n  // observes the table but not the calling file). Scoped to the client vars found\n  // above so `Array.from` and unrelated `.from` never mint a phantom table.\n  const clientVars = supabaseClientVars(file.content, ctx)\n  for (const clientVar of clientVars) {\n    const accessRe = new RegExp(\n      `\\\\b${clientVar}\\\\s*\\\\.\\\\s*(from|rpc)\\\\s*\\\\(\\\\s*['\"\\`]([\\\\w.-]+)['\"\\`]`,\n      'g',\n    )\n    let am: RegExpExecArray | null\n    while ((am = accessRe.exec(file.content)) !== null) {\n      const kind = am[1] === 'rpc' ? 'supabase-rpc' : 'supabase-table'\n      const resource = am[2]!\n      const key = `${kind}/${resource}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      const line = lineOf(file.content, am[0])\n      out.push({\n        infraId: infraId(kind, resource),\n        name: resource,\n        kind,\n        edgeType: 'CALLS',\n        confidenceKind: 'verified-call-site',\n        evidence: {\n          file: path.relative(serviceDir, file.path),\n          line,\n          snippet: snippet(file.content, line),\n        },\n      })\n    }\n  }\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport { infraId } from '@neat.is/types'\nimport { GRAMMAR_BY_EXT, parseSource } from '../symbols.js'\nimport { resolveJsImport } from '../imports.js'\nimport { snippet, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Firestore call sites (ADR-167). The collection-grained analog of\n// calls/supabase.ts (`.from('table')`) and calls/mongoose.ts (`.collection(...)`):\n// it names the collection a file reads or writes so a Firebase/Next.js app's\n// datastore surface — collections, and the fields the code writes — becomes\n// first-class in the graph at the same grain as `sql-table` + `ColumnAttr`.\n//\n//   // modular (firebase/firestore)\n//   import { getFirestore, collection, doc, addDoc, setDoc, query, where } from 'firebase/firestore'\n//   const db = getFirestore(app)\n//   collection(db, 'orders')                        // → collection 'orders'\n//   doc(db, 'orders', id)                            // → collection 'orders'\n//   collection(doc(db, 'users', id), 'posts')        // → 'users/{}/posts'\n//   addDoc(collection(db, 'orders'), { total, status })   // → written fields\n//   query(collection(db, 'orders'), where('status', '==', s))  // → read field\n//\n//   // namespaced / admin (firebase-admin/firestore)\n//   import admin from 'firebase-admin'\n//   const db = admin.firestore()\n//   db.collection('orders').doc(id).set({ total })   // → collection + written field\n//   db.collection('orders').where('status', '==', s) // → read field\n//\n// Firestore has no least-privilege telemetry path (ADR-128 makes its runtime an\n// explicit connector non-goal), so its value is EXTRACTED-only. The load-bearing\n// distinction for the field-guard policy (ADR-169) is whether a write comes from\n// the client SDK (`firebase/firestore`, governed by security rules) or the admin\n// SDK (`firebase-admin/firestore`, which bypasses rules entirely) — recorded per\n// written field as `sdkWrites`.\n//\n// Classification is import-aware, the same discipline calls/supabase.ts uses: the\n// producer is gated on a firebase import, and `collection(` / `.collection(` are\n// only claimed when scoped to a recognized Firestore client var (or an inline\n// client factory) — a bare `collection(...)` could be Mongoose's native driver.\n// A computed or interpolated path segment is left unclaimed rather than guessed.\n\nconst FIRESTORE_CLIENT_IMPORT_RE =\n  /(?:from\\s+['\"`]|require\\(\\s*['\"`])firebase\\/firestore['\"`]/\nconst FIRESTORE_ADMIN_IMPORT_RE =\n  /(?:from\\s+['\"`]|require\\(\\s*['\"`])firebase-admin(?:\\/firestore)?['\"`]/\n\ntype SdkWrite = 'client' | 'admin'\n\nfunction parserForExt(ext: string): Parser {\n  const p = new Parser()\n  p.setLanguage(GRAMMAR_BY_EXT[ext] ?? JavaScript)\n  return p\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\n// The literal text inside a `string` node (quotes stripped). Null for a template /\n// interpolated string — never guessed at (identical to drizzle.ts).\nfunction stringLiteralText(node: Parser.SyntaxNode | null): string | null {\n  if (!node || node.type !== 'string') return null\n  for (const child of namedChildren(node)) {\n    if (child.type === 'string_fragment') return child.text\n  }\n  return '' // an empty '' literal has no string_fragment child\n}\n\nfunction callArgs(call: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const args = call.childForFieldName('arguments')\n  return args ? namedChildren(args) : []\n}\n\n// A `getFirestore(...)` / `initializeFirestore(...)` call, or an `X.firestore()`\n// namespaced/admin client — the factory shapes a Firestore client comes from.\nfunction isFirestoreClientFactory(node: Parser.SyntaxNode | null): boolean {\n  if (node?.type !== 'call_expression') return false\n  const fn = node.childForFieldName('function')\n  if (fn?.type === 'identifier') return fn.text === 'getFirestore' || fn.text === 'initializeFirestore'\n  if (fn?.type === 'member_expression') return fn.childForFieldName('property')?.text === 'firestore'\n  return false\n}\n\n// Variables assigned from a Firestore client factory in this file, e.g.\n// `const db = getFirestore(app)` / `const db = admin.firestore()`. We scope the\n// `collection(db, …)` and `db.collection(…)` matching to these so an unrelated\n// `.collection` (Mongoose's native driver, an array helper) never mints a phantom\n// collection — the same scoping calls/supabase.ts applies to `.from()`.\nfunction firestoreClientVars(root: Parser.SyntaxNode): Set<string> {\n  const vars = new Set<string>()\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'variable_declarator') {\n      const name = node.childForFieldName('name')\n      let value = node.childForFieldName('value')\n      if (value?.type === 'await_expression') value = namedChildren(value)[0] ?? null\n      if (name?.type === 'identifier' && isFirestoreClientFactory(value)) {\n        vars.add(name.text)\n      }\n    }\n    for (const c of namedChildren(node)) walk(c)\n  }\n  walk(root)\n  return vars\n}\n\nfunction isClientExpr(node: Parser.SyntaxNode | null, clientVars: Set<string>): boolean {\n  if (!node) return false\n  if (node.type === 'identifier') return clientVars.has(node.text)\n  return isFirestoreClientFactory(node)\n}\n\n// Resolve a modular `collection(...)` / `doc(...)` call to its ordered Firestore\n// path segments, where a collection name is its literal string and a document id\n// collapses to '{}' (the path-template placeholder — the collection template is\n// the same whatever the doc id). Returns null when the base is not a recognized\n// client or any collection-position segment is computed/interpolated: left\n// unclaimed, never guessed. Segments alternate collection(0)/doc(1)/collection(2)…\nfunction resolveModular(node: Parser.SyntaxNode, clientVars: Set<string>): string[] | null {\n  const fn = node.childForFieldName('function')\n  if (fn?.type !== 'identifier' || (fn.text !== 'collection' && fn.text !== 'doc')) return null\n  const args = callArgs(node)\n  const first = args[0]\n  if (!first) return null\n\n  let segs: string[]\n  if (first.type === 'call_expression') {\n    const base = resolveModular(first, clientVars)\n    if (base === null) return null\n    segs = [...base]\n  } else if (isClientExpr(first, clientVars)) {\n    segs = []\n  } else {\n    return null // first arg is not a firestore client — not our call\n  }\n\n  for (let i = 1; i < args.length; i++) {\n    const isCollectionPos = segs.length % 2 === 0\n    if (isCollectionPos) {\n      const lit = stringLiteralText(args[i]!)\n      if (lit === null) return null // computed collection name → unclaimed\n      segs.push(lit)\n    } else {\n      segs.push('{}') // a document id — literal or computed alike → placeholder\n    }\n  }\n  return segs\n}\n\n// Resolve a namespaced `<client>.collection('x')` / `.doc(id)` chain to its\n// ordered path segments, the same segment model as the modular resolver.\nfunction resolveNamespaced(node: Parser.SyntaxNode, clientVars: Set<string>): string[] | null {\n  if (node.type !== 'call_expression') return null\n  const fn = node.childForFieldName('function')\n  if (fn?.type !== 'member_expression') return null\n  const prop = fn.childForFieldName('property')?.text\n  if (prop !== 'collection' && prop !== 'doc') return null\n  const obj = fn.childForFieldName('object')\n\n  let base: string[]\n  if (obj?.type === 'call_expression') {\n    const inner = resolveNamespaced(obj, clientVars)\n    if (inner === null) return null\n    base = inner\n  } else if (isClientExpr(obj, clientVars)) {\n    base = []\n  } else {\n    return null\n  }\n\n  if (prop === 'doc') return [...base, '{}']\n  const lit = stringLiteralText(callArgs(node)[0] ?? null)\n  if (lit === null) return null // computed collection name → unclaimed\n  return [...base, lit]\n}\n\n// The collection path a resolved segment list names: a `collection(...)` call\n// ends on a collection (odd length), a `doc(...)` call ends on a document — drop\n// its trailing id to get the collection it belongs to. Joined with '/'.\nfunction collectionPathOf(node: Parser.SyntaxNode, segs: string[] | null): string | null {\n  if (segs === null || segs.length === 0) return null\n  const fn = node.childForFieldName('function')\n  const prop =\n    fn?.type === 'identifier'\n      ? fn.text\n      : fn?.type === 'member_expression'\n        ? fn.childForFieldName('property')?.text\n        : null\n  const collSegs = prop === 'doc' ? segs.slice(0, -1) : segs\n  if (collSegs.length === 0) return null\n  return collSegs.join('/')\n}\n\n// The collection path any collection/doc reference (modular or namespaced) names.\nfunction collectionPathFromCall(node: Parser.SyntaxNode, clientVars: Set<string>): string | null {\n  const modular = resolveModular(node, clientVars)\n  if (modular !== null) return collectionPathOf(node, modular)\n  const namespaced = resolveNamespaced(node, clientVars)\n  if (namespaced !== null) return collectionPathOf(node, namespaced)\n  return null\n}\n\n// Descend a namespaced query/write receiver chain (`.where().orderBy()`, or a\n// bare collection/doc ref) to the collection it targets.\nfunction receiverColl(node: Parser.SyntaxNode | null, clientVars: Set<string>): string | null {\n  let cur: Parser.SyntaxNode | null = node\n  while (cur?.type === 'call_expression') {\n    const fn = cur.childForFieldName('function')\n    if (fn?.type !== 'member_expression') return null\n    const prop = fn.childForFieldName('property')?.text\n    if (prop === 'collection' || prop === 'doc') return collectionPathFromCall(cur, clientVars)\n    cur = fn.childForFieldName('object') // skip query methods (where/orderBy/limit/…)\n  }\n  return null\n}\n\n// The collection a modular `query(collRef, …)` reads — arg0 is the collection ref\n// or a nested `query(...)`.\nfunction modularQueryColl(node: Parser.SyntaxNode, clientVars: Set<string>): string | null {\n  const fn = node.childForFieldName('function')\n  if (fn?.type !== 'identifier') return null\n  if (fn.text === 'query') {\n    const arg0 = callArgs(node)[0]\n    return arg0?.type === 'call_expression' ? modularQueryColl(arg0, clientVars) : null\n  }\n  if (fn.text === 'collection' || fn.text === 'doc') return collectionPathFromCall(node, clientVars)\n  return null\n}\n\n// A property name, the way drizzle.ts reads it: a bare `status:` or quoted\n// `'status':` key, or a `{ status }` shorthand. A computed / spread key is skipped\n// (returns null / not a pair) rather than guessed at.\nfunction keyName(key: Parser.SyntaxNode | null): string | null {\n  if (!key) return null\n  if (key.type === 'property_identifier') return key.text\n  if (key.type === 'string') return stringLiteralText(key)\n  return null\n}\n\nfunction objectKeys(obj: Parser.SyntaxNode | undefined): string[] {\n  if (obj?.type !== 'object') return []\n  const out: string[] = []\n  for (const child of namedChildren(obj)) {\n    if (child.type === 'pair') {\n      const k = keyName(child.childForFieldName('key'))\n      if (k) out.push(k)\n    } else if (child.type === 'shorthand_property_identifier') {\n      out.push(child.text)\n    }\n    // spread_element / computed key → left unclaimed\n  }\n  return out\n}\n\nconst MODULAR_WRITES = new Set(['addDoc', 'setDoc', 'updateDoc'])\nconst NAMESPACED_WRITES = new Set(['add', 'set', 'update'])\nconst READ_CLAUSES = new Set(['where', 'orderBy'])\n\n/** A Firestore client this file imported from another module, resolved by the cross-file\n *  pass (#1223). `sdk` is the *exporting* file's SDK, since the importing file may name no\n *  Firestore package itself. */\nexport interface ImportedFirestoreClients {\n  names: Set<string>\n  sdk: SdkWrite | null\n}\n\nexport function firestoreEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n  imported?: ImportedFirestoreClients,\n): ExternalEndpoint[] {\n  const hasClient = FIRESTORE_CLIENT_IMPORT_RE.test(file.content)\n  const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(file.content)\n  // A file that imports its client from elsewhere may name no Firestore package at all —\n  // `import { db } from './firebase'` then `db.collection('orders')` under the admin SDK.\n  // The resolved import is the evidence there, so the package gate only decides when\n  // there are no imported clients to go on.\n  const importedNames = imported?.names ?? new Set<string>()\n  if (!hasClient && !hasAdmin && importedNames.size === 0) return []\n\n  // The writing SDK is the file's imported Firestore SDK: a file uses one SDK\n  // (`getFirestore` resolves to client under firebase/firestore, admin under\n  // firebase-admin/firestore; `admin.firestore()` is admin). When a file imports\n  // both — rare — the per-write SDK is genuinely ambiguous, so we leave the tag\n  // off (the field still lands as a column); ADR-169 reads `sdkWrites ?? []`, so\n  // an untagged write degrades to silence, never a false positive.\n  // A file with no SDK import of its own inherits the exporting file's SDK, which is\n  // where its client was actually constructed.\n  const ownSdk: SdkWrite | null =\n    hasClient && !hasAdmin ? 'client' : hasAdmin && !hasClient ? 'admin' : null\n  const fileSdk: SdkWrite | null = !hasClient && !hasAdmin ? (imported?.sdk ?? null) : ownSdk\n\n  const tree = parseSource(parserForExt(path.extname(file.path)), file.content)\n  const clientVars = firestoreClientVars(tree.rootNode)\n  for (const n of importedNames) clientVars.add(n)\n\n  const collLine = new Map<string, number>() // path → first evidence line\n  const writes = new Map<string, Map<string, Set<SdkWrite>>>() // path → field → sdks\n  const reads = new Map<string, Set<string>>() // path → read field names\n\n  const noteColl = (p: string, line: number): void => {\n    if (!collLine.has(p)) collLine.set(p, line)\n  }\n  const noteWrite = (p: string, fields: string[], line: number): void => {\n    if (fields.length === 0) return\n    noteColl(p, line)\n    let byField = writes.get(p)\n    if (!byField) {\n      byField = new Map()\n      writes.set(p, byField)\n    }\n    for (const f of fields) {\n      let sdks = byField.get(f)\n      if (!sdks) {\n        sdks = new Set()\n        byField.set(f, sdks)\n      }\n      if (fileSdk) sdks.add(fileSdk)\n    }\n  }\n  const noteRead = (p: string, field: string, line: number): void => {\n    noteColl(p, line)\n    let s = reads.get(p)\n    if (!s) {\n      s = new Set()\n      reads.set(p, s)\n    }\n    s.add(field)\n  }\n\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'call_expression') {\n      const fn = node.childForFieldName('function')\n      const line = node.startPosition.row + 1\n\n      // A collection / doc reference — the collection node itself.\n      const collPath = collectionPathFromCall(node, clientVars)\n      if (collPath) noteColl(collPath, line)\n\n      if (fn?.type === 'identifier') {\n        // Modular write: setDoc(ref, {…}) / updateDoc(ref, {…}) / addDoc(ref, {…}).\n        if (MODULAR_WRITES.has(fn.text)) {\n          const args = callArgs(node)\n          const ref = args[0]\n          const p = ref?.type === 'call_expression' ? collectionPathFromCall(ref, clientVars) : null\n          if (p) noteWrite(p, objectKeys(args[1]), line)\n        }\n        // Modular read: query(collRef, where('field', …), orderBy('field')).\n        if (fn.text === 'query') {\n          const p = modularQueryColl(node, clientVars)\n          if (p) {\n            for (const arg of callArgs(node)) {\n              if (arg.type !== 'call_expression') continue\n              const cfn = arg.childForFieldName('function')\n              if (cfn?.type === 'identifier' && READ_CLAUSES.has(cfn.text)) {\n                const field = stringLiteralText(callArgs(arg)[0] ?? null)\n                if (field) noteRead(p, field, arg.startPosition.row + 1)\n              }\n            }\n          }\n        }\n      } else if (fn?.type === 'member_expression') {\n        const prop = fn.childForFieldName('property')?.text\n        const receiver = fn.childForFieldName('object')\n        // Namespaced write: <ref>.set({…}) / .update({…}) / .add({…}).\n        if (prop && NAMESPACED_WRITES.has(prop)) {\n          const p = receiverColl(receiver, clientVars)\n          if (p) noteWrite(p, objectKeys(callArgs(node)[0]), line)\n        }\n        // Namespaced read: <ref>.where('field', …) / .orderBy('field').\n        if (prop && READ_CLAUSES.has(prop)) {\n          const p = receiverColl(receiver, clientVars)\n          const field = stringLiteralText(callArgs(node)[0] ?? null)\n          if (p && field) noteRead(p, field, line)\n        }\n      }\n    }\n    for (const c of namedChildren(node)) walk(c)\n  }\n  walk(tree.rootNode)\n\n  const out: ExternalEndpoint[] = []\n  for (const [collPath, line] of collLine) {\n    const byField = writes.get(collPath)\n    const readFields = reads.get(collPath)\n    // Union of written + read field names → columns (the existing columns fold in\n    // calls/index.ts lands these with EXTRACTED provenance).\n    const columnSet = new Set<string>()\n    if (byField) for (const f of byField.keys()) columnSet.add(f)\n    if (readFields) for (const f of readFields) columnSet.add(f)\n\n    // Per-written-field SDK tags → the seam ADR-169 joins on. Only fields with a\n    // known writing SDK carry a tag; an ambiguous (both-imports) write is a column\n    // with no tag.\n    let sdkWrites: Record<string, SdkWrite[]> | undefined\n    if (byField) {\n      for (const [field, sdks] of byField) {\n        if (sdks.size === 0) continue\n        if (!sdkWrites) sdkWrites = {}\n        sdkWrites[field] = [...sdks].sort()\n      }\n    }\n\n    out.push({\n      infraId: infraId('firestore-collection', collPath),\n      name: collPath,\n      kind: 'firestore-collection',\n      edgeType: 'CALLS',\n      // A firebase import is in scope and the call is scoped to a recognized\n      // Firestore client — a framework-aware recognizer matched the SDK shape.\n      // Verified-call-site tier (ADR-066), the grade calls/supabase.ts emits at.\n      confidenceKind: 'verified-call-site',\n      ...(columnSet.size > 0 ? { columns: [...columnSet] } : {}),\n      ...(sdkWrites ? { sdkWrites } : {}),\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n  return out\n}\n\n// ── Cross-file client resolution (#1223) ──────────────────────────────────────────────\n//\n// The per-file pass only claims a call whose client variable was declared in the same\n// file, which misses the layout nearly every Firebase app uses: one module constructs the\n// client and exports it, every querying module imports it. That left a Firestore-heavy\n// codebase looking like one with no Firestore at all.\n//\n// This is the whole-program pass mongoose already has (ADR-149, `mongooseCrossFileEndpoints`)\n// applied to the client rather than the model: build a registry of which module exports a\n// Firestore client under which name, then re-run the per-file recognizer on each importer\n// with those local bindings treated as clients.\n\n/** Client vars a file EXPORTS — `export const db = getFirestore(app)`. */\nfunction exportedFirestoreClients(root: Parser.SyntaxNode): Set<string> {\n  const out = new Set<string>()\n  const collect = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'variable_declarator') {\n      const name = node.childForFieldName('name')\n      let value = node.childForFieldName('value')\n      if (value?.type === 'await_expression') value = namedChildren(value)[0] ?? null\n      if (name?.type === 'identifier' && isFirestoreClientFactory(value)) out.add(name.text)\n    }\n    for (const c of namedChildren(node)) collect(c)\n  }\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'export_statement') collect(node)\n    else for (const c of namedChildren(node)) walk(c)\n  }\n  walk(root)\n  return out\n}\n\ninterface NamedBinding {\n  local: string\n  imported: string\n  specifier: string\n}\n\n/** Named import bindings only. A Firestore client is a named export, so a default or\n *  namespace import can't name one — the same reasoning the Server Action stitch uses. */\nfunction namedImportBindings(root: Parser.SyntaxNode): NamedBinding[] {\n  const out: NamedBinding[] = []\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'import_statement') {\n      const src = node.childForFieldName('source')\n      const specifier = src ? src.text.slice(1, -1) : ''\n      if (specifier.length > 0) {\n        const stack: Parser.SyntaxNode[] = [node]\n        while (stack.length > 0) {\n          const n = stack.pop()!\n          if (n.type === 'import_specifier') {\n            const nameNode = n.childForFieldName('name')\n            const aliasNode = n.childForFieldName('alias')\n            const importedName = nameNode?.text\n            if (importedName) {\n              out.push({ local: aliasNode?.text ?? importedName, imported: importedName, specifier })\n            }\n            continue\n          }\n          for (const c of namedChildren(n)) stack.push(c)\n        }\n      }\n    }\n    for (const c of namedChildren(node)) walk(c)\n  }\n  walk(root)\n  return out\n}\n\nfunction sdkOf(content: string): SdkWrite | null {\n  const hasClient = FIRESTORE_CLIENT_IMPORT_RE.test(content)\n  const hasAdmin = FIRESTORE_ADMIN_IMPORT_RE.test(content)\n  return hasClient && !hasAdmin ? 'client' : hasAdmin && !hasClient ? 'admin' : null\n}\n\nfunction parseOrNull(file: SourceFile): Parser.SyntaxNode | null {\n  const ext = path.extname(file.path)\n  if (!(ext in GRAMMAR_BY_EXT)) return null\n  try {\n    return parseSource(parserForExt(ext), file.content).rootNode\n  } catch {\n    return null\n  }\n}\n\n/**\n * Attribute a Firestore call to a client imported from another module in the same service.\n * Returns endpoints only for files the per-file pass could not already claim on its own, so\n * a file holding both its own client and an imported one isn't walked twice.\n */\nexport async function firestoreCrossFileEndpoints(\n  files: SourceFile[],\n  serviceDir: string,\n): Promise<ExternalEndpoint[]> {\n  // Registry: service-relative posix path → the client names that module exports.\n  const registry = new Map<string, { names: Set<string>; sdk: SdkWrite | null }>()\n  for (const f of files) {\n    if (sdkOf(f.content) === null && !FIRESTORE_CLIENT_IMPORT_RE.test(f.content)) continue\n    const root = parseOrNull(f)\n    if (!root) continue\n    const names = exportedFirestoreClients(root)\n    if (names.size === 0) continue\n    registry.set(toPosix(path.relative(serviceDir, f.path)), { names, sdk: sdkOf(f.content) })\n  }\n  if (registry.size === 0) return []\n\n  const out: ExternalEndpoint[] = []\n  for (const f of files) {\n    const root = parseOrNull(f)\n    if (!root) continue\n    // Files that construct their own client are already fully covered per-file.\n    if (firestoreClientVars(root).size > 0) continue\n    const bindings = namedImportBindings(root)\n    if (bindings.length === 0) continue\n\n    const names = new Set<string>()\n    let sdk: SdkWrite | null = null\n    for (const b of bindings) {\n      const rel = await resolveJsImport(b.specifier, path.dirname(f.path), serviceDir, null)\n      if (!rel) continue\n      const entry = registry.get(rel)\n      if (!entry || !entry.names.has(b.imported)) continue\n      names.add(b.local)\n      sdk ??= entry.sdk\n    }\n    if (names.size === 0) continue\n    out.push(...firestoreEndpointsFromFile(f, serviceDir, { names, sdk }))\n  }\n  return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { resolveJsImport } from '../imports.js'\nimport { lineOf, snippet, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// MongoDB collection call sites (ADR-147 in-file, ADR-149 cross-file). The\n// collection-grained analog of calls/supabase.ts: it names the collection a file\n// reads or writes so a production-observed mongodb operation (ADR-148 mints the\n// OBSERVED side from the driver's OTel spans) has a file-grained static twin to\n// fuse onto.\n//\n//   import mongoose from 'mongoose'\n//   const Order = mongoose.model('Order', orderSchema)   // → collection 'orders'\n//   const Log   = mongoose.model('Log', s, 'audit_logs') // → collection 'audit_logs'\n//\n//   import { MongoClient } from 'mongodb'\n//   db.collection('orders').insertOne(doc)               // → collection 'orders'\n//\n// A Mongoose query names a *model* (`Order`), not a collection; the collection\n// is derived. The derivation reuses Mongoose's own pluralizer VERBATIM (below)\n// because the real collection is named by it — `Goose` → `gooses`, not `geese`\n// — so our string matches the one the OBSERVED span carries. Fidelity is the\n// fusion key, not a nicety (ADR-147). The native-driver path is exact: the\n// collection is the string literal.\n//\n// The model is usually registered in `models/Order.js` and queried across\n// `routes/`, `services/` — so `mongooseCrossFileEndpoints` (ADR-149) resolves a\n// query binding to its defining file through the import graph imports.ts already\n// resolves, and names the collection at the *query* site too.\n\nconst MONGOOSE_IMPORT_RE = /(?:from\\s+['\"`]|require\\(\\s*['\"`])mongoose['\"`]/\nconst MONGODB_IMPORT_RE = /(?:from\\s+['\"`]|require\\(\\s*['\"`])mongodb['\"`]/\n\n// `mongoose.pluralize(null)` / `pluralize(false)` disables pluralization\n// globally — `toCollectionName` then returns the model name unchanged (case\n// preserved).\nconst PLURALIZE_DISABLED_RE = /\\bpluralize\\s*\\(\\s*(?:null|false)\\s*\\)/\n\nconst UNCOUNTABLES = new Set([\n  'advice', 'energy', 'excretion', 'digestion', 'cooperation', 'health', 'justice', 'labour',\n  'machinery', 'equipment', 'information', 'pollution', 'sewage', 'paper', 'money', 'species',\n  'series', 'rain', 'rice', 'fish', 'sheep', 'moose', 'deer', 'news', 'expertise', 'status', 'media',\n])\n\n// Ported verbatim from mongoose-legacy-pluralize@2.0.0 (byte-identical to\n// mongoose 9.x lib/helpers/pluralize.js). Ordered; the first matching rule wins.\n// Do not \"correct\" the quirks — an English-accurate pluralizer would produce\n// names Mongoose never generates and fuse onto nothing.\nconst PLURALIZE_RULES: ReadonlyArray<readonly [RegExp, string]> = [\n  [/human$/gi, 'humans'],\n  [/(m)an$/gi, '$1en'],\n  [/(pe)rson$/gi, '$1ople'],\n  [/(child)$/gi, '$1ren'],\n  [/^(ox)$/gi, '$1en'],\n  [/(ax|test)is$/gi, '$1es'],\n  [/(octop|vir)us$/gi, '$1i'],\n  [/(alias|status)$/gi, '$1es'],\n  [/(bu)s$/gi, '$1ses'],\n  [/(buffal|tomat|potat)o$/gi, '$1oes'],\n  [/([ti])um$/gi, '$1a'],\n  [/sis$/gi, 'ses'],\n  [/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'],\n  [/(hive)$/gi, '$1s'],\n  [/([^aeiouy]|qu)y$/gi, '$1ies'],\n  [/(x|ch|ss|sh)$/gi, '$1es'],\n  [/(matr|vert|ind)ix|ex$/gi, '$1ices'],\n  [/([m|l])ouse$/gi, '$1ice'],\n  [/(kn|w|l)ife$/gi, '$1ives'],\n  [/(quiz)$/gi, '$1zes'],\n  [/s$/gi, 's'],\n  [/([^a-z])$/, '$1'],\n  [/$/gi, 's'],\n]\n\nexport function pluralizeCollection(name: string): string {\n  const str = name.toLowerCase()\n  if (UNCOUNTABLES.has(str)) return str\n  for (const [re, repl] of PLURALIZE_RULES) {\n    if (str.match(re)) return str.replace(re, repl)\n  }\n  return str\n}\n\n// The Mongoose Model query/write methods (statics + instance) plus the pre-v7\n// names still common in older code. A `<binding>.<one-of-these>(` call is a\n// collection access. Used cross-file to attribute a query to its collection.\nconst MODEL_METHODS = [\n  'find', 'findOne', 'findById', 'findByIdAndUpdate', 'findByIdAndDelete', 'findOneAndUpdate',\n  'findOneAndDelete', 'findOneAndReplace', 'countDocuments', 'estimatedDocumentCount', 'distinct',\n  'aggregate', 'exists', 'where', 'populate', 'watch', 'hydrate', 'create', 'insertMany', 'insertOne',\n  'updateOne', 'updateMany', 'replaceOne', 'deleteOne', 'deleteMany', 'bulkWrite', 'bulkSave', 'save',\n  // pre-v7, removed in current mongoose but present in older codebases:\n  'count', 'update', 'remove', 'findOneAndRemove', 'findByIdAndRemove',\n]\nconst MODEL_METHODS_ALT = MODEL_METHODS.join('|')\n\nfunction schemaCollectionVars(content: string): Map<string, string> {\n  const out = new Map<string, string>()\n  const re = /(?:const|let|var)\\s+(\\w+)\\s*=\\s*new\\s+(?:mongoose\\s*\\.\\s*)?Schema\\s*\\(/g\n  let m: RegExpExecArray | null\n  while ((m = re.exec(content)) !== null) {\n    const windowText = content.slice(m.index, m.index + 2000)\n    const opt = /\\bcollection\\s*:\\s*['\"`]([\\w.-]+)['\"`]/.exec(windowText)\n    if (opt) out.set(m[1]!, opt[1]!)\n  }\n  return out\n}\n\ninterface Resolved {\n  name: string\n  kind: 'mongodb-collection' | 'mongodb-model'\n}\n\nfunction resolveModel(\n  modelName: string,\n  rest: string,\n  schemaColl: Map<string, string>,\n  pluralizeOn: boolean,\n): Resolved {\n  const trimmed = rest.trim()\n  const literalThird = /,\\s*['\"`]([\\w.-]+)['\"`]\\s*$/.exec(trimmed)\n  if (literalThird) return { name: literalThird[1]!, kind: 'mongodb-collection' }\n\n  const firstIdent = /^([A-Za-z_$][\\w$]*)/.exec(trimmed)?.[1]\n  if (firstIdent && schemaColl.has(firstIdent)) {\n    return { name: schemaColl.get(firstIdent)!, kind: 'mongodb-collection' }\n  }\n  if (/,\\s*[A-Za-z_$][\\w$]*\\s*$/.test(trimmed)) {\n    return { name: modelName, kind: 'mongodb-model' }\n  }\n  return { name: pluralizeOn ? pluralizeCollection(modelName) : modelName, kind: 'mongodb-collection' }\n}\n\ninterface ModelDef {\n  modelName: string\n  varName: string | null // the `const X =` the registration was assigned to, if any\n  resolved: Resolved\n  matchText: string\n}\n\n// Every `[const X = ][obj.]model('Name'[, schema[, 'coll']])` registration in a\n// file, with its resolved collection. Shared by the in-file emitter and the\n// cross-file registry.\nfunction collectModelDefs(content: string, pluralizeOn: boolean): ModelDef[] {\n  const schemaColl = schemaCollectionVars(content)\n  const out: ModelDef[] = []\n  const re =\n    /(?:(?:const|let|var)\\s+(\\w+)\\s*=\\s*)?(?:await\\s+)?(?:\\b\\w+\\s*\\.\\s*)?\\bmodel\\s*\\(\\s*['\"`]([\\w$]+)['\"`]\\s*(?:,\\s*([\\s\\S]{0,300}?))?\\)/g\n  let m: RegExpExecArray | null\n  while ((m = re.exec(content)) !== null) {\n    out.push({\n      modelName: m[2]!,\n      varName: m[1] ?? null,\n      resolved: resolveModel(m[2]!, m[3] ?? '', schemaColl, pluralizeOn),\n      matchText: m[0],\n    })\n  }\n  return out\n}\n\nfunction endpoint(\n  r: Resolved,\n  file: SourceFile,\n  serviceDir: string,\n  matchText: string,\n): ExternalEndpoint {\n  const line = lineOf(file.content, matchText)\n  return {\n    infraId: infraId(r.kind, r.name),\n    name: r.name,\n    kind: r.kind,\n    edgeType: 'CALLS',\n    confidenceKind: 'verified-call-site',\n    evidence: { file: path.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) },\n  }\n}\n\n// ── in-file (ADR-147) ──────────────────────────────────────────────────────\n\nexport function mongooseEndpointsFromFile(file: SourceFile, serviceDir: string): ExternalEndpoint[] {\n  const hasMongoose = MONGOOSE_IMPORT_RE.test(file.content)\n  const hasMongodb = MONGODB_IMPORT_RE.test(file.content)\n  if (!hasMongoose && !hasMongodb) return []\n\n  const content = file.content\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const push = (r: Resolved, matchText: string): void => {\n    const key = `${r.kind}/${r.name}`\n    if (seen.has(key)) return\n    seen.add(key)\n    out.push(endpoint(r, file, serviceDir, matchText))\n  }\n\n  if (hasMongoose) {\n    const pluralizeOn = !PLURALIZE_DISABLED_RE.test(content)\n    for (const def of collectModelDefs(content, pluralizeOn)) push(def.resolved, def.matchText)\n  }\n\n  // Native driver — `<db>.collection('orders')`. The literal is the collection.\n  const collRe = /\\.\\s*collection\\s*\\(\\s*['\"`]([\\w.$-]+)['\"`]\\s*\\)/g\n  let c: RegExpExecArray | null\n  while ((c = collRe.exec(content)) !== null) {\n    push({ name: c[1]!, kind: 'mongodb-collection' }, c[0])\n  }\n\n  return out\n}\n\n// ── cross-file (ADR-149) ───────────────────────────────────────────────────\n\n// A file's model exports: the collection reachable via each named export, and\n// via the default / whole-module export (`module.exports = Order`).\ninterface FileExports {\n  byName: Map<string, string>\n  default?: string\n}\n\n// A binding imported into a query file. `named` maps a local name to a specific\n// export; `default`/`whole`/`namespace` bind the module object itself.\ninterface ImportBinding {\n  local: string\n  kind: 'named' | 'default' | 'namespace' | 'whole'\n  exportName?: string\n  specifier: string\n}\n\nfunction parseDestructure(inner: string, specifier: string, out: ImportBinding[]): void {\n  for (const raw of inner.split(',')) {\n    const part = raw.trim()\n    if (!part) continue\n    const asM = /^(\\w+)\\s+as\\s+(\\w+)$/.exec(part) // ESM: A as C\n    const colonM = /^(\\w+)\\s*:\\s*(\\w+)$/.exec(part) // CJS: A: C\n    if (asM) out.push({ local: asM[2]!, kind: 'named', exportName: asM[1]!, specifier })\n    else if (colonM) out.push({ local: colonM[2]!, kind: 'named', exportName: colonM[1]!, specifier })\n    else {\n      const id = /^(\\w+)$/.exec(part)\n      if (id) out.push({ local: id[1]!, kind: 'named', exportName: id[1]!, specifier })\n    }\n  }\n}\n\nfunction parseImportBindings(content: string): ImportBinding[] {\n  const out: ImportBinding[] = []\n\n  const esm = /import\\s+([^;'\"`\\n]+?)\\s+from\\s*['\"`]([^'\"`]+)['\"`]/g\n  let m: RegExpExecArray | null\n  while ((m = esm.exec(content)) !== null) {\n    const clause = m[1]!.trim()\n    const spec = m[2]!\n    const ns = /^\\*\\s+as\\s+(\\w+)$/.exec(clause)\n    if (ns) {\n      out.push({ local: ns[1]!, kind: 'namespace', specifier: spec })\n      continue\n    }\n    const named = /\\{([^}]*)\\}/.exec(clause)\n    if (named) parseDestructure(named[1]!, spec, out)\n    const def = /^(\\w+)\\s*(?:,|$)/.exec(clause) // leading default binding, before any `{`\n    if (def && !clause.startsWith('{')) out.push({ local: def[1]!, kind: 'default', specifier: spec })\n  }\n\n  const cjs = /(?:const|let|var)\\s+(\\{[^}]*\\}|\\w+)\\s*=\\s*require\\(\\s*['\"`]([^'\"`]+)['\"`]\\s*\\)/g\n  while ((m = cjs.exec(content)) !== null) {\n    const lhs = m[1]!\n    const spec = m[2]!\n    if (lhs.startsWith('{')) parseDestructure(lhs.slice(1, -1), spec, out)\n    else out.push({ local: lhs, kind: 'whole', specifier: spec }) // require() default IS module.exports\n  }\n\n  return out\n}\n\n// A defining file's exports, keyed for both named and default/whole-module\n// import. `byName` treats every model var as a possible named export — valid\n// source can only import a name it actually exported, so a non-exported var is\n// never asked for. The default is the single-model file's model, or the one\n// named in `module.exports = X` / `export default X`.\nfunction fileExportsOf(content: string, pluralizeOn: boolean): FileExports | null {\n  const defs = collectModelDefs(content, pluralizeOn).filter((d) => d.resolved.kind === 'mongodb-collection')\n  if (defs.length === 0) return null\n\n  const byVar = new Map<string, string>()\n  for (const d of defs) if (d.varName) byVar.set(d.varName, d.resolved.name)\n\n  const byName = new Map(byVar)\n  let def: string | undefined\n\n  const named = /(?:module\\.exports|export\\s+default)\\s*=\\s*(\\w+)\\b/.exec(content)\n  if (named && byVar.has(named[1]!)) def = byVar.get(named[1]!)\n  if (!def) {\n    const inline =\n      /(?:module\\.exports|export\\s+default)\\s*=\\s*(?:await\\s+)?(?:\\w+\\s*\\.\\s*)?model\\s*\\(\\s*['\"`]([\\w$]+)['\"`]/.exec(content)\n    if (inline) def = pluralizeOn ? pluralizeCollection(inline[1]!) : inline[1]!\n  }\n  // Single-model file: a default/whole-module import binds to its one model.\n  if (!def && byVar.size === 1) def = [...byVar.values()][0]!\n\n  return { byName, ...(def ? { default: def } : {}) }\n}\n\n/**\n * Cross-file model→collection resolution (ADR-149). Names the collection at the\n * *query* site — `routes/orders.js` calling `Order.find()` on a model defined in\n * `models/Order.js` — by resolving the imported binding to its defining file\n * through the same import resolution `imports.ts` uses, then attributing the\n * query methods on that binding. Emits onto the same `mongodb-collection` node\n * the in-file and observed paths use, so all three fuse.\n *\n * `files` should be the same masked (comment-stripped) SourceFiles the per-file\n * pass sees. Returns endpoints whose evidence points at the query site.\n */\nexport async function mongooseCrossFileEndpoints(\n  files: SourceFile[],\n  serviceDir: string,\n): Promise<ExternalEndpoint[]> {\n  const mongooseFiles = files.filter((f) => MONGOOSE_IMPORT_RE.test(f.content))\n  if (mongooseFiles.length === 0) return []\n\n  // A single `pluralize(null)` anywhere flips derivation for the whole service.\n  const pluralizeOn = !files.some((f) => PLURALIZE_DISABLED_RE.test(f.content))\n\n  // Registry: service-relative posix path → its model exports.\n  const registry = new Map<string, FileExports>()\n  for (const f of mongooseFiles) {\n    const fx = fileExportsOf(f.content, pluralizeOn)\n    if (fx) registry.set(toPosix(path.relative(serviceDir, f.path)), fx)\n  }\n  if (registry.size === 0) return []\n\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n\n  for (const f of files) {\n    const bindings = parseImportBindings(f.content)\n    if (bindings.length === 0) continue\n\n    // Bindings that ARE a model (named/default import) → `local.method()`.\n    const directColl = new Map<string, string>()\n    // Whole-module / namespace bindings → `local.Export.method()`.\n    const nsExports = new Map<string, FileExports>()\n\n    for (const b of bindings) {\n      const resolvedRel = await resolveJsImport(b.specifier, path.dirname(f.path), serviceDir, null)\n      if (!resolvedRel) continue\n      const fx = registry.get(resolvedRel)\n      if (!fx) continue\n      if (b.kind === 'named' && b.exportName) {\n        const coll = fx.byName.get(b.exportName)\n        if (coll) directColl.set(b.local, coll)\n      } else if (b.kind === 'default') {\n        if (fx.default) directColl.set(b.local, fx.default)\n      } else {\n        // whole (require) or namespace — could be the model itself or the module object.\n        if (fx.default) directColl.set(b.local, fx.default)\n        nsExports.set(b.local, fx)\n      }\n    }\n    if (directColl.size === 0 && nsExports.size === 0) continue\n\n    // A binding defined *in this file* is the in-file pass's job — don't double-count.\n    const localDefs = new Set(\n      collectModelDefs(f.content, pluralizeOn)\n        .map((d) => d.varName)\n        .filter((v): v is string => v !== null),\n    )\n\n    const emit = (collection: string, matchText: string): void => {\n      const key = `${f.path}::${collection}`\n      if (seen.has(key)) return\n      seen.add(key)\n      out.push(endpoint({ name: collection, kind: 'mongodb-collection' }, f, serviceDir, matchText))\n    }\n\n    for (const [local, collection] of directColl) {\n      if (localDefs.has(local)) continue\n      const qre = new RegExp(`\\\\b${local}\\\\s*\\\\.\\\\s*(?:${MODEL_METHODS_ALT})\\\\s*\\\\(`, 'g')\n      let qm: RegExpExecArray | null\n      while ((qm = qre.exec(f.content)) !== null) emit(collection, qm[0])\n    }\n    for (const [local, fx] of nsExports) {\n      const qre = new RegExp(`\\\\b${local}\\\\s*\\\\.\\\\s*(\\\\w+)\\\\s*\\\\.\\\\s*(?:${MODEL_METHODS_ALT})\\\\s*\\\\(`, 'g')\n      let qm: RegExpExecArray | null\n      while ((qm = qre.exec(f.content)) !== null) {\n        const coll = fx.byName.get(qm[1]!)\n        if (coll) emit(coll, qm[0])\n      }\n    }\n  }\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Python from 'tree-sitter-python'\nimport { infraId } from '@neat.is/types'\nimport { snippet, type ExternalEndpoint, type SourceFile, type TableReference } from './shared.js'\n\n// SQLAlchemy / Flask-SQLAlchemy table call sites (ADR-151, ADR-152). The SQL\n// analog of calls/mongoose.ts: it names the table a model maps to, so a\n// production SQLAlchemy query — whose OBSERVED table NEAT recovers by parsing the\n// `db.statement` SQL (the instrumentation emits no table attribute, ADR-152) —\n// has a file-grained static twin to fuse onto at `infra:sql-table:<name>`.\n//\n// The table name is the fusion key, derived VERBATIM the way the ORM derives it\n// so the static string matches the table the running query hits:\n//   - plain SQLAlchemy declarative:  __tablename__ = 'orders'   (explicit, required)\n//   - Flask-SQLAlchemy (no __tablename__):  camel_to_snake_case(ClassName)\n//       class UserProfile(db.Model): ...   → 'user_profile'\n//   - native Core:  Table('orders', metadata, ...)   → the string literal\n\nconst SQLALCHEMY_IMPORT_RE = /(?:from|import)\\s+(?:flask_sqlalchemy|sqlalchemy)\\b/\n\nconst PARSE_CHUNK = 16384\n\nfunction makePyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Python)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\n// Verbatim port of flask_sqlalchemy's `camel_to_snake_case` (model.py, v3.x):\n//   re.sub(r\"((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))\", r\"_\\1\", name).lower().lstrip(\"_\")\n// Reproduced byte-for-byte so a derived table matches the one Flask-SQLAlchemy\n// actually creates — `UserProfile` → `user_profile`, `HTTPRequest` →\n// `http_request`, `OAuth2Token` → `o_auth2_token`. Do not \"improve\" it: an\n// English-nicer version would name a table the ORM never created and fuse onto\n// nothing (the same fidelity rule the Mongoose pluralizer follows).\nexport function flaskSqlalchemyTableName(className: string): string {\n  return className\n    .replace(/((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))/g, '_$1')\n    .toLowerCase()\n    .replace(/^_+/, '')\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\nfunction pyStaticStringText(node: Parser.SyntaxNode): string | null {\n  if (node.type !== 'string') return null\n  for (const child of namedChildren(node)) {\n    if (child.type === 'interpolation') return null // f-string — not a static literal\n    if (child.type === 'string_content') return child.text\n  }\n  return ''\n}\n\n// The explicit `__tablename__ = 'x'` in a class body: its literal name, `'computed'`\n// when it's assigned a non-literal (never guessed), or null when absent.\nfunction explicitTablename(body: Parser.SyntaxNode): { name: string } | 'computed' | null {\n  for (const stmt of namedChildren(body)) {\n    if (stmt.type !== 'expression_statement') continue\n    const assign = stmt.namedChild(0)\n    if (assign?.type !== 'assignment') continue\n    if (assign.childForFieldName('left')?.text !== '__tablename__') continue\n    const right = assign.childForFieldName('right')\n    if (right?.type === 'string') {\n      const s = pyStaticStringText(right)\n      return s ? { name: s } : 'computed'\n    }\n    return 'computed'\n  }\n  return null\n}\n\n// A Flask-SQLAlchemy model derives its table from the class name when it has no\n// `__tablename__` — recognised by a `db.Model` / `Model` base class.\nfunction extendsFlaskModel(cls: Parser.SyntaxNode): boolean {\n  const supers = cls.childForFieldName('superclasses')\n  if (!supers) return false\n  for (const a of namedChildren(supers)) {\n    const t = a.text\n    if (t === 'db.Model' || t === 'Model' || t.endsWith('.Model')) return true\n  }\n  return false\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of namedChildren(node)) walk(c, visit)\n}\n\n// ── declared columns off a SQLAlchemy model body (ADR-157 §3) ────────────────\n\n// The bare builder name a `Column(...)` / `mapped_column(...)` call resolves to,\n// tolerating a `db.` / `sa.` / `orm.` qualifier. Anything else (a `relationship`,\n// a plain value) is not a column.\nconst COLUMN_BUILDERS = new Set(['Column', 'mapped_column'])\nfunction isColumnBuilder(call: Parser.SyntaxNode): boolean {\n  const fn = call.childForFieldName('function')\n  const t = fn?.text\n  if (!t) return false\n  const base = t.includes('.') ? t.slice(t.lastIndexOf('.') + 1) : t\n  return COLUMN_BUILDERS.has(base)\n}\n\n// The first positional argument of a call as a static string, or null when the\n// first positional argument is not a plain string literal (a type like `Integer`)\n// — so the caller falls back to the attribute name.\nfunction firstPositionalString(call: Parser.SyntaxNode): string | null {\n  const args = call.childForFieldName('arguments')\n  if (!args) return null\n  for (const arg of namedChildren(args)) {\n    if (arg.type === 'keyword_argument') continue\n    return arg.type === 'string' ? pyStaticStringText(arg) : null\n  }\n  return null\n}\n\n// The DB columns a declarative model body declares. For each `x = Column(...)` /\n// `x: Mapped[..] = mapped_column(...)` assignment, the column name is the explicit\n// first-string argument where given (`Column('total_amount', Integer)` →\n// `total_amount`), else the attribute name itself — SQLAlchemy's own rule, where\n// the attribute name IS the column name (ADR-157 §3). Non-Column assignments\n// (`__tablename__`, `relationship(...)`) are skipped, and a computed / non-string\n// explicit name is left unclaimed rather than guessed.\nfunction columnsFromClassBody(body: Parser.SyntaxNode): string[] {\n  const out: string[] = []\n  const seen = new Set<string>()\n  for (const stmt of namedChildren(body)) {\n    if (stmt.type !== 'expression_statement') continue\n    const assign = stmt.namedChild(0)\n    if (assign?.type !== 'assignment') continue\n    const left = assign.childForFieldName('left')\n    if (left?.type !== 'identifier') continue\n    const right = assign.childForFieldName('right')\n    if (right?.type !== 'call' || !isColumnBuilder(right)) continue\n    const name = firstPositionalString(right) ?? left.text\n    if (name && !seen.has(name)) {\n      seen.add(name)\n      out.push(name)\n    }\n  }\n  return out\n}\n\n// ── foreign-key table→table references (ADR-161) ─────────────────────────────\n//\n// SQLAlchemy names a FK by the DATABASE table directly: `ForeignKey('users.id')`\n// — the string is `<table>.<column>` (or `<schema>.<table>.<column>`), so the\n// parent table is the segment before the last dot, already at DB-name fidelity\n// (no code-model translation needed, unlike Drizzle/Prisma). The child is the\n// enclosing model's `__tablename__` / Flask-derived table, the same table the\n// column read (ADR-157 §3) lands on. A non-string `ForeignKey(User.id)` (a mapped\n// attribute) is left unclaimed — resolving the class→table there is a follow-on.\n\n// The parent DB table a `ForeignKey('users.id')` names, tolerating a `db.` / `sa.`\n// / `sqlalchemy.` qualifier on the call. Null for a non-string / bare argument.\nfunction foreignKeyParentTable(call: Parser.SyntaxNode): string | null {\n  const fn = call.childForFieldName('function')\n  const t = fn?.text\n  if (!t) return null\n  const base = t.includes('.') ? t.slice(t.lastIndexOf('.') + 1) : t\n  if (base !== 'ForeignKey') return null\n  const target = firstPositionalString(call)\n  if (!target) return null\n  const parts = target.split('.')\n  if (parts.length < 2) return null // needs at least `<table>.<column>`\n  return parts[parts.length - 2]! // `users.id` → users; `public.users.id` → users\n}\n\nexport function sqlalchemyForeignKeys(\n  file: SourceFile,\n  serviceDir: string,\n): TableReference[] {\n  if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(makePyParser(), file.content)\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class_definition') return\n    const body = node.childForFieldName('body')\n    const nameNode = node.childForFieldName('name')\n    if (!body || !nameNode) return\n    const explicit = explicitTablename(body)\n    if (explicit === 'computed') return // named but not a literal — never guess\n    let childTable: string | null = null\n    if (explicit) childTable = explicit.name\n    else if (extendsFlaskModel(node)) childTable = flaskSqlalchemyTableName(nameNode.text)\n    if (!childTable) return\n\n    walk(body, (n) => {\n      if (n.type !== 'call') return\n      const parentTable = foreignKeyParentTable(n)\n      if (!parentTable) return\n      const key = `${childTable}->${parentTable}`\n      if (seen.has(key)) return\n      seen.add(key)\n      const line = n.startPosition.row + 1\n      out.push({\n        childTable: childTable!,\n        parentTable,\n        evidence: {\n          file: path.relative(serviceDir, file.path),\n          line,\n          snippet: snippet(file.content, line),\n        },\n      })\n    })\n  })\n\n  return out\n}\n\nexport function sqlalchemyEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (!SQLALCHEMY_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(makePyParser(), file.content)\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const push = (name: string, line: number, columns?: string[]): void => {\n    if (seen.has(name)) return\n    seen.add(name)\n    out.push({\n      infraId: infraId('sql-table', name),\n      name,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'verified-call-site',\n      ...(columns && columns.length > 0 ? { columns } : {}),\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  walk(tree.rootNode, (node) => {\n    if (node.type === 'class_definition') {\n      const body = node.childForFieldName('body')\n      const nameNode = node.childForFieldName('name')\n      if (!body || !nameNode) return\n      const line = node.startPosition.row + 1\n      const explicit = explicitTablename(body)\n      if (explicit === 'computed') return // named but not a literal — never guess\n      // Declared columns off the model body — the DB name at attribute grain.\n      const columns = columnsFromClassBody(body)\n      if (explicit) {\n        push(explicit.name, line, columns)\n        return\n      }\n      // No __tablename__: Flask-SQLAlchemy derives the table from the class name.\n      if (extendsFlaskModel(node)) push(flaskSqlalchemyTableName(nameNode.text), line, columns)\n      return\n    }\n    // Native Core: `Table('orders', metadata, ...)` — the first positional string.\n    if (node.type === 'call') {\n      const fn = node.childForFieldName('function')\n      const fnText = fn?.text\n      if (fnText !== 'Table' && fnText !== 'sa.Table' && fnText !== 'sqlalchemy.Table') return\n      const first = node.childForFieldName('arguments')?.namedChild(0)\n      if (first?.type === 'string') {\n        const s = pyStaticStringText(first)\n        if (s) push(s, node.startPosition.row + 1)\n      }\n    }\n  })\n\n  return out\n}\n\n// ── cross-file model→table query attribution (ADR-149 analog) ────────────────\n\n// A model class name → its table, service-wide (SQLAlchemy + Flask-SQLAlchemy). A\n// name defined in two files with different tables is dropped — ambiguous, never\n// guessed (the ADR-147 discipline).\nfunction buildSqlalchemyModelRegistry(files: SourceFile[]): Map<string, string> {\n  const table = new Map<string, string>()\n  const ambiguous = new Set<string>()\n  const parser = makePyParser()\n  for (const file of files) {\n    if (!SQLALCHEMY_IMPORT_RE.test(file.content)) continue\n    const tree = parseSource(parser, file.content)\n    walk(tree.rootNode, (node) => {\n      if (node.type !== 'class_definition') return\n      const nameNode = node.childForFieldName('name')\n      const body = node.childForFieldName('body')\n      if (!nameNode || !body) return\n      const explicit = explicitTablename(body)\n      if (explicit === 'computed') return\n      let t: string | null = null\n      if (explicit) t = explicit.name\n      else if (extendsFlaskModel(node)) t = flaskSqlalchemyTableName(nameNode.text)\n      if (!t) return\n      const cls = nameNode.text\n      if (table.has(cls) && table.get(cls) !== t) ambiguous.add(cls)\n      else table.set(cls, t)\n    })\n  }\n  for (const a of ambiguous) table.delete(a)\n  return table\n}\n\n// The model class names a file queries: `session.query(X)` / `db.session.query(X)`\n// / `select(X)` / `session.get(X, …)` (the first argument), and `X.query`\n// (Flask-SQLAlchemy, the object). A non-model receiver (`session.query`) is\n// filtered downstream by the registry.\nfunction queryClassSites(root: Parser.SyntaxNode): { cls: string; line: number }[] {\n  const out: { cls: string; line: number }[] = []\n  walk(root, (node) => {\n    if (node.type === 'call') {\n      const fn = node.childForFieldName('function')\n      const isQueryCall =\n        (fn?.type === 'attribute' &&\n          (fn.childForFieldName('attribute')?.text === 'query' ||\n            fn.childForFieldName('attribute')?.text === 'get')) ||\n        (fn?.type === 'identifier' && fn.text === 'select')\n      if (isQueryCall) {\n        const arg = node.childForFieldName('arguments')?.namedChild(0)\n        if (arg?.type === 'identifier') out.push({ cls: arg.text, line: node.startPosition.row + 1 })\n      }\n    }\n    if (node.type === 'attribute') {\n      const obj = node.childForFieldName('object')\n      if (node.childForFieldName('attribute')?.text === 'query' && obj?.type === 'identifier') {\n        out.push({ cls: obj.text, line: node.startPosition.row + 1 })\n      }\n    }\n  })\n  return out\n}\n\n// Does a file import this name — so a query on it references a model defined\n// elsewhere? Bounds the attribution to a real cross-file reference (the in-file\n// case is already the definition-site edge).\nfunction importsModelName(content: string, name: string): boolean {\n  return new RegExp(`\\\\bimport\\\\b[^\\\\n]*\\\\b${name}\\\\b`).test(content)\n}\n\n// Attribute a cross-file query to its table at the *query* site: a file that runs\n// `session.query(Order)` on an `Order` model defined and imported from another\n// file gets the `file → sql-table:<name>` edge, so the code that actually reads\n// the table is named — not only the model-definition file. A computed model, or\n// a query on a locally-defined model (already the definition-site edge), is not\n// re-emitted here.\nexport function pythonOrmCrossFileEndpoints(\n  files: SourceFile[],\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const registry = buildSqlalchemyModelRegistry(files)\n  if (registry.size === 0) return []\n  const parser = makePyParser()\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  for (const file of files) {\n    if (!SQLALCHEMY_IMPORT_RE.test(file.content)) continue\n    const tree = parseSource(parser, file.content)\n    for (const { cls, line } of queryClassSites(tree.rootNode)) {\n      const t = registry.get(cls)\n      if (!t) continue\n      if (!importsModelName(file.content, cls)) continue // cross-file (imported) only\n      const key = `${file.path}::${t}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      out.push({\n        infraId: infraId('sql-table', t),\n        name: t,\n        kind: 'sql-table',\n        edgeType: 'CALLS',\n        confidenceKind: 'verified-call-site',\n        evidence: {\n          file: path.relative(serviceDir, file.path),\n          line,\n          snippet: snippet(file.content, line),\n        },\n      })\n    }\n  }\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Python from 'tree-sitter-python'\nimport { infraId } from '@neat.is/types'\nimport { snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Raw TCP socket dependencies in Python: `socket.socket(...)` paired with a\n// `<sock>.connect((host, port))`. Frameworked clients have their own recognizers\n// (gRPC stubs, `redis://` URLs, SQLAlchemy models, ...); this catches the bare-socket\n// dependency those miss — a service that speaks a custom line protocol to a datastore\n// over `socket.connect((host, port))`, which otherwise leaves NO EXTRACTED edge at all,\n// so a runtime connection-refused on that hop has no static twin to fuse onto and the\n// dependency is invisible past the last instrumented call.\n//\n// Precision — gated on both `import socket` AND a `socket.socket(...)` constructor in\n// the file, then only a `.connect(...)` whose single positional argument is a 2-element\n// address TUPLE. That tuple is socket.connect's distinctive signature: a DB driver or\n// ORM `.connect()` takes a URL or keyword arguments, never a bare `(host, port)` pair,\n// so the tuple shape is what separates a real socket connect from an unrelated\n// `.connect()` method call.\n//\n// Target naming honors \"evidence is never fabricated\": a string-literal host resolves\n// to a named `infra:socket:<host>[:<port>]` endpoint; a non-literal host — a variable or\n// env-driven address, e.g. `s.connect((host, port))` where `host` came from\n// `os.environ` — is not guessed, it lands on a stable `infra:socket:env` sentinel, the\n// same honest-sentinel discipline calls/supabase.ts uses for `process.env`-driven URLs.\n// Resolving an env-var name or its .env value to the concrete host is a follow-on.\n\nconst SOCKET_IMPORT_RE = /(?:^|\\n)\\s*(?:import\\s+socket\\b|from\\s+socket\\s+import\\b)/\n\nconst PARSE_CHUNK = 16384\n\nfunction makePyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Python)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of namedChildren(node)) walk(c, visit)\n}\n\nfunction pyStaticStringText(node: Parser.SyntaxNode): string | null {\n  if (node.type !== 'string') return null\n  for (const child of namedChildren(node)) {\n    if (child.type === 'interpolation') return null // f-string — not a static literal\n    if (child.type === 'string_content') return child.text\n  }\n  return ''\n}\n\n// The file constructs a raw socket: `socket.socket(...)`, or a `from socket import\n// socket` then a bare `socket(...)`. This gate keeps a `.connect(tuple)` on some other\n// object from ever being read as a socket connect.\nfunction hasSocketConstructor(root: Parser.SyntaxNode): boolean {\n  let found = false\n  walk(root, (n) => {\n    if (found || n.type !== 'call') return\n    const t = n.childForFieldName('function')?.text\n    if (t === 'socket.socket' || t === 'socket') found = true\n  })\n  return found\n}\n\nexport function socketEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (!SOCKET_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(makePyParser(), file.content)\n  if (!hasSocketConstructor(tree.rootNode)) return []\n\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'attribute' || fn.childForFieldName('attribute')?.text !== 'connect') return\n    const args = node.childForFieldName('arguments')\n    const first = args ? namedChildren(args).find((a) => a.type !== 'keyword_argument') : undefined\n    // socket.connect's one positional argument is the address TUPLE `(host, port)` —\n    // the discriminator that separates it from an unrelated `.connect()`.\n    if (!first || first.type !== 'tuple') return\n    const elems = namedChildren(first)\n    if (elems.length < 2) return\n\n    const hostNode = elems[0]!\n    const host = hostNode.type === 'string' ? pyStaticStringText(hostNode) : null\n    const portNode = elems[1]!\n    const port = portNode.type === 'integer' ? portNode.text : null\n    // Literal host → named endpoint; non-literal (variable / env-driven) → honest\n    // sentinel, never a guessed host.\n    const name = host ? (port ? `${host}:${port}` : host) : 'env'\n    if (seen.has(name)) return\n    seen.add(name)\n\n    const line = node.startPosition.row + 1\n    out.push({\n      infraId: infraId('socket', name),\n      name,\n      kind: 'socket',\n      edgeType: 'CALLS',\n      // A verified `socket.socket(...)` + `.connect((host, port))` call site.\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  })\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Python from 'tree-sitter-python'\nimport { infraId } from '@neat.is/types'\nimport { snippet, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Django ORM table call sites (ADR-151). A Django model maps to a table named\n// `<app_label>_<lowercased-model>` unless `Meta.db_table` overrides it; the\n// app_label defaults to the model file's app package (its parent directory),\n// overridable by `Meta.app_label`. This is Django's naming reproduced verbatim —\n// the fusion key, the same discipline the Mongoose pluralizer follows.\n//\n// It emits the same `infra:sql-table:<name>` node the SQLAlchemy extractor and\n// the OBSERVED `db.statement` parse (ADR-152) use, so a declared Django model and\n// the runtime query that hits its table fuse onto one node.\n\nconst DJANGO_IMPORT_RE = /(?:from|import)\\s+django\\b/\nconst PARSE_CHUNK = 16384\n\nfunction makePyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Python)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\nfunction pyStaticStringText(node: Parser.SyntaxNode): string | null {\n  if (node.type !== 'string') return null\n  for (const c of namedChildren(node)) {\n    if (c.type === 'interpolation') return null\n    if (c.type === 'string_content') return c.text\n  }\n  return ''\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of namedChildren(node)) walk(c, visit)\n}\n\nfunction extendsDjangoModel(cls: Parser.SyntaxNode): boolean {\n  const supers = cls.childForFieldName('superclasses')\n  if (!supers) return false\n  for (const a of namedChildren(supers)) {\n    const t = a.text\n    if (t === 'models.Model' || t === 'Model' || t.endsWith('.Model')) return true\n  }\n  return false\n}\n\n// Read `Meta.db_table` / `Meta.app_label` off a model class body (both literal).\nfunction readMeta(body: Parser.SyntaxNode): { dbTable?: string; appLabel?: string } {\n  const out: { dbTable?: string; appLabel?: string } = {}\n  for (const stmt of namedChildren(body)) {\n    if (stmt.type !== 'class_definition') continue\n    if (stmt.childForFieldName('name')?.text !== 'Meta') continue\n    const metaBody = stmt.childForFieldName('body')\n    if (!metaBody) continue\n    for (const ms of namedChildren(metaBody)) {\n      if (ms.type !== 'expression_statement') continue\n      const a = ms.namedChild(0)\n      if (a?.type !== 'assignment') continue\n      const l = a.childForFieldName('left')?.text\n      const r = a.childForFieldName('right')\n      if (r?.type !== 'string') continue\n      if (l === 'db_table') out.dbTable = pyStaticStringText(r) ?? undefined\n      if (l === 'app_label') out.appLabel = pyStaticStringText(r) ?? undefined\n    }\n  }\n  return out\n}\n\nexport function djangoOrmEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (!DJANGO_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(makePyParser(), file.content)\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  // The app_label defaults to the model file's app package — its parent directory.\n  const defaultAppLabel = path.basename(path.dirname(file.path))\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class_definition') return\n    if (!extendsDjangoModel(node)) return\n    const nameNode = node.childForFieldName('name')\n    const body = node.childForFieldName('body')\n    if (!nameNode || !body) return\n    const meta = readMeta(body)\n    const table = meta.dbTable ?? `${meta.appLabel ?? defaultAppLabel}_${nameNode.text.toLowerCase()}`\n    if (seen.has(table)) return\n    seen.add(table)\n    const line = node.startPosition.row + 1\n    out.push({\n      infraId: infraId('sql-table', table),\n      name: table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'verified-call-site',\n      evidence: { file: path.relative(serviceDir, file.path), line, snippet: snippet(file.content, line) },\n    })\n  })\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport { infraId } from '@neat.is/types'\nimport { GRAMMAR_BY_EXT, parseSource } from '../symbols.js'\nimport { snippet, type ExternalEndpoint, type SourceFile, type TableReference } from './shared.js'\n\n// Drizzle schema table + column recognizer (ADR-152 table, ADR-157 §3 columns).\n// The declared side of column grain: it names the table a `pgTable('orders',\n// { … })` (mysqlTable / sqliteTable) declares AND the columns inside it, so a\n// production query — whose OBSERVED table + columns NEAT recovers by parsing\n// `db.statement` (ADR-152 / ADR-157 §2) — has a static twin to fuse onto at\n// `infra:sql-table:<name>`.\n//\n//   import { pgTable, integer, text } from 'drizzle-orm/pg-core'\n//   export const orders = pgTable('orders', {\n//     id: serial('id').primaryKey(),\n//     userId: integer('user_id'),\n//     total: integer(),\n//     status: text('status'),\n//   })\n//\n// The table name is the first string literal. Each COLUMN name is derived the way\n// Drizzle names the DB column, because that string — not the JS field name — is\n// the fusion key the running query carries (ADR-157 §3, the load-bearing rule):\n//   - the explicit column-builder name wins:  integer('user_id')  → user_id\n//   - the object key is Drizzle's own fallback when the builder is given no\n//     name:                                    total: integer()   → total\n// Reading the key alone would name `userId` where production writes `user_id` and\n// fuse onto nothing — the same fidelity rule the Mongoose pluralizer (ADR-147) and\n// the Flask table-name port (ADR-152) follow. A computed / interpolated name is\n// left unclaimed rather than guessed.\n\nconst DRIZZLE_IMPORT_RE = /drizzle-orm/\nconst TABLE_BUILDERS = new Set(['pgTable', 'mysqlTable', 'sqliteTable'])\n\nfunction parserForExt(ext: string): Parser {\n  const p = new Parser()\n  p.setLanguage(GRAMMAR_BY_EXT[ext] ?? JavaScript)\n  return p\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\n// The literal text inside a `string` node (quotes stripped). Null for a template\n// / interpolated string — never guessed at.\nfunction stringLiteralText(node: Parser.SyntaxNode | null): string | null {\n  if (!node || node.type !== 'string') return null\n  for (const child of namedChildren(node)) {\n    if (child.type === 'string_fragment') return child.text\n  }\n  return '' // an empty '' literal has no string_fragment child\n}\n\n// The first positional string argument of a call, or null when the first\n// argument is not a plain string literal (so the caller falls back to the key).\nfunction firstStringArg(call: Parser.SyntaxNode): string | null {\n  const args = call.childForFieldName('arguments')\n  if (!args) return null\n  for (const arg of namedChildren(args)) {\n    if (arg.type === 'string') return stringLiteralText(arg)\n    // Stop at the first positional arg — a non-string first arg means no name.\n    return null\n  }\n  return null\n}\n\n// The DB column name a Drizzle column value declares. Walks to the head builder\n// call at the base of a `.primaryKey().notNull()` chain and reads its first\n// string argument (the explicit column name). Null when the builder is given no\n// name, so the caller falls back to the object key — exactly as Drizzle does.\nfunction builderColumnName(value: Parser.SyntaxNode): string | null {\n  let node: Parser.SyntaxNode | null = value\n  while (node) {\n    if (node.type === 'call_expression') {\n      const fn = node.childForFieldName('function')\n      if (fn?.type === 'identifier') return firstStringArg(node)\n      if (fn?.type === 'member_expression') {\n        node = fn.childForFieldName('object')\n        continue\n      }\n      return null\n    }\n    if (node.type === 'member_expression') {\n      node = node.childForFieldName('object')\n      continue\n    }\n    return null\n  }\n  return null\n}\n\n// A pair key → its column-name string (a bare `total:` or a quoted `'total':`).\nfunction keyName(key: Parser.SyntaxNode | null): string | null {\n  if (!key) return null\n  if (key.type === 'property_identifier') return key.text\n  if (key.type === 'string') return stringLiteralText(key)\n  return null\n}\n\n// The columns declared in a pgTable's second-argument object. Reads each `pair`,\n// preferring the builder's explicit name over the object key, and skips spreads /\n// computed keys rather than guessing.\nfunction columnsFromObject(obj: Parser.SyntaxNode): string[] {\n  const out: string[] = []\n  const seen = new Set<string>()\n  for (const child of namedChildren(obj)) {\n    if (child.type !== 'pair') continue\n    const value = child.childForFieldName('value')\n    const key = keyName(child.childForFieldName('key'))\n    const name = (value ? builderColumnName(value) : null) ?? key\n    if (name && !seen.has(name)) {\n      seen.add(name)\n      out.push(name)\n    }\n  }\n  return out\n}\n\nexport function drizzleEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (!DRIZZLE_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(parserForExt(path.extname(file.path)), file.content)\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'call_expression') {\n      const fn = node.childForFieldName('function')\n      if (fn?.type === 'identifier' && TABLE_BUILDERS.has(fn.text)) {\n        const args = node.childForFieldName('arguments')\n        const argNodes = args ? namedChildren(args) : []\n        const tableName = stringLiteralText(argNodes[0] ?? null)\n        const obj = argNodes[1]\n        if (tableName && obj?.type === 'object' && !seen.has(tableName)) {\n          seen.add(tableName)\n          const columns = columnsFromObject(obj)\n          const line = node.startPosition.row + 1\n          out.push({\n            infraId: infraId('sql-table', tableName),\n            name: tableName,\n            kind: 'sql-table',\n            edgeType: 'CALLS',\n            confidenceKind: 'structural',\n            columns,\n            evidence: {\n              file: path.relative(serviceDir, file.path),\n              line,\n              snippet: snippet(file.content, line),\n            },\n          })\n        }\n      }\n    }\n    for (const c of namedChildren(node)) walk(c)\n  }\n\n  walk(tree.rootNode)\n  return out\n}\n\n// ── foreign-key table→table references (ADR-161) ─────────────────────────────\n//\n// Drizzle declares a FK inline on the column: `.references(() => users.id)`. The\n// referenced `users` is the schema *variable*, so the DB parent-table name is the\n// variable's own `pgTable('...')` first-string argument, NOT the variable name —\n// `export const appUsers = pgTable('app_users', …)` referenced as\n// `.references(() => appUsers.id)` is a FK onto `app_users`. Resolving through the\n// in-file variable→table map keeps the parent at DB-name fidelity, the same\n// fusion key the column/table read (ADR-157 §3) and OTLP already land on. A\n// reference to a table not declared in this file (imported from another schema\n// module) resolves to nothing and is left unclaimed — cross-file FK resolution is\n// a follow-on, not a guess.\n\ninterface DrizzleTable {\n  tableName: string\n  object: Parser.SyntaxNode | null\n}\n\n// Climb from a table-builder call to the `const <var> = …` it is bound to, so the\n// variable a `.references()` names can be resolved back to the DB table. Returns\n// the variable name, or null when the call is not a simple named binding.\nfunction enclosingVarName(call: Parser.SyntaxNode): string | null {\n  let node: Parser.SyntaxNode | null = call\n  while (node?.parent) {\n    const parent = node.parent\n    if (parent.type === 'variable_declarator') {\n      const name = parent.childForFieldName('name')\n      return name?.type === 'identifier' ? name.text : null\n    }\n    // Climb through a wrapping call/member (`pgTable(...).$type<X>()`).\n    if (parent.type === 'call_expression' || parent.type === 'member_expression') {\n      node = parent\n      continue\n    }\n    return null\n  }\n  return null\n}\n\n// Every table-builder declaration in the file: the DB table name (first string\n// argument) and its column object, plus a variable→table map for FK resolution.\nfunction collectDrizzleTables(root: Parser.SyntaxNode): {\n  tables: DrizzleTable[]\n  varToTable: Map<string, string>\n} {\n  const tables: DrizzleTable[] = []\n  const varToTable = new Map<string, string>()\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'call_expression') {\n      const fn = node.childForFieldName('function')\n      if (fn?.type === 'identifier' && TABLE_BUILDERS.has(fn.text)) {\n        const args = node.childForFieldName('arguments')\n        const argNodes = args ? namedChildren(args) : []\n        const tableName = stringLiteralText(argNodes[0] ?? null)\n        const obj = argNodes[1]?.type === 'object' ? argNodes[1] : null\n        if (tableName) {\n          tables.push({ tableName, object: obj })\n          const varName = enclosingVarName(node)\n          if (varName) varToTable.set(varName, tableName)\n        }\n      }\n    }\n    for (const c of namedChildren(node)) walk(c)\n  }\n  walk(root)\n  return { tables, varToTable }\n}\n\n// The referenced table *variable* of a `.references(() => X.col)` call, or null\n// when the target is not a plain `X.col` member on a variable — a computed or\n// dynamic reference (`.references(() => makeRef().id)`) is left unclaimed.\nfunction referencesTargetVar(call: Parser.SyntaxNode): string | null {\n  const fn = call.childForFieldName('function')\n  if (fn?.type !== 'member_expression') return null\n  if (fn.childForFieldName('property')?.text !== 'references') return null\n  const args = call.childForFieldName('arguments')\n  const first = args ? (namedChildren(args)[0] ?? null) : null\n  if (first?.type !== 'arrow_function') return null\n  const body = first.childForFieldName('body')\n  if (body?.type !== 'member_expression') return null\n  const obj = body.childForFieldName('object')\n  return obj?.type === 'identifier' ? obj.text : null\n}\n\nexport function drizzleForeignKeys(file: SourceFile, serviceDir: string): TableReference[] {\n  if (!DRIZZLE_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(parserForExt(path.extname(file.path)), file.content)\n  const { tables, varToTable } = collectDrizzleTables(tree.rootNode)\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n\n  for (const table of tables) {\n    if (!table.object) continue\n    const walk = (node: Parser.SyntaxNode): void => {\n      if (node.type === 'call_expression') {\n        const targetVar = referencesTargetVar(node)\n        const parentTable = targetVar ? varToTable.get(targetVar) : undefined\n        if (parentTable) {\n          const key = `${table.tableName}->${parentTable}`\n          if (!seen.has(key)) {\n            seen.add(key)\n            const line = node.startPosition.row + 1\n            out.push({\n              childTable: table.tableName,\n              parentTable,\n              evidence: {\n                file: path.relative(serviceDir, file.path),\n                line,\n                snippet: snippet(file.content, line),\n              },\n            })\n          }\n        }\n      }\n      for (const c of namedChildren(node)) walk(c)\n    }\n    walk(table.object)\n  }\n\n  return out\n}\n","import path from 'node:path'\nimport { infraId } from '@neat.is/types'\nimport { findFirst, readIfExists } from '../databases/shared.js'\nimport { snippet, type ExternalEndpoint, type SourceFile, type TableReference } from './shared.js'\n\n// Prisma schema table + column recognizer (ADR-157 §3 columns, the named\n// follow-on the ADR reserves after Drizzle). The declared side of column grain\n// for Prisma: it reads each `model` block in `schema.prisma` and emits the table\n// that model maps to AND the scalar columns it declares, so a production query —\n// whose OBSERVED table + columns NEAT recovers by parsing `db.statement`\n// (ADR-152 / ADR-157 §2) — has a static twin to fuse onto at\n// `infra:sql-table:<name>`.\n//\n//   model Article {\n//     id          Int       @id @default(autoincrement())\n//     title       String\n//     body        String    @map(\"article_body\")\n//     authorId    Int\n//     author      User      @relation(fields: [authorId], references: [id])\n//     comments    Comment[]\n//     @@map(\"articles\")\n//   }\n//\n// The fidelity rules are the load-bearing part (ADR-157 §3 — the fusion key the\n// running query carries is the DATABASE name, not the code name):\n//   - TABLE name  = the model name verbatim (Prisma's default is PascalCase, NOT\n//     snake-cased), or the `@@map(\"name\")` value when the model declares one.\n//   - COLUMN name = the field name verbatim, or the `@map(\"db_col\")` value when\n//     the field declares one. Prisma does NOT snake_case by default, so `authorId`\n//     is the column, not `author_id`.\n// A scalar field (`Int String Boolean DateTime Float Decimal BigInt Bytes Json`,\n// or an enum-typed field) is a column — foreign-key scalars like `authorId Int`\n// included. A relation field is NOT a column and is skipped: a field whose base\n// type is another declared model (`author User`, `comments Comment[]`) or that\n// carries `@relation(...)`. `schema.prisma` is not JS, so it is read as text with\n// a small block scanner (the same read-polyglot-as-data discipline `proto.ts`\n// follows). A field whose type is neither a scalar, a declared enum, nor a\n// declared model is left unclaimed rather than guessed.\n\nconst SCALAR_TYPES = new Set([\n  'Int',\n  'String',\n  'Boolean',\n  'DateTime',\n  'Float',\n  'Decimal',\n  'BigInt',\n  'Bytes',\n  'Json',\n])\n\n// Drop a trailing `//` line comment, respecting `\"...\"` strings so a `//` inside\n// a URL default (`@default(\"https://…\")`) is not mistaken for a comment.\nfunction stripLineComment(line: string): string {\n  let inStr = false\n  for (let i = 0; i < line.length; i++) {\n    const ch = line[i]\n    if (ch === '\"' && line[i - 1] !== '\\\\') inStr = !inStr\n    else if (!inStr && ch === '/' && line[i + 1] === '/') return line.slice(0, i)\n  }\n  return line\n}\n\n// Net `{` minus `}` on a line, ignoring comments and string contents so a brace\n// inside a default value can't unbalance the block scan. Prisma blocks don't\n// nest, but counting keeps the scan robust to odd formatting.\nfunction netBraces(line: string): number {\n  const s = stripLineComment(line).replace(/\"(\\\\.|[^\"\\\\])*\"/g, '')\n  let n = 0\n  for (const ch of s) {\n    if (ch === '{') n++\n    else if (ch === '}') n--\n  }\n  return n\n}\n\ninterface ModelBlock {\n  kind: string\n  tableName: string\n  startLine: number\n  columns: string[]\n  seenCol: Set<string>\n}\n\n// Parse a `schema.prisma`'s model blocks into `sql-table` endpoints carrying the\n// declared columns at database-name fidelity. Pure over the file content so a\n// test can drive it without touching the filesystem, mirroring\n// `drizzleEndpointsFromFile`.\nexport function prismaColumnsFromSchema(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const content = file.content\n  if (!/\\bmodel\\s+[A-Za-z_]\\w*\\s*\\{/.test(content)) return []\n\n  const lines = content.split('\\n')\n\n  // First pass: the declared model + enum names. A field whose base type is a\n  // model name is a relation (skipped); an enum-typed field is a column. Names\n  // are collected up front so a relation to a model declared later in the file\n  // still resolves.\n  const modelNames = new Set<string>()\n  const enumNames = new Set<string>()\n  for (const line of lines) {\n    const m = line.match(/^\\s*model\\s+([A-Za-z_]\\w*)\\s*\\{/)\n    if (m) modelNames.add(m[1]!)\n    const e = line.match(/^\\s*enum\\s+([A-Za-z_]\\w*)\\s*\\{/)\n    if (e) enumNames.add(e[1]!)\n  }\n\n  const out: ExternalEndpoint[] = []\n  const seenTable = new Set<string>()\n\n  const finalize = (b: ModelBlock): void => {\n    if (seenTable.has(b.tableName)) return\n    seenTable.add(b.tableName)\n    out.push({\n      infraId: infraId('sql-table', b.tableName),\n      name: b.tableName,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'structural',\n      columns: b.columns,\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line: b.startLine,\n        snippet: snippet(content, b.startLine),\n      },\n    })\n  }\n\n  // Second pass: a line-based block scan. Only `model` blocks contribute\n  // columns; `datasource` / `generator` / `enum` / `type` blocks are consumed so\n  // their closing brace doesn't leak, but produce nothing here.\n  let current: ModelBlock | null = null\n  let depth = 0\n\n  for (let i = 0; i < lines.length; i++) {\n    const raw = lines[i]!\n    const lineNo = i + 1\n\n    if (current === null) {\n      const header = raw.match(/^\\s*(model|enum|datasource|generator|type)\\s+([A-Za-z_]\\w*)\\b/)\n      if (header && raw.includes('{')) {\n        current = {\n          kind: header[1]!,\n          tableName: header[2]!,\n          startLine: lineNo,\n          columns: [],\n          seenCol: new Set(),\n        }\n        depth = netBraces(raw)\n        if (depth <= 0) {\n          if (current.kind === 'model') finalize(current)\n          current = null\n        }\n      }\n      continue\n    }\n\n    depth += netBraces(raw)\n    if (depth <= 0) {\n      if (current.kind === 'model') finalize(current)\n      current = null\n      continue\n    }\n    if (current.kind !== 'model') continue\n\n    const trimmed = stripLineComment(raw).trim()\n    if (!trimmed) continue\n    if (trimmed.startsWith('@@')) {\n      const map = trimmed.match(/@@map\\(\\s*\"([^\"]+)\"\\s*\\)/)\n      if (map) current.tableName = map[1]!\n      continue\n    }\n\n    // `fieldName BaseType[...] attributes…` — the base type is the second token,\n    // with a trailing `[]` array marker stripped by the alternation.\n    const fm = trimmed.match(/^([A-Za-z_]\\w*)\\s+([A-Za-z_]\\w*)/)\n    if (!fm) continue\n    const fieldName = fm[1]!\n    const baseType = fm[2]!\n\n    // Relation fields are not columns: an `@relation(...)` field, or a field whose\n    // base type is another declared model (covers `author User`, `Tag[]`, `Comment[]`).\n    if (/@relation\\b/.test(trimmed) || modelNames.has(baseType)) continue\n    // A column is a scalar-typed or enum-typed field. Anything else (a composite\n    // type, `Unsupported(...)`, a cross-file model) is left unclaimed.\n    if (!enumNames.has(baseType) && !SCALAR_TYPES.has(baseType)) continue\n\n    const mapM = trimmed.match(/(?<!@)@map\\(\\s*\"([^\"]+)\"\\s*\\)/)\n    const columnName = mapM ? mapM[1]! : fieldName\n    if (!current.seenCol.has(columnName)) {\n      current.seenCol.add(columnName)\n      current.columns.push(columnName)\n    }\n  }\n\n  // An unterminated final model (no trailing `}` at EOF) is still emitted.\n  if (current && current.kind === 'model') finalize(current)\n\n  return out\n}\n\n// Per-service pass: locate the service's `schema.prisma` and read its declared\n// columns. `schema.prisma` is not a source file the walker loads (its extension\n// is not in SERVICE_FILE_EXTENSIONS), so — unlike the JS producers that scan an\n// already-loaded file — this reads the schema directly, the same standard\n// location `databases/prisma.ts` reads for the datasource.\nexport async function prismaColumnEndpoints(serviceDir: string): Promise<ExternalEndpoint[]> {\n  const schemaPath = await findFirst(serviceDir, [\n    path.join('prisma', 'schema.prisma'),\n    'schema.prisma',\n  ])\n  if (!schemaPath) return []\n  const content = await readIfExists(schemaPath)\n  if (!content) return []\n  return prismaColumnsFromSchema({ path: schemaPath, content }, serviceDir)\n}\n\n// ── foreign-key table→table references (ADR-161) ─────────────────────────────\n//\n// Prisma declares a FK on the relation field that carries the scalar columns:\n//   model Post {\n//     authorId Int\n//     author   User @relation(fields: [authorId], references: [id])\n//   }\n// The `fields:` side is the child (it holds the FK column); the field's base type\n// is the parent model. The FK edge is `child-table ──REFERENCES──▶ parent-table`,\n// both at DB-name fidelity — the model's `@@map` name where given, the model name\n// verbatim otherwise (ADR-157 §3). The back-relation side (`posts Post[]`, no\n// `fields:`) declares no FK and mints nothing, so the edge is minted once, in the\n// correct direction. A relation whose base type is not a declared model, or a\n// relation without `fields:`, resolves to no parent and is left unclaimed.\n\n// Model name → the DB table it maps to (the `@@map` value, else the model name\n// verbatim). Built up front so a relation to a model declared later still resolves.\nfunction buildModelTableMap(lines: string[]): Map<string, string> {\n  const map = new Map<string, string>()\n  let current: { model: string; table: string } | null = null\n  let depth = 0\n  for (const raw of lines) {\n    if (current === null) {\n      const header = raw.match(/^\\s*model\\s+([A-Za-z_]\\w*)\\b/)\n      if (header && raw.includes('{')) {\n        current = { model: header[1]!, table: header[1]! }\n        depth = netBraces(raw)\n        if (depth <= 0) {\n          map.set(current.model, current.table)\n          current = null\n        }\n      }\n      continue\n    }\n    depth += netBraces(raw)\n    const trimmed = stripLineComment(raw).trim()\n    if (trimmed.startsWith('@@')) {\n      const m = trimmed.match(/@@map\\(\\s*\"([^\"]+)\"\\s*\\)/)\n      if (m) current.table = m[1]!\n    }\n    if (depth <= 0) {\n      map.set(current.model, current.table)\n      current = null\n    }\n  }\n  if (current) map.set(current.model, current.table)\n  return map\n}\n\nexport function prismaForeignKeysFromSchema(\n  file: SourceFile,\n  serviceDir: string,\n): TableReference[] {\n  const content = file.content\n  if (!/\\bmodel\\s+[A-Za-z_]\\w*\\s*\\{/.test(content)) return []\n  const lines = content.split('\\n')\n  const modelToTable = buildModelTableMap(lines)\n\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n  let current: { table: string } | null = null\n  let depth = 0\n\n  for (let i = 0; i < lines.length; i++) {\n    const raw = lines[i]!\n    const lineNo = i + 1\n\n    if (current === null) {\n      const header = raw.match(/^\\s*model\\s+([A-Za-z_]\\w*)\\b/)\n      if (header && raw.includes('{')) {\n        current = { table: modelToTable.get(header[1]!) ?? header[1]! }\n        depth = netBraces(raw)\n        if (depth <= 0) current = null\n      }\n      continue\n    }\n\n    depth += netBraces(raw)\n    const closing = depth <= 0\n    const trimmed = stripLineComment(raw).trim()\n\n    // A relation field holding the FK: `author User @relation(fields: [authorId],\n    // references: [id])`. Only the `fields:` side mints an edge — the back-relation\n    // (`posts Post[]`, no `fields:`) is skipped, so the direction is unambiguous.\n    if (trimmed && !trimmed.startsWith('@@') && !trimmed.startsWith('}')) {\n      const fm = trimmed.match(/^([A-Za-z_]\\w*)\\s+([A-Za-z_]\\w*)/)\n      if (fm && /@relation\\b[^)]*\\bfields\\s*:/.test(trimmed)) {\n        const parentTable = modelToTable.get(fm[2]!)\n        if (parentTable) {\n          const key = `${current.table}->${parentTable}`\n          if (!seen.has(key)) {\n            seen.add(key)\n            out.push({\n              childTable: current.table,\n              parentTable,\n              evidence: {\n                file: path.relative(serviceDir, file.path),\n                line: lineNo,\n                snippet: snippet(content, lineNo),\n              },\n            })\n          }\n        }\n      }\n    }\n\n    if (closing) current = null\n  }\n\n  return out\n}\n\n// Per-service pass: locate `schema.prisma` and read its declared foreign keys.\n// Mirrors `prismaColumnEndpoints` — the schema is not a walked source file, so it\n// is read directly from the standard location.\nexport async function prismaForeignKeys(serviceDir: string): Promise<TableReference[]> {\n  const schemaPath = await findFirst(serviceDir, [\n    path.join('prisma', 'schema.prisma'),\n    'schema.prisma',\n  ])\n  if (!schemaPath) return []\n  const content = await readIfExists(schemaPath)\n  if (!content) return []\n  return prismaForeignKeysFromSchema({ path: schemaPath, content }, serviceDir)\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Ruby from 'tree-sitter-ruby'\nimport { infraId } from '@neat.is/types'\nimport { snippet, type ExternalEndpoint, type SourceFile, type TableReference } from './shared.js'\n\n// Ruby/Rails ActiveRecord data-axis recognizer (ADR-174), the second rung of the\n// Ruby pilot after ADR-173's routes. Rails declares its schema twice — literally\n// in `db/schema.rb` and behaviourally in the ActiveRecord models — and both feed\n// the SAME `sql-table` nodes, `ColumnAttr` columns (ADR-157), and `REFERENCES`\n// edges (ADR-161) Prisma and Drizzle already produce, so the reasoning core learns\n// nothing Rails-specific (calls/prisma.ts is the closest analog).\n//\n//   ActiveRecord::Schema[7.1].define do\n//     create_table \"orders\", force: :cascade do |t|\n//       t.string   \"name\"\n//       t.integer  \"qty\"\n//       t.references :user, foreign_key: true      # -> user_id column + FK to users\n//       t.timestamps                               # -> created_at, updated_at\n//     end\n//     add_foreign_key \"line_items\", \"orders\"       # -> line_items REFERENCES orders\n//   end\n//\n// The fidelity rule (ADR-157 §3): the table/column/FK names in schema.rb are\n// LITERAL — the exact strings the database uses and a query's `db.statement`\n// carries at runtime — so schema.rb is the anchor and needs no pluralization. The\n// models add what the schema can't name on its own: the class↔table link and the\n// association graph. There the ActiveSupport pluralizer is a fallback only, since\n// a wrong guess there is a missed edge, never a wrong table node.\n\nconst AR_SCHEMA_RE = /ActiveRecord::Schema/\n\nconst PARSE_CHUNK = 16384\n\nfunction makeRubyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Ruby)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) walk(c, visit)\n  }\n}\n\n// The interior text of a Ruby string literal, or a symbol's name without its\n// leading colon (`:orders` → 'orders'). Null for an interpolated string — a\n// schema name is always a static literal. Mirrors routes.ts's `rubyLiteral`.\nfunction rubyLiteral(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  if (node.type === 'simple_symbol') return node.text.replace(/^:/, '')\n  if (node.type === 'string') {\n    let text = ''\n    let sawContent = false\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const child = node.namedChild(i)\n      if (!child) continue\n      if (child.type === 'string_content' || child.type === 'escape_sequence') {\n        text += child.text\n        sawContent = true\n      } else {\n        return null // interpolation or anything non-literal\n      }\n    }\n    return sawContent ? text : '' // an empty string literal has no content child\n  }\n  return null\n}\n\nfunction rubyArgs(call: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  return call.childForFieldName('arguments')\n}\n\n// The positional (non-`pair`) arguments of a call, in order.\nfunction rubyPositional(args: Parser.SyntaxNode | null): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!args) return out\n  for (let i = 0; i < args.namedChildCount; i++) {\n    const c = args.namedChild(i)\n    if (c && c.type !== 'pair') out.push(c)\n  }\n  return out\n}\n\n// The value node of a keyword argument `key: …` — a `pair` whose key is a\n// `hash_key_symbol` with the given name. Handles both an inline argument-list\n// pair (`create_table \"x\", id: false`) and a `hash` literal's own pairs\n// (`foreign_key: { to_table: :y }`).\nfunction rubyKwarg(container: Parser.SyntaxNode | null, key: string): Parser.SyntaxNode | null {\n  if (!container) return null\n  for (let i = 0; i < container.namedChildCount; i++) {\n    const pair = container.namedChild(i)\n    if (!pair || pair.type !== 'pair') continue\n    const k = pair.childForFieldName('key')\n    if (k?.type === 'hash_key_symbol' && k.text === key) return pair.childForFieldName('value')\n  }\n  return null\n}\n\n// The `call` statements at the top level of a `do … end` block or a class\n// `body_statement`. tree-sitter-ruby wraps multiple statements in a\n// `body_statement`; fall back to the container's own direct children for the\n// single-statement shape. Mirrors routes.ts's `rubyBlockCalls`.\nfunction rubyBodyCalls(container: Parser.SyntaxNode | null): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!container) return out\n  const pushCalls = (n: Parser.SyntaxNode): void => {\n    for (let i = 0; i < n.namedChildCount; i++) {\n      const c = n.namedChild(i)\n      if (c?.type === 'call') out.push(c)\n    }\n  }\n  let sawBody = false\n  for (let i = 0; i < container.namedChildCount; i++) {\n    const c = container.namedChild(i)\n    if (c?.type === 'body_statement') {\n      pushCalls(c)\n      sawBody = true\n    }\n  }\n  if (!sawBody) pushCalls(container)\n  return out\n}\n\n// ── inflection (model / association fallback only) ───────────────────────────\n//\n// schema.rb names are literal and never routed through here. These reproduce the\n// common-case ActiveSupport rules for the model→table fallback and the singular\n// association→table derivation. Irregulars (person/people, child/children) and a\n// project's custom inflections are a documented refinement (ADR-174) — since the\n// schema.rb literal is the anchor, a wrong guess here is a missed corroborating\n// edge, not a wrong node.\n\n// `Admin::User` → `User`.\nfunction demodulize(name: string): string {\n  const i = name.lastIndexOf('::')\n  return i >= 0 ? name.slice(i + 2) : name\n}\n\n// ActiveSupport underscore: CamelCase → snake_case, keeping acronym runs together\n// (`APIKey` → `api_key`, `LineItem` → `line_item`).\nfunction underscore(name: string): string {\n  return name\n    .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1_$2')\n    .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n    .replace(/-/g, '_')\n    .toLowerCase()\n}\n\n// Common-case English pluralizer — the rules ActiveSupport's default inflections\n// ship for the frequent endings.\nfunction pluralize(word: string): string {\n  if (/[^aeiou]y$/i.test(word)) return word.replace(/y$/i, 'ies')\n  if (/(s|x|z|ch|sh)$/i.test(word)) return word + 'es'\n  return word + 's'\n}\n\n// class name → table name (ActiveSupport `tableize`, default `table_name`):\n// pluralize(underscore(demodulize(name))). `Order` → orders, `LineItem` →\n// line_items, `Admin::User` → users.\nfunction tableize(className: string): string {\n  return pluralize(underscore(demodulize(className)))\n}\n\n// ── db/schema.rb: create_table → sql-table + columns ─────────────────────────\n\n// The ActiveRecord migration column-type methods that declare a column named by\n// their first string/symbol argument. `t.column \"name\", \"type\"` (the generic\n// form) is here too — its first positional is still the name. Non-column table\n// methods (`t.index`, `t.check_constraint`, `t.foreign_key`) are absent, so they\n// contribute nothing — the bounded-set discipline Drizzle's TABLE_BUILDERS and\n// SQLAlchemy's COLUMN_BUILDERS follow. `references`/`belongs_to`/`timestamps` are\n// handled specially below (they expand to `<name>_id` / created_at+updated_at).\nconst AR_COLUMN_TYPES = new Set([\n  'string', 'text', 'integer', 'bigint', 'float', 'decimal', 'numeric',\n  'datetime', 'timestamp', 'timestamptz', 'time', 'date', 'binary', 'boolean',\n  'json', 'jsonb', 'uuid', 'hstore', 'citext', 'inet', 'cidr', 'macaddr',\n  'money', 'xml', 'tsvector', 'ltree', 'interval', 'oid', 'bit', 'blob',\n  'int4range', 'int8range', 'numrange', 'tsrange', 'tstzrange', 'daterange',\n  'point', 'line', 'lseg', 'box', 'path', 'polygon', 'circle', 'enum',\n  'primary_key', 'virtual', 'column',\n])\n\nconst AR_REFERENCE_METHODS = new Set(['references', 'belongs_to'])\n\n// The receiver-and-method of a `t.<method> …` block call. Returns the method name\n// (`string`, `references`, `timestamps`, …) regardless of the block variable name.\nfunction blockCallMethod(call: Parser.SyntaxNode): string | null {\n  return call.childForFieldName('method')?.text ?? null\n}\n\ninterface SchemaTable {\n  name: string\n  line: number\n  columns: string[]\n}\n\n// Read a single `create_table \"orders\", … do |t| … end` call into its table name,\n// the implicit primary key, and the columns its block declares.\nfunction readCreateTable(call: Parser.SyntaxNode): SchemaTable | null {\n  const args = rubyArgs(call)\n  const name = rubyLiteral(rubyPositional(args)[0])\n  if (!name) return null // computed / interpolated table name — never guessed\n  const line = call.startPosition.row + 1\n\n  const columns: string[] = []\n  const seen = new Set<string>()\n  const add = (col: string | null): void => {\n    if (col && !seen.has(col)) {\n      seen.add(col)\n      columns.push(col)\n    }\n  }\n\n  // Implicit primary key, unless `id: false`. A `primary_key: \"uuid\"` renames it.\n  const idOpt = rubyKwarg(args, 'id')\n  if (!idOpt || idOpt.type !== 'false') {\n    add(rubyLiteral(rubyKwarg(args, 'primary_key')) ?? 'id')\n  }\n\n  for (const bc of rubyBodyCalls(call.childForFieldName('block'))) {\n    const method = blockCallMethod(bc)\n    if (!method) continue\n    const bArgs = rubyArgs(bc)\n    if (method === 'timestamps') {\n      add('created_at')\n      add('updated_at')\n    } else if (AR_REFERENCE_METHODS.has(method)) {\n      const refName = rubyLiteral(rubyPositional(bArgs)[0])\n      if (!refName) continue\n      add(`${refName}_id`)\n      // A polymorphic reference also declares a `<name>_type` discriminator.\n      const poly = rubyKwarg(bArgs, 'polymorphic')\n      if (poly && poly.type === 'true') add(`${refName}_type`)\n    } else if (AR_COLUMN_TYPES.has(method)) {\n      add(rubyLiteral(rubyPositional(bArgs)[0]))\n    }\n    // Anything else (index, check_constraint, …) declares no column.\n  }\n\n  return { name, line, columns }\n}\n\n// db/schema.rb tables + columns. Gated on the `ActiveRecord::Schema` marker so it\n// is inert on every other `.rb` file (the import-gate discipline Drizzle and\n// SQLAlchemy follow). Emits one `sql-table` endpoint per `create_table`, carrying\n// the literal column names — the orchestrator (calls/index.ts) mints the node and\n// folds the columns onto it as EXTRACTED `ColumnAttr`s (ADR-157 §3).\nexport function railsSchemaEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (!AR_SCHEMA_RE.test(file.content)) return []\n  const tree = parseSource(makeRubyParser(), file.content)\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call') return\n    if (blockCallMethod(node) !== 'create_table') return\n    const table = readCreateTable(node)\n    if (!table || seen.has(table.name)) return\n    seen.add(table.name)\n    out.push({\n      infraId: infraId('sql-table', table.name),\n      name: table.name,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'structural',\n      ...(table.columns.length > 0 ? { columns: table.columns } : {}),\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line: table.line,\n        snippet: snippet(file.content, table.line),\n      },\n    })\n  })\n\n  return out\n}\n\n// db/schema.rb foreign keys → REFERENCES table→table edges. Two literal sources,\n// both preferred over any model inference: an inline `t.references :user,\n// foreign_key: true` inside a create_table (parent pluralized, or `to_table:`\n// verbatim when given) and a top-level `add_foreign_key \"orders\", \"users\"` (both\n// names literal). A polymorphic reference names no single parent and is left\n// unclaimed. `column:` / `primary_key:` on `add_foreign_key` don't change the\n// table-grain edge and are ignored.\nexport function railsSchemaForeignKeys(\n  file: SourceFile,\n  serviceDir: string,\n): TableReference[] {\n  if (!AR_SCHEMA_RE.test(file.content)) return []\n  const tree = parseSource(makeRubyParser(), file.content)\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n\n  const emit = (childTable: string, parentTable: string, line: number): void => {\n    if (childTable === parentTable) return // self-loop, dropped by the graph anyway\n    const key = `${childTable}->${parentTable}`\n    if (seen.has(key)) return\n    seen.add(key)\n    out.push({\n      childTable,\n      parentTable,\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call') return\n    const method = blockCallMethod(node)\n\n    // Top-level `add_foreign_key \"child\", \"parent\", …` — both names literal.\n    if (method === 'add_foreign_key') {\n      const args = rubyArgs(node)\n      const pos = rubyPositional(args)\n      const child = rubyLiteral(pos[0])\n      const parent = rubyLiteral(pos[1])\n      if (child && parent) emit(child, parent, node.startPosition.row + 1)\n      return\n    }\n\n    // Inline `t.references :user, foreign_key: true` inside a create_table.\n    if (method !== 'create_table') return\n    const table = readCreateTable(node)\n    if (!table) return\n    for (const bc of rubyBodyCalls(node.childForFieldName('block'))) {\n      if (!AR_REFERENCE_METHODS.has(blockCallMethod(bc) ?? '')) continue\n      const bArgs = rubyArgs(bc)\n      const refName = rubyLiteral(rubyPositional(bArgs)[0])\n      if (!refName) continue\n      const poly = rubyKwarg(bArgs, 'polymorphic')\n      if (poly && poly.type === 'true') continue // no single parent to reference\n      const fk = rubyKwarg(bArgs, 'foreign_key')\n      if (!fk || fk.type === 'false') continue // no `foreign_key: true` → no DB FK\n      // `foreign_key: { to_table: :accounts }` overrides the pluralized default.\n      const toTable = fk.type === 'hash' ? rubyLiteral(rubyKwarg(fk, 'to_table')) : null\n      const parent = toTable ?? pluralize(refName)\n      emit(table.name, parent, bc.startPosition.row + 1)\n    }\n  })\n\n  return out\n}\n\n// ── app/models/*.rb: class↔table link + associations ─────────────────────────\n\n// The superclass constant of a `class X < Y` — `Y`'s text, or null when the class\n// has no superclass. Reads the `superclass` node's constant / scope_resolution.\nfunction superclassName(cls: Parser.SyntaxNode): string | null {\n  const sup = cls.childForFieldName('superclass')\n  if (!sup) return null\n  for (let i = 0; i < sup.namedChildCount; i++) {\n    const c = sup.namedChild(i)\n    if (c && (c.type === 'constant' || c.type === 'scope_resolution')) return c.text\n  }\n  return null\n}\n\n// Is this class an ActiveRecord model? `< ApplicationRecord` (the Rails ≥ 5 base)\n// or `< ActiveRecord::Base` (legacy), including a namespaced `Foo::ApplicationRecord`.\nfunction isActiveRecordModel(cls: Parser.SyntaxNode): boolean {\n  const sup = superclassName(cls)\n  if (!sup) return false\n  return sup === 'ApplicationRecord' || sup.endsWith('::ApplicationRecord') || sup === 'ActiveRecord::Base'\n}\n\n// The table a model class maps to: an explicit `self.table_name = \"x\"` when set,\n// else the ActiveSupport pluralisation of the underscored class name (`Order` →\n// orders). schema.rb literals are the anchor; this only names the link.\nfunction modelTable(cls: Parser.SyntaxNode): string | null {\n  const nameNode = cls.childForFieldName('name')\n  if (!nameNode) return null\n  const body = cls.childForFieldName('body')\n  if (body) {\n    for (let i = 0; i < body.namedChildCount; i++) {\n      const stmt = body.namedChild(i)\n      if (stmt?.type !== 'assignment') continue\n      const left = stmt.childForFieldName('left')\n      if (left?.text !== 'self.table_name') continue\n      const explicit = rubyLiteral(stmt.childForFieldName('right'))\n      if (explicit) return explicit\n    }\n  }\n  return tableize(nameNode.text)\n}\n\n// app/models/*.rb: the model→table link. Emits a `sql-table` endpoint so the\n// model file gets a `file ──CALLS──▶ sql-table` edge (the SQLAlchemy model-file\n// pattern) — no columns, since ActiveRecord reads those from the DB, and schema.rb\n// is the column authority.\nexport function railsModelEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const tree = parseSource(makeRubyParser(), file.content)\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class' || !isActiveRecordModel(node)) return\n    const table = modelTable(node)\n    if (!table || seen.has(table)) return\n    seen.add(table)\n    const line = node.startPosition.row + 1\n    out.push({\n      infraId: infraId('sql-table', table),\n      name: table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  })\n\n  return out\n}\n\nconst AR_ASSOCIATIONS = new Set(['belongs_to', 'has_many', 'has_one'])\n\n// app/models/*.rb associations → REFERENCES edges, deduped against the schema.rb\n// FKs at the graph level (table-edges.ts guards every write with `hasEdge`, and\n// the schema.rb refs are added first). The FK lives on the table that holds the\n// `<name>_id` column, so direction depends on the macro:\n//   belongs_to :user     -> this table REFERENCES the association's table (users)\n//   has_many :line_items -> line_items REFERENCES this table (FK on the other side)\n//   has_one :profile     -> profiles REFERENCES this table\n// `class_name:` retargets the association's class (hence table); `through:` (a\n// join through a third model) and `has_and_belongs_to_many` are deferred.\nexport function railsModelForeignKeys(\n  file: SourceFile,\n  serviceDir: string,\n): TableReference[] {\n  const tree = parseSource(makeRubyParser(), file.content)\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class' || !isActiveRecordModel(node)) return\n    const thisTable = modelTable(node)\n    if (!thisTable) return\n\n    for (const call of rubyBodyCalls(node.childForFieldName('body'))) {\n      const macro = blockCallMethod(call)\n      if (!macro || !AR_ASSOCIATIONS.has(macro)) continue\n      const args = rubyArgs(call)\n      const assoc = rubyLiteral(rubyPositional(args)[0])\n      if (!assoc) continue\n      if (rubyKwarg(args, 'through')) continue // has_many/has_one :through — deferred\n\n      // The association's own table: `class_name:` when given, else the\n      // conventional derivation. A has_many name is already the plural table\n      // name; belongs_to / has_one names are singular and pluralize.\n      const className = rubyLiteral(rubyKwarg(args, 'class_name'))\n      const assocTable = className\n        ? tableize(className)\n        : macro === 'has_many'\n          ? assoc\n          : pluralize(assoc)\n\n      const childTable = macro === 'belongs_to' ? thisTable : assocTable\n      const parentTable = macro === 'belongs_to' ? assocTable : thisTable\n      if (childTable === parentTable) continue\n      const key = `${childTable}->${parentTable}`\n      if (seen.has(key)) continue\n      seen.add(key)\n      const line = call.startPosition.row + 1\n      out.push({\n        childTable,\n        parentTable,\n        evidence: {\n          file: path.relative(serviceDir, file.path),\n          line,\n          snippet: snippet(file.content, line),\n        },\n      })\n    }\n  })\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Php from 'tree-sitter-php'\nimport { infraId } from '@neat.is/types'\nimport { snippet, type ExternalEndpoint, type SourceFile, type TableReference } from './shared.js'\n\n// PHP/Laravel data-axis recognizer (ADR-178), the second rung of the PHP pilot\n// after ADR-177's routes. Laravel declares its schema in two places — literally\n// in `database/migrations/*.php` and behaviourally in the Eloquent models — and\n// both feed the SAME `sql-table` nodes, `ColumnAttr` columns (ADR-157), and\n// `REFERENCES` edges (ADR-161) Prisma, Drizzle, and Rails' schema.rb already\n// produce, so the reasoning core learns nothing Laravel-specific\n// (calls/activerecord.ts is the closest analog — a migration is Rails' schema.rb,\n// an Eloquent model is an ActiveRecord model).\n//\n//   Schema::create('orders', function (Blueprint $table) {\n//     $table->id();                              // -> id\n//     $table->string('code');                    // -> code\n//     $table->foreignId('user_id')->constrained();  // -> user_id column + FK to users\n//     $table->timestamps();                      // -> created_at, updated_at\n//   });\n//\n//   class Order extends Model {                  // -> maps to the orders table\n//     public function user() { return $this->belongsTo(User::class); }  // orders -> users\n//   }\n//\n// The fidelity rule (ADR-157 §3): the table/column names inside `Schema::create`\n// are LITERAL — the exact strings the database uses and a query's `db.statement`\n// carries at runtime — so the migration is the anchor and needs no pluralization.\n// The models add what the migration can't name on its own: the class↔table link\n// and the relation graph. There the snake_case pluralizer is a fallback only,\n// since a wrong guess there is a missed corroborating edge, never a wrong table\n// node (the migration literal anchors the node either way).\n\n// Cheap per-file gate — inert on every `.php` file that declares no schema, the\n// import-gate discipline the other data-axis readers follow. A migration always\n// names `Schema::create` / `Schema::table` (or the `createIfNotExists` variant),\n// including the fully-qualified `\\Illuminate\\Support\\Facades\\Schema::create`.\nconst LARAVEL_SCHEMA_RE = /\\bSchema::(create|createIfNotExists|table)\\b/\n\nconst PARSE_CHUNK = 16384\n\nfunction makePhpParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Php.php_only)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) walk(c, visit)\n  }\n}\n\n// ── PHP literal / argument helpers (mirrors routes.ts) ───────────────────────\n\n// The interior text of a PHP single-quoted `string` or double-quoted\n// `encapsed_string`, or null when it carries interpolation (a schema name is a\n// static literal). An empty literal returns ''.\nfunction phpStaticString(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  if (node.type !== 'string' && node.type !== 'encapsed_string') return null\n  let text = ''\n  let sawContent = false\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (!child) continue\n    if (child.type === 'string_content') {\n      text += child.text\n      sawContent = true\n    } else {\n      return null // interpolation / escape / anything non-literal\n    }\n  }\n  return sawContent ? text : ''\n}\n\n// The value nodes of a call's positional arguments. tree-sitter-php wraps each in\n// an `argument`; the value is its last named child (a PHP-8 named argument\n// `name: value` carries a `name` field that precedes the value).\nfunction phpArgumentValues(argsNode: Parser.SyntaxNode | null | undefined): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  if (!argsNode) return out\n  for (let i = 0; i < argsNode.namedChildCount; i++) {\n    const arg = argsNode.namedChild(i)\n    if (!arg || arg.type !== 'argument') continue\n    const val = arg.namedChild(arg.namedChildCount - 1)\n    if (val) out.push(val)\n  }\n  return out\n}\n\n// The first positional argument as a static string, or null.\nfunction phpFirstString(argsNode: Parser.SyntaxNode | null | undefined): string | null {\n  const vals = phpArgumentValues(argsNode)\n  return vals.length > 0 ? phpStaticString(vals[0]) : null\n}\n\n// The basename of a class reference — `User::class` (`class_constant_access_expression`),\n// a namespaced `\\App\\Models\\User::class`, or a `'App\\Models\\User'` string literal —\n// stripped of its namespace: `User`. Null for anything else.\nfunction classRefBasename(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  let raw: string | null = null\n  if (node.type === 'class_constant_access_expression') {\n    // First named child is the class name (`name` or `qualified_name`); the\n    // second is the `class` keyword.\n    raw = node.namedChild(0)?.text ?? null\n  } else if (node.type === 'string' || node.type === 'encapsed_string') {\n    // A `'App\\Models\\User'` string carries the namespace as literal backslashes\n    // (an escape_sequence child), so read the raw interior rather than the\n    // string_content pieces and split on the backslash separator below.\n    const t = node.text\n    raw = t.length >= 2 ? t.slice(1, -1) : null\n  }\n  if (raw === null) return null\n  const seg = raw.replace(/^\\\\+/, '').split(/\\\\+/)\n  return seg[seg.length - 1] || null\n}\n\n// ── inflection (convention / model fallback only) ────────────────────────────\n//\n// Migration `Schema::create` names are literal and never routed through here.\n// These reproduce the common-case Laravel rules for the model→table fallback, the\n// `foreignId('user_id')->constrained()` column→table convention, and the\n// `foreignIdFor(Model::class)` model→table derivation. Irregulars (person/people)\n// are a documented refinement (ADR-178) — since the migration literal is the\n// anchor, a wrong guess here is a missed corroborating edge, not a wrong node.\n\n// StudlyCase → snake_case: `LineItem` → line_item, `APIToken` → api_token.\nfunction snakeCase(name: string): string {\n  return name\n    .replace(/([A-Z\\d]+)([A-Z][a-z])/g, '$1_$2')\n    .replace(/([a-z\\d])([A-Z])/g, '$1_$2')\n    .replace(/-/g, '_')\n    .toLowerCase()\n}\n\n// Common-case English pluralizer — the frequent endings Laravel's Str::plural\n// covers. Irregulars are the documented refinement.\nfunction pluralize(word: string): string {\n  if (/[^aeiou]y$/i.test(word)) return word.replace(/y$/i, 'ies')\n  if (/(s|x|z|ch|sh)$/i.test(word)) return word + 'es'\n  return word + 's'\n}\n\n// class name → table name (Laravel's default `getTable()`): the snake_case plural\n// of the class basename. `Order` → orders, `LineItem` → line_items.\nfunction tableize(className: string): string {\n  return pluralize(snakeCase(className))\n}\n\n// `foreignId('user_id')->constrained()` infers its parent table from the column\n// name the way Laravel does: strip a trailing `_id`, then pluralize the singular.\n// `user_id` → users, `author_id` → authors, `category_id` → categories.\nfunction tableFromForeignKeyColumn(column: string): string | null {\n  const singular = column.replace(/_id$/, '')\n  if (singular.length === 0 || singular === column) return null\n  return pluralize(singular)\n}\n\n// ── member-call chain flattening ─────────────────────────────────────────────\n\ninterface PhpSeg {\n  method: string\n  args: Parser.SyntaxNode | null\n  node: Parser.SyntaxNode\n}\n\n// Flatten a `$table->foreignId('x')->constrained()` fluent chain into its ordered\n// (method, args) segments, innermost first, plus the base receiver. A bare\n// `$table->id()` → { base: $table, segs: [id] }; `$table->foreign('x')->on('y')` →\n// [foreign, on]. Returns null when the chain doesn't root at a `variable_name`.\nfunction unrollMemberChain(\n  node: Parser.SyntaxNode,\n): { base: Parser.SyntaxNode; segs: PhpSeg[] } | null {\n  const segs: PhpSeg[] = []\n  let cur: Parser.SyntaxNode | null = node\n  while (cur && cur.type === 'member_call_expression') {\n    const name = cur.childForFieldName('name')?.text\n    if (!name) return null\n    segs.unshift({ method: name, args: cur.childForFieldName('arguments'), node: cur })\n    cur = cur.childForFieldName('object')\n  }\n  if (!cur || cur.type !== 'variable_name') return null\n  return { base: cur, segs }\n}\n\n// The name of a `variable_name` (`$table` → 'table'), or null.\nfunction variableName(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node || node.type !== 'variable_name') return null\n  return node.namedChild(0)?.text ?? null\n}\n\n// ── Schema::create / Schema::table discovery ─────────────────────────────────\n\ninterface Blueprint {\n  table: string\n  line: number\n  blueprintVar: string | null // the closure's Blueprint parameter name (`table`)\n  closureBody: Parser.SyntaxNode | null // compound_statement or an arrow body\n}\n\n// The closure a `Schema::create('x', …)` carries — an anonymous `function () {}`\n// (`anonymous_function_creation_expression`) or a `fn () => …` (`arrow_function`).\nfunction schemaClosure(argsNode: Parser.SyntaxNode | null): Parser.SyntaxNode | null {\n  for (const v of phpArgumentValues(argsNode)) {\n    if (v.type === 'anonymous_function_creation_expression' || v.type === 'arrow_function') return v\n  }\n  return null\n}\n\n// The Blueprint parameter name of a schema closure (`function (Blueprint $table)`\n// → 'table'), so column calls can be matched to that receiver and unrelated\n// `$other->foo()` statements in the body are ignored.\nfunction blueprintParamName(closure: Parser.SyntaxNode): string | null {\n  const params = closure.childForFieldName('parameters')\n  if (!params) return null\n  for (let i = 0; i < params.namedChildCount; i++) {\n    const p = params.namedChild(i)\n    if (p?.type === 'simple_parameter') return variableName(p.childForFieldName('name'))\n  }\n  return null\n}\n\n// The `$table->…()` statement chains inside a schema closure — the outer\n// `member_call_expression` of each, whether in a `{ … }` block or a single-\n// expression arrow body.\nfunction closureCalls(closure: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  const body = closure.childForFieldName('body')\n  if (!body) return out\n  if (closure.type === 'arrow_function') {\n    if (body.type === 'member_call_expression') out.push(body)\n    return out\n  }\n  for (let i = 0; i < body.namedChildCount; i++) {\n    const stmt = body.namedChild(i)\n    if (stmt?.type !== 'expression_statement') continue\n    const call = stmt.namedChild(0)\n    if (call?.type === 'member_call_expression') out.push(call)\n  }\n  return out\n}\n\n// Is this scoped call a `Schema::create` / `Schema::table` (or the FQ facade)?\nfunction isSchemaCall(node: Parser.SyntaxNode): boolean {\n  if (node.type !== 'scoped_call_expression') return false\n  const scope = node.childForFieldName('scope')?.text ?? ''\n  const rooted = scope === 'Schema' || scope.endsWith('\\\\Schema')\n  if (!rooted) return false\n  const method = node.childForFieldName('name')?.text ?? ''\n  return method === 'create' || method === 'createIfNotExists' || method === 'table'\n}\n\n// Read a `Schema::create('orders', function (Blueprint $table) { … })` into its\n// literal table name and the closure to scan for columns / FKs. A computed table\n// name (interpolated, a constant) is left unclaimed — never guessed.\nfunction readBlueprint(node: Parser.SyntaxNode): Blueprint | null {\n  const args = node.childForFieldName('arguments')\n  const table = phpFirstString(args)\n  if (table === null || table.length === 0) return null\n  const closure = schemaClosure(args)\n  return {\n    table,\n    line: node.startPosition.row + 1,\n    blueprintVar: closure ? blueprintParamName(closure) : null,\n    closureBody: closure,\n  }\n}\n\n// ── columns ──────────────────────────────────────────────────────────────────\n\n// The Blueprint methods whose FIRST string argument is the column name — the\n// bounded set the fidelity discipline keeps (the analog of ActiveRecord's\n// AR_COLUMN_TYPES and Drizzle's TABLE_BUILDERS). Non-column methods (index,\n// unique, primary, dropColumn, foreign) are absent, so they contribute nothing.\n// `id` / `timestamps` / `softDeletes` / `rememberToken` / `foreignId` /\n// `foreignIdFor` expand specially below.\nconst NAMED_COLUMN_METHODS = new Set([\n  'bigIncrements', 'bigInteger', 'binary', 'boolean', 'char', 'dateTime', 'dateTimeTz',\n  'date', 'decimal', 'double', 'enum', 'float', 'foreignUlid', 'foreignUuid', 'fullText',\n  'geography', 'geometry', 'increments', 'integer', 'ipAddress', 'json', 'jsonb', 'lineString',\n  'longText', 'macAddress', 'mediumIncrements', 'mediumInteger', 'mediumText', 'multiLineString',\n  'multiPoint', 'multiPolygon', 'point', 'polygon', 'set', 'smallIncrements', 'smallInteger',\n  'string', 'text', 'time', 'timeTz', 'timestamp', 'timestampTz', 'tinyIncrements',\n  'tinyInteger', 'tinyText', 'ulid', 'unsignedBigInteger', 'unsignedDecimal', 'unsignedInteger',\n  'unsignedMediumInteger', 'unsignedSmallInteger', 'unsignedTinyInteger', 'uuid', 'year',\n])\n\n// The column(s) a single `$table->…()` statement declares, or [] for a\n// non-column statement (an index, a bare `foreign()` constraint, a deferred\n// `morphs()`). The base segment is the column-defining method; chained modifiers\n// (`->nullable()`, `->constrained()`, …) don't rename the column.\nfunction columnsFromCall(chain: Parser.SyntaxNode, blueprintVar: string | null): string[] {\n  const un = unrollMemberChain(chain)\n  if (!un) return []\n  // Only columns on the Blueprint receiver, when the param name is known.\n  if (blueprintVar !== null && variableName(un.base) !== blueprintVar) return []\n  const base = un.segs[0]\n  if (!base) return []\n  const m = base.method\n  const first = phpFirstString(base.args)\n\n  if (m === 'id') return [first ?? 'id']\n  if (m === 'timestamps' || m === 'timestampsTz' || m === 'nullableTimestamps') {\n    return ['created_at', 'updated_at']\n  }\n  if (m === 'softDeletes' || m === 'softDeletesTz') return [first ?? 'deleted_at']\n  if (m === 'rememberToken') return ['remember_token']\n  if (m === 'foreignId') return first ? [first] : []\n  if (m === 'foreignIdFor') {\n    // The column Laravel derives from the model: snake_case(basename) + '_id'.\n    const cls = classRefBasename(phpArgumentValues(base.args)[0])\n    return cls ? [`${snakeCase(cls)}_id`] : []\n  }\n  if (NAMED_COLUMN_METHODS.has(m)) return first ? [first] : []\n  // Everything else (index, unique, primary, foreign, morphs, dropColumn, …)\n  // declares no column here.\n  return []\n}\n\n// database/migrations/*.php tables + columns. Gated on the `Schema::` marker so it\n// is inert on every other `.php` file. Emits one `sql-table` endpoint per\n// `Schema::create` / `Schema::table`, carrying the literal column names — the\n// orchestrator (calls/index.ts) mints the node and folds the columns onto it as\n// EXTRACTED `ColumnAttr`s (ADR-157 §3). `Schema::table` (an alter) folds its added\n// columns onto the same node the create minted.\nexport function laravelMigrationEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (!LARAVEL_SCHEMA_RE.test(file.content)) return []\n  const tree = parseSource(makePhpParser(), file.content)\n  const out: ExternalEndpoint[] = []\n\n  walk(tree.rootNode, (node) => {\n    if (!isSchemaCall(node)) return\n    const bp = readBlueprint(node)\n    if (!bp) return\n\n    const columns: string[] = []\n    const seen = new Set<string>()\n    if (bp.closureBody) {\n      for (const call of closureCalls(bp.closureBody)) {\n        for (const col of columnsFromCall(call, bp.blueprintVar)) {\n          if (!seen.has(col)) {\n            seen.add(col)\n            columns.push(col)\n          }\n        }\n      }\n    }\n\n    out.push({\n      infraId: infraId('sql-table', bp.table),\n      name: bp.table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'structural',\n      ...(columns.length > 0 ? { columns } : {}),\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line: bp.line,\n        snippet: snippet(file.content, bp.line),\n      },\n    })\n  })\n\n  return out\n}\n\n// ── migration foreign keys ───────────────────────────────────────────────────\n\n// database/migrations/*.php foreign keys → REFERENCES table→table edges (ADR-161),\n// from the three literal migration sources:\n//   $table->foreignId('user_id')->constrained()          -> orders REFERENCES users\n//   $table->foreignId('acct_id')->constrained('accounts') -> orders REFERENCES accounts\n//   $table->foreignIdFor(User::class)                    -> orders REFERENCES users\n//   $table->foreign('buyer_id')->references('id')->on('buyers') -> orders REFERENCES buyers\n// A bare `foreignId('user_id')` with no `->constrained()` is a column only (no DB\n// FK), so it mints no edge. A computed / unresolvable target is left unclaimed.\nexport function laravelMigrationForeignKeys(\n  file: SourceFile,\n  serviceDir: string,\n): TableReference[] {\n  if (!LARAVEL_SCHEMA_RE.test(file.content)) return []\n  const tree = parseSource(makePhpParser(), file.content)\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n\n  const emit = (childTable: string, parentTable: string, line: number): void => {\n    if (!parentTable || childTable === parentTable) return\n    const key = `${childTable}->${parentTable}`\n    if (seen.has(key)) return\n    seen.add(key)\n    out.push({\n      childTable,\n      parentTable,\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  walk(tree.rootNode, (node) => {\n    if (!isSchemaCall(node)) return\n    const bp = readBlueprint(node)\n    if (!bp || !bp.closureBody) return\n\n    for (const chain of closureCalls(bp.closureBody)) {\n      const un = unrollMemberChain(chain)\n      if (!un) continue\n      if (bp.blueprintVar !== null && variableName(un.base) !== bp.blueprintVar) continue\n      const base = un.segs[0]\n      if (!base) continue\n      const line = chain.startPosition.row + 1\n\n      // `foreignId('user_id')->constrained(['accounts'])` — FK only when a\n      // `constrained` segment is present; the parent is its explicit table\n      // argument, else the column-name convention.\n      if (base.method === 'foreignId' || base.method === 'foreignUuid') {\n        const constrained = un.segs.find((s) => s.method === 'constrained')\n        if (!constrained) continue\n        const column = phpFirstString(base.args)\n        if (!column) continue\n        const explicit = phpFirstString(constrained.args)\n        const parent = explicit ?? tableFromForeignKeyColumn(column)\n        if (parent) emit(bp.table, parent, line)\n        continue\n      }\n\n      // `foreignIdFor(User::class)` — the model names its table directly.\n      if (base.method === 'foreignIdFor') {\n        const cls = classRefBasename(phpArgumentValues(base.args)[0])\n        if (cls) emit(bp.table, tableize(cls), line)\n        continue\n      }\n\n      // `foreign('buyer_id')->references('id')->on('buyers')` — the parent table\n      // is the `on(...)` argument; `references(...)` is the parent column, ignored\n      // at table grain.\n      if (base.method === 'foreign') {\n        const on = un.segs.find((s) => s.method === 'on')\n        const parent = on ? phpFirstString(on.args) : null\n        if (parent) emit(bp.table, parent, line)\n        continue\n      }\n    }\n  })\n\n  return out\n}\n\n// ── app/Models/*.php: class↔table link + relations ───────────────────────────\n\n// The base-class basename of a `class X extends Y` — `Y`'s trailing name, or null.\nfunction baseClassName(cls: Parser.SyntaxNode): string | null {\n  for (let i = 0; i < cls.namedChildCount; i++) {\n    const c = cls.namedChild(i)\n    if (c?.type !== 'base_clause') continue\n    const ref = c.namedChild(0)\n    if (!ref) return null\n    const seg = ref.text.replace(/^\\\\+/, '').split('\\\\')\n    return seg[seg.length - 1] || null\n  }\n  return null\n}\n\n// Is this class an Eloquent model? `extends Model` (the Eloquent base) or\n// `extends Authenticatable` (the base Laravel's own `User` model uses), including\n// a fully-qualified `\\Illuminate\\Database\\Eloquent\\Model`.\nfunction isEloquentModel(cls: Parser.SyntaxNode): boolean {\n  const base = baseClassName(cls)\n  return base === 'Model' || base === 'Authenticatable'\n}\n\n// The `declaration_list` body of a class.\nfunction classBody(cls: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  for (let i = 0; i < cls.namedChildCount; i++) {\n    const c = cls.namedChild(i)\n    if (c?.type === 'declaration_list') return c\n  }\n  return null\n}\n\n// The explicit `protected $table = 'x'` override on a model, or null.\nfunction modelTableOverride(cls: Parser.SyntaxNode): string | null {\n  const body = classBody(cls)\n  if (!body) return null\n  for (let i = 0; i < body.namedChildCount; i++) {\n    const decl = body.namedChild(i)\n    if (decl?.type !== 'property_declaration') continue\n    for (let j = 0; j < decl.namedChildCount; j++) {\n      const el = decl.namedChild(j)\n      if (el?.type !== 'property_element') continue\n      // property_element's first named child is the `variable_name`; a\n      // `property_initializer` (when the property has a default) wraps its value.\n      if (variableName(el.namedChild(0)) !== 'table') continue\n      for (let k = 0; k < el.namedChildCount; k++) {\n        const child = el.namedChild(k)\n        if (child?.type !== 'property_initializer') continue\n        const str = phpStaticString(child.namedChild(child.namedChildCount - 1))\n        if (str) return str\n      }\n    }\n  }\n  return null\n}\n\n// The table a model maps to: `protected $table` when set, else the snake_case\n// plural of the class name. The migration literal is the anchor; this only names\n// the link.\nfunction modelTable(cls: Parser.SyntaxNode): string | null {\n  const nameNode = cls.childForFieldName('name')\n  if (!nameNode) return null\n  return modelTableOverride(cls) ?? tableize(nameNode.text)\n}\n\n// Walk a class subtree WITHOUT crossing into a nested class / anonymous class, so\n// `$this->belongsTo(...)` calls inside the model's relation methods are found but\n// a nested declaration's calls are not attributed here.\nfunction walkWithinClass(cls: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  const body = classBody(cls)\n  if (!body) return\n  const recur = (n: Parser.SyntaxNode): void => {\n    visit(n)\n    for (let i = 0; i < n.namedChildCount; i++) {\n      const c = n.namedChild(i)\n      if (!c) continue\n      if (c.type === 'class_declaration' || c.type === 'object_creation_expression') continue\n      recur(c)\n    }\n  }\n  recur(body)\n}\n\n// app/Models/*.php: the model→table link. Emits a `sql-table` endpoint so the\n// model file gets a `file ──CALLS──▶ sql-table` edge (the ActiveRecord/SQLAlchemy\n// model-file pattern) — no columns, since Eloquent reads those from the DB and the\n// migration is the column authority.\nexport function laravelModelEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const tree = parseSource(makePhpParser(), file.content)\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class_declaration' || !isEloquentModel(node)) return\n    const table = modelTable(node)\n    if (!table || seen.has(table)) return\n    seen.add(table)\n    const line = node.startPosition.row + 1\n    out.push({\n      infraId: infraId('sql-table', table),\n      name: table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'verified-call-site',\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  })\n\n  return out\n}\n\nconst ELOQUENT_RELATIONS = new Set(['belongsTo', 'hasMany', 'hasOne'])\n\n// app/Models/*.php relations → REFERENCES edges, deduped against the migration FKs\n// at the graph level (table-edges.ts guards every write with `hasEdge`, and the\n// migration refs are added first). The FK lives on the table that holds the\n// `<name>_id` column, so direction depends on the relation macro:\n//   belongsTo(User::class)     -> this table REFERENCES the relation's table (users)\n//   hasMany(LineItem::class)   -> line_items REFERENCES this table (FK on the other side)\n//   hasOne(Profile::class)     -> profiles REFERENCES this table\n// The first argument is the related model class; `belongsToMany` (pivot) and\n// `hasManyThrough` are deferred.\nexport function laravelModelForeignKeys(\n  file: SourceFile,\n  serviceDir: string,\n): TableReference[] {\n  const tree = parseSource(makePhpParser(), file.content)\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'class_declaration' || !isEloquentModel(node)) return\n    const thisTable = modelTable(node)\n    if (!thisTable) return\n\n    walkWithinClass(node, (call) => {\n      if (call.type !== 'member_call_expression') return\n      if (variableName(call.childForFieldName('object')) !== 'this') return\n      const macro = call.childForFieldName('name')?.text\n      if (!macro || !ELOQUENT_RELATIONS.has(macro)) return\n      const related = classRefBasename(phpArgumentValues(call.childForFieldName('arguments'))[0])\n      if (!related) return\n      const relatedTable = tableize(related)\n\n      const childTable = macro === 'belongsTo' ? thisTable : relatedTable\n      const parentTable = macro === 'belongsTo' ? relatedTable : thisTable\n      if (childTable === parentTable) return\n      const key = `${childTable}->${parentTable}`\n      if (seen.has(key)) return\n      seen.add(key)\n      const line = call.startPosition.row + 1\n      out.push({\n        childTable,\n        parentTable,\n        evidence: {\n          file: path.relative(serviceDir, file.path),\n          line,\n          snippet: snippet(file.content, line),\n        },\n      })\n    })\n  })\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Go from 'tree-sitter-go'\nimport { infraId } from '@neat.is/types'\nimport { tableFromSqlStatement, columnsFromSqlStatement } from '../../otel.js'\nimport type { ExternalEndpoint, SourceFile } from './shared.js'\nimport { snippet, toPosix } from './shared.js'\n\n// Go raw-SQL data-axis recognizer. ADR-154 seeded this with the six `database/sql`\n// query/exec methods and the table alone; ADR-184 rounds it out into a real data\n// reader — the sqlx surface, the touched columns, and a structural import gate.\n//\n//   db.Query(\"SELECT id, email FROM users WHERE id = $1\")\n//   db.ExecContext(ctx, \"INSERT INTO orders (total) VALUES ($1)\")\n//   db.Get(&u, `SELECT id, email FROM accounts WHERE id = $1`)   // sqlx\n//\n// GORM (ADR-180) covers the ORM case; plenty of Go services skip the ORM and hand\n// `database/sql` or `github.com/jmoiron/sqlx` a literal SQL string, and those table\n// reads/writes land on the SAME `infra:sql-table:<name>` nodes every ORM reader\n// produces.\n//\n// THE POINT is fusion, not a static table list (that's what every other tool already\n// does). The OBSERVED ingest recovers the table by running `tableFromSqlStatement` on\n// the span's `db.statement` / `db.query.text` — there is no dedicated table attribute\n// (ADR-152) — so this recognizer runs the EXACT SAME helper on the SAME SQL text. The\n// extracted table name is therefore byte-identical to the observed one and the two\n// fuse on `infraId('sql-table', <name>)` rather than twinning. `columnsFromSqlStatement`\n// does the same for the touched columns, folded as `ColumnAttr` (ADR-157 §3). Don't\n// write a second SQL parser here — divergence from the ingest parse is the one way\n// this breaks.\n//\n// Import gate (mirrors net/http's structural gate in routes.ts): recognize only in a\n// file that imports `database/sql` and/or `github.com/jmoiron/sqlx`. Without it an\n// arbitrary `.Query(...)` / `.Exec(...)` on any object — an HTTP client, a template\n// engine — mints a phantom table from any string that happens to parse as SQL. The\n// sqlx-only methods (`Get`, `Select`, …) are common names, so they are recognized\n// only when sqlx is actually imported.\n\nconst PARSE_CHUNK = 16384\n\n// `database/sql`'s statement-taking methods. A `*sqlx.DB` embeds `*sql.DB`, so these\n// are recognized whenever EITHER import is present.\nconst DATABASE_SQL_METHODS = new Set([\n  'Query',\n  'QueryContext',\n  'QueryRow',\n  'QueryRowContext',\n  'Exec',\n  'ExecContext',\n  'Prepare',\n  'PrepareContext',\n])\n\n// sqlx's own statement-taking surface — recognized only when `sqlx` is imported.\n// `Get`/`Select`/`GetContext`/`SelectContext` take a destination pointer first, so\n// the SQL isn't argument 0; the \"first string-literal argument\" scan below handles\n// that the same way it skips a leading `ctx`.\nconst SQLX_METHODS = new Set([\n  'Get',\n  'Select',\n  'Queryx',\n  'QueryRowx',\n  'NamedExec',\n  'NamedQuery',\n  'MustExec',\n  'Preparex',\n  'GetContext',\n  'SelectContext',\n])\n\nconst DATABASE_SQL_IMPORT = 'database/sql'\nconst SQLX_IMPORT = 'github.com/jmoiron/sqlx'\n\nfunction makeGoParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Go)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (node: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const child = node.namedChild(i)\n    if (child) walk(child, visit)\n  }\n}\n\n// The literal value of an interpreted (`\"...\"`) or raw/backtick (`` `...` ``) Go\n// string literal, delimiters stripped; null for anything else. Multi-line backtick\n// SQL is idiomatic in Go, so both node types are read verbatim — the backtick body\n// needs no unescaping.\nfunction goStringLiteralValue(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  if (node.type === 'interpreted_string_literal' || node.type === 'raw_string_literal') {\n    const t = node.text\n    return t.length >= 2 ? t.slice(1, -1) : ''\n  }\n  return null\n}\n\n// Whether the file imports any of `names` — the structural half of the gate, read off\n// both the grouped `import ( … )` and the single `import \"database/sql\"` forms (each\n// yields an `import_spec` whose path is a string literal). Mirrors `goImportsNetHttp`\n// in routes.ts.\nfunction goImportsAny(root: Parser.SyntaxNode, names: Set<string>): boolean {\n  let found = false\n  walk(root, (node) => {\n    if (found || node.type !== 'import_spec') return\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const value = goStringLiteralValue(node.namedChild(i))\n      if (value !== null && names.has(value)) found = true\n    }\n  })\n  return found\n}\n\n// The first DIRECT argument that is itself a string literal — the SQL statement.\n// Scanning direct args (not recursing) both skips a leading `ctx` / destination\n// pointer and refuses a computed statement: a `fmt.Sprintf(...)` or `base + \" ...\"`\n// argument is a call/binary expression, not a string literal, so nothing matches and\n// the call site is left unclaimed rather than guessed.\nfunction firstStringLiteralArg(argsNode: Parser.SyntaxNode | null): string | null {\n  if (!argsNode) return null\n  for (let i = 0; i < argsNode.namedChildCount; i++) {\n    const value = goStringLiteralValue(argsNode.namedChild(i))\n    if (value !== null) return value\n  }\n  return null\n}\n\n// Raw-SQL call sites → `infra:sql-table:<name>` endpoints carrying the touched\n// columns (ADR-157 §3). Gated on the `database/sql` / `sqlx` import. One endpoint per\n// call site (not per table) so a SELECT and an INSERT to the same table each\n// contribute their columns — the orchestrator (calls/index.ts) dedupes the CALLS edge\n// and folds the union of columns onto the one node.\nexport function goSqlEndpointsFromFile(file: SourceFile, serviceDir: string): ExternalEndpoint[] {\n  if (path.extname(file.path) !== '.go') return []\n  // Cheap textual pre-check before parsing — inert on the vast majority of `.go`\n  // files that touch no SQL driver at all.\n  if (!file.content.includes(DATABASE_SQL_IMPORT) && !file.content.includes(SQLX_IMPORT)) return []\n\n  const tree = parseSource(makeGoParser(), file.content)\n  const importsDatabaseSql = goImportsAny(tree.rootNode, new Set([DATABASE_SQL_IMPORT]))\n  const importsSqlx = goImportsAny(tree.rootNode, new Set([SQLX_IMPORT]))\n  if (!importsDatabaseSql && !importsSqlx) return []\n\n  const out: ExternalEndpoint[] = []\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call_expression') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'selector_expression') return\n    const method = fn.childForFieldName('field')?.text\n    if (!method) return\n    const recognized = DATABASE_SQL_METHODS.has(method) || (importsSqlx && SQLX_METHODS.has(method))\n    if (!recognized) return\n\n    const sql = firstStringLiteralArg(node.childForFieldName('arguments'))\n    if (sql === null) return\n    const table = tableFromSqlStatement(sql)\n    if (!table) return\n    const columns = columnsFromSqlStatement(sql)\n    const line = node.startPosition.row + 1\n\n    out.push({\n      infraId: infraId('sql-table', table),\n      name: table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'verified-call-site',\n      ...(columns.length > 0 ? { columns } : {}),\n      evidence: {\n        file: toPosix(path.relative(serviceDir, file.path)),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  })\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Go from 'tree-sitter-go'\nimport { infraId } from '@neat.is/types'\nimport { snippet, toPosix, type ExternalEndpoint, type SourceFile, type TableReference } from './shared.js'\n\n// Go/GORM data-axis recognizer (ADR-180), the data rung for Go after ADR-154's\n// route + `database/sql` call sites. GORM model structs feed the SAME `sql-table`\n// nodes, `ColumnAttr` columns (ADR-157), and `REFERENCES` edges (ADR-161) Prisma,\n// Drizzle, Rails, and Laravel already produce, so the reasoning core learns nothing\n// GORM-specific (calls/activerecord.ts and calls/eloquent.ts are the closest\n// analogs — a Rails model or an Eloquent model is a GORM struct).\n//\n//   type User struct {\n//     gorm.Model                  // -> id, created_at, updated_at, deleted_at\n//     Name      string            // -> name\n//     CompanyID uint              // -> company_id (the belongs-to FK column)\n//     Company   Company           // belongs-to: users -> companies\n//     Orders    []Order           // has-many:   orders -> users\n//   }\n//   db.AutoMigrate(&User{}, &Company{}, &Order{})\n//\n// THE LOAD-BEARING DIFFERENCE from Rails/Laravel: GORM has no literal schema file.\n// Rails' `db/schema.rb` and Laravel's migrations spell the table/column names out\n// as the exact database strings; GORM DERIVES the table name from the struct name\n// by `inflection.Plural(toDBName(StructName))` (schema.NamingStrategy.TableName,\n// https://gorm.io/docs/conventions.html). So the pluralizer must reproduce GORM's\n// own — an initialism-aware snake_case plus a jinzhu/inflection-style pluralizer\n// with irregulars — because a wrong derivation mints a table node the runtime\n// never creates (a FALSE node), not merely a missed edge. The OBSERVED table is\n// the ground truth: the GORM OTel plugin reports `tx.Statement.Table` as\n// `db.collection.name`, which ADR-179 taught ingest to read into the table key, so\n// the extracted node fuses onto `infra:sql-table:<name>` by table NAME — the\n// derivation is aimed at exactly that string. Where the derivation is wrong, the\n// OBSERVED side is the anchor and the divergence surfaces the miss.\n\n// Cheap per-file gate — inert on every `.go` file that isn't a GORM model file,\n// the import-gate discipline the other data-axis readers follow.\nconst GORM_IMPORT_RE = /gorm\\.io\\/gorm/\n\nconst PARSE_CHUNK = 16384\n\nfunction makeGoParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Go)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) walk(c, visit)\n  }\n}\n\n// ── inflection (GORM's schema.NamingStrategy, reproduced) ────────────────────\n//\n// Unlike the Rails/Laravel readers, where the schema literal is the anchor and the\n// pluralizer is a fallback, here the derived name IS the table name for every\n// struct without a `TableName()` override — so it must match GORM byte-for-byte or\n// the node fuses onto nothing.\n\n// The golint common-initialism list GORM's naming strategy links to. GORM replaces\n// each with its Title-case form BEFORE snake-casing, so a run like `API` collapses\n// to one word (`api`) instead of `a_p_i`. The exact set is GORM-version-sensitive\n// (GORM trims a few from golint's list across releases); this is the documented\n// best-effort surface where the OBSERVED table (ADR-179) is the ground-truth\n// anchor. Sorted longest-first so `HTTPS` wins over its `HTTP` prefix, matching\n// Go's `strings.Replacer` trie (longest match).\nconst COMMON_INITIALISMS = [\n  'ASCII', 'HTTPS', 'UTF8', 'XSRF', 'HTML', 'HTTP', 'JSON', 'UUID', 'XMPP',\n  'ACL', 'API', 'CPU', 'CSS', 'DNS', 'EOF', 'GUID', 'LHS', 'QPS', 'RAM', 'RHS',\n  'RPC', 'SLA', 'SQL', 'SSH', 'TCP', 'TLS', 'TTL', 'UDP', 'UID', 'URI', 'URL',\n  'UID', 'XSS', 'ID', 'IP', 'UI', 'VM', 'XML',\n].sort((a, b) => b.length - a.length)\n\nfunction titleCase(word: string): string {\n  return word.charAt(0) + word.slice(1).toLowerCase()\n}\n\n// Reproduce GORM's `commonInitialismsReplacer` — replace each initialism with its\n// Title-case form, scanning left-to-right, longest match first (Go's Replacer).\nfunction replaceInitialisms(name: string): string {\n  let out = ''\n  let i = 0\n  while (i < name.length) {\n    let matched = false\n    for (const init of COMMON_INITIALISMS) {\n      if (name.startsWith(init, i)) {\n        out += titleCase(init)\n        i += init.length\n        matched = true\n        break\n      }\n    }\n    if (!matched) {\n      out += name[i]\n      i++\n    }\n  }\n  return out\n}\n\nconst isUpper = (c: string): boolean => c >= 'A' && c <= 'Z'\nconst isDigit = (c: string): boolean => c >= '0' && c <= '9'\n\n// A faithful port of GORM's `NamingStrategy.toDBName` (schema/naming.go): run the\n// initialism replacer, then a CamelCase→snake pass that keeps capital runs\n// together (`APIKey` → `api_key`, `LineItem` → `line_item`, `GormUserName` →\n// `gorm_user_name`). Ported char-by-char since Go identifiers are ASCII.\nfunction toDBName(name: string): string {\n  if (name === '') return ''\n  const value = replaceInitialisms(name)\n  if (value.length === 1) return value.toLowerCase()\n\n  let buf = ''\n  let lastCase = false\n  let curCase = isUpper(value[0]!)\n  for (let i = 0; i < value.length - 1; i++) {\n    const v = value[i]!\n    const nextCase = isUpper(value[i + 1]!)\n    const nextNumber = isDigit(value[i + 1]!)\n    if (curCase) {\n      if (lastCase && (nextCase || nextNumber)) {\n        buf += v.toLowerCase()\n      } else {\n        if (i > 0 && value[i - 1] !== '_' && lastCase !== curCase) buf += '_'\n        buf += v.toLowerCase()\n      }\n    } else {\n      buf += v\n    }\n    lastCase = curCase\n    curCase = nextCase\n  }\n  const last = value[value.length - 1]!\n  if (curCase) {\n    if (!lastCase && value.length > 1) buf += '_'\n    buf += last.toLowerCase()\n  } else {\n    buf += last\n  }\n  return buf\n}\n\n// github.com/jinzhu/inflection (a Rails-ActiveSupport port) is what GORM pluralizes\n// with. Uncountables pass through, irregulars map directly, then the ordered rules\n// fire first-match-wins (specific before the generic `+s`). The irregular set is\n// finite/best-effort — documented in ADR-180, with the OBSERVED table as the\n// anchor where a rule is wrong. Operates on the snake_cased struct name, so the\n// rules anchor on the trailing word of a multi-word name (`line_item` → `line_items`).\nconst UNCOUNTABLE = new Set([\n  'equipment', 'information', 'rice', 'money', 'species', 'series', 'fish',\n  'sheep', 'jeans', 'police',\n])\n\nconst IRREGULAR: Array<[string, string]> = [\n  ['person', 'people'],\n  ['man', 'men'],\n  ['child', 'children'],\n  ['sex', 'sexes'],\n  ['move', 'moves'],\n]\n\nconst PLURAL_RULES: Array<[RegExp, string]> = [\n  [/(quiz)$/i, '$1zes'],\n  [/^(ox)$/i, '$1en'],\n  [/([ml])ouse$/i, '$1ice'],\n  [/(matr|vert|ind)(?:ix|ex)$/i, '$1ices'],\n  [/(x|ch|ss|sh)$/i, '$1es'],\n  [/([^aeiouy]|qu)y$/i, '$1ies'],\n  [/(hive)$/i, '$1s'],\n  [/(?:([^f])fe|([lr])f)$/i, '$1$2ves'],\n  [/sis$/i, 'ses'],\n  [/([ti])um$/i, '$1a'],\n  [/([ti])a$/i, '$1a'],\n  [/(buffal|tomat)o$/i, '$1oes'],\n  [/(bu)s$/i, '$1ses'],\n  [/(alias|status)$/i, '$1es'],\n  [/(octop|vir)i$/i, '$1i'],\n  [/(octop|vir)us$/i, '$1i'],\n  [/(ax|test)is$/i, '$1es'],\n  [/s$/i, 's'],\n]\n\nfunction pluralize(word: string): string {\n  if (word === '') return word\n  const lower = word.toLowerCase()\n  for (const u of UNCOUNTABLE) {\n    if (lower === u || lower.endsWith('_' + u)) return word\n  }\n  for (const [sing, plur] of IRREGULAR) {\n    const re = new RegExp(sing + '$', 'i')\n    if (re.test(word)) return word.replace(re, plur)\n  }\n  for (const [re, rep] of PLURAL_RULES) {\n    if (re.test(word)) return word.replace(re, rep)\n  }\n  return word + 's'\n}\n\n// struct name → GORM's default table name: `inflection.Plural(toDBName(name))`.\n// `User` → users, `LineItem` → line_items, `APIKey` → api_keys, `Person` → people.\nfunction deriveTableName(structName: string): string {\n  return pluralize(toDBName(structName))\n}\n\n// ── struct / field model ─────────────────────────────────────────────────────\n\ninterface GormTag {\n  column?: string\n  skip?: boolean // gorm:\"-\"\n  primaryKey?: boolean\n  foreignKey?: string\n  many2many?: string\n  embedded?: boolean\n  embeddedPrefix?: string\n}\n\ninterface GoField {\n  names: string[] // empty for an embedded (anonymous) field\n  typeName: string | null // base type name, slice/pointer/array unwrapped\n  qualifier: string | null // package part of a qualified type (`gorm` in gorm.Model)\n  isSlice: boolean\n  isPointer: boolean\n  isQualified: boolean\n  tag: GormTag\n  line: number\n}\n\ninterface StructInfo {\n  name: string\n  fields: GoField[]\n  line: number\n}\n\nfunction stringLiteralValue(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node) return null\n  if (node.type === 'interpreted_string_literal' || node.type === 'raw_string_literal') {\n    const t = node.text\n    return t.length >= 2 ? t.slice(1, -1) : ''\n  }\n  return null\n}\n\n// Parse a struct field's `gorm:\"...\"` tag. The tag node text carries its delimiters\n// (backticks for a raw string, quotes for an interpreted one); an interpreted tag\n// escapes its inner quotes, so unescape first.\nfunction parseGormTag(tagNode: Parser.SyntaxNode | null | undefined): GormTag {\n  const tag: GormTag = {}\n  if (!tagNode) return tag\n  let inner = tagNode.text\n  if (inner.length >= 2) inner = inner.slice(1, -1)\n  if (tagNode.type === 'interpreted_string_literal') inner = inner.replace(/\\\\\"/g, '\"')\n  const m = inner.match(/gorm:\"([^\"]*)\"/)\n  if (!m) return tag\n  for (const part of m[1]!.split(';')) {\n    if (part === '') continue\n    const idx = part.indexOf(':')\n    const key = (idx >= 0 ? part.slice(0, idx) : part).trim().toLowerCase()\n    const value = idx >= 0 ? part.slice(idx + 1).trim() : ''\n    if (key === '-') tag.skip = true\n    else if (key === 'column') tag.column = value\n    else if (key === 'primarykey' || key === 'primary_key') tag.primaryKey = true\n    else if (key === 'foreignkey') tag.foreignKey = value\n    else if (key === 'many2many') tag.many2many = value\n    else if (key === 'embedded') tag.embedded = true\n    else if (key === 'embeddedprefix') tag.embeddedPrefix = value\n  }\n  return tag\n}\n\n// Unwrap a field's type through any slice / array / pointer layers to the base\n// named type. `[]Order` → { name: 'Order', isSlice }, `*Company` → { name:\n// 'Company', isPointer }, `time.Time` → { name: 'Time', qualifier: 'time' }.\nfunction unwrapType(typeNode: Parser.SyntaxNode | null): {\n  name: string | null\n  qualifier: string | null\n  isSlice: boolean\n  isPointer: boolean\n  isQualified: boolean\n} {\n  let isSlice = false\n  let isPointer = false\n  let n: Parser.SyntaxNode | null = typeNode\n  while (n && (n.type === 'slice_type' || n.type === 'array_type' || n.type === 'pointer_type')) {\n    if (n.type === 'slice_type' || n.type === 'array_type') isSlice = true\n    if (n.type === 'pointer_type') isPointer = true\n    n = n.childForFieldName('element') ?? n.namedChild(n.namedChildCount - 1)\n  }\n  if (!n) return { name: null, qualifier: null, isSlice, isPointer, isQualified: false }\n  if (n.type === 'type_identifier') {\n    return { name: n.text, qualifier: null, isSlice, isPointer, isQualified: false }\n  }\n  if (n.type === 'qualified_type') {\n    const pkg = n.childForFieldName('package')?.text ?? n.namedChild(0)?.text ?? null\n    const nm = n.childForFieldName('name')?.text ?? n.namedChild(1)?.text ?? null\n    return { name: nm, qualifier: pkg, isSlice, isPointer, isQualified: true }\n  }\n  // map / func / interface / channel types are never a column or a relation.\n  return { name: null, qualifier: null, isSlice, isPointer, isQualified: false }\n}\n\nfunction readField(fieldDecl: Parser.SyntaxNode): GoField {\n  const names: string[] = []\n  let tagNode: Parser.SyntaxNode | null = null\n  for (let i = 0; i < fieldDecl.namedChildCount; i++) {\n    const c = fieldDecl.namedChild(i)\n    if (!c) continue\n    if (c.type === 'field_identifier') names.push(c.text)\n    else if (c.type === 'raw_string_literal' || c.type === 'interpreted_string_literal') tagNode = c\n  }\n  const typeNode = fieldDecl.childForFieldName('type')\n  const t = unwrapType(typeNode)\n  return {\n    names,\n    typeName: t.name,\n    qualifier: t.qualifier,\n    isSlice: t.isSlice,\n    isPointer: t.isPointer,\n    isQualified: t.isQualified,\n    tag: parseGormTag(tagNode),\n    line: fieldDecl.startPosition.row + 1,\n  }\n}\n\n// Every `type X struct { … }` in the file, keyed by name.\nfunction collectStructs(tree: Parser.Tree): Map<string, StructInfo> {\n  const structs = new Map<string, StructInfo>()\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'type_spec') return\n    const nameNode = node.childForFieldName('name')\n    const typeNode = node.childForFieldName('type')\n    if (!nameNode || typeNode?.type !== 'struct_type') return\n    const list = typeNode.childForFieldName('body') ?? typeNode.namedChild(0)\n    const fields: GoField[] = []\n    if (list && list.type === 'field_declaration_list') {\n      for (let i = 0; i < list.namedChildCount; i++) {\n        const fd = list.namedChild(i)\n        if (fd?.type === 'field_declaration') fields.push(readField(fd))\n      }\n    }\n    structs.set(nameNode.text, {\n      name: nameNode.text,\n      fields,\n      line: node.startPosition.row + 1,\n    })\n  })\n  return structs\n}\n\n// GORM entry points that take a model pointer/value and so name a model struct.\n// `AutoMigrate(&A{}, &B{})` is the richest — it enumerates the whole model set in\n// one call.\nconst GORM_MODEL_METHODS = new Set([\n  'AutoMigrate', 'Model', 'Create', 'Find', 'First', 'Take', 'Last', 'Save',\n  'Delete', 'Where', 'FirstOrCreate', 'FirstOrInit',\n])\n\n// The struct name a `&X{}` / `X{}` argument composite-literal names, or null.\nfunction compositeStructName(arg: Parser.SyntaxNode): string | null {\n  let n: Parser.SyntaxNode | null = arg\n  if (n.type === 'unary_expression') n = n.childForFieldName('operand') ?? n.namedChild(0)\n  if (!n || n.type !== 'composite_literal') return null\n  const typeNode = n.childForFieldName('type')\n  if (!typeNode) return null\n  if (typeNode.type === 'type_identifier') return typeNode.text\n  if (typeNode.type === 'qualified_type') {\n    return typeNode.childForFieldName('name')?.text ?? typeNode.namedChild(1)?.text ?? null\n  }\n  return null\n}\n\n// Model structs referenced through a GORM db-method call anywhere in the file.\nfunction collectCallModels(tree: Parser.Tree): Set<string> {\n  const models = new Set<string>()\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'call_expression') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'selector_expression') return\n    const method = fn.childForFieldName('field')?.text\n    if (!method || !GORM_MODEL_METHODS.has(method)) return\n    const args = node.childForFieldName('arguments')\n    if (!args) return\n    for (let i = 0; i < args.namedChildCount; i++) {\n      const arg = args.namedChild(i)\n      if (!arg) continue\n      const name = compositeStructName(arg)\n      if (name) models.add(name)\n    }\n  })\n  return models\n}\n\n// A `func (X) TableName() string { return \"literal\" }` override map. A computed\n// return (a variable, a concatenation) yields no entry — the struct falls back to\n// the derived name — but still counts as a model signal.\nfunction collectTableNameOverrides(\n  tree: Parser.Tree,\n): { overrides: Map<string, string>; declarers: Set<string> } {\n  const overrides = new Map<string, string>()\n  const declarers = new Set<string>()\n  walk(tree.rootNode, (node) => {\n    if (node.type !== 'method_declaration') return\n    if (node.childForFieldName('name')?.text !== 'TableName') return\n    const receiver = node.childForFieldName('receiver')\n    if (!receiver) return\n    let recvType: string | null = null\n    for (let i = 0; i < receiver.namedChildCount; i++) {\n      const pd = receiver.namedChild(i)\n      if (pd?.type !== 'parameter_declaration') continue\n      const t = unwrapType(pd.childForFieldName('type'))\n      recvType = t.name\n    }\n    if (!recvType) return\n    declarers.add(recvType)\n    const body = node.childForFieldName('body')\n    if (!body) return\n    let literal: string | null = null\n    walk(body, (n) => {\n      if (literal !== null) return\n      if (n.type !== 'return_statement') return\n      const exprList = n.namedChild(0)\n      const first = exprList?.namedChild(0) ?? exprList\n      const v = stringLiteralValue(first)\n      if (v) literal = v\n    })\n    if (literal !== null) overrides.set(recvType, literal)\n  })\n  return { overrides, declarers }\n}\n\n// A field is a RELATION (association), not a column, when its base type — slice or\n// pointer unwrapped — is another struct declared in this file, and it is not a\n// qualified type (`time.Time`, `sql.NullString`) or the embedded `gorm.Model`.\nfunction isRelationField(field: GoField, structs: Map<string, StructInfo>): boolean {\n  if (field.names.length === 0) return false // embedded, handled separately\n  if (field.isQualified) return false\n  if (!field.typeName) return false\n  return structs.has(field.typeName)\n}\n\n// Is `gorm.Model`?\nfunction isGormModelEmbed(field: GoField): boolean {\n  return field.names.length === 0 && field.qualifier === 'gorm' && field.typeName === 'Model'\n}\n\n// ── analysis (shared by the endpoint and FK readers) ─────────────────────────\n\ninterface Analysis {\n  structs: Map<string, StructInfo>\n  models: Set<string>\n  tableFor: (structName: string) => string\n}\n\nfunction analyze(tree: Parser.Tree): Analysis {\n  const structs = collectStructs(tree)\n  const { overrides, declarers } = collectTableNameOverrides(tree)\n  const callModels = collectCallModels(tree)\n\n  // Seed the model set from the three direct signals: a gorm.Model embed, a GORM\n  // db-method call arg, or a TableName() declaration.\n  const models = new Set<string>()\n  for (const [name, info] of structs) {\n    if (info.fields.some(isGormModelEmbed)) models.add(name)\n  }\n  for (const name of callModels) if (structs.has(name)) models.add(name)\n  for (const name of declarers) if (structs.has(name)) models.add(name)\n\n  // Expand: a struct referenced as a relation field by a model is itself a model\n  // (GORM requires the related type to be a registered model). Fixpoint over the\n  // relation graph so a related model's own relations pull their targets in too.\n  let grew = true\n  while (grew) {\n    grew = false\n    for (const name of Array.from(models)) {\n      const info = structs.get(name)\n      if (!info) continue\n      for (const field of info.fields) {\n        if (!isRelationField(field, structs)) continue\n        const target = field.typeName!\n        if (!models.has(target) && structs.has(target)) {\n          models.add(target)\n          grew = true\n        }\n      }\n    }\n  }\n\n  const tableFor = (structName: string): string =>\n    overrides.get(structName) ?? deriveTableName(structName)\n\n  return { structs, models, tableFor }\n}\n\n// Expand a model struct's fields into its database column names. Anonymous\n// embedded fields inline: `gorm.Model` → the four audit columns, and an embedded\n// LOCAL struct (`type Base struct{…}; type User struct{ Base; … }`) inlines its own\n// columns (one level, cycle-guarded). A named field with `gorm:\"embedded\"` inlines\n// with an optional prefix. `gorm:\"-\"` skips; a relation field is not a column.\nfunction collectColumns(\n  struct: StructInfo,\n  structs: Map<string, StructInfo>,\n  seen: Set<string>,\n  prefix: string,\n  out: string[],\n  emitted: Set<string>,\n): void {\n  if (seen.has(struct.name)) return\n  seen.add(struct.name)\n\n  const add = (col: string): void => {\n    const full = prefix + col\n    if (!emitted.has(full)) {\n      emitted.add(full)\n      out.push(full)\n    }\n  }\n\n  for (const field of struct.fields) {\n    if (field.tag.skip) continue\n\n    // Anonymous embedded field.\n    if (field.names.length === 0) {\n      if (isGormModelEmbed(field)) {\n        add('id')\n        add('created_at')\n        add('updated_at')\n        add('deleted_at')\n      } else if (!field.isQualified && field.typeName && structs.has(field.typeName)) {\n        collectColumns(structs.get(field.typeName)!, structs, seen, prefix, out, emitted)\n      }\n      // An unresolved external embed (some other package's base) can't be inlined.\n      continue\n    }\n\n    // A named field tagged embedded inlines the target struct's columns.\n    if (field.tag.embedded && !field.isQualified && field.typeName && structs.has(field.typeName)) {\n      collectColumns(\n        structs.get(field.typeName)!,\n        structs,\n        seen,\n        prefix + (field.tag.embeddedPrefix ?? ''),\n        out,\n        emitted,\n      )\n      continue\n    }\n\n    // A relation to another model is not a column (its FK companion scalar is).\n    if (isRelationField(field, structs)) continue\n\n    // A scalar / time.Time / sql.Null* / []byte / named-scalar field is a column.\n    // The `gorm:\"column:x\"` override wins (verbatim); otherwise snake_case each\n    // name. The override only makes sense for a single-name declaration.\n    if (field.names.length === 1 && field.tag.column) {\n      add(field.tag.column)\n    } else {\n      for (const n of field.names) add(toDBName(n))\n    }\n  }\n\n  seen.delete(struct.name)\n}\n\n// GORM model structs → `infra:sql-table:<name>` endpoints carrying EXTRACTED\n// columns (ADR-157 §3). Gated on the `gorm.io/gorm` import. One endpoint per\n// distinct table; the orchestrator (calls/index.ts) mints the node, folds the\n// columns, and originates the `file ──CALLS──▶ sql-table` edge.\nexport function gormEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (path.extname(file.path) !== '.go') return []\n  if (!GORM_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(makeGoParser(), file.content)\n  const { structs, models, tableFor } = analyze(tree)\n\n  const out: ExternalEndpoint[] = []\n  const seenTables = new Set<string>()\n  for (const name of models) {\n    const struct = structs.get(name)\n    if (!struct) continue\n    const table = tableFor(name)\n    if (seenTables.has(table)) continue\n    seenTables.add(table)\n\n    const columns: string[] = []\n    collectColumns(struct, structs, new Set(), '', columns, new Set())\n\n    out.push({\n      infraId: infraId('sql-table', table),\n      name: table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'structural',\n      ...(columns.length > 0 ? { columns } : {}),\n      evidence: {\n        file: toPosix(path.relative(serviceDir, file.path)),\n        line: struct.line,\n        snippet: snippet(file.content, struct.line),\n      },\n    })\n  }\n  return out\n}\n\n// GORM associations → `REFERENCES` table→table edges (ADR-161). The FK lives on the\n// table holding the `<Field>ID` column, so direction depends on the association:\n//   belongs to (User has CompanyID + Company Company) -> users REFERENCES companies\n//   has one    (User has CreditCard CreditCard)       -> credit_cards REFERENCES users\n//   has many   (User has Orders []Order)              -> orders REFERENCES users\n//   many2many  (User has Languages []Language `many2many:user_languages`)\n//                                    -> user_languages REFERENCES users + languages\n// A singular struct field is belongs-to when THIS struct also holds the\n// conventional `<Field>ID` (or `foreignKey:`-named) scalar; otherwise has-one.\n// `table-edges.ts` dedupes at the graph level and drops self-loops.\nexport function gormForeignKeys(file: SourceFile, serviceDir: string): TableReference[] {\n  if (path.extname(file.path) !== '.go') return []\n  if (!GORM_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(makeGoParser(), file.content)\n  const { structs, models, tableFor } = analyze(tree)\n\n  const out: TableReference[] = []\n  const seen = new Set<string>()\n  const emit = (childTable: string, parentTable: string, line: number): void => {\n    if (!childTable || !parentTable || childTable === parentTable) return\n    const key = `${childTable}->${parentTable}`\n    if (seen.has(key)) return\n    seen.add(key)\n    out.push({\n      childTable,\n      parentTable,\n      evidence: {\n        file: toPosix(path.relative(serviceDir, file.path)),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  for (const name of models) {\n    const struct = structs.get(name)\n    if (!struct) continue\n    const thisTable = tableFor(name)\n    const scalarNames = new Set(\n      struct.fields\n        .filter((f) => f.names.length > 0 && !isRelationField(f, structs))\n        .flatMap((f) => f.names),\n    )\n\n    for (const field of struct.fields) {\n      if (field.tag.skip) continue\n      if (!isRelationField(field, structs)) continue\n      const relTable = tableFor(field.typeName!)\n\n      // many2many: synthesize the join table and reference both sides.\n      if (field.tag.many2many) {\n        emit(field.tag.many2many, thisTable, field.line)\n        emit(field.tag.many2many, relTable, field.line)\n        continue\n      }\n\n      if (field.isSlice) {\n        // has many — FK on the other table.\n        emit(relTable, thisTable, field.line)\n        continue\n      }\n\n      // Singular struct field: belongs-to when this struct carries the FK column.\n      const convFk = field.names[0]! + 'ID'\n      const belongsTo =\n        scalarNames.has(convFk) ||\n        (field.tag.foreignKey ? scalarNames.has(field.tag.foreignKey) : false)\n      if (belongsTo) emit(thisTable, relTable, field.line)\n      else emit(relTable, thisTable, field.line)\n    }\n  }\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport CSharp from 'tree-sitter-c-sharp'\nimport { infraId } from '@neat.is/types'\nimport { snippet, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// EF Core / .NET data-axis recognizer (ADR-203) — the C# rung of the same\n// `infra:sql-table:<name>` grain the SQLAlchemy, GORM, ActiveRecord, and Eloquent\n// readers already produce. The SQL analog of calls/gorm.ts, but with the opposite\n// fidelity problem solved for free: where GORM *derives* the table name from the\n// struct (so the pluralizer has to match byte-for-byte), EF Core's fusion-anchored\n// shape is an EXPLICIT table name, so the recognizer reads a literal and never\n// guesses:\n//\n//   [Table(\"orderitem\", Schema = \"accounting\")]          // data annotation\n//   public class OrderItemEntity { ... }\n//\n//   modelBuilder.Entity<OrderEntity>().ToTable(\"order\"); // fluent API\n//\n// Both name the database table VERBATIM — the same string the running query hits,\n// which is the string an OBSERVED db span reports (recovered from `db.statement`\n// the way ADR-152 recovers SQLAlchemy's), so the extracted node fuses onto\n// `infra:sql-table:<name>` by table name. The otel-demo `accounting` service names\n// `orderitem` / `order` / `shipping` this way, so its OBSERVED `CALLS\n// infra:sql-table:orderitem` edge gets a static twin instead of orphaning.\n//\n// Table grain only. EF Core's COLUMN names are convention-transformed\n// (`UseSnakeCaseNamingConvention()` and friends, configured in a different file\n// than the entity), so reproducing them faithfully is not a per-file fact the way\n// GORM's tags are — and a PARTIAL column set would manufacture false column-drift.\n// The OBSERVED side anchors columns regardless, so column grain is left as a named\n// follow-on rather than guessed at.\n\n// Cheap per-file gate — inert on any `.cs` file that isn't an EF Core entity /\n// model-configuration file, the import-gate discipline the data-axis readers share.\n// The `[Table]` / `[Column]` annotations live in\n// `System.ComponentModel.DataAnnotations.Schema`; `DbContext` / `DbSet<>` and the\n// fluent API live in `Microsoft.EntityFrameworkCore`.\nconst EFCORE_GATE =\n  /Microsoft\\.EntityFrameworkCore|DataAnnotations\\.Schema|\\bDbContext\\b|\\bDbSet\\s*</\n\nconst PARSE_CHUNK = 16384\n\nfunction makeCsParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(CSharp)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) walk(c, visit)\n  }\n}\n\nfunction firstChildOfType(node: Parser.SyntaxNode, type: string): Parser.SyntaxNode | null {\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c?.type === type) return c\n  }\n  return null\n}\n\n// A C# string literal node's value, or null when it is not a plain string (an\n// interpolated `$\"...\"` carries a runtime hole — never a static table name).\n// A regular `\"orders\"` exposes its text through a `string_literal_content` child;\n// a verbatim `@\"orders\"` is a leaf whose `@\"` / `\"` delimiters (and doubled `\"\"`\n// escapes) are stripped here.\nfunction csStringLiteral(node: Parser.SyntaxNode): string | null {\n  if (node.type === 'string_literal') {\n    let out = ''\n    for (let i = 0; i < node.namedChildCount; i++) {\n      const c = node.namedChild(i)\n      if (c?.type === 'string_literal_content') out += c.text\n    }\n    return out\n  }\n  if (node.type === 'verbatim_string_literal') {\n    const t = node.text\n    return t.length >= 3 ? t.slice(2, -1).replace(/\"\"/g, '\"') : ''\n  }\n  return null\n}\n\n// The trailing identifier of an attribute name (`Table`, or the last segment of a\n// qualified `…Schema.Table`), so `[Table(...)]` and a fully-qualified spelling\n// both resolve to `Table`. Tolerates the `Attribute` suffix C# allows to be\n// dropped (`[TableAttribute(...)]`).\nfunction attributeName(attr: Parser.SyntaxNode): string | null {\n  const nameNode = attr.childForFieldName('name') ?? attr.namedChild(0)\n  if (!nameNode) return null\n  const text = nameNode.text\n  const base = text.includes('.') ? text.slice(text.lastIndexOf('.') + 1) : text\n  return base.endsWith('Attribute') ? base.slice(0, -'Attribute'.length) : base\n}\n\n// The literal table name a `[Table(\"orders\", …)]` attribute declares: the value of\n// its first POSITIONAL string argument. A `[Table(nameof(X))]` or a keyword-only\n// form (`[Table(Schema = \"s\")]`) yields no positional string and is left unclaimed\n// rather than guessed.\nfunction tableFromAttribute(attr: Parser.SyntaxNode): string | null {\n  if (attributeName(attr) !== 'Table') return null\n  const args = attr.childForFieldName('arguments') ?? firstChildOfType(attr, 'attribute_argument_list')\n  if (!args) return null\n  for (let i = 0; i < args.namedChildCount; i++) {\n    const arg = args.namedChild(i)\n    if (arg?.type !== 'attribute_argument') continue\n    // A named argument (`Schema = \"accounting\"`) is an assignment_expression — not\n    // the positional table name. The positional table name is a bare string child.\n    const first = arg.namedChild(0)\n    if (!first) continue\n    const value = csStringLiteral(first)\n    if (value !== null) return value\n    return null // first positional arg is not a plain string — don't guess\n  }\n  return null\n}\n\n// The literal table name a `.ToTable(\"orders\")` fluent call declares: the value of\n// its first string argument. `.ToTable(t => …)` (a table-builder overload) and any\n// non-string first argument yield nothing.\nfunction tableFromToTable(call: Parser.SyntaxNode): string | null {\n  const fn = call.childForFieldName('function')\n  if (fn?.type !== 'member_access_expression') return null\n  const method = fn.childForFieldName('name') ?? fn.namedChild(fn.namedChildCount - 1)\n  if (method?.text !== 'ToTable') return null\n  const args = call.childForFieldName('arguments')\n  const firstArg = args?.namedChild(0)\n  if (firstArg?.type !== 'argument') return null\n  const value = firstArg.namedChild(0)\n  return value ? csStringLiteral(value) : null\n}\n\n// EF Core entity / model-configuration files → `infra:sql-table:<name>` endpoints\n// (ADR-203). Gated on an EF Core signal; parsed with tree-sitter-c-sharp from the\n// RAW file (comments are structural `comment` nodes, so a `[Table(\"x\")]` in a `//`\n// or `/* */` comment never mints a node). One endpoint per distinct table name;\n// the orchestrator (calls/index.ts) mints the node and the `file ──CALLS──▶\n// sql-table` edge. Table grain — no columns (see the file header).\nexport function efcoreEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (path.extname(file.path) !== '.cs') return []\n  if (!EFCORE_GATE.test(file.content)) return []\n  const tree = parseSource(makeCsParser(), file.content)\n\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const push = (name: string, line: number): void => {\n    if (!name || seen.has(name)) return\n    seen.add(name)\n    out.push({\n      infraId: infraId('sql-table', name),\n      name,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'structural',\n      evidence: {\n        file: toPosix(path.relative(serviceDir, file.path)),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n\n  walk(tree.rootNode, (node) => {\n    if (node.type === 'attribute') {\n      const table = tableFromAttribute(node)\n      if (table) push(table, node.startPosition.row + 1)\n      return\n    }\n    if (node.type === 'invocation_expression') {\n      const table = tableFromToTable(node)\n      if (table) push(table, node.startPosition.row + 1)\n    }\n  })\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport { infraId } from '@neat.is/types'\nimport { tableFromSqlStatement, columnsFromSqlStatement } from '../../otel.js'\nimport { GRAMMAR_BY_EXT, parseSource } from '../symbols.js'\nimport { snippet, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// JS/TS raw-SQL data-axis recognizer for the `mysql` / `mysql2` drivers (#1432) —\n// the JavaScript sibling of the Go `database/sql` reader (calls/go.ts, ADR-184).\n// A service that talks to MySQL through a plain driver with SQL in strings gets no\n// table grain today: the JS ORM readers cover knex / sequelize / prisma / drizzle /\n// typeorm, but a bare `mysql`/`mysql2` connection handed a literal statement lands\n// nothing. This reads the table (and the touched columns) off that statement and\n// mints the same `infra:sql-table:<name>` node every ORM reader and the OBSERVED\n// ingest produce.\n//\n//   const mysql = require('mysql')\n//   conn.query(\"SELECT * FROM office\", cb)                         // inline literal\n//   const sql = \"SELECT * FROM office \" + where_sql; conn.query(sql, cb)   // var + head\n//   conn.execute(\"INSERT INTO office (name) VALUES (?)\", [n])      // mysql2\n//\n// THE POINT is fusion, not a static table list. The OBSERVED ingest recovers the\n// table by running `tableFromSqlStatement` on a span's `db.statement` (there is no\n// dedicated table attribute — ADR-152), so this recognizer runs the EXACT SAME\n// shared helper on the SAME SQL text and the extracted table is byte-identical to\n// the observed one — the two fuse on `infraId('sql-table', <name>)` rather than\n// twinning. `columnsFromSqlStatement` does the same for the touched columns (ADR-157\n// §3). Both live in otel.ts, their one home — never a second SQL parser here, since\n// divergence from the ingest parse is the one way this breaks.\n//\n// Statement shape (#1432 ruling a): a statement whose literal HEAD parses to\n// `SELECT … FROM <t>` / `INSERT INTO <t>` / `UPDATE <t>` / `DELETE FROM <t>` is\n// claimed with the table from the head; a runtime tail (`\"… FROM office \" + where`)\n// does not block it. A `CREATE TABLE` has no FROM/INTO/UPDATE keyword, so\n// `tableFromSqlStatement` returns null and it is left unclaimed — the honest,\n// conservative default, never guessed.\n//\n// Variable resolution (#1432): the statement is usually built into a local variable\n// first (`const sql = …; conn.query(sql, cb)`), so a `.query`/`.execute` whose first\n// argument is an identifier is resolved to its SAME-FILE, ENCLOSING-FUNCTION,\n// NEAREST-PRECEDING assignment, and only when that value is a string literal or a\n// literal-headed concatenation. An identifier reassigned in between (the nearest\n// assignment is then the non-literal one), a function parameter, or an argument with\n// no literal head stays unclaimed. This is the same literal inlining the URL-helper\n// recognizer (#1426) does for one-return helpers — precedent, not a new shape.\n//\n// Import gate (mirrors calls/go.ts' driver gate): recognized only in a file that\n// imports `mysql` or `mysql2` (incl. `mysql2/promise`). Without it a `.query(...)` /\n// `.execute(...)` on any object — an HTTP client, an ORM — could mint a phantom\n// table from any string that happens to parse as SQL. The SQL-parse gate\n// (`tableFromSqlStatement` returning a table) is the second filter, so a non-SQL\n// `.execute(\"...\")` in a mysql-importing file still claims nothing.\n\n// `require('mysql')` / `require('mysql2')` / `require('mysql2/promise')` and the\n// `import … from 'mysql2/promise'` forms.\nconst MYSQL_IMPORT_RE = /(?:from\\s+['\"`]|require\\(\\s*['\"`])mysql2?(?:\\/promise)?['\"`]/\n\n// Statement-taking methods on a `mysql`/`mysql2` connection, pool, or promise\n// wrapper. `query` is `mysql` + `mysql2`; `execute` is `mysql2`'s prepared path.\nconst SQL_METHODS = new Set(['query', 'execute'])\n\nconst JS_EXTS = new Set(['.js', '.jsx', '.mjs', '.cjs', '.ts', '.tsx'])\n\n// Nodes that open a new function scope — the boundary variable resolution does not\n// cross (a `.query(sql)` resolves `sql` only within its own enclosing function).\nconst FUNCTION_NODE_TYPES = new Set([\n  'function_declaration',\n  'function_expression',\n  'arrow_function',\n  'method_definition',\n  'generator_function',\n  'generator_function_declaration',\n])\n\nfunction parserForExt(ext: string): Parser {\n  const p = new Parser()\n  p.setLanguage(GRAMMAR_BY_EXT[ext] ?? JavaScript)\n  return p\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\n// The full literal value of a plain `string` node (quotes stripped); null for a\n// template / any non-string node. An empty `''` has no `string_fragment` child.\nfunction stringLiteralValue(node: Parser.SyntaxNode | null): string | null {\n  if (!node || node.type !== 'string') return null\n  for (const c of namedChildren(node)) {\n    if (c.type === 'string_fragment') return c.text\n  }\n  return ''\n}\n\n// The value of an expression that is ENTIRELY string-literal — a `string`, a\n// template with no `${}`, or a `+` concatenation of such — else null.\nfunction pureLiteral(node: Parser.SyntaxNode | null): string | null {\n  if (!node) return null\n  if (node.type === 'string') return stringLiteralValue(node)\n  if (node.type === 'template_string') {\n    let v = ''\n    for (const c of namedChildren(node)) {\n      if (c.type === 'template_substitution') return null\n      if (c.type === 'string_fragment') v += c.text\n      else if (c.type === 'escape_sequence') return null\n    }\n    return v\n  }\n  if (node.type === 'binary_expression' && node.childForFieldName('operator')?.text === '+') {\n    const l = pureLiteral(node.childForFieldName('left'))\n    const r = pureLiteral(node.childForFieldName('right'))\n    return l !== null && r !== null ? l + r : null\n  }\n  return null\n}\n\n// The leading literal portion of an expression (#1432 ruling a): the statement head\n// even when a runtime tail follows. null when there is no literal head.\nfunction literalHead(node: Parser.SyntaxNode | null): string | null {\n  if (!node) return null\n  const whole = pureLiteral(node)\n  if (whole !== null) return whole\n  if (node.type === 'template_string') {\n    let head = ''\n    let saw = false\n    for (const c of namedChildren(node)) {\n      if (c.type === 'template_substitution') break\n      if (c.type === 'string_fragment') {\n        head += c.text\n        saw = true\n      } else if (c.type === 'escape_sequence') break\n    }\n    return saw ? head : null\n  }\n  if (node.type === 'binary_expression' && node.childForFieldName('operator')?.text === '+') {\n    const left = node.childForFieldName('left')\n    const leftFull = pureLiteral(left)\n    if (leftFull !== null) {\n      const rightHead = literalHead(node.childForFieldName('right'))\n      return rightHead !== null ? leftFull + rightHead : leftFull\n    }\n    return literalHead(left)\n  }\n  return null\n}\n\nfunction enclosingFunction(node: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  let cur = node.parent\n  while (cur) {\n    if (FUNCTION_NODE_TYPES.has(cur.type)) return cur\n    cur = cur.parent\n  }\n  return null\n}\n\n// The value node of the nearest preceding assignment to `name` within `scope`, not\n// descending into nested function scopes. Handles both `var/let/const name = …`\n// (`variable_declarator`) and `name = …` (`assignment_expression`).\nfunction nearestAssignmentValue(\n  scope: Parser.SyntaxNode,\n  name: string,\n  beforeIndex: number,\n): Parser.SyntaxNode | null {\n  let best: { pos: number; value: Parser.SyntaxNode } | null = null\n  const visit = (node: Parser.SyntaxNode): void => {\n    for (const c of namedChildren(node)) {\n      if (c.type === 'variable_declarator') {\n        const nm = c.childForFieldName('name')\n        const val = c.childForFieldName('value')\n        if (nm?.type === 'identifier' && nm.text === name && val && c.startIndex < beforeIndex) {\n          if (!best || c.startIndex > best.pos) best = { pos: c.startIndex, value: val }\n        }\n      } else if (c.type === 'assignment_expression') {\n        const lhs = c.childForFieldName('left')\n        const val = c.childForFieldName('right')\n        if (lhs?.type === 'identifier' && lhs.text === name && val && c.startIndex < beforeIndex) {\n          if (!best || c.startIndex > best.pos) best = { pos: c.startIndex, value: val }\n        }\n      }\n      if (!FUNCTION_NODE_TYPES.has(c.type)) visit(c)\n    }\n  }\n  visit(scope)\n  return best ? best.value : null\n}\n\nexport function mysqlJsEndpointsFromFile(file: SourceFile, serviceDir: string): ExternalEndpoint[] {\n  const ext = path.extname(file.path)\n  if (!JS_EXTS.has(ext)) return []\n  // Cheap textual pre-check before parsing — inert on files that import no driver.\n  if (!MYSQL_IMPORT_RE.test(file.content)) return []\n\n  const tree = parseSource(parserForExt(ext), file.content)\n  const root = tree.rootNode\n  const out: ExternalEndpoint[] = []\n\n  const walk = (node: Parser.SyntaxNode): void => {\n    if (node.type === 'call_expression') {\n      const fn = node.childForFieldName('function')\n      if (fn?.type === 'member_expression') {\n        const method = fn.childForFieldName('property')?.text\n        if (method && SQL_METHODS.has(method)) {\n          const argsNode = node.childForFieldName('arguments')\n          const first = argsNode ? namedChildren(argsNode)[0] : undefined\n          if (first) {\n            let head = literalHead(first)\n            if (head === null && first.type === 'identifier') {\n              const scope = enclosingFunction(node) ?? root\n              const val = nearestAssignmentValue(scope, first.text, node.startIndex)\n              if (val) head = literalHead(val)\n            }\n            if (head !== null) {\n              const table = tableFromSqlStatement(head)\n              if (table) {\n                const columns = columnsFromSqlStatement(head)\n                const line = node.startPosition.row + 1\n                out.push({\n                  infraId: infraId('sql-table', table),\n                  name: table,\n                  kind: 'sql-table',\n                  edgeType: 'CALLS',\n                  confidenceKind: 'verified-call-site',\n                  ...(columns.length > 0 ? { columns } : {}),\n                  evidence: {\n                    file: toPosix(path.relative(serviceDir, file.path)),\n                    line,\n                    snippet: snippet(file.content, line),\n                  },\n                })\n              }\n            }\n          }\n        }\n      }\n    }\n    for (const c of namedChildren(node)) walk(c)\n  }\n  walk(root)\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Python from 'tree-sitter-python'\nimport { infraId } from '@neat.is/types'\nimport { tableFromSqlStatement, columnsFromSqlStatement } from '../../otel.js'\nimport { snippet, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// Python raw-SQL data-axis recognizer for the DB-API drivers (#1432) — the Python\n// sibling of the Go `database/sql` reader (calls/go.ts, ADR-184) and the JS\n// `mysql`/`mysql2` reader (calls/mysql-js.ts). A service that talks to its database\n// through a plain DB-API cursor with SQL in strings gets no table grain today: the\n// Python ORM readers cover SQLAlchemy and the Django ORM, but a bare\n// `cursor.execute(sql, params)` lands nothing. This reads the table (and the touched\n// columns) off that statement and mints the same `infra:sql-table:<name>` node every\n// ORM reader and the OBSERVED ingest produce.\n//\n//   import pymysql\n//   cur.execute(\"SELECT * FROM voucher where order_id = %s\", (oid,))   // inline\n//   sql = 'INSERT INTO voucher (order_id) VALUES (%s)'; cur.execute(sql, (oid,))  // var\n//\n// THE POINT is fusion, not a static table list. The OBSERVED dbapi instrumentation\n// emits no dedicated table attribute (ADR-152), so the table is recovered from a\n// span's `db.statement` by `tableFromSqlStatement`; this recognizer runs the EXACT\n// SAME shared helper on the SAME SQL text, so the extracted table is byte-identical\n// to the observed one and the two fuse on `infraId('sql-table', <name>)` rather than\n// twinning. `columnsFromSqlStatement` does the same for the touched columns (ADR-157\n// §3). Both live in otel.ts, their one home — never a second SQL parser here.\n//\n// Statement shape (#1432 ruling a): a statement whose literal HEAD parses to\n// `SELECT … FROM <t>` / `INSERT INTO <t>` / `UPDATE <t>` / `DELETE FROM <t>` is\n// claimed with the table from the head; a runtime tail does not block it. A\n// `CREATE TABLE` has no FROM/INTO/UPDATE keyword, so `tableFromSqlStatement` returns\n// null and it is left unclaimed — never guessed.\n//\n// Variable resolution (#1432): the statement is usually built into a local variable\n// first (`sql = …; cur.execute(sql, params)`), so a `.execute`/`.executemany` whose\n// first positional argument is an identifier is resolved to its SAME-FILE,\n// ENCLOSING-FUNCTION, NEAREST-PRECEDING assignment, and only when that value is a\n// string literal or a literal-headed concatenation. An identifier reassigned in\n// between, a function parameter, or an argument with no literal head stays unclaimed.\n// Same literal inlining the URL-helper recognizer (#1426) does — precedent, not a new\n// shape.\n//\n// Import gate (mirrors calls/socket.ts' import gate): recognized only in a file that\n// imports a DB-API driver — `pymysql`, `MySQLdb`, `psycopg2`, `psycopg`, or\n// `sqlite3`. Without it a `.execute(...)` on any object could mint a phantom table\n// from any string that happens to parse as SQL. The SQL-parse gate\n// (`tableFromSqlStatement` returning a table) is the second filter.\n\n// `import pymysql` / `from pymysql import …` for the common DB-API drivers. `psycopg`\n// is psycopg3; `psycopg2` its predecessor; `MySQLdb` is mysqlclient; `sqlite3` is the\n// stdlib driver.\nconst DBAPI_IMPORT_RE =\n  /(?:^|\\n)\\s*(?:import|from)\\s+(?:pymysql|MySQLdb|psycopg2|psycopg|sqlite3)\\b/\n\n// DB-API cursor statement methods. `executescript` (sqlite-only, multi-statement) is\n// intentionally excluded — it is not a single-statement, single-table shape.\nconst EXEC_METHODS = new Set(['execute', 'executemany'])\n\nconst PARSE_CHUNK = 16384\n\nfunction makePyParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Python)\n  return p\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of namedChildren(node)) walk(c, visit)\n}\n\n// The full literal value of a `string` node (`string_content` + any escapes), or\n// null if it carries an `interpolation` (an f-string — not a pure literal).\nfunction pyStringFull(node: Parser.SyntaxNode): string | null {\n  let v = ''\n  for (const c of namedChildren(node)) {\n    if (c.type === 'interpolation') return null\n    if (c.type === 'string_content' || c.type === 'escape_sequence') v += c.text\n  }\n  return v\n}\n\n// The leading literal text of a `string` node, up to the first `interpolation` —\n// the head of an f-string. null if it opens with an interpolation.\nfunction pyStringHead(node: Parser.SyntaxNode): string | null {\n  let head = ''\n  let saw = false\n  for (const c of namedChildren(node)) {\n    if (c.type === 'interpolation') break\n    if (c.type === 'string_content' || c.type === 'escape_sequence') {\n      head += c.text\n      saw = true\n    }\n  }\n  return saw ? head : null\n}\n\n// The value of an expression that is ENTIRELY string-literal — a `string`, an\n// adjacency `concatenated_string`, or a `+` `binary_operator` of such — else null.\nfunction pyPureLiteral(node: Parser.SyntaxNode | null): string | null {\n  if (!node) return null\n  if (node.type === 'string') return pyStringFull(node)\n  if (node.type === 'concatenated_string') {\n    let v = ''\n    for (const c of namedChildren(node)) {\n      const s = pyPureLiteral(c)\n      if (s === null) return null\n      v += s\n    }\n    return v\n  }\n  if (node.type === 'binary_operator' && node.childForFieldName('operator')?.text === '+') {\n    const l = pyPureLiteral(node.childForFieldName('left'))\n    const r = pyPureLiteral(node.childForFieldName('right'))\n    return l !== null && r !== null ? l + r : null\n  }\n  return null\n}\n\n// The leading literal portion of an expression (#1432 ruling a): the statement head\n// even when a runtime tail follows. null when there is no literal head.\nfunction pyLiteralHead(node: Parser.SyntaxNode | null): string | null {\n  if (!node) return null\n  const whole = pyPureLiteral(node)\n  if (whole !== null) return whole\n  if (node.type === 'string') return pyStringHead(node)\n  if (node.type === 'concatenated_string') {\n    let v = ''\n    let saw = false\n    for (const c of namedChildren(node)) {\n      const pure = pyPureLiteral(c)\n      if (pure !== null) {\n        v += pure\n        saw = true\n        continue\n      }\n      const h = pyLiteralHead(c)\n      if (h !== null) {\n        v += h\n        saw = true\n      }\n      break\n    }\n    return saw ? v : null\n  }\n  if (node.type === 'binary_operator' && node.childForFieldName('operator')?.text === '+') {\n    const left = node.childForFieldName('left')\n    const leftFull = pyPureLiteral(left)\n    if (leftFull !== null) {\n      const rightHead = pyLiteralHead(node.childForFieldName('right'))\n      return rightHead !== null ? leftFull + rightHead : leftFull\n    }\n    return pyLiteralHead(left)\n  }\n  return null\n}\n\nfunction enclosingFunction(node: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  let cur = node.parent\n  while (cur) {\n    if (cur.type === 'function_definition') return cur\n    cur = cur.parent\n  }\n  return null\n}\n\n// The value node of the nearest preceding `name = …` assignment within `scope`, not\n// descending into nested function scopes.\nfunction nearestAssignmentValue(\n  scope: Parser.SyntaxNode,\n  name: string,\n  beforeIndex: number,\n): Parser.SyntaxNode | null {\n  let best: { pos: number; value: Parser.SyntaxNode } | null = null\n  const visit = (node: Parser.SyntaxNode): void => {\n    for (const c of namedChildren(node)) {\n      if (c.type === 'assignment') {\n        const lhs = c.childForFieldName('left')\n        const val = c.childForFieldName('right')\n        if (lhs?.type === 'identifier' && lhs.text === name && val && c.startIndex < beforeIndex) {\n          if (!best || c.startIndex > best.pos) best = { pos: c.startIndex, value: val }\n        }\n      }\n      if (c.type !== 'function_definition' && c.type !== 'lambda') visit(c)\n    }\n  }\n  visit(scope)\n  return best ? best.value : null\n}\n\nexport function pythonDbapiEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  if (path.extname(file.path) !== '.py') return []\n  if (!DBAPI_IMPORT_RE.test(file.content)) return []\n\n  const tree = parseSource(makePyParser(), file.content)\n  const root = tree.rootNode\n  const out: ExternalEndpoint[] = []\n\n  walk(root, (node) => {\n    if (node.type !== 'call') return\n    const fn = node.childForFieldName('function')\n    if (fn?.type !== 'attribute') return\n    const method = fn.childForFieldName('attribute')?.text\n    if (!method || !EXEC_METHODS.has(method)) return\n\n    const argsNode = node.childForFieldName('arguments')\n    const first = argsNode\n      ? namedChildren(argsNode).find((a) => a.type !== 'keyword_argument')\n      : undefined\n    if (!first) return\n\n    let head = pyLiteralHead(first)\n    if (head === null && first.type === 'identifier') {\n      const scope = enclosingFunction(node) ?? root\n      const val = nearestAssignmentValue(scope, first.text, node.startIndex)\n      if (val) head = pyLiteralHead(val)\n    }\n    if (head === null) return\n\n    const table = tableFromSqlStatement(head)\n    if (!table) return\n    const columns = columnsFromSqlStatement(head)\n    const line = node.startPosition.row + 1\n    out.push({\n      infraId: infraId('sql-table', table),\n      name: table,\n      kind: 'sql-table',\n      edgeType: 'CALLS',\n      confidenceKind: 'verified-call-site',\n      ...(columns.length > 0 ? { columns } : {}),\n      evidence: {\n        file: toPosix(path.relative(serviceDir, file.path)),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  })\n\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Java from 'tree-sitter-java'\nimport { infraId } from '@neat.is/types'\nimport { snippet, toPosix, type ExternalEndpoint, type SourceFile } from './shared.js'\n\n// JPA / Spring Data data axis — the Java rung of the `infra:sql-table:<name>` grain\n// the EF Core, GORM, SQLAlchemy, ActiveRecord and Eloquent readers produce.\n//\n//   @Entity\n//   @Table(name = \"orders\")                  // the table, verbatim\n//   public class Order { ... }\n//\n//   public interface OrderRepository extends CrudRepository<Order, String> { }\n//\n// The entity's `@Table(name = \"…\")` names the database table verbatim — the\n// string an OBSERVED db span reports — so the node fuses by name. The entity\n// file gets `file ──CALLS──▶ sql-table`, and so does every Spring Data\n// repository over that entity (`CrudRepository<Order, …>`, `JpaRepository`,\n// `PagingAndSortingRepository`, the `List*` variants), resolved across the\n// service's files by the entity's simple class name. That is the file the\n// queries actually run from.\n//\n// An entity with no `@Table(name)` is left unclaimed. Its table name then comes\n// from the configured physical naming strategy, which lives outside the entity,\n// so reading the class name would be a guess. A name that isn't a plain literal,\n// an entity class name declared twice in one service, and a repository over an\n// unclaimed entity are all left unclaimed the same way.\n//\n// Table grain only: column names go through the same naming strategy.\n\nconst PARSE_CHUNK = 16384\nconst JPA_GATE = /\\b(?:javax|jakarta)\\.persistence\\b|@Entity\\b|Repository\\s*</\nconst REPOSITORY_BASES = new Set([\n  'CrudRepository',\n  'ListCrudRepository',\n  'JpaRepository',\n  'PagingAndSortingRepository',\n  'ListPagingAndSortingRepository',\n  'Repository',\n])\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of node.namedChildren) walk(c, visit)\n}\n\nfunction annotations(decl: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const mods = decl.namedChildren.find((c) => c.type === 'modifiers')\n  return mods ? mods.namedChildren.filter((c) => c.type === 'annotation' || c.type === 'marker_annotation') : []\n}\n\nfunction simpleName(annotation: Parser.SyntaxNode): string {\n  const text = annotation.childForFieldName('name')?.text ?? ''\n  return text.slice(text.lastIndexOf('.') + 1)\n}\n\nfunction stringLiteral(node: Parser.SyntaxNode | null | undefined): string | null {\n  if (!node || node.type !== 'string_literal') return null\n  let out = ''\n  for (const c of node.namedChildren) {\n    if (c.type === 'string_fragment') out += c.text\n    else return null\n  }\n  return out\n}\n\n// `@Table(name = \"orders\")` → orders. A `@Table` without a literal `name` (only\n// `schema`, or a constant) → null.\nfunction tableName(annotation: Parser.SyntaxNode): string | null {\n  const args = annotation.childForFieldName('arguments')\n  if (!args) return null\n  for (const c of args.namedChildren) {\n    if (c.type === 'element_value_pair' && c.childForFieldName('key')?.text === 'name') {\n      return stringLiteral(c.childForFieldName('value'))\n    }\n  }\n  return null\n}\n\ninterface Entity {\n  table: string | null\n  file: SourceFile\n  line: number\n}\n\n// The entity type a Spring Data repository interface manages: the first type\n// argument of a known repository base in its `extends` list.\nfunction repositoryEntity(iface: Parser.SyntaxNode): string | null {\n  const ext = iface.namedChildren.find((c) => c.type === 'extends_interfaces')\n  if (!ext) return null\n  let found: string | null = null\n  walk(ext, (n) => {\n    if (found || n.type !== 'generic_type') return\n    const base = n.namedChildren.find((c) => c.type === 'type_identifier' || c.type === 'scoped_type_identifier')\n    const baseName = base?.text.slice(base.text.lastIndexOf('.') + 1) ?? ''\n    if (!REPOSITORY_BASES.has(baseName)) return\n    const first = n.namedChildren.find((c) => c.type === 'type_arguments')?.namedChildren[0]\n    if (first && (first.type === 'type_identifier' || first.type === 'scoped_type_identifier')) {\n      found = first.text.slice(first.text.lastIndexOf('.') + 1)\n    }\n  })\n  return found\n}\n\nfunction endpoint(table: string, file: SourceFile, serviceDir: string, line: number): ExternalEndpoint {\n  return {\n    infraId: infraId('sql-table', table),\n    name: table,\n    kind: 'sql-table',\n    edgeType: 'CALLS',\n    confidenceKind: 'structural',\n    evidence: {\n      file: toPosix(path.relative(serviceDir, file.path)),\n      line,\n      snippet: snippet(file.content, line),\n    },\n  }\n}\n\n/** JPA entities and Spring Data repositories across one service's files. */\nexport function jpaEndpoints(files: SourceFile[], serviceDir: string): ExternalEndpoint[] {\n  const javaFiles = files.filter((f) => path.extname(f.path) === '.java' && JPA_GATE.test(f.content))\n  if (javaFiles.length === 0) return []\n  const parser = new Parser()\n  parser.setLanguage(Java)\n\n  const entities = new Map<string, Entity | null>() // null: declared twice\n  const repositories: { entity: string; file: SourceFile; line: number }[] = []\n\n  for (const file of javaFiles) {\n    const root = parseSource(parser, file.content).rootNode\n    walk(root, (n) => {\n      if (n.type === 'class_declaration') {\n        const anns = annotations(n)\n        if (!anns.some((a) => simpleName(a) === 'Entity')) return\n        const name = n.childForFieldName('name')?.text\n        if (!name) return\n        const tableAnn = anns.find((a) => simpleName(a) === 'Table')\n        const entity: Entity = {\n          table: tableAnn ? tableName(tableAnn) : null,\n          file,\n          line: (tableAnn ?? n).startPosition.row + 1,\n        }\n        entities.set(name, entities.has(name) ? null : entity)\n      } else if (n.type === 'interface_declaration') {\n        const entity = repositoryEntity(n)\n        if (entity) repositories.push({ entity, file, line: n.startPosition.row + 1 })\n      }\n    })\n  }\n\n  const out: ExternalEndpoint[] = []\n  for (const entity of entities.values()) {\n    if (entity?.table) out.push(endpoint(entity.table, entity.file, serviceDir, entity.line))\n  }\n  for (const repo of repositories) {\n    const table = entities.get(repo.entity)?.table\n    if (table) out.push(endpoint(table, repo.file, serviceDir, repo.line))\n  }\n  return out\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport Java from 'tree-sitter-java'\nimport type { ExtractedConfidenceKind, GraphEdge, RouteNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  passesExtractedFloor,\n  serviceId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, makeEdgeId, type DiscoveredService } from './shared.js'\nimport { recordExtractionError, noteExtractedDropped } from './errors.js'\nimport { buildServiceHostIndex, ensureFileNode, loadSourceFiles, snippet, toPosix } from './calls/shared.js'\nimport { normalizePathTemplate } from './routes.js'\n\n// Outbound HTTP from Java services: Spring's RestTemplate and WebClient.\n//\n// A call's URL is rarely one literal. train-ticket, for one, writes\n//   String url = getServiceUrl(\"ts-basic-service\");     // returns \"http://\" + name\n//   restTemplate.exchange(url + \"/api/v1/basicservice/basic/travel\", HttpMethod.POST, …)\n// so the URL is resolved by evaluating the argument as a string expression:\n// literals, `+`, same-file `static final String` constants, the enclosing\n// method's local variables, and calls to a same-file helper whose body is a\n// single `return` of the same kinds of pieces (inlined with its literal\n// arguments). Any other piece — a runtime value, a getter, an injected `@Value`\n// — becomes a `:param` path segment, or, in the host, leaves the host unknown.\n//\n// What it emits, the same shapes the JS/TS producers do:\n//   - file ──CALLS──▶ service, when the host names a service in the graph\n//     (http.ts's shape, graded verified-call-site: a client call wraps the URL);\n//   - file ──CALLS──▶ route, when the path also matches one of that service's\n//     RouteNodes (route-match.ts's shape and grading, ADR-119 / ADR-219).\n// A call whose host can't be resolved stays unclaimed: the file still surfaces,\n// and the call is recorded as a drop with its reason, never guessed.\n\nconst PARSE_CHUNK = 16384\n// Stands for a piece of the URL that isn't known statically.\nconst HOLE = '\\u0000'\n\nconst REST_TEMPLATE_METHODS: Record<string, string | null> = {\n  getForObject: 'GET',\n  getForEntity: 'GET',\n  postForObject: 'POST',\n  postForEntity: 'POST',\n  postForLocation: 'POST',\n  put: 'PUT',\n  delete: 'DELETE',\n  patchForObject: 'PATCH',\n  // The HTTP method is the second argument.\n  exchange: null,\n  execute: null,\n}\nconst HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'])\nconst WEBCLIENT_VERBS: Record<string, string> = {\n  get: 'GET',\n  post: 'POST',\n  put: 'PUT',\n  delete: 'DELETE',\n  patch: 'PATCH',\n  head: 'HEAD',\n  options: 'OPTIONS',\n}\n\nexport interface JavaCallSite {\n  method?: string\n  // The resolved host, or null when it couldn't be read statically.\n  host: string | null\n  // The path with `:param` for each unknown piece; '/' when the URL has none.\n  pathTemplate: string\n  approximate: boolean\n  line: number\n  reason?: string\n}\n\nfunction parseSource(parser: Parser, source: string): Parser.Tree {\n  return parser.parse((index: number) =>\n    index >= source.length ? '' : source.slice(index, index + PARSE_CHUNK),\n  )\n}\n\nfunction makeJavaParser(): Parser {\n  const p = new Parser()\n  p.setLanguage(Java)\n  return p\n}\n\nfunction walk(node: Parser.SyntaxNode, visit: (n: Parser.SyntaxNode) => void): void {\n  visit(node)\n  for (const c of node.namedChildren) walk(c, visit)\n}\n\nfunction stringLiteral(node: Parser.SyntaxNode): string | null {\n  let out = ''\n  for (const c of node.namedChildren) {\n    if (c.type === 'string_fragment') out += c.text\n    else return null\n  }\n  return out\n}\n\ninterface Helper {\n  params: string[]\n  body: Parser.SyntaxNode\n}\n\ninterface FileScope {\n  constants: Map<string, Parser.SyntaxNode>\n  helpers: Map<string, Helper>\n}\n\n// Same-file `static final` fields and single-return helper methods.\nfunction fileScope(root: Parser.SyntaxNode): FileScope {\n  const constants = new Map<string, Parser.SyntaxNode>()\n  const helpers = new Map<string, Helper>()\n  const dupHelpers = new Set<string>()\n  walk(root, (n) => {\n    if (n.type === 'field_declaration') {\n      const mods = n.namedChildren.find((c) => c.type === 'modifiers')?.text ?? ''\n      if (!/\\bstatic\\b/.test(mods) || !/\\bfinal\\b/.test(mods)) return\n      for (const d of n.namedChildren) {\n        if (d.type !== 'variable_declarator') continue\n        const name = d.childForFieldName('name')?.text\n        const value = d.childForFieldName('value')\n        if (name && value) constants.set(name, value)\n      }\n    } else if (n.type === 'method_declaration') {\n      const name = n.childForFieldName('name')?.text\n      const body = n.childForFieldName('body')\n      const params = n.childForFieldName('parameters')\n      if (!name || !body || !params) return\n      const stmts = body.namedChildren.filter((c) => c.type !== 'line_comment' && c.type !== 'block_comment')\n      const ret = stmts.length === 1 && stmts[0]!.type === 'return_statement' ? stmts[0]!.namedChildren[0] : undefined\n      if (!ret) return\n      if (helpers.has(name)) dupHelpers.add(name) // overloads: ambiguous\n      helpers.set(name, {\n        params: params.namedChildren\n          .filter((p) => p.type === 'formal_parameter')\n          .map((p) => p.childForFieldName('name')?.text ?? ''),\n        body: ret,\n      })\n    }\n  })\n  for (const name of dupHelpers) helpers.delete(name)\n  return { constants, helpers }\n}\n\n// The enclosing method's locals: name → initializer, or null when assigned more\n// than once (which value reaches the call isn't known statically).\nfunction methodLocals(call: Parser.SyntaxNode): Map<string, Parser.SyntaxNode | null> {\n  const out = new Map<string, Parser.SyntaxNode | null>()\n  let m: Parser.SyntaxNode | null = call.parent\n  while (m && m.type !== 'method_declaration' && m.type !== 'constructor_declaration' && m.type !== 'lambda_expression') {\n    m = m.parent\n  }\n  const body = m?.childForFieldName('body')\n  if (!body) return out\n  walk(body, (n) => {\n    if (n.type === 'local_variable_declaration') {\n      for (const d of n.namedChildren) {\n        if (d.type !== 'variable_declarator') continue\n        const name = d.childForFieldName('name')?.text\n        if (!name) continue\n        out.set(name, out.has(name) ? null : d.childForFieldName('value'))\n      }\n    } else if (n.type === 'assignment_expression') {\n      const left = n.childForFieldName('left')\n      if (left?.type === 'identifier') out.set(left.text, null)\n    }\n  })\n  return out\n}\n\ninterface EvalCtx {\n  scope: FileScope\n  locals: Map<string, Parser.SyntaxNode | null>\n  // Bound helper parameters while inlining.\n  bound: Map<string, string>\n  depth: number\n}\n\n// A string expression as text, with HOLE for each piece that isn't static.\nfunction evalString(node: Parser.SyntaxNode, ctx: EvalCtx): string {\n  if (ctx.depth > 8) return HOLE\n  const next = (n: Parser.SyntaxNode, extra?: Partial<EvalCtx>): string =>\n    evalString(n, { ...ctx, ...extra, depth: ctx.depth + 1 })\n  switch (node.type) {\n    case 'string_literal':\n      return stringLiteral(node) ?? HOLE\n    case 'parenthesized_expression':\n      return node.namedChildren[0] ? next(node.namedChildren[0]) : HOLE\n    case 'binary_expression': {\n      if (node.childForFieldName('operator')?.text !== '+') return HOLE\n      const l = node.childForFieldName('left')\n      const r = node.childForFieldName('right')\n      return (l ? next(l) : HOLE) + (r ? next(r) : HOLE)\n    }\n    case 'identifier': {\n      const name = node.text\n      if (ctx.bound.has(name)) return ctx.bound.get(name)!\n      if (ctx.locals.has(name)) {\n        const init = ctx.locals.get(name)\n        return init ? next(init) : HOLE\n      }\n      const c = ctx.scope.constants.get(name)\n      return c ? next(c, { locals: new Map(), bound: new Map() }) : HOLE\n    }\n    case 'method_invocation': {\n      const obj = node.childForFieldName('object')\n      if (obj && obj.type !== 'this') return HOLE\n      const helper = ctx.scope.helpers.get(node.childForFieldName('name')?.text ?? '')\n      const args = node.childForFieldName('arguments')?.namedChildren ?? []\n      if (!helper || helper.params.length !== args.length) return HOLE\n      const bound = new Map<string, string>()\n      helper.params.forEach((p, i) => bound.set(p, next(args[i]!)))\n      return next(helper.body, { locals: new Map(), bound })\n    }\n    default:\n      return HOLE\n  }\n}\n\n// Split an evaluated URL into host and path. A host is only taken from an\n// `http(s)://` URL whose host part is fully static.\nfunction splitUrl(url: string): { host: string | null; pathTemplate: string; approximate: boolean; reason?: string } {\n  const approximate = url.includes(HOLE)\n  const m = /^https?:\\/\\/([^/]*)(.*)$/.exec(url)\n  if (!m) {\n    return { host: null, pathTemplate: '/', approximate: true, reason: 'the URL has no static scheme and host' }\n  }\n  const hostPort = m[1]!\n  if (!hostPort || hostPort.includes(HOLE)) {\n    return { host: null, pathTemplate: '/', approximate: true, reason: 'the host is not static' }\n  }\n  const host = hostPort.replace(/:\\d+$/, '')\n  let p = (m[2] ?? '').split('?')[0]!.split('#')[0]!\n  // A hole mid-segment (`/order/` + id) or as a whole segment is one param.\n  p = p\n    .split('/')\n    .map((seg) => (seg.includes(HOLE) ? ':param' : seg))\n    .join('/')\n  if (!p.startsWith('/')) p = '/' + p\n  return { host, pathTemplate: p, approximate }\n}\n\nfunction httpMethodArg(node: Parser.SyntaxNode | undefined): string | undefined {\n  if (!node) return undefined\n  const name = node.type === 'field_access' ? node.childForFieldName('field')?.text : node.text\n  return name && HTTP_METHODS.has(name) ? name : undefined\n}\n\n// For `….get().uri(x)` / `….method(HttpMethod.X).uri(x)`: the verb in the chain.\nfunction webClientMethod(uriCall: Parser.SyntaxNode): string | null {\n  let cur: Parser.SyntaxNode | null = uriCall.childForFieldName('object')\n  while (cur && cur.type === 'method_invocation') {\n    const name = cur.childForFieldName('name')?.text ?? ''\n    const args = cur.childForFieldName('arguments')?.namedChildren ?? []\n    if (WEBCLIENT_VERBS[name] && args.length === 0) return WEBCLIENT_VERBS[name]!\n    if (name === 'method') return httpMethodArg(args[0]) ?? null\n    cur = cur.childForFieldName('object')\n  }\n  return null\n}\n\n// Names declared with type RestTemplate (fields, locals, parameters), so a\n// `put` / `delete` on a map or a repository is never read as an HTTP call.\nfunction restTemplateNames(root: Parser.SyntaxNode): Set<string> {\n  const out = new Set<string>()\n  walk(root, (n) => {\n    if (n.type !== 'field_declaration' && n.type !== 'local_variable_declaration' && n.type !== 'formal_parameter') return\n    const type = n.childForFieldName('type')?.text ?? ''\n    if (!/(^|\\.)RestTemplate$/.test(type)) return\n    if (n.type === 'formal_parameter') {\n      const name = n.childForFieldName('name')?.text\n      if (name) out.add(name)\n      return\n    }\n    for (const d of n.namedChildren) {\n      if (d.type === 'variable_declarator') {\n        const name = d.childForFieldName('name')?.text\n        if (name) out.add(name)\n      }\n    }\n  })\n  return out\n}\n\nfunction isRestTemplateReceiver(obj: Parser.SyntaxNode | null, names: Set<string>): boolean {\n  if (!obj) return false\n  if (obj.type === 'identifier') return names.has(obj.text)\n  if (obj.type === 'field_access' && obj.childForFieldName('object')?.type === 'this') {\n    return names.has(obj.childForFieldName('field')?.text ?? '')\n  }\n  return false\n}\n\n/** RestTemplate / WebClient call sites in one Java source file. */\nexport function javaCallSitesFromSource(source: string, parser: Parser): JavaCallSite[] {\n  const usesRestTemplate = source.includes('RestTemplate')\n  const usesWebClient = source.includes('WebClient')\n  if (!usesRestTemplate && !usesWebClient) return []\n  const root = parseSource(parser, source).rootNode\n  const scope = fileScope(root)\n  const templates = usesRestTemplate ? restTemplateNames(root) : new Set<string>()\n  const out: JavaCallSite[] = []\n\n  walk(root, (n) => {\n    if (n.type !== 'method_invocation') return\n    const name = n.childForFieldName('name')?.text ?? ''\n    const args = n.childForFieldName('arguments')?.namedChildren ?? []\n    let method: string | undefined\n    if (name in REST_TEMPLATE_METHODS && isRestTemplateReceiver(n.childForFieldName('object'), templates)) {\n      method = REST_TEMPLATE_METHODS[name] ?? httpMethodArg(args[1])\n      if (!method) return\n    } else if (usesWebClient && name === 'uri') {\n      const verb = webClientMethod(n)\n      if (!verb) return\n      method = verb\n    } else {\n      return\n    }\n    const urlNode = args[0]\n    if (!urlNode) return\n    const url = evalString(urlNode, { scope, locals: methodLocals(n), bound: new Map(), depth: 0 })\n    out.push({ method, ...splitUrl(url), line: n.startPosition.row + 1 })\n  })\n  return out\n}\n\ninterface RouteEntry {\n  method: string\n  normalizedPath: string\n  routeNodeId: string\n}\n\nfunction buildRouteIndex(graph: NeatGraph): Map<string, RouteEntry[]> {\n  const index = new Map<string, RouteEntry[]>()\n  graph.forEachNode((_id, attrs) => {\n    if ((attrs as { type?: string }).type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    const owner = serviceId(route.service)\n    const list = index.get(owner) ?? []\n    list.push({\n      method: route.method.toUpperCase(),\n      normalizedPath: normalizePathTemplate(route.pathTemplate),\n      routeNodeId: route.id,\n    })\n    index.set(owner, list)\n  })\n  return index\n}\n\n// A path with at least one literal segment says which route it names.\nfunction hasLiteralAnchor(pathTemplate: string): boolean {\n  return pathTemplate.split('/').some((s) => s.length > 0 && s !== ':param')\n}\n\n/** File → service (and file → route) CALLS for Java RestTemplate / WebClient calls. */\nexport async function addJavaCallEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const javaServices = services.filter((s) => s.node.language === 'java')\n  if (javaServices.length === 0) return { nodesAdded: 0, edgesAdded: 0 }\n  const parser = makeJavaParser()\n  const { hostToNodeId } = buildServiceHostIndex(services)\n  const routeIndex = buildRouteIndex(graph)\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  const addEdge = (source: string, target: string, kind: ExtractedConfidenceKind, ev: GraphEdge['evidence']): void => {\n    const confidence = confidenceForExtracted(kind)\n    if (!passesExtractedFloor(confidence)) {\n      noteExtractedDropped({ source, target, type: EdgeType.CALLS, confidence, confidenceKind: kind, evidence: ev! })\n      return\n    }\n    const id = makeEdgeId(source, target, EdgeType.CALLS)\n    if (graph.hasEdge(id)) return\n    const edge: GraphEdge = {\n      id,\n      source,\n      target,\n      type: EdgeType.CALLS,\n      provenance: Provenance.EXTRACTED,\n      confidence,\n      evidence: ev,\n    }\n    graph.addEdgeWithKey(id, source, target, edge)\n    edgesAdded++\n  }\n\n  for (const service of javaServices) {\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    const seen = new Set<string>()\n    for (const file of files) {\n      if (path.extname(file.path) !== '.java' || isTestPath(file.path)) continue\n      let sites: JavaCallSite[]\n      try {\n        sites = javaCallSitesFromSource(file.content, parser)\n      } catch (err) {\n        recordExtractionError('java http call extraction', file.path, err)\n        continue\n      }\n      if (sites.length === 0) continue\n      const relFile = toPosix(path.relative(service.dir, file.path))\n\n      for (const site of sites) {\n        const targetService = site.host === null ? undefined : hostToNodeId.get(site.host)\n        // A literal host outside the graph (a third party, or a service not in\n        // this scan) is skipped, as http.ts skips it.\n        if (site.host !== null && !targetService) continue\n        if (targetService === service.node.id) continue\n\n        const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n          graph,\n          service.pkg.name,\n          service.node.id,\n          relFile,\n        )\n        nodesAdded += n\n        edgesAdded += e\n        const ev = {\n          file: relFile,\n          line: site.line,\n          snippet: snippet(file.content, site.line),\n          method: site.method,\n          pathTemplate: site.pathTemplate,\n        }\n\n        if (!targetService) {\n          const key = `${relFile}|unresolved|${site.line}`\n          if (seen.has(key)) continue\n          seen.add(key)\n          noteExtractedDropped({\n            source: fileNodeId,\n            target: 'route:unresolved',\n            type: EdgeType.CALLS,\n            confidence: confidenceForExtracted('reconstructed-approximate'),\n            confidenceKind: 'reconstructed-approximate',\n            evidence: { ...ev, approximate: true, reason: site.reason },\n          })\n          continue\n        }\n\n        if (!seen.has(`${relFile}|${targetService}`)) {\n          seen.add(`${relFile}|${targetService}`)\n          addEdge(fileNodeId, targetService, 'verified-call-site', ev)\n        }\n\n        const route = routeIndex\n          .get(targetService)\n          ?.find(\n            (r) =>\n              r.normalizedPath === normalizePathTemplate(site.pathTemplate) &&\n              (r.method === 'ALL' || site.method === undefined || r.method === site.method),\n          )\n        if (!route || seen.has(`${relFile}|${route.routeNodeId}`)) continue\n        seen.add(`${relFile}|${route.routeNodeId}`)\n        const anchored = hasLiteralAnchor(site.pathTemplate)\n        addEdge(\n          fileNodeId,\n          route.routeNodeId,\n          site.approximate && !anchored ? 'reconstructed-approximate' : 'verified-call-site',\n          site.approximate && !anchored ? { ...ev, approximate: true, reason: 'no literal path segment' } : ev,\n        )\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import type { GraphEdge, InfraNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  infraId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { loadSourceFiles, type TableReference } from './calls/shared.js'\nimport { drizzleForeignKeys } from './calls/drizzle.js'\nimport { prismaForeignKeys } from './calls/prisma.js'\nimport { sqlalchemyForeignKeys } from './calls/sqlalchemy.js'\nimport { railsSchemaForeignKeys, railsModelForeignKeys } from './calls/activerecord.js'\nimport { laravelMigrationForeignKeys, laravelModelForeignKeys } from './calls/eloquent.js'\nimport { gormForeignKeys } from './calls/gorm.js'\n\n// Foreign-key table→table edges (ADR-161). The data-axis sibling of the symbol\n// heritage producer (`symbol-edges.ts`, ADR-158 §3): column grain (ADR-157) gave\n// a `infra:sql-table:<name>` node its columns but no edges *between* tables, so\n// blast-radius / dependencies / root-cause could not walk the data axis. This\n// mints one `infra:sql-table:<child> ──REFERENCES──▶ infra:sql-table:<parent>`\n// EXTRACTED edge per resolved foreign key.\n//\n// The per-ORM readers live beside the columns each already parses — Drizzle's\n// `.references(() => users.id)`, Prisma's `@relation(fields:[…], references:[…])`,\n// SQLAlchemy's `ForeignKey('users.id')`. Each resolves the parent to the DATABASE\n// table name (`infraId('sql-table', name)` — the same node the column/table\n// extractors and OTLP already target), reproduced verbatim the ORM's way, so the\n// FK lands on the fused table node rather than a code-model twin. A computed or\n// cross-file-unresolvable reference is left unclaimed by the reader (it returns\n// nothing) — never guessed, the never-fabricate discipline of file-awareness.md\n// §6. Every edge grades `structural` EXTRACTED with `evidence.file`/`line` pinned\n// to the FK declaration site, so ghost-edge cleanup (`retire.ts`) keys off it like\n// any other EXTRACTED edge, and every write is `hasNode` / `hasEdge`-guarded.\n//\n// Runs after `addCallEdges`, whose column/table read has already minted both\n// endpoints' InfraNodes; `ensureTableNode` is a self-contained safety net that\n// mints a bare table node (same id, no twin) when a referenced table was named in\n// a FK but not otherwise picked up. The reasoning core stays agnostic: REFERENCES\n// is a plain edge type the generic graph walk admits with no traversal change\n// (ADR-158 §6).\n\nexport async function addTableEdges(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    const refs: TableReference[] = []\n    // Rails model associations (ADR-174) and Laravel Eloquent relations\n    // (ADR-178) corroborate the schema literals — a relationship is often\n    // declared on both sides. They are collected here and appended AFTER the\n    // schema/ORM literals, so when the same child→parent pair appears twice the\n    // literal (schema.rb / migration) evidence wins the graph-level dedup.\n    const modelRefs: TableReference[] = []\n\n    for (const file of files) {\n      try {\n        refs.push(...drizzleForeignKeys(file, service.dir))\n        refs.push(...sqlalchemyForeignKeys(file, service.dir))\n        refs.push(...railsSchemaForeignKeys(file, service.dir))\n        refs.push(...laravelMigrationForeignKeys(file, service.dir))\n        refs.push(...gormForeignKeys(file, service.dir))\n        modelRefs.push(...railsModelForeignKeys(file, service.dir))\n        modelRefs.push(...laravelModelForeignKeys(file, service.dir))\n      } catch (err) {\n        recordExtractionError('foreign-key extraction', file.path, err)\n      }\n    }\n    // Prisma's `schema.prisma` is not a walked source file — read once per service.\n    try {\n      refs.push(...(await prismaForeignKeys(service.dir)))\n    } catch (err) {\n      recordExtractionError('prisma foreign-key extraction', service.dir, err)\n    }\n    refs.push(...modelRefs)\n\n    for (const ref of refs) {\n      const childId = infraId('sql-table', ref.childTable)\n      const parentId = infraId('sql-table', ref.parentTable)\n      // A self-referential FK (a tree's `parent_id`) would be a self-loop; the\n      // graph disallows them, and a table referencing itself carries no cross-table\n      // blast radius, so it is skipped rather than emitted.\n      if (childId === parentId) continue\n\n      nodesAdded += ensureTableNode(graph, childId, ref.childTable)\n      nodesAdded += ensureTableNode(graph, parentId, ref.parentTable)\n\n      const edgeId = extractedEdgeId(childId, parentId, EdgeType.REFERENCES)\n      if (graph.hasEdge(edgeId)) continue\n      const edge: GraphEdge = {\n        id: edgeId,\n        source: childId,\n        target: parentId,\n        type: EdgeType.REFERENCES,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: ref.evidence,\n      }\n      graph.addEdgeWithKey(edgeId, childId, parentId, edge)\n      edgesAdded++\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n\n// Mint a bare `sql-table` InfraNode if the FK named a table nothing else did.\n// Idempotent — same `infra:sql-table:<name>` id the column/table extractors and\n// OTLP use, so it fuses onto the existing node and never twins. Returns 1 when a\n// node was minted, 0 when it already existed.\nfunction ensureTableNode(graph: NeatGraph, id: string, name: string): number {\n  if (graph.hasNode(id)) return 0\n  const node: InfraNode = {\n    id,\n    type: NodeType.InfraNode,\n    name,\n    provider: 'self',\n    kind: 'sql-table',\n  }\n  graph.addNode(id, node)\n  return 1\n}\n","import type { NeatGraph } from '../../graph.js'\nimport { type DiscoveredService } from '../shared.js'\nimport { addComposeInfra } from './docker-compose.js'\nimport { addDockerfileRuntimes } from './dockerfile.js'\nimport { addTerraformResources } from './terraform.js'\nimport { addK8sResources } from './k8s.js'\nimport { addCloudflareWorkers } from './cloudflare.js'\nimport { addVercelServices } from './vercel.js'\nimport { addRailwayServices } from './railway.js'\nimport { addSupabaseProjects } from './supabase.js'\nimport { addNginxProxies } from './nginx.js'\n\nexport interface InfraExtractResult {\n  nodesAdded: number\n  edgesAdded: number\n}\n\n// Phase 5 — infrastructure. Runs after services so RUNS_ON edges have a\n// ServiceNode to anchor on. Each sub-source contributes its own nodes/edges\n// independently. The platform producers (`cloudflare.ts`, `vercel.ts`,\n// `railway.ts`, `supabase.ts`) also tag existing ServiceNode/FileNode\n// attributes (`platform`/`platformName`, ADR-133) rather than only adding new\n// nodes/edges — property updates on existing nodes are allowed per ADR-030.\nexport async function addInfra(\n  graph: NeatGraph,\n  scanPath: string,\n  services: DiscoveredService[],\n): Promise<InfraExtractResult> {\n  const compose = await addComposeInfra(graph, scanPath, services)\n  const dockerfile = await addDockerfileRuntimes(graph, services, scanPath)\n  const terraform = await addTerraformResources(graph, scanPath)\n  const k8s = await addK8sResources(graph, scanPath)\n  const cloudflare = await addCloudflareWorkers(graph, services, scanPath)\n  const vercel = await addVercelServices(graph, services, scanPath)\n  const railway = await addRailwayServices(graph, services, scanPath)\n  const supabase = await addSupabaseProjects(graph, services, scanPath)\n  const nginx = await addNginxProxies(graph, services)\n\n  return {\n    nodesAdded:\n      compose.nodesAdded +\n      dockerfile.nodesAdded +\n      terraform.nodesAdded +\n      k8s.nodesAdded +\n      cloudflare.nodesAdded +\n      vercel.nodesAdded +\n      railway.nodesAdded +\n      supabase.nodesAdded +\n      nginx.nodesAdded,\n    edgesAdded:\n      compose.edgesAdded +\n      dockerfile.edgesAdded +\n      terraform.edgesAdded +\n      k8s.edgesAdded +\n      cloudflare.edgesAdded +\n      vercel.edgesAdded +\n      railway.edgesAdded +\n      supabase.edgesAdded +\n      nginx.edgesAdded,\n  }\n}\n","import path from 'node:path'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, makeEdgeId, readYaml, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { classifyImage, makeInfraNode } from './shared.js'\n\ninterface ComposeService {\n  image?: string\n  build?: string | { context?: string }\n  depends_on?: string[] | Record<string, unknown>\n}\n\ninterface ComposeFile {\n  services?: Record<string, ComposeService>\n}\n\nfunction dependsOnList(value: ComposeService['depends_on']): string[] {\n  if (!value) return []\n  if (Array.isArray(value)) return value\n  return Object.keys(value)\n}\n\nfunction serviceNameToServiceNode(\n  name: string,\n  services: DiscoveredService[],\n): string | null {\n  for (const s of services) {\n    if (s.node.name === name || path.basename(s.dir) === name) return s.node.id\n  }\n  return null\n}\n\n// Project-level docker-compose.yml describes deployment topology. Each compose\n// service that is *not* one of the discovered ServiceNodes becomes an\n// InfraNode (databases, brokers, caches). depends_on lists become DEPENDS_ON\n// edges from the dependent to its dependency, regardless of whether the\n// endpoint is a ServiceNode or InfraNode — the edge itself is the deployment\n// fact, not the role.\nexport async function addComposeInfra(\n  graph: NeatGraph,\n  scanPath: string,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  let composePath: string | null = null\n  for (const name of ['docker-compose.yml', 'docker-compose.yaml']) {\n    const abs = path.join(scanPath, name)\n    if (await exists(abs)) {\n      composePath = abs\n      break\n    }\n  }\n  if (!composePath) return { nodesAdded, edgesAdded }\n\n  let compose: ComposeFile\n  try {\n    compose = await readYaml<ComposeFile>(composePath)\n  } catch (err) {\n    recordExtractionError(\n      'infra docker-compose',\n      path.relative(scanPath, composePath),\n      err,\n    )\n    return { nodesAdded, edgesAdded }\n  }\n  if (!compose?.services) return { nodesAdded, edgesAdded }\n  const evidenceFile = path.relative(scanPath, composePath).split(path.sep).join('/')\n\n  const composeNameToNodeId = new Map<string, string>()\n  for (const [composeName, svc] of Object.entries(compose.services)) {\n    const matchedServiceId = serviceNameToServiceNode(composeName, services)\n    if (matchedServiceId) {\n      composeNameToNodeId.set(composeName, matchedServiceId)\n      continue\n    }\n    const kind = svc.image ? classifyImage(svc.image) : 'container'\n    const node = makeInfraNode(kind, composeName)\n    if (!graph.hasNode(node.id)) {\n      graph.addNode(node.id, node)\n      nodesAdded++\n    }\n    composeNameToNodeId.set(composeName, node.id)\n  }\n\n  for (const [composeName, svc] of Object.entries(compose.services)) {\n    const sourceId = composeNameToNodeId.get(composeName)\n    if (!sourceId) continue\n    for (const dep of dependsOnList(svc.depends_on)) {\n      const targetId = composeNameToNodeId.get(dep)\n      if (!targetId) continue\n      const edgeId = makeEdgeId(sourceId, targetId, EdgeType.DEPENDS_ON)\n      if (graph.hasEdge(edgeId)) continue\n      // depends_on declaration from docker-compose.yml — structural deployment\n      // fact, structural tier per ADR-066.\n      const edge: GraphEdge = {\n        id: edgeId,\n        source: sourceId,\n        target: targetId,\n        type: EdgeType.DEPENDS_ON,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: { file: evidenceFile },\n      }\n      graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n      edgesAdded++\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport { promises as fs } from 'node:fs'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { makeInfraNode } from './shared.js'\nimport { ensureFileNode, toPosix } from '../calls/shared.js'\n\ninterface DockerfileFacts {\n  image: string | null\n  // Ports declared with `EXPOSE`, in declaration order, deduped. Each one is a\n  // network endpoint the container listens on — the structural answer to \"what\n  // is this service reachable at\".\n  ports: number[]\n  // The trimmed `ENTRYPOINT` / `CMD` line that names the process the container\n  // runs. Carried as edge evidence so the entrypoint is queryable instead of\n  // being a silent fact only the Dockerfile knows.\n  entrypoint: string | null\n}\n\n// Read the runtime-shaping instructions out of a Dockerfile in one pass:\n//\n//   - FROM   → the runtime image. Multi-stage builds report the *runtime* image\n//              (the last FROM that isn't `scratch` / a stage alias).\n//   - EXPOSE → the ports the container listens on (`EXPOSE 8080 9090`,\n//              `EXPOSE 8080/tcp`).\n//   - CMD / ENTRYPOINT → the process the container runs. ENTRYPOINT wins when\n//              both are present, matching Docker's precedence.\nfunction readDockerfile(content: string): DockerfileFacts {\n  let image: string | null = null\n  const ports: number[] = []\n  let cmd: string | null = null\n  let entrypoint: string | null = null\n  for (const raw of content.split('\\n')) {\n    const line = raw.trim()\n    if (!line || line.startsWith('#')) continue\n    if (/^from\\s+/i.test(line)) {\n      const candidate = line.split(/\\s+/)[1]\n      if (candidate && candidate.toLowerCase() !== 'scratch') image = candidate\n    } else if (/^expose\\s+/i.test(line)) {\n      for (const token of line.split(/\\s+/).slice(1)) {\n        const port = Number.parseInt(token.split('/')[0]!, 10)\n        if (Number.isInteger(port) && !ports.includes(port)) ports.push(port)\n      }\n    } else if (/^entrypoint\\s+/i.test(line)) {\n      entrypoint = line\n    } else if (/^cmd\\s+/i.test(line)) {\n      cmd = line\n    }\n  }\n  return { image, ports, entrypoint: entrypoint ?? cmd }\n}\n\n// For each ServiceNode that has a Dockerfile in its dir, emit a\n// `infra:container-image:<image>` InfraNode and a RUNS_ON edge from the\n// service to the image.\nexport async function addDockerfileRuntimes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const dockerfilePath = path.join(service.dir, 'Dockerfile')\n    if (!(await exists(dockerfilePath))) continue\n    let content: string\n    try {\n      content = await fs.readFile(dockerfilePath, 'utf8')\n    } catch (err) {\n      recordExtractionError(\n        'infra dockerfile',\n        path.relative(scanPath, dockerfilePath),\n        err,\n      )\n      continue\n    }\n    const facts = readDockerfile(content)\n    if (!facts.image) continue\n\n    const node = makeInfraNode('container-image', facts.image)\n    if (!graph.hasNode(node.id)) {\n      graph.addNode(node.id, node)\n      nodesAdded++\n    }\n\n    // file-awareness §1 — the Dockerfile IS the file that declares the runtime;\n    // anchor the infra edges on a FileNode for it, not on the service. The file\n    // node is service-scoped, so two services that both `FROM node:20` keep\n    // distinct entrypoints and exposed ports instead of colliding on the shared\n    // image node.\n    const relDockerfile = toPosix(path.relative(service.dir, dockerfilePath))\n    const evidenceFile = toPosix(path.relative(scanPath, dockerfilePath))\n    const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n      graph,\n      service.pkg.name,\n      service.node.id,\n      relDockerfile,\n    )\n    nodesAdded += fn\n    edgesAdded += fe\n\n    // RUNS_ON carries the runtime image, and — when the Dockerfile declares one\n    // — the entrypoint/CMD line as evidence.snippet, so the process the\n    // container runs is queryable instead of a silent fact.\n    const edgeId = makeEdgeId(fileNodeId, node.id, EdgeType.RUNS_ON)\n    if (!graph.hasEdge(edgeId)) {\n      const edge: GraphEdge = {\n        id: edgeId,\n        source: fileNodeId,\n        target: node.id,\n        type: EdgeType.RUNS_ON,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: {\n          file: evidenceFile,\n          ...(facts.entrypoint ? { snippet: facts.entrypoint.slice(0, 120) } : {}),\n        },\n      }\n      graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n      edgesAdded++\n    }\n\n    // Each EXPOSE port becomes an `infra:port:<n>` node the Dockerfile\n    // CONNECTS_TO — the structural answer to \"what is this service reachable\n    // at\". Without this, a declared listener is a fact only the Dockerfile\n    // knows; with it, the port is a first-class node the topology can reach.\n    for (const port of facts.ports) {\n      const portNode = makeInfraNode('port', String(port))\n      if (!graph.hasNode(portNode.id)) {\n        graph.addNode(portNode.id, portNode)\n        nodesAdded++\n      }\n      const portEdgeId = makeEdgeId(fileNodeId, portNode.id, EdgeType.CONNECTS_TO)\n      if (graph.hasEdge(portEdgeId)) continue\n      const portEdge: GraphEdge = {\n        id: portEdgeId,\n        source: fileNodeId,\n        target: portNode.id,\n        type: EdgeType.CONNECTS_TO,\n        provenance: Provenance.EXTRACTED,\n        confidence: confidenceForExtracted('structural'),\n        evidence: { file: evidenceFile, snippet: `EXPOSE ${port}` },\n      }\n      graph.addEdgeWithKey(portEdgeId, portEdge.source, portEdge.target, portEdge)\n      edgesAdded++\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { GraphEdge } from '@neat.is/types'\nimport { EdgeType, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { IGNORED_DIRS, isPythonVenvDir, makeEdgeId } from '../shared.js'\nimport { toPosix } from '../calls/shared.js'\nimport { makeInfraNode } from './shared.js'\n\n// Light pass: catalogue `resource \"aws_*\" \"name\"` blocks in any *.tf file and\n// wire the references between them. We don't run a real Terraform backend, but\n// the body of every resource block names the other resources it consumes\n// (`aws_db_instance.main.endpoint`, `${aws_security_group.db.id}`, …). Those\n// `<type>.<name>` references are the structural fact that turns an edgeless\n// catalogue into a topology: a resource nothing points at is declared-but-unused,\n// a resource something points at is in use. Without this, an RDS instance the\n// app server depends on looks identical to a forgotten S3 bucket.\nconst RESOURCE_RE = /resource\\s+\"(aws_[A-Za-z0-9_]+)\"\\s+\"([A-Za-z0-9_-]+)\"/g\n// A reference to another declared resource. The negative look-behind keeps us\n// from matching the tail of a longer identifier (`my_aws_thing.x`).\nconst REFERENCE_RE = /(?<![\\w.])(aws_[A-Za-z0-9_]+)\\.([A-Za-z0-9_-]+)/g\n\ninterface TfResource {\n  type: string\n  name: string\n  nodeId: string\n  body: string\n  bodyOffset: number\n}\n\nasync function walkTfFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n  if (depth > max) return []\n  const out: string[] = []\n  const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n  for (const entry of entries) {\n    if (entry.isDirectory()) {\n      if (IGNORED_DIRS.has(entry.name) || entry.name === '.terraform') continue\n      const child = path.join(start, entry.name)\n      if (await isPythonVenvDir(child)) continue\n      out.push(...(await walkTfFiles(child, depth + 1, max)))\n    } else if (entry.isFile() && entry.name.endsWith('.tf')) {\n      out.push(path.join(start, entry.name))\n    }\n  }\n  return out\n}\n\n// Find the index just past the `}` that closes the block whose opening `{`\n// sits at or after `from`. Returns the body span (exclusive of the braces).\n// Balanced-brace scan — good enough for HCL, which doesn't put bare braces in\n// string literals often enough to matter for a reference catalogue.\nfunction blockBody(content: string, from: number): { body: string; offset: number } | null {\n  const open = content.indexOf('{', from)\n  if (open === -1) return null\n  let depth = 0\n  for (let i = open; i < content.length; i++) {\n    const ch = content[i]\n    if (ch === '{') depth++\n    else if (ch === '}') {\n      depth--\n      if (depth === 0) return { body: content.slice(open + 1, i), offset: open + 1 }\n    }\n  }\n  return null\n}\n\nfunction lineAt(content: string, index: number): number {\n  let line = 1\n  for (let i = 0; i < index && i < content.length; i++) {\n    if (content[i] === '\\n') line++\n  }\n  return line\n}\n\nexport async function addTerraformResources(\n  graph: NeatGraph,\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  const files = await walkTfFiles(scanPath)\n  for (const file of files) {\n    const content = await fs.readFile(file, 'utf8')\n    const evidenceFile = toPosix(path.relative(scanPath, file))\n\n    // First pass: register every resource as a node and remember its body so\n    // the second pass can resolve references against the set of declared names.\n    const resources: TfResource[] = []\n    const byKey = new Map<string, TfResource>()\n    RESOURCE_RE.lastIndex = 0\n    let m: RegExpExecArray | null\n    while ((m = RESOURCE_RE.exec(content)) !== null) {\n      const type = m[1]!\n      const name = m[2]!\n      const node = makeInfraNode(type, name, 'aws')\n      if (!graph.hasNode(node.id)) {\n        graph.addNode(node.id, node)\n        nodesAdded++\n      }\n      const span = blockBody(content, RESOURCE_RE.lastIndex)\n      const resource: TfResource = {\n        type,\n        name,\n        nodeId: node.id,\n        body: span?.body ?? '',\n        bodyOffset: span?.offset ?? RESOURCE_RE.lastIndex,\n      }\n      resources.push(resource)\n      byKey.set(`${type}.${name}`, resource)\n    }\n\n    // Second pass: a `<type>.<name>` reference inside a resource body that\n    // names another declared resource becomes a DEPENDS_ON edge from the\n    // referencing resource to the one it consumes. Structural tier (ADR-066) —\n    // the HCL literally says it depends on it.\n    for (const resource of resources) {\n      const seen = new Set<string>()\n      REFERENCE_RE.lastIndex = 0\n      let ref: RegExpExecArray | null\n      while ((ref = REFERENCE_RE.exec(resource.body)) !== null) {\n        const key = `${ref[1]!}.${ref[2]!}`\n        if (key === `${resource.type}.${resource.name}`) continue\n        const target = byKey.get(key)\n        if (!target) continue\n        if (seen.has(target.nodeId)) continue\n        seen.add(target.nodeId)\n        const edgeId = makeEdgeId(resource.nodeId, target.nodeId, EdgeType.DEPENDS_ON)\n        if (graph.hasEdge(edgeId)) continue\n        const line = lineAt(content, resource.bodyOffset + ref.index)\n        const edge: GraphEdge = {\n          id: edgeId,\n          source: resource.nodeId,\n          target: target.nodeId,\n          type: EdgeType.DEPENDS_ON,\n          provenance: Provenance.EXTRACTED,\n          confidence: confidenceForExtracted('structural'),\n          evidence: { file: evidenceFile, line, snippet: key },\n        }\n        graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n        edgesAdded++\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parseAllDocuments } from 'yaml'\nimport { EdgeType, serviceId } from '@neat.is/types'\nimport type { InfraNode, ServiceNode } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { CONFIG_FILE_EXTENSIONS, IGNORED_DIRS, isPythonVenvDir } from '../shared.js'\nimport { toPosix } from '../calls/shared.js'\nimport { emitPlatformResourceEdge, lineContaining, makeInfraNode } from './shared.js'\n\ninterface K8sDoc {\n  kind?: string\n  metadata?: { name?: string; namespace?: string }\n  spec?: {\n    replicas?: number\n    template?: { spec?: { containers?: Array<{ image?: string }> } }\n  }\n}\n\nconst K8S_KIND_TO_INFRA_KIND: Record<string, string> = {\n  Service: 'k8s-service',\n  Deployment: 'k8s-deployment',\n  StatefulSet: 'k8s-statefulset',\n  DaemonSet: 'k8s-daemonset',\n  CronJob: 'k8s-cronjob',\n  Job: 'k8s-job',\n  Ingress: 'k8s-ingress',\n}\n\n// The kinds that carry a pod template we read the declared image + replica count\n// from. Service / Ingress / Job-style kinds have neither (a Job/CronJob nests its\n// template a level deeper and is left for a later rung).\nconst WORKLOAD_KINDS = new Set(['Deployment', 'StatefulSet', 'DaemonSet'])\n\nasync function walkYamlFiles(start: string, depth = 0, max = 5): Promise<string[]> {\n  if (depth > max) return []\n  const out: string[] = []\n  const entries = await fs.readdir(start, { withFileTypes: true }).catch(() => [])\n  for (const entry of entries) {\n    if (entry.isDirectory()) {\n      if (IGNORED_DIRS.has(entry.name)) continue\n      const child = path.join(start, entry.name)\n      if (await isPythonVenvDir(child)) continue\n      out.push(...(await walkYamlFiles(child, depth + 1, max)))\n    } else if (entry.isFile() && CONFIG_FILE_EXTENSIONS.has(path.extname(entry.name))) {\n      out.push(path.join(start, entry.name))\n    }\n  }\n  return out\n}\n\n// The k8s deployment substrate — the DECLARED half. Reads workload manifests\n// (multi-document YAML with a `kind`/`metadata.name`) and records the desired\n// deploy state: the container image and replica count a Deployment/StatefulSet/\n// DaemonSet declares. The declared state is stamped onto the `service:<name>` node\n// the workload runs (`declaredImage`/`declaredReplicas`), where the k8s observed\n// reader stamps the running image / ready replicas — the two provenances fuse on\n// one node so the divergence detector can name a declared-vs-running deploy drift,\n// including the stuck rollout that mints no incident (service still up on the old\n// image). The workload also gets its own `infra:k8s-deployment:<name>` InfraNode\n// with image/replicas + a RUNS_ON edge, for topology and blast-radius.\n//\n// The InfraNode is keyed NAME-ONLY (`infraId(kind, metadata.name)`), not\n// `<ns>/<name>`: a manifest frequently omits `metadata.namespace` (relying on\n// `kubectl apply -n`), so the name is the only key the declared manifest and the\n// live cluster can both produce, and it matches NEAT's name-based identity (a\n// ServiceNode is `service:<name>`, ADR-010). The namespace rides as an attribute.\nexport async function addK8sResources(\n  graph: NeatGraph,\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  const files = await walkYamlFiles(scanPath)\n  for (const file of files) {\n    const content = await fs.readFile(file, 'utf8')\n    let docs: K8sDoc[]\n    try {\n      docs = parseAllDocuments(content).map((d) => d.toJSON() as K8sDoc)\n    } catch {\n      continue\n    }\n    const relFile = toPosix(path.relative(scanPath, file))\n    for (const doc of docs) {\n      if (!doc?.kind || !doc.metadata?.name) continue\n      const infraKind = K8S_KIND_TO_INFRA_KIND[doc.kind]\n      if (!infraKind) continue\n      const name = doc.metadata.name\n\n      const isWorkload = WORKLOAD_KINDS.has(doc.kind)\n      const image = isWorkload ? doc.spec?.template?.spec?.containers?.[0]?.image : undefined\n      const replicas =\n        isWorkload && typeof doc.spec?.replicas === 'number' ? doc.spec.replicas : undefined\n\n      const base = makeInfraNode(infraKind, name, 'kubernetes')\n      const node: InfraNode = {\n        ...base,\n        ...(doc.metadata.namespace ? { namespace: doc.metadata.namespace } : {}),\n        ...(image ? { image } : {}),\n        ...(replicas !== undefined ? { replicas } : {}),\n      }\n      if (!graph.hasNode(node.id)) {\n        graph.addNode(node.id, node)\n        nodesAdded++\n      }\n\n      // Stamp the declared deploy state on the ServiceNode the workload runs — the\n      // node the observed cluster reader stamps running-image/ready onto, so the two\n      // fuse there. Only when the service already exists: no phantom, no dangle.\n      if (isWorkload) {\n        const svcId = serviceId(name)\n        if (graph.hasNode(svcId)) {\n          const svc = graph.getNodeAttributes(svcId) as ServiceNode\n          graph.replaceNodeAttributes(svcId, {\n            ...svc,\n            platform: svc.platform ?? 'kubernetes',\n            ...(image ? { declaredImage: image } : {}),\n            ...(replicas !== undefined ? { declaredReplicas: replicas } : {}),\n          })\n          // Topology edge — the service runs on this declared k8s workload. The\n          // InfraNode already exists (enriched above), so this only adds the edge.\n          edgesAdded += emitPlatformResourceEdge(\n            graph,\n            svcId,\n            EdgeType.RUNS_ON,\n            infraKind,\n            name,\n            'kubernetes',\n            relFile,\n            lineContaining(content, image),\n          ).edgesAdded\n        }\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded }\n}\n","// Cloudflare Workers/Pages extraction (ADR-133, docs/contracts/static-extraction.md).\n//\n// Reads a service's `wrangler.toml`/`wrangler.jsonc`/`wrangler.json` and stamps\n// the `platform: cloudflare` identifier every downstream consumer keys on: the\n// ServiceNode (the frontend's icon key at the service-rollup level) and the\n// Worker's entry FileNode, which also carries `platformName` — the Worker's own\n// script name, the only identifier Cloudflare's own telemetry carries and what\n// the Cloudflare connector's resolveTarget looks up against\n// (docs/contracts/connectors.md §4a).\n//\n// Declared resources (bindings, routes, cron triggers, env-var names) become\n// InfraNodes wired from the entry file, the same shape dockerfile.ts/k8s.ts/\n// docker-compose.ts already use — no new NodeType. Per-environment `[env.X]`\n// wrangler sections are out of scope for v1; only top-level config is read.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport type { FileNode, GraphEdge, ServiceNode } from '@neat.is/types'\nimport { EdgeType, EdgeTypeValue, Provenance, confidenceForExtracted } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, maskCommentsInSource, makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { ensureFileNode, toPosix } from '../calls/shared.js'\nimport { makeInfraNode } from './shared.js'\n\ninterface WranglerBindingLike {\n  binding?: string\n  name?: string\n  queue?: string\n}\n\ninterface WranglerRouteLike {\n  pattern?: string\n}\n\ninterface WranglerServiceBinding {\n  binding?: string\n  service?: string\n}\n\ninterface WranglerConfig {\n  name?: string\n  main?: string\n  compatibility_date?: string\n  routes?: (string | WranglerRouteLike)[]\n  route?: string | WranglerRouteLike\n  kv_namespaces?: WranglerBindingLike[]\n  d1_databases?: WranglerBindingLike[]\n  r2_buckets?: WranglerBindingLike[]\n  durable_objects?: { bindings?: WranglerBindingLike[] }\n  queues?: { producers?: WranglerBindingLike[]; consumers?: WranglerBindingLike[] }\n  triggers?: { crons?: string[] }\n  services?: WranglerServiceBinding[]\n  vars?: Record<string, unknown>\n}\n\ninterface WranglerRead {\n  config: WranglerConfig\n  relFile: string\n  raw: string\n}\n\nconst WRANGLER_FILENAMES = ['wrangler.toml', 'wrangler.jsonc', 'wrangler.json']\n\nasync function readWranglerConfig(dir: string): Promise<WranglerRead | null> {\n  for (const filename of WRANGLER_FILENAMES) {\n    const abs = path.join(dir, filename)\n    if (!(await exists(abs))) continue\n    const raw = await fs.readFile(abs, 'utf8')\n    const config =\n      filename === 'wrangler.toml'\n        ? (parseToml(raw) as unknown as WranglerConfig)\n        : (JSON.parse(maskCommentsInSource(raw)) as WranglerConfig)\n    return { config, relFile: filename, raw }\n  }\n  return null\n}\n\n// Best-effort 1-indexed line for a declared value — a simple text search, the\n// same \"read config as data\" discipline `proto.ts`'s brace-balanced scan and\n// `terraform.ts`'s `lineAt` already use rather than a real TOML/JSONC AST.\nfunction lineContaining(raw: string, needle: string | undefined): number | undefined {\n  if (!needle) return undefined\n  const idx = raw.indexOf(needle)\n  if (idx === -1) return undefined\n  let line = 1\n  for (let i = 0; i < idx; i++) if (raw[i] === '\\n') line++\n  return line\n}\n\nfunction normalizeRoutes(config: WranglerConfig): string[] {\n  const out: string[] = []\n  const pushOne = (r: unknown): void => {\n    if (typeof r === 'string') out.push(r)\n    else if (r && typeof r === 'object' && typeof (r as WranglerRouteLike).pattern === 'string') {\n      out.push((r as WranglerRouteLike).pattern!)\n    }\n  }\n  if (Array.isArray(config.routes)) config.routes.forEach(pushOne)\n  else if (config.route) pushOne(config.route)\n  return out\n}\n\n// One declared-resource InfraNode + edge from the entry anchor (FileNode, or\n// the ServiceNode itself when no entry file resolved — the honest\n// service-level fallback file-awareness.md already names for this case).\nfunction addResourceEdge(\n  graph: NeatGraph,\n  anchorId: string,\n  edgeType: EdgeTypeValue,\n  kind: string,\n  name: string,\n  evidenceFile: string,\n  line: number | undefined,\n): { nodesAdded: number; edgesAdded: number } {\n  let nodesAdded = 0\n  let edgesAdded = 0\n  const node = makeInfraNode(kind, name, 'cloudflare')\n  if (!graph.hasNode(node.id)) {\n    graph.addNode(node.id, node)\n    nodesAdded++\n  }\n  if (node.id === anchorId) return { nodesAdded, edgesAdded } // no self-loops\n  const edgeId = makeEdgeId(anchorId, node.id, edgeType)\n  if (!graph.hasEdge(edgeId)) {\n    const edge: GraphEdge = {\n      id: edgeId,\n      source: anchorId,\n      target: node.id,\n      type: edgeType,\n      provenance: Provenance.EXTRACTED,\n      confidence: confidenceForExtracted('structural'),\n      evidence: { file: evidenceFile, ...(line !== undefined ? { line } : {}) },\n    }\n    graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n    edgesAdded++\n  }\n  return { nodesAdded, edgesAdded }\n}\n\ninterface DiscoveredWorker {\n  service: DiscoveredService\n  config: WranglerConfig\n  relFile: string\n  raw: string\n  evidenceFile: string\n}\n\nexport async function addCloudflareWorkers(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  // Pass 1 — read every service's wrangler config (if any) before writing a\n  // single node, so pass 2's service-binding resolution sees the full\n  // worker-name → entry-file map for this scan, same discipline `route-match.ts`\n  // uses running routes before calls.\n  const discovered: DiscoveredWorker[] = []\n  const workerIndex = new Map<string, { anchorId: string }>()\n\n  for (const service of services) {\n    let read: WranglerRead | null\n    try {\n      read = await readWranglerConfig(service.dir)\n    } catch (err) {\n      recordExtractionError('infra cloudflare', path.relative(scanPath, service.dir), err)\n      continue\n    }\n    if (!read || !read.config.name) continue\n\n    const evidenceFile = toPosix(path.relative(scanPath, path.join(service.dir, read.relFile)))\n    discovered.push({ service, config: read.config, relFile: read.relFile, raw: read.raw, evidenceFile })\n  }\n\n  // Tag every ServiceNode + entry FileNode first, populating workerIndex, so\n  // pass 2's service-binding resolution can target a real FileNode even when\n  // the referenced Worker is later in `services` than the one declaring the\n  // binding.\n  for (const worker of discovered) {\n    const { service, config } = worker\n\n    const serviceNode = graph.getNodeAttributes(service.node.id) as ServiceNode\n    if (serviceNode.platform !== 'cloudflare') {\n      const updated: ServiceNode = { ...serviceNode, platform: 'cloudflare' }\n      graph.replaceNodeAttributes(service.node.id, updated)\n    }\n\n    let anchorId = service.node.id\n    if (config.main) {\n      const entryRelPath = toPosix(path.normalize(config.main))\n      const { fileNodeId, nodesAdded: fn, edgesAdded: fe } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        entryRelPath,\n      )\n      nodesAdded += fn\n      edgesAdded += fe\n      const fileNode = graph.getNodeAttributes(fileNodeId) as FileNode\n      if (fileNode.platform !== 'cloudflare' || fileNode.platformName !== config.name) {\n        const updated: FileNode = { ...fileNode, platform: 'cloudflare', platformName: config.name }\n        graph.replaceNodeAttributes(fileNodeId, updated)\n      }\n      anchorId = fileNodeId\n    }\n\n    workerIndex.set(config.name!, { anchorId })\n  }\n\n  // Pass 2 — declared resources, wired from each worker's anchor (entry\n  // FileNode, or the ServiceNode when `main` was absent).\n  for (const worker of discovered) {\n    const { config, evidenceFile, raw } = worker\n    const anchorId = workerIndex.get(config.name!)!.anchorId\n\n    // Runtime marker — one shared node every Cloudflare Worker in this scan\n    // RUNS_ON, compat date carried as evidence.snippet (mirrors dockerfile.ts's\n    // image-node + entrypoint-snippet pattern).\n    const runtimeNode = makeInfraNode('workerd', 'cloudflare', 'cloudflare')\n    if (!graph.hasNode(runtimeNode.id)) {\n      graph.addNode(runtimeNode.id, runtimeNode)\n      nodesAdded++\n    }\n    if (runtimeNode.id !== anchorId) {\n      const runsOnId = makeEdgeId(anchorId, runtimeNode.id, EdgeType.RUNS_ON)\n      if (!graph.hasEdge(runsOnId)) {\n        const edge: GraphEdge = {\n          id: runsOnId,\n          source: anchorId,\n          target: runtimeNode.id,\n          type: EdgeType.RUNS_ON,\n          provenance: Provenance.EXTRACTED,\n          confidence: confidenceForExtracted('structural'),\n          evidence: {\n            file: evidenceFile,\n            ...(config.compatibility_date\n              ? { snippet: `compatibility_date = ${config.compatibility_date}`.slice(0, 120) }\n              : {}),\n          },\n        }\n        graph.addEdgeWithKey(runsOnId, edge.source, edge.target, edge)\n        edgesAdded++\n      }\n    }\n\n    // Routes / custom domains — network-reachability, same CONNECTS_TO\n    // semantics dockerfile.ts's EXPOSE→port edge already uses.\n    for (const route of normalizeRoutes(config)) {\n      const result = addResourceEdge(\n        graph,\n        anchorId,\n        EdgeType.CONNECTS_TO,\n        'cloudflare-route',\n        route,\n        evidenceFile,\n        lineContaining(raw, route),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n\n    // Bindings — declared runtime dependencies, DEPENDS_ON.\n    const bindingGroups: { kind: string; entries: WranglerBindingLike[]; nameOf: (b: WranglerBindingLike) => string | undefined }[] = [\n      { kind: 'cloudflare-kv', entries: config.kv_namespaces ?? [], nameOf: (b) => b.binding },\n      { kind: 'cloudflare-d1', entries: config.d1_databases ?? [], nameOf: (b) => b.binding },\n      { kind: 'cloudflare-r2', entries: config.r2_buckets ?? [], nameOf: (b) => b.binding },\n      { kind: 'cloudflare-durable-object', entries: config.durable_objects?.bindings ?? [], nameOf: (b) => b.name },\n      { kind: 'cloudflare-queue', entries: config.queues?.producers ?? [], nameOf: (b) => b.queue },\n      { kind: 'cloudflare-queue', entries: config.queues?.consumers ?? [], nameOf: (b) => b.queue },\n    ]\n    for (const group of bindingGroups) {\n      for (const entry of group.entries) {\n        const name = group.nameOf(entry)\n        if (!name) continue\n        const result = addResourceEdge(\n          graph,\n          anchorId,\n          EdgeType.DEPENDS_ON,\n          group.kind,\n          name,\n          evidenceFile,\n          lineContaining(raw, name),\n        )\n        nodesAdded += result.nodesAdded\n        edgesAdded += result.edgesAdded\n      }\n    }\n\n    // Cron triggers.\n    for (const cron of config.triggers?.crons ?? []) {\n      const result = addResourceEdge(\n        graph,\n        anchorId,\n        EdgeType.DEPENDS_ON,\n        'cloudflare-cron',\n        cron,\n        evidenceFile,\n        lineContaining(raw, cron),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n\n    // Declared env vars — name only, value never read (ADR-016 spirit).\n    for (const varName of Object.keys(config.vars ?? {})) {\n      const result = addResourceEdge(\n        graph,\n        anchorId,\n        EdgeType.DEPENDS_ON,\n        'cloudflare-env-var',\n        varName,\n        evidenceFile,\n        lineContaining(raw, varName),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n\n    // Service bindings — resolve directly onto the target Worker's own entry\n    // node when it's tagged in this same scan (CALLS: this Worker can invoke\n    // that one); otherwise an honest InfraNode fallback, never guessed.\n    for (const svc of config.services ?? []) {\n      if (!svc.service) continue\n      const target = workerIndex.get(svc.service)\n      if (target && target.anchorId !== anchorId) {\n        const edgeId = makeEdgeId(anchorId, target.anchorId, EdgeType.CALLS)\n        if (!graph.hasEdge(edgeId)) {\n          const edge: GraphEdge = {\n            id: edgeId,\n            source: anchorId,\n            target: target.anchorId,\n            type: EdgeType.CALLS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: { file: evidenceFile, line: lineContaining(raw, svc.service) },\n          }\n          graph.addEdgeWithKey(edgeId, edge.source, edge.target, edge)\n          edgesAdded++\n        }\n        continue\n      }\n      const result = addResourceEdge(\n        graph,\n        anchorId,\n        EdgeType.DEPENDS_ON,\n        'cloudflare-service-binding',\n        svc.service,\n        evidenceFile,\n        lineContaining(raw, svc.service),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","// Vercel project extraction. Stamps the `platform: vercel` identifier the\n// frontend service-rollup badge keys on (static-extraction.md, mirroring ADR-133\n// for Cloudflare) whenever a service carries a `vercel.json`/`vercel.jsonc` or a\n// linked `.vercel/project.json`, and models the config's declared resources —\n// crons, env-var names, routes/rewrites — as InfraNodes wired from the\n// ServiceNode. No new NodeType; env-var values are never read (ADR-016 spirit),\n// only names. Vercel apps have no single Worker-style entry file, so the tag and\n// the resource edges anchor on the ServiceNode itself.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ServiceNode } from '@neat.is/types'\nimport { EdgeType, EdgeTypeValue } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, maskCommentsInSource, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { toPosix } from '../calls/shared.js'\nimport { emitPlatformResourceEdge, lineContaining } from './shared.js'\n\ninterface VercelCron {\n  path?: string\n  schedule?: string\n}\n\ninterface VercelRoute {\n  source?: string\n  src?: string\n}\n\ninterface VercelConfig {\n  crons?: VercelCron[]\n  env?: Record<string, unknown>\n  build?: { env?: Record<string, unknown> }\n  rewrites?: VercelRoute[]\n  redirects?: VercelRoute[]\n  routes?: VercelRoute[]\n}\n\nconst VERCEL_CONFIG_FILENAMES = ['vercel.json', 'vercel.jsonc']\n\ninterface VercelRead {\n  config: VercelConfig\n  relFile: string\n  raw: string\n}\n\nasync function readVercelConfig(dir: string): Promise<VercelRead | null> {\n  for (const filename of VERCEL_CONFIG_FILENAMES) {\n    const abs = path.join(dir, filename)\n    if (!(await exists(abs))) continue\n    const raw = await fs.readFile(abs, 'utf8')\n    const config = JSON.parse(maskCommentsInSource(raw)) as VercelConfig\n    return { config, relFile: filename, raw }\n  }\n  return null\n}\n\n// `vercel link` writes `.vercel/project.json` — a strong platform signal even\n// when the repo carries no vercel.json, and the only place the human-readable\n// project name lives (the equivalent of a Worker's script name).\nasync function readLinkedProjectName(dir: string): Promise<string | undefined> {\n  const abs = path.join(dir, '.vercel', 'project.json')\n  if (!(await exists(abs))) return undefined\n  const parsed = JSON.parse(await fs.readFile(abs, 'utf8')) as { projectName?: unknown }\n  return typeof parsed.projectName === 'string' ? parsed.projectName : undefined\n}\n\nfunction routeSource(route: VercelRoute): string | undefined {\n  return route.source ?? route.src\n}\n\nexport async function addVercelServices(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    let read: VercelRead | null = null\n    let projectName: string | undefined\n    try {\n      read = await readVercelConfig(service.dir)\n      projectName = await readLinkedProjectName(service.dir)\n    } catch (err) {\n      recordExtractionError('infra vercel', path.relative(scanPath, service.dir), err)\n      continue\n    }\n    // A Vercel service is one with a vercel.json or a linked .vercel/project.json.\n    if (!read && !projectName) continue\n\n    const serviceNode = graph.getNodeAttributes(service.node.id) as ServiceNode\n    if (serviceNode.platform !== 'vercel' || (projectName && serviceNode.platformName !== projectName)) {\n      const updated: ServiceNode = {\n        ...serviceNode,\n        platform: 'vercel',\n        ...(projectName ? { platformName: projectName } : {}),\n      }\n      graph.replaceNodeAttributes(service.node.id, updated)\n    }\n\n    const anchorId = service.node.id\n    if (!read) continue // linked but no config file to mine resources from\n    const { config, relFile, raw } = read\n    const evidenceFile = toPosix(path.relative(scanPath, path.join(service.dir, relFile)))\n\n    const add = (edgeType: EdgeTypeValue, kind: string, name: string | undefined): void => {\n      if (!name) return\n      const result = emitPlatformResourceEdge(\n        graph,\n        anchorId,\n        edgeType,\n        kind,\n        name,\n        'vercel',\n        evidenceFile,\n        lineContaining(raw, name),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n\n    // Runtime marker — one shared node every Vercel service RUNS_ON.\n    add(EdgeType.RUNS_ON, 'vercel', 'vercel')\n\n    // Scheduled functions.\n    for (const cron of config.crons ?? []) add(EdgeType.DEPENDS_ON, 'vercel-cron', cron.path ?? cron.schedule)\n\n    // Declared env vars — names only, value never read.\n    for (const varName of Object.keys(config.env ?? {})) add(EdgeType.DEPENDS_ON, 'vercel-env-var', varName)\n    for (const varName of Object.keys(config.build?.env ?? {})) add(EdgeType.DEPENDS_ON, 'vercel-env-var', varName)\n\n    // Routes / rewrites / redirects — network-reachability, CONNECTS_TO.\n    for (const route of [...(config.rewrites ?? []), ...(config.redirects ?? []), ...(config.routes ?? [])]) {\n      add(EdgeType.CONNECTS_TO, 'vercel-route', routeSource(route))\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","// Railway service extraction. Stamps the `platform: railway` identifier the\n// frontend service-rollup badge keys on (mirroring ADR-133 for Cloudflare) when a\n// service carries a `railway.toml`/`railway.json`/`railway.jsonc`, and models the\n// config's declared surfaces — the healthcheck path and a cron schedule — as\n// InfraNodes wired from the ServiceNode. No new NodeType. Railway's config names\n// no service (that lives in Railway's own system, which the connector resolves by\n// deploymentId), so no platformName is stamped here.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport type { ServiceNode } from '@neat.is/types'\nimport { EdgeType, EdgeTypeValue } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, maskCommentsInSource, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { toPosix } from '../calls/shared.js'\nimport { emitPlatformResourceEdge, lineContaining } from './shared.js'\n\ninterface RailwayDeploy {\n  healthcheckPath?: string\n  cronSchedule?: string\n}\n\ninterface RailwayConfig {\n  deploy?: RailwayDeploy\n}\n\nconst RAILWAY_FILENAMES = ['railway.toml', 'railway.json', 'railway.jsonc']\n\ninterface RailwayRead {\n  config: RailwayConfig\n  relFile: string\n  raw: string\n}\n\nasync function readRailwayConfig(dir: string): Promise<RailwayRead | null> {\n  for (const filename of RAILWAY_FILENAMES) {\n    const abs = path.join(dir, filename)\n    if (!(await exists(abs))) continue\n    const raw = await fs.readFile(abs, 'utf8')\n    const config =\n      filename === 'railway.toml'\n        ? (parseToml(raw) as unknown as RailwayConfig)\n        : (JSON.parse(maskCommentsInSource(raw)) as RailwayConfig)\n    return { config, relFile: filename, raw }\n  }\n  return null\n}\n\nexport async function addRailwayServices(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    let read: RailwayRead | null = null\n    try {\n      read = await readRailwayConfig(service.dir)\n    } catch (err) {\n      recordExtractionError('infra railway', path.relative(scanPath, service.dir), err)\n      continue\n    }\n    if (!read) continue\n\n    const serviceNode = graph.getNodeAttributes(service.node.id) as ServiceNode\n    if (serviceNode.platform !== 'railway') {\n      graph.replaceNodeAttributes(service.node.id, { ...serviceNode, platform: 'railway' })\n    }\n\n    const anchorId = service.node.id\n    const { config, relFile, raw } = read\n    const evidenceFile = toPosix(path.relative(scanPath, path.join(service.dir, relFile)))\n\n    const add = (edgeType: EdgeTypeValue, kind: string, name: string | undefined): void => {\n      if (!name) return\n      const result = emitPlatformResourceEdge(\n        graph,\n        anchorId,\n        edgeType,\n        kind,\n        name,\n        'railway',\n        evidenceFile,\n        lineContaining(raw, name),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n\n    add(EdgeType.RUNS_ON, 'railway', 'railway')\n    add(EdgeType.CONNECTS_TO, 'railway-route', config.deploy?.healthcheckPath)\n    add(EdgeType.DEPENDS_ON, 'railway-cron', config.deploy?.cronSchedule)\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","// Supabase project extraction. Stamps the `platform: supabase` identifier the\n// frontend service-rollup badge keys on (mirroring ADR-133 for Cloudflare) when a\n// service carries a `supabase/config.toml`, using the config's `project_id` as\n// platformName (the ref the Supabase connector resolves against), and models the\n// declared surfaces — edge functions, storage, auth — as InfraNodes wired from\n// the ServiceNode. No new NodeType.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { parse as parseToml } from 'smol-toml'\nimport type { ServiceNode } from '@neat.is/types'\nimport { EdgeType, EdgeTypeValue } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { exists, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError } from '../errors.js'\nimport { toPosix } from '../calls/shared.js'\nimport { emitPlatformResourceEdge, lineContaining } from './shared.js'\n\ninterface SupabaseConfig {\n  project_id?: string\n  functions?: Record<string, unknown>\n  storage?: Record<string, unknown>\n  auth?: Record<string, unknown>\n}\n\ninterface SupabaseRead {\n  config: SupabaseConfig\n  relFile: string\n  raw: string\n}\n\n// Supabase's config lives at <service>/supabase/config.toml, not the service root.\nasync function readSupabaseConfig(dir: string): Promise<SupabaseRead | null> {\n  const relFile = path.join('supabase', 'config.toml')\n  const abs = path.join(dir, relFile)\n  if (!(await exists(abs))) return null\n  const raw = await fs.readFile(abs, 'utf8')\n  const config = parseToml(raw) as unknown as SupabaseConfig\n  return { config, relFile, raw }\n}\n\nexport async function addSupabaseProjects(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    let read: SupabaseRead | null = null\n    try {\n      read = await readSupabaseConfig(service.dir)\n    } catch (err) {\n      recordExtractionError('infra supabase', path.relative(scanPath, service.dir), err)\n      continue\n    }\n    if (!read) continue\n\n    const { config, relFile, raw } = read\n    const projectId = typeof config.project_id === 'string' ? config.project_id : undefined\n\n    const serviceNode = graph.getNodeAttributes(service.node.id) as ServiceNode\n    if (serviceNode.platform !== 'supabase' || (projectId && serviceNode.platformName !== projectId)) {\n      graph.replaceNodeAttributes(service.node.id, {\n        ...serviceNode,\n        platform: 'supabase',\n        ...(projectId ? { platformName: projectId } : {}),\n      })\n    }\n\n    const anchorId = service.node.id\n    const evidenceFile = toPosix(path.relative(scanPath, path.join(service.dir, relFile)))\n\n    const add = (edgeType: EdgeTypeValue, kind: string, name: string | undefined): void => {\n      if (!name) return\n      const result = emitPlatformResourceEdge(\n        graph,\n        anchorId,\n        edgeType,\n        kind,\n        name,\n        'supabase',\n        evidenceFile,\n        lineContaining(raw, name),\n      )\n      nodesAdded += result.nodesAdded\n      edgesAdded += result.edgesAdded\n    }\n\n    add(EdgeType.RUNS_ON, 'supabase', 'supabase')\n    // Edge functions — each [functions.X] section becomes a declared function.\n    for (const fn of Object.keys(config.functions ?? {})) add(EdgeType.DEPENDS_ON, 'supabase-function', fn)\n    // Managed surfaces the project declares.\n    if (config.storage) add(EdgeType.DEPENDS_ON, 'supabase-storage', 'storage')\n    if (config.auth) add(EdgeType.DEPENDS_ON, 'supabase-auth', 'auth')\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { GraphEdge, RouteNode, ServiceNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  routeId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { makeEdgeId, type DiscoveredService } from '../shared.js'\nimport { recordExtractionError, noteExtractedDropped } from '../errors.js'\nimport { ensureFileNode, snippet, toPosix } from '../calls/shared.js'\n\n// nginx `proxy_pass` — config as a source. A front end that is only nginx (or\n// OpenResty) hands requests to a service through its config:\n//\n//   location /api/v1/ {\n//     proxy_pass http://ts-gateway-service:18888;\n//   }\n//\n// For each service directory carrying an nginx config (`nginx.conf`,\n// `conf/nginx.conf`, `conf.d/*.conf`), each `location` whose block holds a\n// literal `proxy_pass http(s)://<host>[:port][/path]` mints:\n//   - a RouteNode for the location path on that service (ALL), when the location\n//     is a plain or exact (`=`) path; a regex location (`~`, `~*`) has no path\n//     template, so it gets no route, though its proxy edge still stands;\n//   - `file ──CALLS──▶ service` from the config file to the service <host> names,\n//     matched against service names, directory names and aliases. A host naming an\n//     `upstream` block resolves through that block's `server` hosts.\n// A host from a variable (`proxy_pass http://$backend`) is recorded as a drop with\n// its reason; a literal host naming no service in the graph gets no edge. A\n// location served by Lua (`content_by_lua*`) or by files has no proxy_pass and\n// mints nothing here.\n\nconst CONFIG_CANDIDATES = ['nginx.conf', path.join('conf', 'nginx.conf')]\n\ninterface Token {\n  text: string\n  line: number\n}\n\n// nginx's grammar: words, quoted strings, `;`, `{`, `}`, and `#` comments.\nfunction tokenize(text: string): Token[] {\n  const out: Token[] = []\n  let i = 0\n  let line = 1\n  while (i < text.length) {\n    const c = text[i]!\n    if (c === '\\n') {\n      line++\n      i++\n    } else if (/\\s/.test(c)) {\n      i++\n    } else if (c === '#') {\n      while (i < text.length && text[i] !== '\\n') i++\n    } else if (c === ';' || c === '{' || c === '}') {\n      out.push({ text: c, line })\n      i++\n    } else if (c === '\"' || c === \"'\") {\n      const start = line\n      let j = i + 1\n      let s = ''\n      while (j < text.length && text[j] !== c) {\n        if (text[j] === '\\\\' && j + 1 < text.length) j++\n        if (text[j] === '\\n') line++\n        s += text[j]\n        j++\n      }\n      out.push({ text: s, line: start })\n      i = j + 1\n    } else {\n      let j = i\n      while (j < text.length && !/[\\s;{}#]/.test(text[j]!)) j++\n      out.push({ text: text.slice(i, j), line })\n      i = j\n    }\n  }\n  return out\n}\n\ninterface Directive {\n  name: string\n  args: string[]\n  line: number\n  block?: Directive[]\n}\n\nfunction parseBlock(tokens: Token[], pos: { i: number }): Directive[] {\n  const out: Directive[] = []\n  while (pos.i < tokens.length) {\n    const t = tokens[pos.i]!\n    if (t.text === '}') {\n      pos.i++\n      return out\n    }\n    const words: Token[] = []\n    while (pos.i < tokens.length && ![';', '{', '}'].includes(tokens[pos.i]!.text)) {\n      words.push(tokens[pos.i]!)\n      pos.i++\n    }\n    const end = tokens[pos.i]\n    if (!words.length) {\n      pos.i++\n      continue\n    }\n    const d: Directive = { name: words[0]!.text, args: words.slice(1).map((w) => w.text), line: words[0]!.line }\n    if (end?.text === '{') {\n      pos.i++\n      // A Lua block (`content_by_lua_block { … }`) holds Lua, not nginx syntax;\n      // skip to its matching brace.\n      if (d.name.endsWith('_by_lua_block')) {\n        let depth = 1\n        while (pos.i < tokens.length && depth > 0) {\n          if (tokens[pos.i]!.text === '{') depth++\n          else if (tokens[pos.i]!.text === '}') depth--\n          pos.i++\n        }\n      } else {\n        d.block = parseBlock(tokens, pos)\n      }\n    } else if (end?.text === ';') {\n      pos.i++\n    }\n    out.push(d)\n  }\n  return out\n}\n\nexport interface NginxProxy {\n  // The location's path template, or null for a regex location.\n  locationPath: string | null\n  // The proxied hosts (an upstream resolves to its servers), or null when the\n  // proxy_pass host is a variable.\n  hosts: string[] | null\n  target: string\n  line: number\n}\n\nfunction walkDirectives(ds: Directive[], visit: (d: Directive) => void): void {\n  for (const d of ds) {\n    visit(d)\n    if (d.block) walkDirectives(d.block, visit)\n  }\n}\n\n/** The proxy_pass locations one nginx config declares. */\nexport function nginxProxiesFromConfig(text: string): NginxProxy[] {\n  const root = parseBlock(tokenize(text), { i: 0 })\n  const upstreams = new Map<string, string[]>()\n  walkDirectives(root, (d) => {\n    if (d.name !== 'upstream' || !d.args[0] || !d.block) return\n    const hosts = d.block\n      .filter((s) => s.name === 'server' && s.args[0])\n      .map((s) => s.args[0]!.replace(/^[a-z]+:\\/\\//i, '').replace(/:\\d+$/, ''))\n    upstreams.set(d.args[0], hosts)\n  })\n\n  const out: NginxProxy[] = []\n  walkDirectives(root, (d) => {\n    if (d.name !== 'location' || !d.block) return\n    const proxy = d.block.find((s) => s.name === 'proxy_pass' && s.args[0])\n    if (!proxy) return\n    const [modifier, maybePath] = d.args\n    const isRegex = modifier === '~' || modifier === '~*'\n    const rawPath = modifier === '=' || modifier === '^~' || isRegex ? maybePath : modifier\n    const locationPath = !isRegex && rawPath && rawPath.startsWith('/') ? rawPath : null\n    const target = proxy.args[0]!\n    const m = /^https?:\\/\\/([^/:]+)/i.exec(target)\n    let hosts: string[] | null = null\n    if (m && !m[1]!.includes('$')) {\n      const host = m[1]!\n      hosts = upstreams.get(host) ?? [host]\n    }\n    out.push({ locationPath, hosts, target, line: proxy.line })\n  })\n  return out\n}\n\nasync function configFiles(dir: string): Promise<string[]> {\n  const out: string[] = []\n  for (const rel of CONFIG_CANDIDATES) {\n    const p = path.join(dir, rel)\n    if (await fs.stat(p).then((s) => s.isFile()).catch(() => false)) out.push(p)\n  }\n  const confd = path.join(dir, 'conf.d')\n  for (const name of await fs.readdir(confd).catch(() => [] as string[])) {\n    if (name.endsWith('.conf')) out.push(path.join(confd, name))\n  }\n  return out\n}\n\n/** Gateway-style edges from nginx configs in service directories. */\nexport async function addNginxProxies(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  // Host → service: service names, directory names, and aliases.\n  const hostToService = new Map<string, string>()\n  for (const s of services) {\n    hostToService.set(s.pkg.name, s.node.id)\n    hostToService.set(path.basename(s.dir), s.node.id)\n    const node = graph.hasNode(s.node.id) ? (graph.getNodeAttributes(s.node.id) as ServiceNode) : s.node\n    for (const a of node.aliases ?? []) if (!hostToService.has(a)) hostToService.set(a, s.node.id)\n  }\n\n  let nodesAdded = 0\n  let edgesAdded = 0\n  for (const service of services) {\n    for (const abs of await configFiles(service.dir)) {\n      const text = await fs.readFile(abs, 'utf8').catch(() => null)\n      if (text === null || !text.includes('proxy_pass')) continue\n      let proxies: NginxProxy[]\n      try {\n        proxies = nginxProxiesFromConfig(text)\n      } catch (err) {\n        recordExtractionError('nginx config extraction', abs, err)\n        continue\n      }\n      if (proxies.length === 0) continue\n      const relFile = toPosix(path.relative(service.dir, abs))\n      const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n        graph,\n        service.pkg.name,\n        service.node.id,\n        relFile,\n      )\n      nodesAdded += n\n      edgesAdded += e\n\n      for (const p of proxies) {\n        const ev = { file: relFile, line: p.line, snippet: snippet(text, p.line) }\n        if (p.locationPath) {\n          const rid = routeId(service.pkg.name, 'ALL', p.locationPath)\n          if (!graph.hasNode(rid)) {\n            const node: RouteNode = {\n              id: rid,\n              type: NodeType.RouteNode,\n              name: `ALL ${p.locationPath}`,\n              service: service.pkg.name,\n              method: 'ALL',\n              pathTemplate: p.locationPath,\n              path: relFile,\n              line: p.line,\n              framework: 'nginx',\n              discoveredVia: 'static',\n            }\n            graph.addNode(rid, node)\n            nodesAdded++\n          }\n          const containsId = extractedEdgeId(service.node.id, rid, EdgeType.CONTAINS)\n          if (!graph.hasEdge(containsId)) {\n            const edge: GraphEdge = {\n              id: containsId,\n              source: service.node.id,\n              target: rid,\n              type: EdgeType.CONTAINS,\n              provenance: Provenance.EXTRACTED,\n              confidence: confidenceForExtracted('structural'),\n              evidence: ev,\n            }\n            graph.addEdgeWithKey(containsId, service.node.id, rid, edge)\n            edgesAdded++\n          }\n        }\n\n        if (p.hosts === null) {\n          noteExtractedDropped({\n            source: fileNodeId,\n            target: 'service:unresolved',\n            type: EdgeType.CALLS,\n            confidence: confidenceForExtracted('reconstructed-approximate'),\n            confidenceKind: 'reconstructed-approximate',\n            evidence: { ...ev, approximate: true, reason: `proxy_pass host isn't literal: ${p.target}` },\n          })\n          continue\n        }\n        for (const host of p.hosts) {\n          const target = hostToService.get(host)\n          if (!target || target === service.node.id) continue\n          const edgeId = makeEdgeId(fileNodeId, target, EdgeType.CALLS)\n          if (graph.hasEdge(edgeId)) continue\n          const edge: GraphEdge = {\n            id: edgeId,\n            source: fileNodeId,\n            target,\n            type: EdgeType.CALLS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: { ...ev, ...(p.locationPath ? { pathTemplate: p.locationPath } : {}) },\n          }\n          graph.addEdgeWithKey(edgeId, fileNodeId, target, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded }\n}\n","import path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\nimport type { EdgeEvidence, GraphEdge, InfraNode } from '@neat.is/types'\nimport {\n  EdgeType,\n  NodeType,\n  Provenance,\n  confidenceForExtracted,\n  extractedEdgeId,\n  infraId,\n} from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { isTestPath, type DiscoveredService } from './shared.js'\nimport { recordExtractionError } from './errors.js'\nimport { GRAMMAR_BY_EXT, parseSource } from './symbols.js'\nimport {\n  ensureFileNode,\n  loadSourceFiles,\n  snippet,\n  toPosix,\n  type SourceFile,\n} from './calls/shared.js'\nimport { foldColumns } from '../columns.js'\n\n// Zod-as-contract declared-shape recognizer (ADR-170). For an app that treats\n// Zod as the source of truth, the declared shape is invisible to the graph — a\n// `const UserSchema` bound to a `z.object` shape is not even a SymbolNode\n// (`collectSymbolDefs` mints `const` only for arrow / function values, not call\n// expressions). This producer reads the top-level `z.object` / `z.enum` shape\n// literals and mints each as an `InfraNode` of kind `zod-schema`, its fields\n// folded on as `ColumnAttr` — the same column grain a `sql-table` node carries\n// (ADR-157 §3), so a future declared-vs-observed field comparison has a static\n// twin to land on.\n//\n//   A module-level  const UserSchema = z.object  whose body is\n//   { id: z.string(), age: z.number() }  becomes an InfraNode\n//   infra:zod-schema:UserSchema  with columns [id, age].\n//\n// A dedicated `zod-schema` kind — NOT a new NodeType and NOT a SymbolKind\n// (minting Zod consts as symbols would ripple into symbol-edges.ts, symbol-grain\n// OBSERVED fusion, and divergences.ts). `kind` is an open string, so this is a\n// zero-schema-version change, and the read is EXTRACTED-only (no OBSERVED fusion:\n// a runtime parse failure is not observed at field grain today).\n//\n// Scope is deliberately narrow — only a literal top-level `z.object` or `z.enum`\n// shape bound directly to a module-level `const`. Composed / computed forms\n// (`.extend`, `.merge`, `.pick`, unions, refinements, spreads, computed keys)\n// name a partial or dynamic field set, so claiming them would misrepresent the\n// contract — they are left unclaimed rather than guessed, a follow-on rung.\n// Object-literal keys are read the way `calls/drizzle.ts` `columnsFromObject`\n// reads a table's second-argument object.\n//\n// NOTE: comments here name the forms as `z.object` / `z.enum` without a trailing\n// call paren on purpose — the Rule-5 audit (contracts.test.ts) forbids the literal\n// `z.<object|enum>(` token in core/mcp src to stop schema *definitions* leaking in.\n// This file recognizes those shapes, it does not define any.\n\nconst ZOD_IMPORT_RE = /\\bzod\\b/\n// The conventional binding names for the Zod namespace: `import { z } from 'zod'`\n// and `import * as z from 'zod'` (or `zod`). Any other alias is left unclaimed.\nconst ZOD_OBJECTS = new Set(['z', 'zod'])\n\n// A schema recognized in one file: the InfraNode id it implies, its display\n// name, and the declared top-level field set at code-name fidelity.\nexport interface ZodShape {\n  infraId: string\n  name: string\n  fields: string[]\n  evidence: EdgeEvidence\n}\n\nfunction parserForExt(ext: string): Parser {\n  const p = new Parser()\n  p.setLanguage(GRAMMAR_BY_EXT[ext] ?? JavaScript)\n  return p\n}\n\nfunction namedChildren(node: Parser.SyntaxNode): Parser.SyntaxNode[] {\n  const out: Parser.SyntaxNode[] = []\n  for (let i = 0; i < node.namedChildCount; i++) {\n    const c = node.namedChild(i)\n    if (c) out.push(c)\n  }\n  return out\n}\n\n// The literal text inside a `string` node (quotes stripped). Null for a template\n// / interpolated string — never guessed at. (Cloned from calls/drizzle.ts.)\nfunction stringLiteralText(node: Parser.SyntaxNode | null): string | null {\n  if (!node || node.type !== 'string') return null\n  for (const child of namedChildren(node)) {\n    if (child.type === 'string_fragment') return child.text\n  }\n  return '' // an empty '' literal has no string_fragment child\n}\n\n// A pair key → its field-name string (a bare `id:` or a quoted `'id':`).\nfunction keyName(key: Parser.SyntaxNode | null): string | null {\n  if (!key) return null\n  if (key.type === 'property_identifier') return key.text\n  if (key.type === 'string') return stringLiteralText(key)\n  return null\n}\n\n// `z.object` / `z.enum` classification for a call, or null when the callee is\n// not a `<z|zod>.object` / `<z|zod>.enum` member expression.\nfunction zodCallKind(call: Parser.SyntaxNode): 'object' | 'enum' | null {\n  const fn = call.childForFieldName('function')\n  if (fn?.type !== 'member_expression') return null\n  const obj = fn.childForFieldName('object')\n  const prop = fn.childForFieldName('property')\n  if (obj?.type !== 'identifier' || !ZOD_OBJECTS.has(obj.text)) return null\n  if (prop?.type !== 'property_identifier') return null\n  if (prop.text === 'object') return 'object'\n  if (prop.text === 'enum') return 'enum'\n  return null\n}\n\n// The first positional argument node of a call, or null.\nfunction firstArg(call: Parser.SyntaxNode): Parser.SyntaxNode | null {\n  const args = call.childForFieldName('arguments')\n  if (!args) return null\n  return namedChildren(args)[0] ?? null\n}\n\n// The declared field names of a `z.object` shape literal, or null when the\n// object is a composed / computed form (a spread or a computed key) — those name\n// a partial or dynamic set, so the whole schema is left unclaimed.\nfunction fieldsFromObject(obj: Parser.SyntaxNode): string[] | null {\n  const out: string[] = []\n  const seen = new Set<string>()\n  for (const child of namedChildren(obj)) {\n    if (child.type === 'spread_element') return null\n    if (child.type !== 'pair') continue\n    const key = child.childForFieldName('key')\n    if (key?.type === 'computed_property_name') return null\n    const name = keyName(key)\n    if (name && !seen.has(name)) {\n      seen.add(name)\n      out.push(name)\n    }\n  }\n  return out\n}\n\n// The declared member set of a `z.enum` shape literal, or null when a member is\n// not a plain string literal (a spread or a computed value) — left unclaimed.\nfunction membersFromEnum(arr: Parser.SyntaxNode): string[] | null {\n  const out: string[] = []\n  const seen = new Set<string>()\n  for (const child of namedChildren(arr)) {\n    if (child.type !== 'string') return null\n    const value = stringLiteralText(child)\n    if (value !== null && value !== '' && !seen.has(value)) {\n      seen.add(value)\n      out.push(value)\n    }\n  }\n  return out.length > 0 ? out : null\n}\n\n// Every top-level `const <Name>` bound directly to a `z.object` / `z.enum` shape\n// literal in the program, as its schema name and the bound call node. Direct\n// binding is the claim gate: a `.extend` / `.merge` wrapper makes the declarator's\n// value the wrapping call, not the recognized shape call, so a composed form never\n// matches.\nfunction topLevelSchemas(root: Parser.SyntaxNode): { name: string; call: Parser.SyntaxNode }[] {\n  const out: { name: string; call: Parser.SyntaxNode }[] = []\n  for (const stmt of namedChildren(root)) {\n    // Unwrap `export const …` to the declaration it fronts.\n    const decl = stmt.type === 'export_statement' ? stmt.childForFieldName('declaration') : stmt\n    if (decl?.type !== 'lexical_declaration' && decl?.type !== 'variable_declaration') continue\n    for (const declarator of namedChildren(decl)) {\n      if (declarator.type !== 'variable_declarator') continue\n      const name = declarator.childForFieldName('name')\n      const value = declarator.childForFieldName('value')\n      if (name?.type !== 'identifier' || value?.type !== 'call_expression') continue\n      if (zodCallKind(value) === null) continue\n      out.push({ name: name.text, call: value })\n    }\n  }\n  return out\n}\n\nexport function zodShapesFromFile(file: SourceFile, serviceDir: string): ZodShape[] {\n  if (!ZOD_IMPORT_RE.test(file.content)) return []\n  const tree = parseSource(parserForExt(path.extname(file.path)), file.content)\n  const out: ZodShape[] = []\n  const seen = new Set<string>()\n\n  for (const { name, call } of topLevelSchemas(tree.rootNode)) {\n    const kind = zodCallKind(call)\n    const arg = firstArg(call)\n    let fields: string[] | null = null\n    if (kind === 'object' && arg?.type === 'object') fields = fieldsFromObject(arg)\n    else if (kind === 'enum' && arg?.type === 'array') fields = membersFromEnum(arg)\n    // A composed / computed form (fields === null) or a non-literal argument is\n    // left unclaimed — no node, rather than a partial contract.\n    if (fields === null) continue\n    if (seen.has(name)) continue\n    seen.add(name)\n    const line = call.startPosition.row + 1\n    out.push({\n      infraId: infraId('zod-schema', name),\n      name,\n      fields,\n      evidence: {\n        file: path.relative(serviceDir, file.path),\n        line,\n        snippet: snippet(file.content, line),\n      },\n    })\n  }\n  return out\n}\n\nexport interface ZodExtractResult {\n  nodesAdded: number\n  edgesAdded: number\n}\n\n// Standalone extraction phase (registered in extract/index.ts). Gated per service\n// on the `zod` dependency — a service that doesn't declare Zod is skipped. Each\n// recognized schema mints an `infra:zod-schema:<name>` InfraNode with its fields\n// folded on as EXTRACTED `ColumnAttr` (via the read-only `foldColumns`), owned by\n// its file through a `file ──CONTAINS──▶ zod-schema` edge — the same containment\n// spine symbols use under files (file-awareness.md §2). CONTAINS is structural,\n// divergence-excluded, so the node carries no spurious `missing-observed` finding.\nexport async function addZodShapes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<ZodExtractResult> {\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const service of services) {\n    const deps = {\n      ...(service.pkg.dependencies ?? {}),\n      ...(service.pkg.devDependencies ?? {}),\n    }\n    if (deps['zod'] === undefined) continue\n\n    const files = await loadSourceFiles(service.dir, service.excludeDirs)\n    for (const file of files) {\n      // Test scope is excluded from outbound inference the same way the CALLS\n      // producers exclude it (ADR-065 #1) — a fixture schema is not app surface.\n      if (isTestPath(file.path)) continue\n      let shapes: ZodShape[]\n      try {\n        shapes = zodShapesFromFile(file, service.dir)\n      } catch (err) {\n        recordExtractionError('zod shape extraction', file.path, err)\n        continue\n      }\n      for (const shape of shapes) {\n        if (!graph.hasNode(shape.infraId)) {\n          const node: InfraNode = {\n            id: shape.infraId,\n            type: NodeType.InfraNode,\n            name: shape.name,\n            provider: 'self',\n            kind: 'zod-schema',\n          }\n          graph.addNode(node.id, node)\n          nodesAdded++\n        }\n\n        // Fold the declared fields onto the node as EXTRACTED columns (ADR-157 §3\n        // grain), read-only through `foldColumns`. Mutation is allowed here —\n        // extract/* is a lifecycle authority (lifecycle.md §3).\n        if (shape.fields.length > 0) {\n          const node = graph.getNodeAttributes(shape.infraId) as InfraNode\n          if (node.type === NodeType.InfraNode) {\n            graph.replaceNodeAttributes(shape.infraId, {\n              ...node,\n              columns: foldColumns(\n                node.columns,\n                shape.fields,\n                Provenance.EXTRACTED,\n                confidenceForExtracted('structural'),\n              ),\n            })\n          }\n        }\n\n        // File-first ownership (file-awareness.md §1–2): the schema is owned by\n        // the file it is declared in, through a `file ──CONTAINS──▶ zod-schema`\n        // edge alongside the `service ──CONTAINS──▶ file` edge ensureFileNode mints.\n        const relFile = toPosix(shape.evidence.file)\n        const { fileNodeId, nodesAdded: n, edgesAdded: e } = ensureFileNode(\n          graph,\n          service.pkg.name,\n          service.node.id,\n          relFile,\n        )\n        nodesAdded += n\n        edgesAdded += e\n        const edgeId = extractedEdgeId(fileNodeId, shape.infraId, EdgeType.CONTAINS)\n        if (!graph.hasEdge(edgeId)) {\n          const edge: GraphEdge = {\n            id: edgeId,\n            source: fileNodeId,\n            target: shape.infraId,\n            type: EdgeType.CONTAINS,\n            provenance: Provenance.EXTRACTED,\n            confidence: confidenceForExtracted('structural'),\n            evidence: shape.evidence,\n          }\n          graph.addEdgeWithKey(edgeId, fileNodeId, shape.infraId, edge)\n          edgesAdded++\n        }\n      }\n    }\n  }\n\n  return { nodesAdded, edgesAdded }\n}\n","import type { GraphNode, InfraNode } from '@neat.is/types'\nimport { NodeType } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport type { DiscoveredService } from './shared.js'\nimport { findFirst, readIfExists } from './databases/shared.js'\n\n// firestore.rules guard-set producer (ADR-169). A **standalone** extract phase —\n// not a `calls/` producer — that reads each service's checked-in `firestore.rules`\n// as a declared artifact and folds a `guardedFields` set onto the\n// `firestore-collection` InfraNodes the F1 recognizer (ADR-167) mints in the calls\n// phase. Reading a checked-in rules file as text is the same read-polyglot-as-data\n// discipline `calls/prisma.ts` follows for `schema.prisma`.\n//\n// The `field-guard` policy (ADR-169, packages/core/src/policy.ts) is the consumer:\n// it asserts every client-written column on a collection appears in that\n// collection's `guardedFields`. The load-bearing rule is honesty about what the\n// scanner can and cannot reduce — a guard that is condition-based,\n// function-indirected, or otherwise not an explicit field list leaves the\n// collection INDETERMINATE (no `guardedFields` folded), and the policy then stays\n// silent rather than firing a false positive.\n\nexport const FIRESTORE_COLLECTION_KIND = 'firestore-collection'\n\n// The write-family rule methods. A guard only matters on the write path — a read\n// rule constrains no field the code writes, so it never contributes.\nconst WRITE_METHODS = new Set(['write', 'create', 'update'])\n\n// Strip `//` line and `/* */` block comments, honoring string literals so a `/`\n// inside a quoted path or message is not mistaken for a comment.\nfunction stripComments(src: string): string {\n  let out = ''\n  let i = 0\n  const n = src.length\n  let inStr: string | null = null\n  while (i < n) {\n    const ch = src[i]!\n    const next = src[i + 1]\n    if (inStr) {\n      out += ch\n      if (ch === '\\\\') {\n        out += next ?? ''\n        i += 2\n        continue\n      }\n      if (ch === inStr) inStr = null\n      i++\n      continue\n    }\n    if (ch === '\"' || ch === \"'\") {\n      inStr = ch\n      out += ch\n      i++\n      continue\n    }\n    if (ch === '/' && next === '/') {\n      while (i < n && src[i] !== '\\n') i++\n      continue\n    }\n    if (ch === '/' && next === '*') {\n      i += 2\n      while (i < n && !(src[i] === '*' && src[i + 1] === '/')) i++\n      i += 2\n      continue\n    }\n    out += ch\n    i++\n  }\n  return out\n}\n\nfunction segmentsFromMatchPath(pathToken: string): string[] {\n  return pathToken.split('/').filter((s) => s.length > 0)\n}\n\n// A recursive-wildcard segment — `{document=**}` — matches every path below the match,\n// not one document id. It looks identical to `{orgId}` once wildcards are stripped, so\n// it has to be recognised before the key is built.\nfunction isRecursiveWildcard(seg: string): boolean {\n  return /^\\{[^}]*=\\s*\\*\\*\\}$/.test(seg)\n}\n\n// Normalize a sequence of match-path segments to the collection join key: strip\n// the standard `/databases/{db}/documents` root wrapper, drop `{wildcard}`\n// document-id segments, lowercase the remaining collection names, join with `/`.\n// A nested `/users/{userId}/posts/{postId}` becomes `users/posts`. Field names in\n// the graph are lowercased by `foldColumns`, so the key is lowercased too, keeping\n// the join case-insensitive.\nfunction collectionKeyFromSegments(segments: string[]): string {\n  let segs = segments\n  if (\n    segs.length >= 3 &&\n    segs[0] === 'databases' &&\n    /^\\{.*\\}$/.test(segs[1]!) &&\n    segs[2] === 'documents'\n  ) {\n    segs = segs.slice(3)\n  }\n  return segs\n    .filter((seg) => !/^\\{.*\\}$/.test(seg))\n    .map((seg) => seg.toLowerCase())\n    .join('/')\n}\n\n// A `firestore-collection` InfraNode's `name` is its collection path (F1 names it\n// from the code call site). Normalize it the same way as the rules match path so\n// the two join, regardless of whether F1 carries wildcard segments verbatim.\nfunction collectionKeyFromName(name: string): string {\n  return collectionKeyFromSegments(name.split('/').filter((s) => s.length > 0))\n}\n\n// Pull the explicit field-name literals out of a rule condition — the string\n// arguments to `keys().hasAll([...])` / `hasOnly([...])` / `hasAny([...])`. These\n// are the fields the rules explicitly name; any other condition shape (a function\n// call, an `request.auth` check, a comparison) names no field and contributes\n// nothing. Field names are lowercased to match `foldColumns`.\n//\n// A **negated** call is skipped rather than read. `!keys().hasAny(['ownerId'])` is a\n// denylist: it names the fields a write may NOT carry, which is the inverse of the\n// set this function exists to collect. Reading it as an allowlist would record the\n// forbidden fields as guarded and then flag every legitimately written field as\n// unguarded — a false claim, which is the one thing the never-guess bar forbids\n// (static-extraction.md §Firestore rules). Skipping it contributes no fields, so a\n// rule whose only field reference is negated reduces to nothing and its collection\n// goes indeterminate — silence, which is the documented degradation.\n//\n// A positive call alongside a negated one still counts: `hasOnly([a,b]) && !hasAny([c])`\n// names a real allowlist in its first clause.\nfunction fieldsFromCondition(cond: string): string[] {\n  const out: string[] = []\n  const callRe = /(!\\s*)?\\b(?:hasAll|hasOnly|hasAny)\\s*\\(\\s*\\[([^\\]]*)\\]\\s*\\)/g\n  let m: RegExpExecArray | null\n  while ((m = callRe.exec(cond)) !== null) {\n    // The `!` can sit anywhere left of the receiver chain (`!request.resource...hasAny`),\n    // so the capture above only catches it when adjacent. Walk back over the receiver\n    // to find a negation that applies to this call.\n    if (m[1] !== undefined || isNegatedAt(cond, m.index)) continue\n    const inner = m[2]!\n    const litRe = /'([^']*)'|\"([^\"]*)\"/g\n    let lm: RegExpExecArray | null\n    while ((lm = litRe.exec(inner)) !== null) {\n      const val = lm[1] ?? lm[2] ?? ''\n      if (val.length > 0) out.push(val.toLowerCase())\n    }\n  }\n  return out\n}\n\n// True when the call starting at `idx` is negated. Firestore conditions put the `!`\n// before the whole receiver chain — `!request.resource.data.keys().hasAny([...])` — so\n// the marker is not adjacent to the matched call. Walk left over the chain (identifiers,\n// dots, and the balanced `()` of intermediate calls like `keys()`) and report whether\n// the first character that isn't part of it is a `!`.\nfunction isNegatedAt(cond: string, idx: number): boolean {\n  let i = idx - 1\n  while (i >= 0) {\n    const ch = cond[i]!\n    if (ch === ')') {\n      // Skip a balanced intermediate call, e.g. the `()` of `.keys()`.\n      let depth = 1\n      i--\n      while (i >= 0 && depth > 0) {\n        if (cond[i] === ')') depth++\n        else if (cond[i] === '(') depth--\n        i--\n      }\n      continue\n    }\n    if (/[A-Za-z0-9_$.\\]['\"]/.test(ch) || ch === ' ') {\n      i--\n      continue\n    }\n    return ch === '!'\n  }\n  return false\n}\n\n// Parse a `firestore.rules` file into a map of collection key → the explicit set\n// of guarded fields on its write path. Pure over the file content so a test can\n// drive it without touching the filesystem, mirroring `prismaColumnsFromSchema`.\n//\n// A collection appears in the result ONLY when at least one write-family rule\n// reduces to an explicit field list AND no write-family rule on the same\n// collection is non-reducible. Any condition-based / function-indirected write\n// guard poisons the collection to INDETERMINATE — it is omitted, and the check\n// stays silent. This is the conservative choice: we opine only where the rules\n// give us an explicit set to opine with.\nexport function parseFirestoreRules(content: string): Map<string, string[]> {\n  const src = stripComments(content)\n\n  // One positional scan interleaving, in document order: a `match <path> {`\n  // opener (which consumes its own brace), an `allow …;` statement, a bare `{`\n  // (a `service {` / `function …() {` block), and a `}` closer. The wildcard\n  // `{userId}` inside a match path is matched as part of the path, so it is not\n  // mistaken for the block-opening brace.\n  const tokenRe = /match\\s+((?:\\/(?:\\{[^}]*\\}|[^\\s/{}]+))+)\\s*\\{|allow\\b([^;{}]*);|(\\{)|(\\})/g\n\n  interface Frame {\n    depth: number\n    segs: string[]\n    /** True when this match path contains a recursive wildcard (`{document=**}`). */\n    recursive: boolean\n  }\n  const matchStack: Frame[] = []\n  let depth = 0\n\n  const determinate = new Map<string, Set<string>>()\n  const indeterminate = new Set<string>()\n\n  const currentKey = (): string =>\n    collectionKeyFromSegments(matchStack.flatMap((f) => f.segs))\n\n  let m: RegExpExecArray | null\n  while ((m = tokenRe.exec(src)) !== null) {\n    if (m[1] !== undefined) {\n      // `match <path> {` — opens a block and consumes its brace.\n      depth++\n      const segs = segmentsFromMatchPath(m[1])\n      matchStack.push({ depth, segs, recursive: segs.some(isRecursiveWildcard) })\n      continue\n    }\n    if (m[2] !== undefined) {\n      // `allow <methods> [: if <cond>] ;`\n      const body = m[2]\n      const colon = body.indexOf(':')\n      const methodsPart = colon === -1 ? body : body.slice(0, colon)\n      const methods = methodsPart\n        .split(',')\n        .map((s) => s.trim().toLowerCase())\n        .filter(Boolean)\n      if (!methods.some((mm) => WRITE_METHODS.has(mm))) continue\n      const key = currentKey()\n      if (key.length === 0) continue\n      // A recursive wildcard spans every collection below the match, so whatever field\n      // list the rule names cannot be attributed to the one collection the stripped key\n      // happens to spell — `/orgs/{document=**}` strips to `orgs` exactly as\n      // `/orgs/{orgId}` does, and filing a sweeping rule under the narrow path is a\n      // false claim. Indeterminate, per the never-guess bar.\n      if (matchStack.some((f) => f.recursive)) {\n        indeterminate.add(key)\n        continue\n      }\n      const cond = colon === -1 ? '' : body.slice(colon + 1)\n      const fields = fieldsFromCondition(cond)\n      if (fields.length > 0) {\n        const set = determinate.get(key) ?? new Set<string>()\n        for (const f of fields) set.add(f)\n        determinate.set(key, set)\n      } else {\n        // A write-family rule with no reducible field list — condition-based or\n        // function-indirected. Indeterminate.\n        indeterminate.add(key)\n      }\n      continue\n    }\n    if (m[3] !== undefined) {\n      // A bare `{` (a `service {` / `function {` block).\n      depth++\n      continue\n    }\n    if (m[4] !== undefined) {\n      // A `}` closer. Pop the match frame opened at this depth, if any.\n      if (matchStack.length > 0 && matchStack[matchStack.length - 1]!.depth === depth) {\n        matchStack.pop()\n      }\n      depth--\n      continue\n    }\n  }\n\n  const out = new Map<string, string[]>()\n  for (const [key, set] of determinate) {\n    if (indeterminate.has(key)) continue\n    out.set(key, [...set].sort())\n  }\n  return out\n}\n\n// Standalone extract phase (ADR-169). Reads every service's `firestore.rules` and\n// folds the parsed `guardedFields` onto the matching `firestore-collection`\n// InfraNodes. Adds no nodes or edges — it only enriches existing ones — so it\n// contributes nothing to the extract counts. Inert until the F1 recognizer\n// (ADR-167) has minted `firestore-collection` nodes; when it hasn't, there is\n// nothing to fold onto and this is a no-op. Mutation is allowed here — extract/*\n// is a lifecycle authority (lifecycle.md §3).\nexport async function addFirestoreRules(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  // Merge every service's parsed rules into one collection-key → guarded-fields\n  // map. A monorepo can hold a single `firestore.rules` governing collections\n  // named across services; folding by collection key keeps the join independent\n  // of which service's calls minted the node.\n  const guards = new Map<string, Set<string>>()\n  for (const service of services) {\n    const rulesPath = await findFirst(service.dir, ['firestore.rules'])\n    if (!rulesPath) continue\n    const content = await readIfExists(rulesPath)\n    if (!content) continue\n    for (const [key, fields] of parseFirestoreRules(content)) {\n      const set = guards.get(key) ?? new Set<string>()\n      for (const f of fields) set.add(f)\n      guards.set(key, set)\n    }\n  }\n  if (guards.size === 0) return { nodesAdded: 0, edgesAdded: 0 }\n\n  graph.forEachNode((id, attrs) => {\n    const node = attrs as GraphNode\n    if (node.type !== NodeType.InfraNode) return\n    if (node.kind !== FIRESTORE_COLLECTION_KIND) return\n    const fields = guards.get(collectionKeyFromName(node.name))\n    if (!fields || fields.size === 0) return\n    graph.replaceNodeAttributes(id, {\n      ...node,\n      guardedFields: [...fields].sort(),\n    } as InfraNode)\n  })\n\n  return { nodesAdded: 0, edgesAdded: 0 }\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { FileNode, GraphEdge, GraphNode } from '@neat.is/types'\nimport { NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\n\n// Drop any FileNode left with no edges. A FileNode exists to originate a\n// relationship (file-awareness.md §1); once its CALLS / CONTAINS edges are\n// retired and no OBSERVED traffic remains, the bare node carries nothing and\n// goes too. Called after edge retirement so the snapshot stays consistent with\n// what's on disk. Returns the count dropped.\nfunction dropOrphanedFileNodes(graph: NeatGraph, source?: string): number {\n  const orphans: string[] = []\n  graph.forEachNode((id, attrs) => {\n    const node = attrs as GraphNode\n    if (node.type !== NodeType.FileNode) return\n    // Same scope rule as the edge sweep (ADR-233): a pass doesn't clean up after\n    // a source it didn't read. Otherwise a restored file whose edges another\n    // pass hasn't rebuilt yet is dropped by whichever repo syncs first.\n    if (source && (node as FileNode).source !== source) return\n    if (graph.inboundEdges(id).length === 0 && graph.outboundEdges(id).length === 0) {\n      orphans.push(id)\n    }\n  })\n  for (const id of orphans) graph.dropNode(id)\n  return orphans.length\n}\n\n// Drop every EXTRACTED edge whose evidence.file matches the given path, then\n// sweep any FileNode the retirement left orphaned. Called from watch.ts before\n// re-running an extract phase, so the producer's idempotent re-write recreates\n// only the edges that still apply. Edges from the deleted code stay deleted.\n// See docs/contracts/static-extraction.md §Ghost-edge cleanup. Mutation\n// authority lives under extract/* per ADR-030, so the dropEdge call must happen\n// here, not in watch.ts. The returned count is edges dropped (FileNode cleanup\n// is a structural side effect, not a ghost-edge count).\nexport function retireEdgesByFile(graph: NeatGraph, file: string): number {\n  const normalized = file.split('\\\\').join('/')\n  const toDrop: string[] = []\n  graph.forEachEdge((id, attrs) => {\n    const edge = attrs as GraphEdge\n    if (edge.provenance !== Provenance.EXTRACTED) return\n    if (!edge.evidence?.file) return\n    if (edge.evidence.file === normalized) toDrop.push(id)\n  })\n  for (const id of toDrop) graph.dropEdge(id)\n  dropOrphanedFileNodes(graph)\n  return toDrop.length\n}\n\n// #140 — full-pass cleanup. Walk every EXTRACTED edge in the graph; if its\n// `evidence.file` cannot be resolved on disk against the scan root or any\n// discovered service directory, drop it. extractFromDirectory calls this at\n// the end of every pass so a daemon bootstrap (or a re-init after the\n// operator deleted some source) gets a snapshot consistent with what's\n// actually on disk.\n//\n// Handles the deleted-file half of the ghost-edge bug. The edited-file half\n// (file still exists, producer no longer emits the edge) is handled by\n// watch.ts's per-file `retireEdgesByFile` on the mtime trigger.\n//\n// Path resolution is tolerant: producers in this tree are inconsistent about\n// whether `evidence.file` is scanPath-relative (configs, databases, infra)\n// or service-dir-relative (calls/*). We try every candidate base before\n// concluding the file is gone — the cost is one extra `existsSync` per\n// service dir per ghost candidate, which is cheap.\n\n// A pass may only retire what its own source produced (ADR-233).\n//\n// The sweep's reach is the whole graph; its evidence is one directory. That is\n// sound while the graph has one source and the pass is scanning it — a local\n// daemon — and wrong the moment it doesn't. A hosted daemon breaks both halves:\n// each bound repo is cloned to its own temp dir and extracted into the same\n// graph, so repo B's pass finds none of repo A's files and retires them\n// (#1294); and the boot pass runs over a path that holds no source at all, so\n// it retires every restored edge (#1291).\n//\n// So a pass that names a source retires only the files carrying that source,\n// and a pass that names none behaves exactly as it always has — which is every\n// local daemon, untouched.\n//\n// A file carrying *no* source is out of scope too, not judged by existence.\n// That looks over-cautious and isn't: a snapshot written before this field\n// existed has no sources on it at all, so judging those the old way would have\n// the first repo to sync after an upgrade sweep every other repo's restored\n// files — the bug, surviving its own fix, once. Unowned files are instead\n// claimed by the first pass that reads one (`ensureFileNode`), and are\n// retirable from then on.\n//\n// The cost is bounded and worth naming: a file deleted from a repo while the\n// daemon was down, and never read again, stays unowned and so is never retired.\n// It lingers as a ghost rather than taking a live repo's graph down with it.\nfunction outOfScope(graph: NeatGraph, edge: GraphEdge, source: string | undefined): boolean {\n  if (!source) return false\n  // The file an edge is about is its origin for a call, and its target for the\n  // service ──CONTAINS──▶ file edge.\n  for (const endpoint of [edge.source, edge.target]) {\n    if (!graph.hasNode(endpoint)) continue\n    const node = graph.getNodeAttributes(endpoint) as GraphNode\n    if (node.type !== NodeType.FileNode) continue\n    return (node as FileNode).source !== source\n  }\n  return false\n}\n\nexport function retireExtractedEdgesByMissingFile(\n  graph: NeatGraph,\n  scanPath: string,\n  serviceDirs: readonly string[] = [],\n  source?: string,\n): number {\n  const toDrop: string[] = []\n  const bases = [scanPath, ...serviceDirs]\n  graph.forEachEdge((id, attrs) => {\n    const edge = attrs as GraphEdge\n    if (edge.provenance !== Provenance.EXTRACTED) return\n    if (outOfScope(graph, edge, source)) return\n    const evidenceFile = edge.evidence?.file\n    if (!evidenceFile) return\n    if (path.isAbsolute(evidenceFile)) {\n      if (!existsSync(evidenceFile)) toDrop.push(id)\n      return\n    }\n    // Tolerant: the file is \"present\" if any base resolves it.\n    const found = bases.some((base) => existsSync(path.join(base, evidenceFile)))\n    if (!found) toDrop.push(id)\n  })\n  for (const id of toDrop) graph.dropEdge(id)\n  dropOrphanedFileNodes(graph, source)\n  return toDrop.length\n}\n","// computeDivergences — the thesis surface, derived (ADR-060).\n//\n// Walks the live graph and surfaces the edge-grain divergence shapes:\n// missing-observed, missing-extracted, version-mismatch, host-mismatch, and\n// compat-violation. When the caller passes the recorded incidents, it also\n// surfaces observed-symbol-mismatch (ADR-215) — a symbol/field-grain code↔runtime\n// disagreement fused from an OBSERVED incident and the EXTRACTED code location it\n// localized to, the one shape that never appears as a missing edge. It also\n// surfaces observed-failing (ADR-220) — a declared dependency that IS observed\n// but whose calls predominantly fail (a high edge error rate, or a declared\n// external call whose incident shows a transport/5xx failure), the truest\n// declared-intent-vs-observed-reality divergence, which is neither a missing edge\n// nor a member mismatch and was falling through. Pure: no\n// I/O, no mutation, no async. The function operates on a NeatGraph reference (and\n// the in-memory incidents array the caller supplies) and returns a fresh\n// DivergenceResult each call — there is no persistence (binding rule 2).\n//\n// Mutation authority (ADR-030 / contract #3) is locked to ingest.ts and\n// extract/*; this module reads only. The contract test\n// `packages/core/test/audits/contracts.test.ts` enforces it.\n\nimport type {\n  CompatRuleRef,\n  DatabaseNode,\n  Divergence,\n  DivergenceResult,\n  DivergenceType,\n  EdgeTypeValue,\n  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  InfraNode,\n  ObservedFailureKind,\n  ServiceNode,\n  SymbolMismatchKind,\n} from '@neat.is/types'\nimport {\n  databaseId,\n  DivergenceResultSchema,\n  EdgeType,\n  NodeType,\n  parseEdgeId,\n  parseFileId,\n  parseSymbolId,\n  Provenance,\n  serviceId,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { columnIsDeclared, columnIsObserved } from './columns.js'\nimport { FLAG_STORE_KIND, flagFieldsChanged } from './flags.js'\nimport {\n  checkCompatibility,\n  checkDeprecatedApi,\n  compatPairs,\n  deprecatedApis,\n} from './compat.js'\nimport { confidenceForEdge } from './traverse.js'\nimport { codeFilepathOf, codeLinenoOf } from './ingest.js'\n\nexport interface DivergenceQueryOpts {\n  // Filter the result to a subset of divergence types. Undefined keeps all of\n  // them. Empty set returns nothing.\n  type?: ReadonlySet<DivergenceType>\n  // Drop divergences below this confidence threshold. Undefined keeps all.\n  minConfidence?: number\n  // Scope to divergences that involve this node (as source or target).\n  node?: string\n  // The recorded incident store (ADR-215). Symbol/field-grain divergence is not\n  // in the edge sets — it lives in the OBSERVED error content — so the detector\n  // needs the incidents the caller has already read off the sidecar. Passing an\n  // in-memory array keeps `computeDivergences` pure: no I/O, no mutation, no\n  // async; the read stays at the call site. Omitted or empty means the\n  // symbol-grain pass contributes nothing and the edge-grain result is identical\n  // to before.\n  incidents?: readonly ErrorEvent[]\n}\n\n// (source, target, type) → which provenance variants are present. Each\n// bucket is the unit the missing-observed / missing-extracted detectors\n// operate over.\ninterface EdgeBucket {\n  source: string\n  target: string\n  type: GraphEdge['type']\n  extracted?: GraphEdge\n  observed?: GraphEdge\n  inferred?: GraphEdge\n  stale?: GraphEdge\n}\n\nfunction bucketKey(source: string, target: string, type: string): string {\n  return `${type}|${source}|${target}`\n}\n\n// A database CONNECTS_TO is *declared* in a config file (its connection string)\n// but *executed* from a code file (the query call site) — inherently different\n// files. Comparing them at file grain would flag both a `missing-observed` (on\n// the config-file edge) and a `missing-extracted` (on the code-file edge) for a\n// database the service both declares and drives — a false pair on every ORM app\n// (ADR-141). So roll a database CONNECTS_TO's source up to its owning service:\n// declared and observed then compare at the grain they actually share. The\n// file-grained edges stay in the graph untouched — only this comparison\n// coarsens, and only for database targets (a route or service edge keeps its\n// file grain per the ADR-119 route-grained comparison).\nfunction bucketSourceFor(graph: NeatGraph, edge: GraphEdge): string {\n  if (edge.type !== EdgeType.CONNECTS_TO) return edge.source\n  const parsed = parseFileId(edge.source)\n  if (!parsed || !graph.hasNode(edge.target)) return edge.source\n  const target = graph.getNodeAttributes(edge.target) as GraphNode\n  // A flag store is a dependency the same way (ADR-242): the literal join\n  // declares it from the file that holds the key, and an evaluation observes it\n  // from wherever the span had a call site, often only the service.\n  const isFlagStore = target.type === NodeType.InfraNode && target.kind === FLAG_STORE_KIND\n  if (target.type !== NodeType.DatabaseNode && !isFlagStore) return edge.source\n  return serviceId(parsed.service)\n}\n\nfunction bucketEdges(graph: NeatGraph): Map<string, EdgeBucket> {\n  const buckets = new Map<string, EdgeBucket>()\n  graph.forEachEdge((id, attrs) => {\n    const e = attrs as GraphEdge\n    const parsed = parseEdgeId(id)\n    // parseEdgeId can fall through to EXTRACTED for unknown shapes — fall\n    // back to the edge's own provenance when the id doesn't parse cleanly.\n    const provenance = parsed?.provenance ?? e.provenance\n    const source = bucketSourceFor(graph, e)\n    const key = bucketKey(source, e.target, e.type)\n    const cur =\n      buckets.get(key) ?? { source, target: e.target, type: e.type }\n    switch (provenance) {\n      case Provenance.EXTRACTED:\n        cur.extracted = e\n        break\n      case Provenance.OBSERVED:\n        cur.observed = e\n        break\n      case Provenance.INFERRED:\n        cur.inferred = e\n        break\n      default:\n        // STALE rides on what used to be an OBSERVED edge — the id format\n        // stays OBSERVED per identity.ts, so this branch is mostly defensive.\n        if (e.provenance === Provenance.STALE) cur.stale = e\n    }\n    buckets.set(key, cur)\n  })\n  return buckets\n}\n\nfunction nodeIsFrontier(graph: NeatGraph, nodeId: string): boolean {\n  if (!graph.hasNode(nodeId)) return false\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  return attrs.type === NodeType.FrontierNode\n}\n\n// A WebSocketChannelNode is minted OBSERVED-only from the HTTP upgrade span\n// (ADR-125): a channel is known from observation, never from static extraction,\n// so it has no declared twin to diverge against. Its edge is a `CONNECTS_TO`,\n// which is in the OBSERVABLE_EDGE_TYPES allowlist, so an OBSERVED-only\n// `service ──CONNECTS_TO──▶ ws-channel` would otherwise flag a spurious\n// `missing-extracted`. Suppressing it where the target is a channel node is\n// signal-preserving — there is no static edge that \"should\" exist — not\n// signal-hiding. See docs/contracts/divergence-query.md.\nfunction nodeIsWebsocketChannel(graph: NeatGraph, nodeId: string): boolean {\n  if (!graph.hasNode(nodeId)) return false\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  return attrs.type === NodeType.WebSocketChannelNode\n}\n\n// A ServerActionNode is minted EXTRACTED-only from a `\"use server\"` directive\n// (ADR-168); its inbound `file ──CALLS──▶ action` client-stitch has no OBSERVED\n// twin by construction (Next serialises actions to opaque `Next-Action` hashes,\n// so runtime never names the action). CALLS is in OBSERVABLE_EDGE_TYPES, so an\n// EXTRACTED-only CALLS onto an action would otherwise flag a spurious\n// `missing-observed`. Suppressing it where the target is an action node is\n// signal-preserving — the OBSERVED twin cannot exist yet — not signal-hiding.\n// A bounded target-exclusion, mirroring nodeIsWebsocketChannel; not a taxonomy\n// change. See docs/contracts/divergence-query.md.\nfunction nodeIsServerAction(graph: NeatGraph, nodeId: string): boolean {\n  if (!graph.hasNode(nodeId)) return false\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  return attrs.type === NodeType.ServerActionNode\n}\n\n// A SymbolNode endpoint marks a symbol-grained edge (static heritage, or a\n// symbol→symbol EXTRACTED CALLS from Phase 2). Those live one grain below the\n// file/service grain this query compares (file-awareness.md §7 — \"compare\n// CALLS-family edges at the shared grain\"), and a static intra-process symbol\n// call has no boundary-observed twin by construction (observed CALLS are\n// boundary-grained, §5). Comparing them here would report every declared\n// heritage link and every static call as a spurious `missing-observed`. This\n// edge-bucket exclusion is independent of the symbol/field-grain divergence\n// ADR-215 wires below (detectSymbolMismatches): that one is sourced from the\n// incident store, not from comparing symbol edge buckets, so a symbol→symbol edge\n// with no observed twin still stays out of this surface.\nfunction nodeIsSymbol(graph: NeatGraph, nodeId: string): boolean {\n  if (!graph.hasNode(nodeId)) return false\n  const attrs = graph.getNodeAttributes(nodeId) as GraphNode\n  return attrs.type === NodeType.SymbolNode\n}\n\nfunction clampConfidence(n: number): number {\n  if (!Number.isFinite(n)) return 0\n  return Math.max(0, Math.min(1, n))\n}\n\nfunction reasonForMissingObserved(source: string, target: string, type: string): string {\n  return `Code declares ${source} → ${target} (${type}) but no production traffic has been observed for this edge.`\n}\n\nfunction reasonForMissingExtracted(source: string, target: string, type: string): string {\n  return `Production observed ${source} → ${target} (${type}) but static analysis did not surface this edge.`\n}\n\nconst RECOMMENDATION_MISSING_OBSERVED =\n  'Verify the code path is exercised in production; check feature flags or conditional branches that might gate the call.'\nconst RECOMMENDATION_MISSING_EXTRACTED =\n  'Likely dynamic dispatch, reflection, or a coverage gap in tree-sitter extraction. Consider an `aliases` entry on the source service or file an extractor issue.'\nconst RECOMMENDATION_HOST_MISMATCH =\n  'Check environment-specific config overrides — the runtime host differs from what static configuration declares.'\n\n// ADR-066 §4 — reweight against graded confidence.\n//\n// `missing-extracted` (OBSERVED-led) cascades from the OBSERVED edge's\n// graded confidence (signal-block grade per ADR-066 §2). `missing-observed`\n// weights by the EXTRACTED edge's graded confidence (per-extractor grade\n// per ADR-066 §1). Sub-floor EXTRACTED candidates never enter the graph\n// (precision floor, §3) so what surfaces here is backed by structural or\n// verified-call-site evidence.\n//\n// Falls back to confidenceForEdge for legacy edges loaded from a pre-v0.3.4\n// snapshot that don't carry a stored `confidence` field.\nfunction gradedConfidence(edge: GraphEdge): number {\n  if (typeof edge.confidence === 'number') return clampConfidence(edge.confidence)\n  return clampConfidence(confidenceForEdge(edge))\n}\n\n// Edge types production can actually emit as OBSERVED traffic — the CALLS\n// family plus cross-service and connection edges. `missing-observed` only\n// makes sense for these: an EXTRACTED edge of one of these types with no\n// OBSERVED twin is a real \"code declares it, production never ran it\" finding.\n//\n// Structural / static-only edge types (IMPORTS, CONFIGURED_BY, CONTAINS,\n// DEPENDS_ON, RUNS_ON) have no runtime span behind them, so there is never an\n// OBSERVED twin to be \"missing\" — measuring their tiers would report every\n// import and every config wire as a missing-observed divergence, which is\n// noise, not signal. Keep this an allowlist (not a denylist) so a new\n// structural edge type stays out of the missing-observed surface by default\n// until it is deliberately added here (divergence-query.md — the five locked\n// types compare CALLS-family edges at the shared grain).\nconst OBSERVABLE_EDGE_TYPES: ReadonlySet<EdgeTypeValue> = new Set([\n  EdgeType.CALLS,\n  EdgeType.CONNECTS_TO,\n  EdgeType.PUBLISHES_TO,\n  EdgeType.CONSUMES_FROM,\n])\n\nfunction detectMissingDivergences(\n  graph: NeatGraph,\n  bucket: EdgeBucket,\n): Divergence[] {\n  const out: Divergence[] = []\n\n  // CONTAINS is structural ownership (service → file), not a declared-vs-\n  // observed relationship — comparing its tiers would surface an OTel-only\n  // file node as a spurious missing-extracted finding (file-awareness.md §2).\n  // Divergence compares CALLS-family edges at the shared grain (§7).\n  if (bucket.type === EdgeType.CONTAINS) return out\n\n  // Symbol-grained buckets (heritage, symbol→symbol CALLS) are out of scope for\n  // the file/service-grain divergence surface — see nodeIsSymbol.\n  if (nodeIsSymbol(graph, bucket.source) || nodeIsSymbol(graph, bucket.target)) return out\n\n  if (bucket.extracted && !bucket.observed && OBSERVABLE_EDGE_TYPES.has(bucket.type)) {\n    // Skip when the would-be target is a FrontierNode — those represent\n    // unresolved span peers, not real entities we expect OBSERVED traffic\n    // to. The coexistence contract is between EXTRACTED and OBSERVED on\n    // real nodes; FRONTIER is unknown territory.\n    if (!nodeIsFrontier(graph, bucket.target) && !nodeIsServerAction(graph, bucket.target)) {\n      // ADR-066 §4 — weight by the EXTRACTED edge's graded confidence.\n      // Substring/hostname-shape candidates already dropped at the precision\n      // floor; what remains is structural or verified-call-site evidence.\n      out.push({\n        type: 'missing-observed',\n        source: bucket.source,\n        target: bucket.target,\n        edgeType: bucket.type,\n        extracted: bucket.extracted,\n        confidence: gradedConfidence(bucket.extracted),\n        reason: reasonForMissingObserved(bucket.source, bucket.target, bucket.type),\n        recommendation: RECOMMENDATION_MISSING_OBSERVED,\n      })\n    }\n  }\n\n  if (bucket.observed && !bucket.extracted && !nodeIsWebsocketChannel(graph, bucket.target)) {\n    // ADR-066 §4 — cascade from the OBSERVED edge's graded confidence.\n    // OBSERVED-led finding; the headline divergence type. A WebSocketChannelNode\n    // target is skipped: it is OBSERVED-only by design (ADR-125), so an\n    // OBSERVED-only CONNECTS_TO onto it is expected, not a missing-extracted\n    // divergence — mirrors the CONTAINS exclusion above, keyed on target type.\n    // No FrontierNode guard here, unlike missing-observed: production traffic\n    // to a peer the code never declared is exactly the finding this reports.\n    out.push({\n      type: 'missing-extracted',\n      source: bucket.source,\n      target: bucket.target,\n      edgeType: bucket.type,\n      observed: bucket.observed,\n      confidence: gradedConfidence(bucket.observed),\n      reason: reasonForMissingExtracted(bucket.source, bucket.target, bucket.type),\n      recommendation: RECOMMENDATION_MISSING_EXTRACTED,\n    })\n  }\n\n  return out\n}\n\n// Returns the declared host of the service's static DB target, when\n// recoverable. ServiceNode.dbConnectionTarget is the static-extraction\n// surface for \"this service connects to X\" — `X` is host[:port] or a\n// docker-compose-style service name. Empty / undefined means we have no\n// EXTRACTED host to compare against and host-mismatch can't fire.\nfunction declaredHostFor(svc: ServiceNode): string | null {\n  const raw = svc.dbConnectionTarget?.trim()\n  if (!raw) return null\n  // Strip a trailing port if present so it lines up with DatabaseNode.host\n  // (ADR-028 §6 — DatabaseNode id excludes port).\n  const colon = raw.lastIndexOf(':')\n  if (colon === -1) return raw\n  const port = raw.slice(colon + 1)\n  if (/^\\d+$/.test(port)) return raw.slice(0, colon)\n  return raw\n}\n\nfunction hasExtractedConfiguredBy(graph: NeatGraph, svcId: string): boolean {\n  for (const edgeId of graph.outboundEdges(svcId)) {\n    const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (e.type === EdgeType.CONFIGURED_BY && e.provenance === Provenance.EXTRACTED) {\n      return true\n    }\n  }\n  return false\n}\n\nfunction detectHostMismatch(\n  graph: NeatGraph,\n  svcId: string,\n  svc: ServiceNode,\n): Divergence[] {\n  const declaredHost = declaredHostFor(svc)\n  if (!declaredHost) return []\n  if (!hasExtractedConfiguredBy(graph, svcId)) return []\n\n  const out: Divergence[] = []\n  for (const edgeId of graph.outboundEdges(svcId)) {\n    const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (edge.type !== EdgeType.CONNECTS_TO) continue\n    if (edge.provenance !== Provenance.OBSERVED) continue\n    const target = graph.getNodeAttributes(edge.target) as GraphNode\n    if (target.type !== NodeType.DatabaseNode) continue\n    const observedHost = target.host?.trim()\n    if (!observedHost) continue\n    if (observedHost === declaredHost) continue\n\n    out.push({\n      type: 'host-mismatch',\n      source: svcId,\n      target: edge.target,\n      extractedHost: declaredHost,\n      observedHost,\n      confidence: clampConfidence(confidenceForEdge(edge)),\n      reason: `Config declares ${svcId} connects to ${declaredHost}; production connects to ${observedHost}.`,\n      recommendation: RECOMMENDATION_HOST_MISMATCH,\n    })\n  }\n  return out\n}\n\nfunction detectCompatDivergences(\n  graph: NeatGraph,\n  svcId: string,\n  svc: ServiceNode,\n): Divergence[] {\n  const out: Divergence[] = []\n  const deps = svc.dependencies ?? {}\n\n  for (const edgeId of graph.outboundEdges(svcId)) {\n    const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (edge.type !== EdgeType.CONNECTS_TO) continue\n    if (edge.provenance !== Provenance.OBSERVED) continue\n    const target = graph.getNodeAttributes(edge.target) as GraphNode\n    if (target.type !== NodeType.DatabaseNode) continue\n\n    // Driver-engine compat. Definitive — when a rule fires it's a\n    // version-mismatch with confidence 1.0.\n    for (const pair of compatPairs()) {\n      if (pair.engine !== target.engine) continue\n      const declared = deps[pair.driver]\n      if (!declared) continue\n      const result = checkCompatibility(\n        pair.driver,\n        declared,\n        target.engine,\n        target.engineVersion,\n      )\n      if (!result.compatible && result.reason) {\n        out.push({\n          type: 'version-mismatch',\n          source: svcId,\n          target: edge.target,\n          extractedVersion: declared,\n          observedVersion: target.engineVersion,\n          compatibility: 'incompatible',\n          confidence: 1.0,\n          reason: result.reason,\n          recommendation: result.minDriverVersion\n            ? `Upgrade ${pair.driver} to >= ${result.minDriverVersion}.`\n            : `Update the ${pair.driver} driver to a version compatible with ${target.engine} ${target.engineVersion}.`,\n        })\n      }\n    }\n\n    // Deprecated-api compat. Broader than version-mismatch — surfaces as\n    // compat-violation. Driver-engine rules above already covered the\n    // \"version is too low\" shape; deprecated covers \"version is too high\n    // / no longer supported.\"\n    for (const rule of deprecatedApis()) {\n      const declared = deps[rule.package]\n      if (!declared) continue\n      const result = checkDeprecatedApi(rule, declared)\n      if (!result.compatible && result.reason) {\n        const ruleRef: CompatRuleRef = {\n          kind: rule.kind ?? 'deprecated-api',\n          reason: result.reason,\n          package: rule.package,\n        }\n        out.push({\n          type: 'compat-violation',\n          source: svcId,\n          target: edge.target,\n          rule: ruleRef,\n          observed: edge,\n          confidence: 1.0,\n          reason: result.reason,\n          recommendation: `Replace deprecated ${rule.package}@${declared} with a supported version.`,\n        })\n      }\n    }\n  }\n  return out\n}\n\nconst RECOMMENDATION_COLUMN_MISSING_OBSERVED =\n  'Verify the column is exercised in production; a migration that renamed or dropped it may have left a writer declaring the old name.'\nconst RECOMMENDATION_COLUMN_MISSING_EXTRACTED =\n  'The schema or migration is likely behind the code — production writes a column the declared schema does not carry. Check for a field rename that updated the query but not the model.'\n\n// Column-drift (ADR-157 §4) — the same missing-observed / missing-extracted\n// semantics, computed over the declared and observed column sets on one\n// `sql-table` node instead of across an edge triple. A declared-only column is\n// `missing-observed`, an observed-only column is `missing-extracted`, reported at\n// column grain (`orders.total`). Each column carries the sides it was seen with in\n// its `provenances` set, so the declared set and the observed set read straight off\n// one node: a column with EXTRACTED but no OBSERVED is declared-only, OBSERVED but\n// no EXTRACTED is observed-only, and a column with both is fused — not drift.\n//\n// A node with only one side present anywhere emits nothing — no drift claim without\n// both a declared and an observed column somewhere on the table (the ADR-141 fusion\n// discipline). A table that is only declared, or only observed, is the edge-grain\n// detectors' business, not column drift: the observed half stands alone as the\n// \"which columns does production touch\" view, and a schema NEAT has parsed but never\n// seen driven should not read as all-columns-missing.\nfunction detectColumnDrift(node: InfraNode): Divergence[] {\n  const columns = node.columns\n  if (!columns || columns.length === 0) return []\n\n  // Both sides must be present *somewhere* on the table, or there is no fused\n  // picture to diverge against.\n  const anyDeclared = columns.some(columnIsDeclared)\n  const anyObserved = columns.some(columnIsObserved)\n  if (!anyDeclared || !anyObserved) return []\n\n  const out: Divergence[] = []\n  for (const col of columns) {\n    const declared = columnIsDeclared(col)\n    const observed = columnIsObserved(col)\n    if (declared && !observed) {\n      out.push({\n        type: 'missing-observed',\n        source: node.id,\n        target: node.id,\n        table: node.id,\n        column: col.name,\n        confidence: clampConfidence(col.confidence),\n        reason: `Schema declares column ${node.name}.${col.name} but no production statement has touched it.`,\n        recommendation: RECOMMENDATION_COLUMN_MISSING_OBSERVED,\n      })\n    } else if (observed && !declared) {\n      out.push({\n        type: 'missing-extracted',\n        source: node.id,\n        target: node.id,\n        table: node.id,\n        column: col.name,\n        confidence: clampConfidence(col.confidence),\n        reason: `Production touched column ${node.name}.${col.name} but the schema does not declare it.`,\n        recommendation: RECOMMENDATION_COLUMN_MISSING_EXTRACTED,\n      })\n    }\n  }\n  return out\n}\n\n// ── Deploy divergence (ADR-225 + successor, the k8s deployment substrate payoff) ─\n//\n// The declared side (a workload manifest → `declaredImage`/`declaredReplicas`,\n// `extract/infra/k8s.ts`) and the observed side (live cluster → `observedImage`/\n// `observedReadyReplicas`, the k8s reader's deploy-state stamp) both land on one\n// `service:<name>` node. This detector compares them. The headline is the *stuck\n// rollout*: the manifest declares a new image but the old ReplicaSet still serves\n// the old one — the service is up, so no incident fires, yet declared ≠ running.\n// That case is invisible to an outage reader and to a vendor connector (which has\n// no declared twin); the fused node is what surfaces it.\n//\n// But declared ≠ running runs two ways, and only one is a stuck rollout. The\n// reading is read from the image tags: the running image *older* than declared is\n// the stuck rollout (high confidence); the running image *newer* than declared is\n// the cluster running ahead of the manifest (a stale checkout or an out-of-band\n// change — a real but benign drift, never an incident, so it is dampened well\n// below the root-cause surfaces, the §5e convention); tags that are not comparable\n// (`latest`, a digest/sha) leave the direction undetermined and keep a neutral\n// mid-confidence. The detector never narrates a stuck rollout it cannot establish.\nconst RECOMMENDATION_DEPLOY_STUCK_ROLLOUT =\n  'The running image is older than the manifest-declared image — the rollout has not taken (the old ReplicaSet is still serving). Re-apply the deployment or investigate why the new image failed to roll out.'\nconst RECOMMENDATION_DEPLOY_RUNNING_AHEAD =\n  'The running image is newer than the manifest-declared image — the running cluster is ahead of the manifest (the manifest, or the checkout it was extracted from, is behind the deployed image). Update the manifest to the deployed image, or confirm the newer image is intended. This is not a stuck rollout and is not an incident.'\nconst RECOMMENDATION_DEPLOY_IMAGE_DIFFERS =\n  'The running image differs from the manifest-declared image, but their tags are not directly comparable, so the direction of the drift is undetermined. Reconcile the manifest with the running image.'\nconst DEPLOY_STUCK_ROLLOUT_CONFIDENCE = 0.9\nconst DEPLOY_RUNNING_AHEAD_CONFIDENCE = 0.1\nconst DEPLOY_IMAGE_DIFFERS_CONFIDENCE = 0.6\n\n// The tag of a container image ref, or undefined when it carries none.\n// `ghcr.io/open-telemetry/demo:2.2.0-shipping` → `2.2.0-shipping`; a `repo@sha256:…`\n// digest is stripped first; a registry `host:5000/repo` with no tag (the colon\n// sits before a `/`) yields undefined.\nfunction imageTag(ref: string): string | undefined {\n  const noDigest = ref.split('@')[0] ?? ref\n  const colon = noDigest.lastIndexOf(':')\n  if (colon === -1) return undefined\n  const tag = noDigest.slice(colon + 1)\n  return tag.length > 0 && !tag.includes('/') ? tag : undefined\n}\n\n// The leading dotted-numeric version of a tag ([2,2,0] from `2.2.0-shipping`), or\n// undefined when the tag is not dotted-numeric (`latest`, a sha, a word). Mirrors\n// version-skew's `isLocalBehind` segment parse but refuses a non-numeric segment,\n// so an unorderable tag falls to an undetermined direction, never a guessed one.\nfunction imageNumericVersion(tag: string): number[] | undefined {\n  const core = tag.split(/[-+]/)[0] ?? tag\n  const segs = core.split('.')\n  if (segs.length === 0 || !segs.every((s) => /^[0-9]+$/.test(s))) return undefined\n  return segs.map((s) => Number.parseInt(s, 10))\n}\n\ntype ImageDriftDirection = 'running-older' | 'running-newer' | 'undetermined'\n\n// Which way a declared ≠ running image disagreement runs, read from the two tags.\n// Both tags must be dotted-numeric to order them; anything else is `undetermined`.\nfunction imageDriftDirection(declared: string, observed: string): ImageDriftDirection {\n  const dTag = imageTag(declared)\n  const oTag = imageTag(observed)\n  if (dTag === undefined || oTag === undefined) return 'undetermined'\n  const d = imageNumericVersion(dTag)\n  const o = imageNumericVersion(oTag)\n  if (d === undefined || o === undefined) return 'undetermined'\n  const len = Math.max(d.length, o.length)\n  for (let i = 0; i < len; i++) {\n    const dv = d[i] ?? 0\n    const ov = o[i] ?? 0\n    if (ov < dv) return 'running-older'\n    if (ov > dv) return 'running-newer'\n  }\n  return 'undetermined'\n}\n\nfunction detectDeployDivergence(svc: ServiceNode): Divergence[] {\n  const out: Divergence[] = []\n  // Image mismatch — the stuck rollout. Both sides must be present to compare: a\n  // workload with no manifest (no declaredImage) or no running pods (no\n  // observedImage) has no fused picture, so it is not a divergence.\n  if (\n    typeof svc.declaredImage === 'string' &&\n    typeof svc.observedImage === 'string' &&\n    svc.declaredImage !== svc.observedImage\n  ) {\n    const direction = imageDriftDirection(svc.declaredImage, svc.observedImage)\n    let confidence: number\n    let reason: string\n    let recommendation: string\n    if (direction === 'running-older') {\n      // The stuck rollout: the manifest declares a newer image the cluster has\n      // not rolled to, so the old ReplicaSet still serves — up, no incident.\n      confidence = DEPLOY_STUCK_ROLLOUT_CONFIDENCE\n      reason = `Service ${svc.name} declares image ${svc.declaredImage} but its running pods report the older ${svc.observedImage} — the deploy has not taken (the old version is still serving), so no incident fires.`\n      recommendation = RECOMMENDATION_DEPLOY_STUCK_ROLLOUT\n    } else if (direction === 'running-newer') {\n      // Running ahead of the manifest: the cluster serves a newer image than the\n      // checkout declares — a stale manifest or an out-of-band change, not a\n      // rollout that failed. Dampened so it never anchors a root cause.\n      confidence = DEPLOY_RUNNING_AHEAD_CONFIDENCE\n      reason = `Service ${svc.name} declares image ${svc.declaredImage} but its running pods report the newer ${svc.observedImage} — the running cluster is ahead of the manifest (the manifest, or the checkout it was extracted from, is behind the deployed image), not a stuck rollout, so no incident fires.`\n      recommendation = RECOMMENDATION_DEPLOY_RUNNING_AHEAD\n    } else {\n      // The tags disagree but are not comparable (a `latest`/digest tag on either\n      // side): a real mismatch whose direction the detector does not assert.\n      confidence = DEPLOY_IMAGE_DIFFERS_CONFIDENCE\n      reason = `Service ${svc.name} declares image ${svc.declaredImage} but its running pods report ${svc.observedImage} — the two differ; their tags are not directly comparable, so the direction of the drift is undetermined.`\n      recommendation = RECOMMENDATION_DEPLOY_IMAGE_DIFFERS\n    }\n    out.push({\n      type: 'deploy-mismatch',\n      kind: 'image',\n      source: svc.id,\n      target: svc.id,\n      declaredImage: svc.declaredImage,\n      observedImage: svc.observedImage,\n      confidence,\n      reason,\n      recommendation,\n    })\n  }\n  // A declared-vs-ready replica mismatch (`kind: 'replicas'`) is reserved in the\n  // schema but not emitted yet: `declaredReplicas !== observedReadyReplicas`\n  // fires transiently during any rolling update or scale, and the fully-down case\n  // is already the `no-ready-replicas` incident. A stable, debounced replica\n  // divergence is a documented follow-on; the `observedReadyReplicas` stamp it\n  // needs is already recorded.\n  return out\n}\n\n// ── Flag-grain divergence (ADR-242) ─────────────────────────────────────────\n//\n// A flag store's grain carries each flag's committed definition (EXTRACTED) and\n// what the store is serving (OBSERVED). When they differ, the services that read\n// the key are running under a flag state nobody committed. The fault shows up\n// downstream only as its symptom, so the divergence lands on each reading service\n// (`source`) against the store (`target`), and a service's incident card names\n// the flag. A flag with no reader in the code base lands on the store alone.\n//\n// The store's served definition is the authority when present. Without one, a\n// service's own evaluation stands in, but only an untargeted resolution\n// (`static`/`default`) is compared to the committed default: a targeted variant\n// is the flag working as committed.\nconst RECOMMENDATION_FLAG_MISMATCH =\n  'The flag store is serving a definition that differs from the committed flag file. If the change is unintended, restore the committed definition in the store; if it is intended, commit it to the flag file so declared and running agree.'\nconst FLAG_DIVERGENCE_CONFIDENCE = 0.9\nconst UNTARGETED_REASONS = new Set(['static', 'default'])\n\nfunction readerLocation(fileNodeId: string, line: number | undefined): string {\n  const parsed = parseFileId(fileNodeId)\n  const file = parsed ? parsed.relPath : fileNodeId\n  return line !== undefined ? `${file}:${line}` : file\n}\n\nfunction quoteVariant(v: string | null | undefined): string {\n  return v === null || v === undefined ? 'none' : `\"${v}\"`\n}\n\nfunction detectFlagMismatch(node: InfraNode): Divergence[] {\n  const out: Divergence[] = []\n  for (const flag of node.flags ?? []) {\n    const declared = flag.declared\n    if (!declared) continue\n    let changed: string[] = []\n    let observedVariant: string | null | undefined\n    let via = 'the store is serving'\n    if (flag.observed) {\n      changed = flagFieldsChanged(declared, flag.observed)\n      observedVariant = flag.observed.defaultVariant\n    } else if (\n      flag.observedVariant !== undefined &&\n      flag.observedVariantReason !== undefined &&\n      UNTARGETED_REASONS.has(flag.observedVariantReason.toLowerCase()) &&\n      flag.observedVariant !== declared.defaultVariant\n    ) {\n      changed = ['defaultVariant']\n      observedVariant = flag.observedVariant\n      via = 'an evaluation resolved'\n    }\n    if (changed.length === 0) continue\n\n    const what = changed.includes('defaultVariant')\n      ? `committed with defaultVariant ${quoteVariant(declared.defaultVariant)} but ${via} ${quoteVariant(observedVariant)}`\n      : `committed definition differs from what ${via} (${changed.join(', ')} changed)`\n\n    const byService = new Map<string, string[]>()\n    for (const r of flag.readers ?? []) {\n      const list = byService.get(r.service) ?? []\n      list.push(readerLocation(r.file, r.line))\n      byService.set(r.service, list)\n    }\n    const base = {\n      type: 'flag-mismatch' as const,\n      target: node.id,\n      flagKey: flag.key,\n      changed,\n      declaredVariant: declared.defaultVariant,\n      ...(observedVariant !== undefined ? { observedVariant } : {}),\n      confidence: FLAG_DIVERGENCE_CONFIDENCE,\n      recommendation: RECOMMENDATION_FLAG_MISMATCH,\n    }\n    if (byService.size === 0) {\n      out.push({\n        ...base,\n        source: node.id,\n        reason: `Flag ${flag.key} is ${what}. No code in the scanned source reads the key as a literal.`,\n      })\n      continue\n    }\n    for (const [svc, readers] of byService) {\n      const name = svc.startsWith('service:') ? svc.slice('service:'.length) : svc\n      out.push({\n        ...base,\n        source: svc,\n        readers,\n        reason: `Flag ${flag.key} is ${what}; ${name} reads it at ${readers.join(', ')}.`,\n      })\n    }\n  }\n  return out\n}\n\n// ── Symbol/field-grain divergence (ADR-215) ────────────────────────────────\n//\n// The edge detectors above compare declared and observed *edges* — \"does a\n// declared edge have an observed twin?\". A whole class of code↔runtime\n// disagreement never shows up as a missing edge: the code declares access to a\n// field / attribute / method / column the runtime object does not have. The call\n// the member sits behind is made and observed — the edge is present — but the\n// access fails at runtime, recorded as an incident localized to the declaring\n// `code.filepath`/`code.lineno`. This detector fuses that OBSERVED incident with\n// the EXTRACTED code location and surfaces it here, so `get_divergences` answers\n// \"where does declared disagree with observed\" at symbol grain too, not only at\n// edge grain. This is the purest fusion win — invisible to a code-only reader,\n// decisive once the runtime error is joined to the declared access.\n//\n// The classifier keys ONLY on generic error *semantics* — the shape of the\n// failure — never a language / framework / provider / field name (ADR-158 §6,\n// scanned). Each entry pairs a neutral mismatch category with the phrasings\n// runtimes use to report it; the capture group, when present, recovers the\n// member the runtime lacked. New phrasings are added to a category, never a\n// per-language branch.\nconst SYMBOL_MISMATCH_PATTERNS: ReadonlyArray<{\n  kind: SymbolMismatchKind\n  patterns: readonly RegExp[]\n}> = [\n  {\n    // \"'ListProductsResponse' object has no attribute 'products_list'\" and kin.\n    kind: 'missing-attribute',\n    patterns: [/\\bhas no attribute\\b[\\s:=]*['\"`]?([A-Za-z_$][\\w$]*)['\"`]?/i],\n  },\n  {\n    // \"object has no field 'X'\", \"no such field X\", \"unknown field X\".\n    kind: 'missing-field',\n    patterns: [\n      /\\b(?:has no field|no such field|unknown field)\\b(?:\\s+named)?[\\s:=]*['\"`]?([A-Za-z_$][\\w$.]*)['\"`]?/i,\n    ],\n  },\n  {\n    // \"has no property X\", \"no property named X\".\n    kind: 'missing-property',\n    patterns: [\n      /\\b(?:has no property|no property named)\\b[\\s:=]*['\"`]?([A-Za-z_$][\\w$]*)['\"`]?/i,\n    ],\n  },\n  {\n    // \"no such column: X\", \"unknown column 'X'\", \"column X does not exist\".\n    kind: 'missing-column',\n    patterns: [\n      /\\bno such column\\b[\\s:=]*['\"`]?([\\w$.]+)['\"`]?/i,\n      /\\bunknown column\\b[\\s:=]*['\"`]?([\\w$.]+)['\"`]?/i,\n      /\\bcolumn\\b[\\s:=]*['\"`]?([\\w$.]+)['\"`]?\\s+does not exist/i,\n    ],\n  },\n  {\n    // \"undefined method `foo' for X\" — kept to the unambiguous form so a generic\n    // \"method not found\" (an unimplemented RPC — an edge/route gap, not a symbol\n    // mismatch) does not get miscategorised here.\n    kind: 'undefined-method',\n    patterns: [/\\bundefined method\\b\\s*[`'\"]?([\\w$?!]+)/i],\n  },\n]\n\n// Classify an error message by generic semantics. Returns the neutral mismatch\n// category and, when the message names it, the member the runtime lacked.\nfunction classifySymbolMismatch(\n  message: string,\n): { kind: SymbolMismatchKind; symbol?: string } | null {\n  for (const entry of SYMBOL_MISMATCH_PATTERNS) {\n    for (const re of entry.patterns) {\n      const m = re.exec(message)\n      if (m) {\n        const captured = m[1]\n        return captured ? { kind: entry.kind, symbol: captured } : { kind: entry.kind }\n      }\n    }\n  }\n  return null\n}\n\n// The finest code node an incident fused to, plus the declaring `file:line`. The\n// strong path: the incident localized to a symbol or file node the graph carries\n// (the EXTRACTED code location the runtime named, already joined by ingest —\n// file-awareness §4 / ADR-158 §5). Falls back to the owning service when we still\n// have a `file:line` to point at. Returns null when the incident names no code\n// location at all — there is nothing honest to surface without one.\nfunction symbolLocus(\n  graph: NeatGraph,\n  ev: ErrorEvent,\n): { node: string; location?: string } | null {\n  const attrs = ev.attributes ?? {}\n  const filepath = codeFilepathOf(attrs)\n  const lineno = codeLinenoOf(attrs)\n  const location = filepath\n    ? `${filepath}${lineno !== undefined ? `:${lineno}` : ''}`\n    : undefined\n\n  const affected = ev.affectedNode\n  const affectedInGraph = affected.length > 0 && graph.hasNode(affected)\n  const affectedIsCode =\n    affectedInGraph && (parseSymbolId(affected) !== null || parseFileId(affected) !== null)\n\n  // Strong path — the incident sits on a symbol/file node; that node is the\n  // declared code location, and points at code with or without a captured line.\n  if (affectedIsCode) return { node: affected, ...(location ? { location } : {}) }\n\n  // Weaker paths must carry a `file:line`: the finding names a declaring code\n  // location, so without one there is nothing to surface.\n  if (!location) return null\n  if (affectedInGraph) return { node: affected, location }\n  const svc = serviceId(ev.service)\n  if (graph.hasNode(svc)) return { node: svc, location }\n  return null\n}\n\n// Confidence a symbol/field-grain finding carries: the INFERRED stitch grade\n// (~0.6, the same grade a stitched edge and an incident-localized root cause\n// take). It ranks below the high-confidence edge divergences — structural\n// `missing-extracted`, definitive `version-mismatch`/`compat-violation` at 1.0 —\n// while sitting well above a dampened dead-code probe (0.1). The classification\n// itself is unambiguous, but the claim that this error corresponds to a declared\n// access at this line is an inference joining two layers, so INFERRED is the\n// honest grade.\nconst SYMBOL_MISMATCH_CONFIDENCE = 0.6\n\nfunction detectSymbolMismatches(\n  graph: NeatGraph,\n  incidents: readonly ErrorEvent[],\n): Divergence[] {\n  // Collapse the same failing access reported many times into one finding that\n  // carries the count — the \"count this failure mode, not every incident on the\n  // node\" discipline the root-cause localizer uses (issue #624). Key on the\n  // (locus node, mismatch kind, member) triple.\n  interface Group {\n    node: string\n    kind: SymbolMismatchKind\n    symbol?: string\n    location?: string\n    latest: ErrorEvent\n    count: number\n  }\n  const groups = new Map<string, Group>()\n\n  for (const ev of incidents) {\n    const classified = classifySymbolMismatch(ev.errorMessage)\n    if (!classified) continue\n    const locus = symbolLocus(graph, ev)\n    if (!locus) continue\n    const key = `${locus.node}|${classified.kind}|${classified.symbol ?? ''}`\n    const existing = groups.get(key)\n    if (!existing) {\n      groups.set(key, {\n        node: locus.node,\n        kind: classified.kind,\n        ...(classified.symbol ? { symbol: classified.symbol } : {}),\n        ...(locus.location ? { location: locus.location } : {}),\n        latest: ev,\n        count: 1,\n      })\n    } else {\n      existing.count += 1\n      // Most recent incident is the representative; ISO timestamps sort lexically.\n      if (ev.timestamp.localeCompare(existing.latest.timestamp) > 0) {\n        existing.latest = ev\n        if (locus.location) existing.location = locus.location\n      }\n    }\n  }\n\n  const out: Divergence[] = []\n  for (const g of groups.values()) {\n    const member = g.symbol ? `\\`${g.symbol}\\`` : 'a member'\n    const where = g.location ? ` at ${g.location}` : ''\n    const times =\n      g.count > 1 ? ` (${g.count} recorded incidents)` : ' (1 recorded incident)'\n    out.push({\n      type: 'observed-symbol-mismatch',\n      source: g.node,\n      target: g.node,\n      mismatchKind: g.kind,\n      ...(g.symbol ? { symbol: g.symbol } : {}),\n      ...(g.location ? { location: g.location } : {}),\n      provenance: Provenance.INFERRED,\n      incidentId: g.latest.id,\n      errorMessage: g.latest.errorMessage,\n      incidentCount: g.count,\n      confidence: SYMBOL_MISMATCH_CONFIDENCE,\n      reason:\n        `Code${where} declares access to ${member} the runtime object does not have — ` +\n        `${g.latest.service} raised \"${g.latest.errorMessage}\"${times}. ` +\n        `The declared access (EXTRACTED) and the runtime shape (OBSERVED) disagree at symbol grain.`,\n      recommendation:\n        'Reconcile the declared access with the runtime shape: a field, attribute, method, or column was ' +\n        'renamed, removed, or never existed on the object this code reaches. Update the code to the current ' +\n        'shape, or restore the member.',\n    })\n  }\n  return out\n}\n\n// ── Behavioral-failure divergence (ADR-220) ─────────────────────────────────\n//\n// The detectors above answer \"does a declared edge have an observed twin?\" and\n// \"does the runtime shape match the declared access?\". Neither surfaces a\n// dependency the code declares AND production observes whose calls predominantly\n// *fail*: the edge is present (not missing-observed, not missing-extracted) and\n// the access is fine (not observed-symbol-mismatch), yet the declared intent\n// \"this dependency works\" diverges from the observed reality \"it fails every\n// call.\" This is the truest declared-intent-vs-observed-reality divergence, and\n// it was falling straight through.\n//\n// Two loci, both graded INFERRED (the cross-layer stitch between the declared\n// call and the observed failure, the ADR-215 grade):\n//   - Edge locus: a declared+observed dependency edge whose observed error rate\n//     is over the threshold. Read straight off the edge's `signal`.\n//   - Incident locus: a declared external call whose recorded incident carries a\n//     transport/5xx failure semantic, fused to the declaring `file:line` through\n//     the same locus machinery ADR-215 uses (and #1087 makes recoverable).\n//\n// Both key STRICTLY on generic failure semantics — an error rate, and the\n// deadline / timeout / connection / 5xx families — never a provider, framework,\n// host, or language name (ADR-158 §6, scanned).\n\n// A declared+observed dependency edge counts as \"predominantly failing\" only\n// when it has been exercised enough to trust the rate (MIN_SPANS) AND at least\n// half of those calls errored (ERROR_RATE). Half is the defensible line between\n// \"degraded\" (a working dependency erroring on a minority of calls — an SLO /\n// alerting concern, not a declared-vs-observed divergence) and \"broken\" (the\n// declared intent is not being realized for most calls). The floor keeps a\n// one-off or low-volume blip (1/1 errors) off the surface; the evidence\n// (span/error counts) rides on the finding so an operator sees the sample size.\n// See docs/contracts/divergence-query.md §5g.\nconst OBSERVED_FAILING_ERROR_RATE = 0.5\nconst OBSERVED_FAILING_MIN_SPANS = 5\n\n// The INFERRED stitch grade, the same ~0.6 an ADR-215 symbol/field finding and an\n// incident-localized root cause take. The failure itself is observed for certain;\n// the claim that it is *the declared dependency* diverging is a cross-layer join,\n// so INFERRED is the honest grade. It sorts beneath the definitive edge\n// divergences and, at equal confidence, below the symbol/field finding (type\n// leadership), so a same-confidence structural or symbol divergence still leads.\nconst OBSERVED_FAILING_CONFIDENCE = 0.6\n\n// Edge locus (Path A): a declared+observed dependency edge whose observed calls\n// predominantly fail. Requires BOTH sides present (a declared intent to diverge\n// against, and observed traffic to measure) — an observed-only failing edge is\n// already a `missing-extracted` finding, and a declared-only edge has no observed\n// calls to fail, so neither is re-flagged here.\nfunction detectObservedFailingEdge(graph: NeatGraph, bucket: EdgeBucket): Divergence[] {\n  if (!bucket.extracted || !bucket.observed) return []\n  if (!OBSERVABLE_EDGE_TYPES.has(bucket.type)) return []\n  // Only a live OBSERVED edge — a STALE twin (which rides the OBSERVED-format id\n  // into `.observed`) is \"went quiet\", the stale-edges surface's business, not a\n  // failing-call divergence.\n  if (bucket.observed.provenance !== Provenance.OBSERVED) return []\n  const signal = bucket.observed.signal\n  if (!signal) return []\n  const { spanCount, errorCount } = signal\n  if (spanCount < OBSERVED_FAILING_MIN_SPANS) return []\n  const errorRate = errorCount / spanCount\n  if (errorRate < OBSERVED_FAILING_ERROR_RATE) return []\n\n  const pct = Math.round(errorRate * 100)\n  return [\n    {\n      type: 'observed-failing',\n      source: bucket.source,\n      target: bucket.target,\n      failureKind: 'error-rate',\n      provenance: Provenance.INFERRED,\n      edgeType: bucket.type,\n      observed: bucket.observed,\n      spanCount,\n      errorCount,\n      errorRate: clampConfidence(errorRate),\n      // The bounded last-error exemplar rides the finding as evidence (ADR-236):\n      // the error rate says HOW MUCH is failing, the exemplar says WHAT failed —\n      // a timeout vs a deadlock vs a connection-refused, which `errorCount`\n      // alone cannot name. Present only when the observed edge carries one.\n      ...(signal.lastError ? { lastError: signal.lastError } : {}),\n      confidence: OBSERVED_FAILING_CONFIDENCE,\n      reason:\n        `Code declares ${bucket.source} → ${bucket.target} (${bucket.type}) and production observes it, ` +\n        `but ${errorCount}/${spanCount} observed calls fail (${pct}% error rate) — the declared dependency ` +\n        `is predominantly failing. The declared intent (EXTRACTED) and the observed behaviour (OBSERVED) diverge.`,\n      recommendation:\n        'Treat this as a broken declared dependency, not a coverage gap: production runs the call the code ' +\n        'declares and most calls error. Check the dependency’s health, recent deploys, and the observed error ' +\n        'responses on this edge.',\n    },\n  ]\n}\n\n// The generic failure families for the incident locus (Path B). Each pairs a\n// neutral kind with the phrasings runtimes use to report it — a gRPC/status-code\n// name (`DEADLINE_EXCEEDED`, `UNAVAILABLE`), a POSIX errno (`ECONNREFUSED`,\n// `ETIMEDOUT`, `ECONNRESET`), and their plain-English equivalents. These are\n// cross-language transport semantics, never a provider/framework/host/language\n// name (ADR-158 §6). A new phrasing joins a family; a new language never gets a\n// branch. 5xx is classified structurally off `httpStatusCode`, below.\nconst OBSERVED_FAILURE_PATTERNS: ReadonlyArray<{\n  kind: ObservedFailureKind\n  patterns: readonly RegExp[]\n}> = [\n  {\n    kind: 'connection-refused',\n    patterns: [/\\bECONNREFUSED\\b/i, /\\bconnection refused\\b/i],\n  },\n  {\n    kind: 'deadline-exceeded',\n    patterns: [/\\bDEADLINE_EXCEEDED\\b/i, /\\bdeadline exceeded\\b/i],\n  },\n  {\n    kind: 'timeout',\n    patterns: [/\\bETIMEDOUT\\b/i, /\\btimed[\\s-]?out\\b/i, /\\btimeout\\b/i],\n  },\n  {\n    kind: 'unavailable',\n    patterns: [\n      /\\bUNAVAILABLE\\b/i,\n      /\\bservice unavailable\\b/i,\n      /\\bECONNRESET\\b/i,\n      /\\bconnection reset\\b/i,\n      /\\bno healthy upstream\\b/i,\n    ],\n  },\n]\n\n// Classify an incident by generic failure semantics: a transport family from the\n// error text (type / exception type / message), else a 5xx off the structured\n// status code. Returns null when the incident is not a behavioral failure — a\n// symbol/field mismatch, a 4xx, or a benign record — so Path B stays disjoint\n// from the symbol detector and does not fire on client-side or non-failures.\nfunction classifyObservedFailure(ev: ErrorEvent): ObservedFailureKind | null {\n  const haystack = [ev.errorType, ev.exceptionType, ev.errorMessage]\n    .filter((s): s is string => typeof s === 'string')\n    .join(' \\n ')\n  for (const entry of OBSERVED_FAILURE_PATTERNS) {\n    for (const re of entry.patterns) {\n      if (re.test(haystack)) return entry.kind\n    }\n  }\n  // 5xx keyed on the structured status code, not a message substring (so a\n  // literal like \"500ms\" never trips it). 4xx is a client-side / caller concern,\n  // not a declared-dependency failure, so it is left out.\n  const code = ev.httpStatusCode\n  if (typeof code === 'number' && code >= 500 && code < 600) return 'server-error'\n  return null\n}\n\nfunction observedFailureLabel(kind: ObservedFailureKind): string {\n  switch (kind) {\n    case 'error-rate':\n      return 'a high error rate'\n    case 'connection-refused':\n      return 'a refused connection'\n    case 'deadline-exceeded':\n      return 'a deadline exceeded'\n    case 'timeout':\n      return 'a timeout'\n    case 'unavailable':\n      return 'an unavailable or reset connection'\n    case 'server-error':\n      return 'a server error (5xx)'\n  }\n}\n\n// Incident locus (Path B): a declared external call whose recorded incident\n// shows a transport/5xx failure, fused to the declaring `file:line`. Sourced from\n// the incident store like ADR-215 — the failing target is often an env-var host\n// that never mints a successful observed edge (the 413/414 wrong-host /\n// connection-refused and 405–410 deadline cases), so the signal lives only in the\n// incident, not on any edge. Repeated incidents of one (locus, family) collapse\n// to a single finding carrying the count.\nfunction detectObservedFailingIncidents(\n  graph: NeatGraph,\n  incidents: readonly ErrorEvent[],\n): Divergence[] {\n  interface Group {\n    node: string\n    kind: ObservedFailureKind\n    location?: string\n    latest: ErrorEvent\n    count: number\n    httpStatusCode?: number\n  }\n  const groups = new Map<string, Group>()\n\n  for (const ev of incidents) {\n    const kind = classifyObservedFailure(ev)\n    if (!kind) continue\n    const locus = symbolLocus(graph, ev)\n    if (!locus) continue\n    const key = `${locus.node}|${kind}`\n    const existing = groups.get(key)\n    if (!existing) {\n      groups.set(key, {\n        node: locus.node,\n        kind,\n        ...(locus.location ? { location: locus.location } : {}),\n        latest: ev,\n        count: 1,\n        ...(typeof ev.httpStatusCode === 'number' ? { httpStatusCode: ev.httpStatusCode } : {}),\n      })\n    } else {\n      existing.count += 1\n      if (ev.timestamp.localeCompare(existing.latest.timestamp) > 0) {\n        existing.latest = ev\n        if (locus.location) existing.location = locus.location\n        if (typeof ev.httpStatusCode === 'number') existing.httpStatusCode = ev.httpStatusCode\n      }\n    }\n  }\n\n  const out: Divergence[] = []\n  for (const g of groups.values()) {\n    const where = g.location ? ` at ${g.location}` : ''\n    const label = observedFailureLabel(g.kind)\n    const times = g.count > 1 ? ` (${g.count} recorded incidents)` : ' (1 recorded incident)'\n    out.push({\n      type: 'observed-failing',\n      source: g.node,\n      target: g.node,\n      failureKind: g.kind,\n      provenance: Provenance.INFERRED,\n      ...(g.location ? { location: g.location } : {}),\n      incidentId: g.latest.id,\n      errorMessage: g.latest.errorMessage,\n      incidentCount: g.count,\n      ...(typeof g.httpStatusCode === 'number' ? { httpStatusCode: g.httpStatusCode } : {}),\n      confidence: OBSERVED_FAILING_CONFIDENCE,\n      reason:\n        `Code${where} declares an external call that production observes failing — ` +\n        `${g.latest.service} recorded ${label}: \"${g.latest.errorMessage}\"${times}. ` +\n        `The declared call (EXTRACTED) and the observed failure (OBSERVED) diverge — ` +\n        `the dependency is reached and does not work.`,\n      recommendation:\n        `The declared call is running in production and failing at the transport or response level (${label}). ` +\n        'Check the target host/endpoint the code reaches, connectivity, and the call’s deadline — a wrong or ' +\n        'unreachable host and an exceeded deadline both land here.',\n    })\n  }\n  return out\n}\n\nfunction involvesNode(d: Divergence, nodeId: string): boolean {\n  return d.source === nodeId || d.target === nodeId\n}\n\n// A datastore host production has actually connected to — now, or before it went\n// quiet. `discoveredVia` is the durable marker: a DatabaseNode OTel ever minted\n// or merged carries `otel`/`merged` and keeps it even after its OBSERVED edge is\n// culled, so a host that was observed then went dark still reads as ever-observed.\n// The inbound OBSERVED/STALE edge is the live read for the same fact (a STALE\n// edge kept its OBSERVED-format id, so it is the transitioned twin of a host that\n// was observed). A purely-static node with no observed edge anywhere is not.\nfunction datastoreEverObserved(graph: NeatGraph, nodeId: string): boolean {\n  if (!graph.hasNode(nodeId)) return false\n  const n = graph.getNodeAttributes(nodeId) as GraphNode\n  if (n.type === NodeType.DatabaseNode) {\n    const via = (n as DatabaseNode).discoveredVia\n    if (via === 'otel' || via === 'merged') return true\n  }\n  for (const edgeId of graph.inboundEdges(nodeId)) {\n    const e = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (e.provenance === Provenance.OBSERVED || e.provenance === Provenance.STALE) return true\n  }\n  return false\n}\n\n// Does `serviceId` connect to a DatabaseNode of `engine`, other than\n// `excludeTarget`, that production is or was observed talking to? The sibling\n// side of the dead-code-probe signature (ADR-213): the service clearly drives a\n// real store of this kind, so an extra never-observed literal alternate reads as\n// dead code. Reuses the buckets already grouped by (service, target, type); a\n// datastore CONNECTS_TO bucket's `source` is the owning service id\n// (bucketSourceFor), and a STALE twin lands in `.observed` (its id stays\n// OBSERVED-format), so `.observed` here means \"is or was observed\".\nfunction serviceHasObservedSameEngineStore(\n  graph: NeatGraph,\n  buckets: Map<string, EdgeBucket>,\n  serviceId: string,\n  engine: string,\n  excludeTarget: string,\n): boolean {\n  for (const bucket of buckets.values()) {\n    if (bucket.type !== EdgeType.CONNECTS_TO) continue\n    if (bucket.source !== serviceId) continue\n    if (bucket.target === excludeTarget) continue\n    if (!graph.hasNode(bucket.target)) continue\n    const target = graph.getNodeAttributes(bucket.target) as GraphNode\n    if (target.type !== NodeType.DatabaseNode) continue\n    if ((target as DatabaseNode).engine !== engine) continue\n    if (bucket.observed || datastoreEverObserved(graph, bucket.target)) return true\n  }\n  return false\n}\n\n// Confidence a dead-code / flag-gated datastore probe is dampened to (ADR-213).\n// Low enough to fall below the default surfacing thresholds and sort to the\n// bottom, but not zero: a genuinely-suspicious dead declaration can still be\n// found at low confidence rather than vanishing (dampen, don't delete).\nconst DEAD_CODE_PROBE_CONFIDENCE = 0.1\n\n// A hardcoded-literal datastore host that (a) production has never observed and\n// (b) sits beside another datastore of the SAME engine on the SAME service that\n// production IS or WAS observed talking to is a dead-code / fault-injection probe\n// (ADR-213) — e.g. the otel-demo cart's hardcoded `\"badhost:1234\"` store next to\n// its env-configured `valkey-cart`. Its `missing-observed` is a false positive\n// against the divergence thesis: \"declared but never driven\" is by design here,\n// not a declared-vs-observed gap, and on a code/config RCA it steers the agent\n// wrong. Dampen it to low confidence (not deletion) so it drops off the top-line\n// while a genuinely-suspicious dead declaration can still surface.\n//\n// The real broken-dependency divergence — the signal the divergence pitch rests\n// on — never matches this signature and keeps its full confidence: a host that\n// WAS observed and went dark reads as ever-observed (its DatabaseNode kept\n// `discoveredVia: 'merged'`, or a STALE twin still stands), and the service's\n// sole or env-configured store is `config`-sourced, not a hardcoded literal, so\n// neither the never-observed test nor the literal test that gate this ever fire\n// on it. The three gates are conjunctive by design — dropping any one would risk\n// dampening a real never-observed dependency (see docs/contracts/divergence-query.md).\nfunction dampenDeadCodeProbes(\n  graph: NeatGraph,\n  buckets: Map<string, EdgeBucket>,\n  all: Divergence[],\n): Divergence[] {\n  return all.map((d) => {\n    if (d.type !== 'missing-observed') return d\n    // Edge locus only — a column-locus drift carries no `extracted` edge.\n    if (!d.extracted || d.edgeType !== EdgeType.CONNECTS_TO) return d\n    if (!graph.hasNode(d.target)) return d\n    const target = graph.getNodeAttributes(d.target) as GraphNode\n    if (target.type !== NodeType.DatabaseNode) return d\n    // Gate 1 — the host was recovered from a hardcoded literal, not config/env.\n    if (d.extracted.evidence?.hostSource !== 'literal') return d\n    // Gate 2 — production has never observed this host (now or before).\n    if (datastoreEverObserved(graph, d.target)) return d\n    // Gate 3 — the service does observe a real store of the same engine.\n    const engine = (target as DatabaseNode).engine\n    if (!serviceHasObservedSameEngineStore(graph, buckets, d.source, engine, d.target)) return d\n\n    const host = (target as DatabaseNode).host ?? target.name\n    return {\n      ...d,\n      confidence: Math.min(d.confidence, DEAD_CODE_PROBE_CONFIDENCE),\n      reason:\n        `${d.source} declares a ${engine} connection to a hardcoded-literal host (${host}) that production has never observed, ` +\n        `while it does observe another ${engine} store — this reads as a flag-gated or dead-code declaration (e.g. a fault-injection probe), not a real declared-vs-observed gap.`,\n      recommendation:\n        'Confirm this is an intentional dead alternate — a fault-injection probe or a flag-gated branch. ' +\n        'If it is meant to run in production, check the feature flag or conditional that gates it; if not, it can be ignored or removed.',\n    }\n  })\n}\n\n// A single service<->DB host drift lights up three ways: the host-mismatch\n// itself, a missing-extracted on the observed DB node (the OBSERVED CONNECTS_TO\n// edge went to the *wrong* host, so it has no EXTRACTED twin), and a\n// missing-observed on the declared DB node (the EXTRACTED wire to the declared\n// host was never driven because traffic went elsewhere). The two missing-*\n// findings are just the halves of the drift the host-mismatch already names in\n// full, so they collapse into it — one divergence per distinct problem, so\n// blast-radius counts stay honest (issue #591). Pass 1 and Pass 2 run\n// independently, so this reconciles them after both have emitted.\nfunction suppressHostMismatchHalves(all: Divergence[]): Divergence[] {\n  const observedHalf = new Set<string>() // `${source}->${target}` of the observed DB edge\n  const declaredHalf = new Set<string>() // declared DB node id\n  for (const d of all) {\n    if (d.type !== 'host-mismatch') continue\n    observedHalf.add(`${d.source}->${d.target}`)\n    declaredHalf.add(databaseId(d.extractedHost))\n  }\n  if (observedHalf.size === 0) return all\n  return all.filter((d) => {\n    if (\n      d.type === 'missing-extracted' &&\n      observedHalf.has(`${d.source}->${d.target}`)\n    ) {\n      return false\n    }\n    if (d.type === 'missing-observed' && declaredHalf.has(d.target)) return false\n    return true\n  })\n}\n\nexport function computeDivergences(\n  graph: NeatGraph,\n  opts: DivergenceQueryOpts = {},\n): DivergenceResult {\n  const all: Divergence[] = []\n\n  // Pass 1 — bucket every edge and emit missing-observed / missing-extracted,\n  // plus observed-failing (ADR-220) for a declared+observed edge whose observed\n  // calls predominantly fail.\n  const buckets = bucketEdges(graph)\n  for (const bucket of buckets.values()) {\n    for (const d of detectMissingDivergences(graph, bucket)) all.push(d)\n    for (const d of detectObservedFailingEdge(graph, bucket)) all.push(d)\n  }\n\n  // Pass 2 — per-service host + compat rules, and per-table column drift.\n  graph.forEachNode((nodeId, attrs) => {\n    const n = attrs as GraphNode\n    if (n.type === NodeType.ServiceNode) {\n      const svc = n as ServiceNode\n      for (const d of detectHostMismatch(graph, nodeId, svc)) all.push(d)\n      for (const d of detectCompatDivergences(graph, nodeId, svc)) all.push(d)\n      for (const d of detectDeployDivergence(svc)) all.push(d)\n      return\n    }\n    // Column drift (ADR-157 §4) rides on `sql-table` InfraNodes.\n    if (n.type === NodeType.InfraNode && n.kind === 'sql-table') {\n      for (const d of detectColumnDrift(n)) all.push(d)\n    }\n    // Flag grain (ADR-242) rides on flag-store InfraNodes.\n    if (n.type === NodeType.InfraNode && n.kind === FLAG_STORE_KIND) {\n      for (const d of detectFlagMismatch(n)) all.push(d)\n    }\n  })\n\n  // Pass 3 — symbol/field-grain divergence (ADR-215). Fuse OBSERVED incidents\n  // whose error semantics name a field/attribute/method/column mismatch with the\n  // EXTRACTED code location that declares the access. Sourced from the incident\n  // store the caller passed in — the mismatch never appears as a missing edge, so\n  // the edge sets can't surface it. Read-only, still pure: incidents are\n  // in-memory data. Skipped entirely (no cost, identical edge-grain output) when\n  // no incidents are supplied.\n  if (opts.incidents && opts.incidents.length > 0) {\n    for (const d of detectSymbolMismatches(graph, opts.incidents)) all.push(d)\n    // Behavioral-failure divergence at the incident locus (ADR-220): a declared\n    // external call whose recorded incident carries a transport/5xx failure,\n    // fused to the declaring file:line. Disjoint from detectSymbolMismatches —\n    // that classifies member mismatches, this classifies transport failures.\n    for (const d of detectObservedFailingIncidents(graph, opts.incidents)) all.push(d)\n  }\n\n  // Reconcile the two passes: a fired host-mismatch already tells the whole\n  // service<->DB drift story, so drop the redundant missing-* halves (#591).\n  const reconciled = suppressHostMismatchHalves(all)\n\n  // Dampen dead-code / flag-gated datastore probes (ADR-213): a never-observed\n  // hardcoded-literal store sitting beside an observed same-engine store on the\n  // same service is a false-positive missing-observed, not a real gap. Real\n  // broken dependencies never match the signature and keep full confidence.\n  const dampened = dampenDeadCodeProbes(graph, buckets, reconciled)\n\n  // Filter + sort. Higher confidence first; within the same confidence,\n  // stable on (type, source, target) so callers see deterministic output.\n  let filtered = dampened\n  if (opts.type) {\n    const allowed = opts.type\n    filtered = filtered.filter((d) => allowed.has(d.type))\n  }\n  if (opts.minConfidence !== undefined) {\n    const threshold = opts.minConfidence\n    filtered = filtered.filter((d) => d.confidence >= threshold)\n  }\n  if (opts.node) {\n    const target = opts.node\n    filtered = filtered.filter((d) => involvesNode(d, target))\n  }\n\n  // ADR-066 §4 / §5 — confidence desc; missing-extracted leads\n  // missing-observed at equal confidence (OBSERVED-led tiebreaker); then\n  // stable on (type, source, target).\n  const TYPE_LEADERSHIP: Record<DivergenceType, number> = {\n    'missing-extracted': 0,\n    'missing-observed': 1,\n    'version-mismatch': 2,\n    'host-mismatch': 3,\n    'compat-violation': 4,\n    // Symbol/field-grain (ADR-215) rides the confidence sort like every other\n    // type; this only breaks a confidence tie, and it orders last so a same-\n    // confidence edge finding leads. In practice it carries the INFERRED grade\n    // (0.6), so it sits below the high-confidence edge divergences already.\n    'observed-symbol-mismatch': 5,\n    // Behavioral-failure (ADR-220) also carries the INFERRED grade (0.6); it\n    // orders last so at equal confidence the structural and symbol divergences\n    // lead, per the contract (\"rank below the definitive structural and symbol\n    // divergences\").\n    'observed-failing': 6,\n    // Deploy mismatch (ADR-225) is a definitive structural declared-vs-observed\n    // divergence carrying high confidence (0.9), so the confidence sort already\n    // places it among the structural leaders; this slot only breaks an exact\n    // confidence tie and sits last as a stable tiebreaker.\n    'deploy-mismatch': 7,\n    // Flag mismatch (ADR-242), like deploy-mismatch, is a node-local compare of\n    // two exact facts at 0.9; this slot only breaks an exact tie.\n    'flag-mismatch': 8,\n  }\n  filtered.sort((a, b) => {\n    if (b.confidence !== a.confidence) return b.confidence - a.confidence\n    const lead = TYPE_LEADERSHIP[a.type] - TYPE_LEADERSHIP[b.type]\n    if (lead !== 0) return lead\n    if (a.type !== b.type) return a.type.localeCompare(b.type)\n    if (a.source !== b.source) return a.source.localeCompare(b.source)\n    if (a.target !== b.target) return a.target.localeCompare(b.target)\n    // Column-locus drift shares source == target (the table node), so break the\n    // final tie on the column name to keep column-grain output deterministic.\n    const ac = 'column' in a && a.column ? a.column : ''\n    const bc = 'column' in b && b.column ? b.column : ''\n    if (ac !== bc) return ac.localeCompare(bc)\n    // Symbol/field-grain (ADR-215) also shares source == target (the code node);\n    // break its final tie on the accessed member so two mismatches on one node\n    // stay deterministically ordered.\n    const asym = 'symbol' in a && a.symbol ? a.symbol : ''\n    const bsym = 'symbol' in b && b.symbol ? b.symbol : ''\n    if (asym !== bsym) return asym.localeCompare(bsym)\n    // Behavioral-failure (ADR-220): two findings can share a node — the incident\n    // locus is source == target and two families land on one node — so break on\n    // the failure kind, then the declaring location, for deterministic output.\n    const afk = 'failureKind' in a && a.failureKind ? a.failureKind : ''\n    const bfk = 'failureKind' in b && b.failureKind ? b.failureKind : ''\n    if (afk !== bfk) return afk.localeCompare(bfk)\n    const aloc = 'location' in a && a.location ? a.location : ''\n    const bloc = 'location' in b && b.location ? b.location : ''\n    return aloc.localeCompare(bloc)\n  })\n\n  return DivergenceResultSchema.parse({\n    divergences: filtered,\n    totalAffected: filtered.length,\n    computedAt: new Date().toISOString(),\n  })\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { NodeType, Provenance, observedEdgeId } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport const SCHEMA_VERSION = 7\n\nexport interface PersistedGraph {\n  schemaVersion: number\n  exportedAt: string\n  graph: ReturnType<NeatGraph['export']>\n}\n\n// v1 → v2: ServiceNode shed `pgDriverVersion` (ADR-019). Compat traversal reads\n// `dependencies[driver]` instead. Strip the field from any v1 snapshot rather\n// than hard-failing — a stale snapshot on disk shouldn't cost a re-extract.\nfunction migrateV1ToV2(payload: PersistedGraph): PersistedGraph {\n  const nodes = (payload.graph as { nodes?: Array<{ attributes?: Record<string, unknown> }> })\n    .nodes\n  if (Array.isArray(nodes)) {\n    for (const node of nodes) {\n      if (node.attributes && 'pgDriverVersion' in node.attributes) {\n        delete node.attributes.pgDriverVersion\n      }\n    }\n  }\n  return { ...payload, schemaVersion: 2 }\n}\n\n// v2 → v3: Provenance enum shrinks to four values (ADR-068). Any edge whose\n// provenance still carries the pre-v0.3.5 'FRONTIER' literal is rewritten to\n// Provenance.OBSERVED on load. The target ref is unchanged — FrontierNodes\n// remain placeholders for unresolved peers; only how the edge was labelled\n// changes. If the edge id still carries the legacy provenance segment, it\n// is re-keyed to the OBSERVED wire format so consumers that parse the id\n// (traversal, divergence query, MCP) see the same shape downstream.\n//\n// The 'FRONTIER' string literal here is the only place in the codebase that\n// recognises the legacy value; the Rule 1 contract scan exempts persist.ts\n// for exactly this reason.\n// v3 → v4: ServiceNode identity gains an optional env discriminator\n// (ADR-074 §2). The v4 wire format reads as a superset of v3 — the\n// env-less `service:<name>` form is preserved as the env=`'unknown'`\n// node and the v3 → v4 migration is a version-only bump.\n//\n// Edges and node ids that pre-date the env discriminator remain valid v4\n// ids; no rewrite is needed. Idempotent — re-running on a v4 snapshot\n// produces an identical payload.\nfunction migrateV3ToV4(payload: PersistedGraph): PersistedGraph {\n  return { ...payload, schemaVersion: 4 }\n}\n\n// v4 → v5: the node union gains `SymbolNode` — a symbol under a file at\n// definition-span grain (ADR-158). The v5 wire format is a strict superset of\n// v4: a v4 snapshot simply carries no symbols, and re-extraction mints them on\n// the next pass. There is no field to rewrite and nothing to backfill — an older\n// snapshot's files and edges stay valid v5 verbatim — so this is a version-only\n// bump, the same shape as the v3 → v4 env-discriminator migration. Idempotent.\nfunction migrateV4ToV5(payload: PersistedGraph): PersistedGraph {\n  return { ...payload, schemaVersion: 5 }\n}\n\n// v5 → v6: a table-grain InfraNode gains a `columns` attribute list (ADR-157 §1)\n// — columns are provenanced attributes on the table node, observed from the\n// `db.statement` production runs. The v6 wire format is a strict superset of v5:\n// an older snapshot's table nodes simply carry no columns, and re-ingestion lands\n// them on the next production statement. Backfill `columns: []` on every table\n// InfraNode (`sql-table` / `supabase-table`) that lacks it, so a loaded snapshot\n// reads uniform — present-and-empty rather than absent — the same shape the mint\n// path grows thereafter. A non-table InfraNode is left untouched (it carries no\n// columns). Idempotent — re-running on a v6 snapshot changes nothing.\nfunction migrateV5ToV6(payload: PersistedGraph): PersistedGraph {\n  const nodes = (payload.graph as {\n    nodes?: Array<{ attributes?: Record<string, unknown> }>\n  }).nodes\n  if (Array.isArray(nodes)) {\n    for (const node of nodes) {\n      const attrs = node.attributes\n      if (!attrs || attrs.type !== NodeType.InfraNode) continue\n      if (attrs.kind !== 'sql-table' && attrs.kind !== 'supabase-table') continue\n      if (!Array.isArray(attrs.columns)) attrs.columns = []\n    }\n  }\n  return { ...payload, schemaVersion: 6 }\n}\n\n// v6 → v7: the node union gains `ServerActionNode` — a Next.js Server Action at\n// (service, module, exportName) grain (ADR-168). The v7 wire format is a strict\n// superset of v6: a v6 snapshot simply carries no actions, and re-extraction\n// mints them on the next pass. There is no field to rewrite and nothing to\n// backfill — an older snapshot's nodes and edges stay valid v7 verbatim — so this\n// is a version-only bump, the same shape as the v4 → v5 SymbolNode migration.\n// Idempotent — re-running on a v7 snapshot produces an identical payload.\nfunction migrateV6ToV7(payload: PersistedGraph): PersistedGraph {\n  return { ...payload, schemaVersion: 7 }\n}\n\nfunction migrateV2ToV3(payload: PersistedGraph): PersistedGraph {\n  const edges = (payload.graph as {\n    edges?: Array<{\n      key?: string\n      attributes?: Record<string, unknown>\n    }>\n  }).edges\n  if (Array.isArray(edges)) {\n    for (const edge of edges) {\n      const attrs = edge.attributes\n      // 'FRONTIER' is the pre-v0.3.5 literal — read-only here, never written\n      // by current producers. The rewrite swaps to Provenance.OBSERVED.\n      if (!attrs || attrs.provenance !== 'FRONTIER') continue\n      attrs.provenance = Provenance.OBSERVED\n      const type = typeof attrs.type === 'string' ? attrs.type : undefined\n      const source = typeof attrs.source === 'string' ? attrs.source : undefined\n      const target = typeof attrs.target === 'string' ? attrs.target : undefined\n      if (type && source && target) {\n        const newId = observedEdgeId(source, target, type)\n        attrs.id = newId\n        if (edge.key) edge.key = newId\n      }\n    }\n  }\n  return { ...payload, schemaVersion: 3 }\n}\n\nasync function ensureDir(filePath: string): Promise<void> {\n  await fs.mkdir(path.dirname(filePath), { recursive: true })\n}\n\n// How much serialized text to accumulate before flushing to the file handle.\n// Big enough that a large graph costs few syscalls, small enough that the\n// buffer never approaches V8's per-string ceiling (#1254).\nconst WRITE_FLUSH_CHARS = 4 * 1024 * 1024\n\n// `JSON.stringify(value)` returns `undefined` for undefined/function/symbol,\n// and the two containers disagree about what to do with that: an object omits\n// the key, an array writes `null`. Both helpers below follow that so the\n// streamed bytes match what `JSON.stringify(payload)` would have produced.\nfunction jsonOrUndefined(value: unknown): string | undefined {\n  return JSON.stringify(value)\n}\n\nfunction* serializeArray(items: readonly unknown[]): Generator<string> {\n  yield '['\n  for (let i = 0; i < items.length; i++) {\n    if (i > 0) yield ','\n    yield jsonOrUndefined(items[i]) ?? 'null'\n  }\n  yield ']'\n}\n\n// A plain object — the only thing worth descending into. A class instance or a\n// Date has its own JSON representation and must be stringified whole.\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n  if (value === null || typeof value !== 'object' || Array.isArray(value)) return false\n  const proto = Object.getPrototypeOf(value)\n  return proto === Object.prototype || proto === null\n}\n\n// One object, descending into nested plain objects and streaming arrays element\n// by element. Descending matters: the unbounded arrays are `nodes` and `edges`\n// *inside* `payload.graph`, so stopping at the top level would stringify the\n// whole graph in one call and stream nothing.\nfunction* serializeObject(obj: Record<string, unknown>): Generator<string> {\n  yield '{'\n  let first = true\n  for (const key of Object.keys(obj)) {\n    const value = obj[key]\n    const descend = Array.isArray(value) || isPlainObject(value)\n    // Match JSON.stringify's object rule: a key whose value serializes to\n    // undefined is omitted entirely, comma included.\n    if (!descend && jsonOrUndefined(value) === undefined) continue\n    if (!first) yield ','\n    first = false\n    yield `${JSON.stringify(key)}:`\n    if (Array.isArray(value)) yield* serializeArray(value)\n    else if (isPlainObject(value)) yield* serializeObject(value)\n    else yield jsonOrUndefined(value)!\n  }\n  yield '}'\n}\n\n/**\n * The snapshot as a stream of chunks whose concatenation is byte-identical to\n * `JSON.stringify(payload)`.\n *\n * Exported for the test that asserts exactly that. Keys are walked in their own\n * insertion order rather than a hardcoded list, so graphology adding a key to\n * `export()` changes the output the same way it always would have, and the\n * on-disk shape stays whatever the readers already expect.\n */\nexport function* serializeGraphChunks(payload: PersistedGraph): Generator<string> {\n  yield* serializeObject(payload as unknown as Record<string, unknown>)\n}\n\n/**\n * Write the snapshot, atomically, without ever holding it as one string.\n *\n * `JSON.stringify` on a whole large graph hits V8's ~2^29-character cap and\n * throws `RangeError: Invalid string length` (#1254) — extraction finishes and\n * the snapshot is simply lost. Streaming the two big arrays element by element\n * bounds the file by disk rather than by string length. The bytes are identical\n * to what the single-call version wrote, so `loadGraphFromDisk` and every other\n * reader are untouched.\n *\n * Note the read side still holds the file as one string, so a snapshot past the\n * same cap will write but not load back. That ceiling is real and separate.\n */\nexport async function saveGraphToDisk(graph: NeatGraph, outPath: string): Promise<void> {\n  await ensureDir(outPath)\n  const payload: PersistedGraph = {\n    schemaVersion: SCHEMA_VERSION,\n    exportedAt: new Date().toISOString(),\n    graph: withoutLiveOnlyAttributes(graph.export()),\n  }\n  // Atomic write: drop into <name>.tmp first, then rename. A crash mid-write\n  // leaves the previous snapshot intact instead of a half-truncated file.\n  const tmp = `${outPath}.tmp`\n  const handle = await fs.open(tmp, 'w')\n  try {\n    let buffered = ''\n    for (const chunk of serializeGraphChunks(payload)) {\n      buffered += chunk\n      if (buffered.length >= WRITE_FLUSH_CHARS) {\n        await handle.write(buffered, null, 'utf8')\n        buffered = ''\n      }\n    }\n    if (buffered.length > 0) await handle.write(buffered, null, 'utf8')\n  } finally {\n    await handle.close()\n  }\n  await fs.rename(tmp, outPath)\n}\n\n/**\n * Bring a snapshot forward to the current schema, or say why it can't be.\n *\n * The chain used to live inside `loadGraphFromDisk`, which meant only a snapshot\n * read off disk got migrated. `POST /snapshot` had the same payload and no way\n * to reach the migrations, so it compared versions for exact equality and\n * rejected anything else — and a `neat sync --to` from any CLI older than the\n * daemon answered 400 (#1307). One schema bump is enough to break every already\n * published client's push, which is not a cost a version-only bump should carry.\n *\n * Throws on a version this build can't reach: a snapshot newer than the daemon\n * (nothing to migrate *down*), or older than the first migration.\n */\n// Node attributes that live on the running graph only and never enter a snapshot,\n// in either direction. A faulted workload's redacted env/args/process log (ADR-243)\n// is live runtime state under the connectors.md §6 carve-out from Rule 13: it is\n// read through the graph by every surface, but it is never written to graph.json,\n// pushed by `neat sync`, or accepted from an incoming snapshot. The k8s poll puts\n// it back on the node after a restart while the fault is still live.\nexport const LIVE_ONLY_NODE_ATTRIBUTES: readonly string[] = ['observedDeployContext']\n\nexport function withoutLiveOnlyAttributes<T>(exported: T): T {\n  const nodes = (exported as { nodes?: Array<{ attributes?: Record<string, unknown> }> })?.nodes\n  if (!Array.isArray(nodes)) return exported\n  for (const node of nodes) {\n    if (!node.attributes) continue\n    for (const key of LIVE_ONLY_NODE_ATTRIBUTES) delete node.attributes[key]\n  }\n  return exported\n}\n\nexport function migrateSnapshot(input: PersistedGraph): PersistedGraph {\n  let payload = input\n  if (payload.schemaVersion === 1) {\n    payload = migrateV1ToV2(payload)\n  }\n  if (payload.schemaVersion === 2) {\n    payload = migrateV2ToV3(payload)\n  }\n  if (payload.schemaVersion === 3) {\n    payload = migrateV3ToV4(payload)\n  }\n  if (payload.schemaVersion === 4) {\n    payload = migrateV4ToV5(payload)\n  }\n  if (payload.schemaVersion === 5) {\n    payload = migrateV5ToV6(payload)\n  }\n  if (payload.schemaVersion === 6) {\n    payload = migrateV6ToV7(payload)\n  }\n  if (payload.schemaVersion !== SCHEMA_VERSION) {\n    throw new Error(\n      `persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`,\n    )\n  }\n  // Every snapshot read (disk load and POST /snapshot) drops live-only state.\n  return { ...payload, graph: withoutLiveOnlyAttributes(payload.graph) }\n}\n\nexport async function loadGraphFromDisk(graph: NeatGraph, outPath: string): Promise<void> {\n  let raw: string\n  try {\n    raw = await fs.readFile(outPath, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return\n    throw err\n  }\n  const payload = migrateSnapshot(JSON.parse(raw) as PersistedGraph)\n  graph.clear()\n  graph.import(payload.graph)\n}\n\nexport interface PersistLoopOptions {\n  // How often the periodic background save fires. Defaults to 60s.\n  intervalMs?: number\n  // Whether a SIGTERM/SIGINT should flush the graph and then exit the process.\n  // Defaults to true, which is what the standalone owners (`neat serve`,\n  // `neat watch`) want: the persist loop is the only thing holding the process\n  // open, so it owns the shutdown — flush, then exit.\n  //\n  // The daemon owns its own orderly shutdown (it closes its listeners, flushes\n  // every slot, clears its `daemon.json` + the machine-wide discovery copy, and\n  // removes its pid file before exiting). It runs many persist loops, one per\n  // project, and an exiting signal handler inside any of them would end the\n  // process out from under that teardown — leaving the discovery copy and pid\n  // file behind. So the daemon passes `false`: each loop still saves on its\n  // interval and unhooks cleanly on teardown, but the daemon decides when the\n  // process exits.\n  exitOnSignal?: boolean\n}\n\n// Periodic save + (optionally) a best-effort save-and-exit on SIGTERM/SIGINT.\n// Returns a cleanup that clears the interval and unhooks any signal handlers —\n// important for tests so they don't keep the process alive, and for the daemon\n// so a torn-down slot's loop stops reacting to signals.\nexport function startPersistLoop(\n  graph: NeatGraph,\n  outPath: string,\n  opts: PersistLoopOptions = {},\n): () => void {\n  const intervalMs = opts.intervalMs ?? 60_000\n  const exitOnSignal = opts.exitOnSignal ?? true\n  let stopped = false\n\n  const tick = async (): Promise<void> => {\n    if (stopped) return\n    try {\n      await saveGraphToDisk(graph, outPath)\n    } catch (err) {\n      console.error('persist: periodic save failed', err)\n    }\n  }\n\n  const interval = setInterval(() => {\n    void tick()\n  }, intervalMs)\n\n  const onSignal = exitOnSignal\n    ? (signal: NodeJS.Signals): void => {\n        void (async () => {\n          try {\n            await saveGraphToDisk(graph, outPath)\n          } catch (err) {\n            console.error(`persist: ${signal} save failed`, err)\n          } finally {\n            process.exit(0)\n          }\n        })()\n      }\n    : null\n\n  if (onSignal) {\n    process.on('SIGTERM', onSignal)\n    process.on('SIGINT', onSignal)\n  }\n\n  return () => {\n    stopped = true\n    clearInterval(interval)\n    if (onSignal) {\n      process.off('SIGTERM', onSignal)\n      process.off('SIGINT', onSignal)\n    }\n  }\n}\n\n// Snapshot merge (ADR-074 §1) lives in ingest.ts — that's the mutation-\n// authority boundary per the lifecycle contract (Rule 3 / ADR-030). The\n// merge is a form of ingestion: an external snapshot lands on the live graph\n// the same way an OTel span does, preserving the EXTRACTED + OBSERVED\n// coexistence contract along the way.\n","/**\n * `.gitignore` automation for the init flow (ADR-073 §6).\n *\n * Init writes a snapshot under `<projectDir>/neat-out/`. Un-ignored, that\n * directory leaks the snapshot into git history within one commit. The\n * helper here ensures `neat-out/` is present in `<projectDir>/.gitignore` —\n * appending to an existing file with a NEAT comment header, creating the\n * file when absent, no-oping when the line is already there.\n *\n * Idempotency rule: an exact-match line (`neat-out/` or `neat-out`, with\n * any surrounding whitespace) counts as already-present. No duplicate\n * line is written on a re-run.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport const NEAT_OUT_LINE = 'neat-out/'\nconst NEAT_HEADER = '# NEAT — machine-local snapshots and events'\n\nexport interface EnsureNeatOutResult {\n  // 'added' when the line was appended to an existing .gitignore.\n  // 'created' when the file did not exist and was created with a single line.\n  // 'unchanged' when the line was already present.\n  action: 'added' | 'created' | 'unchanged'\n  // Absolute path to the .gitignore file, regardless of action.\n  file: string\n}\n\nfunction isNeatOutLine(line: string): boolean {\n  const trimmed = line.trim()\n  return trimmed === 'neat-out/' || trimmed === 'neat-out'\n}\n\nexport async function ensureNeatOutIgnored(projectDir: string): Promise<EnsureNeatOutResult> {\n  const file = path.join(projectDir, '.gitignore')\n  let existing: string | null = null\n  try {\n    existing = await fs.readFile(file, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n  }\n\n  if (existing === null) {\n    await fs.writeFile(file, `${NEAT_HEADER}\\n${NEAT_OUT_LINE}\\n`, 'utf8')\n    return { action: 'created', file }\n  }\n\n  for (const line of existing.split(/\\r?\\n/)) {\n    if (isNeatOutLine(line)) return { action: 'unchanged', file }\n  }\n\n  // Append with a leading newline if the file doesn't already end in one,\n  // so the comment header sits on its own line.\n  const needsLeadingNewline = existing.length > 0 && !existing.endsWith('\\n')\n  const appended = `${needsLeadingNewline ? '\\n' : ''}\\n${NEAT_HEADER}\\n${NEAT_OUT_LINE}\\n`\n  await fs.writeFile(file, existing + appended, 'utf8')\n  return { action: 'added', file }\n}\n","/**\n * Value-forward CLI summary (issue #305, ADR-073 §5).\n *\n * Replaces the per-type node/edge counts that ended `neat init` with a\n * findings-first block — compat violations, top divergences, services\n * that never produced an OBSERVED edge, and the OTel env-vars block the\n * operator pastes into their deploy platform. Per-type counts move behind\n * `--verbose`.\n *\n * The renderer is a pure string builder so tests can assert against its\n * output without spawning the CLI.\n */\n\nimport type {\n  Divergence,\n  FileNode,\n  GraphEdge,\n  GraphNode,\n  InfraNode,\n  RouteNode,\n  ServiceNode,\n  SymbolNode,\n} from '@neat.is/types'\nimport { EdgeType, NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport * as style from './style.js'\nimport { OTLP_BEARER_PREFIX } from './otlp-headers.js'\n\nexport interface SummaryInput {\n  graph: NeatGraph\n  divergences: Divergence[]\n  // True → render the per-type counts after the value-forward block.\n  verbose: boolean\n}\n\n// Static placeholder. The orchestrator and `neat deploy` print the same\n// block; `neat deploy` substitutes the actual token + host. This shape\n// lives in one place so the wire format stays in step.\nexport function renderOtelEnvBlock(): string {\n  return [\n    'for prod OTel routing, set these in your deploy platform\\'s env:',\n    '  OTEL_EXPORTER_OTLP_ENDPOINT=https://<your-neat-host>:4318',\n    `  OTEL_EXPORTER_OTLP_HEADERS=${OTLP_BEARER_PREFIX}<NEAT_AUTH_TOKEN>`,\n  ].join('\\n')\n}\n\nfunction findIncompatServices(nodes: GraphNode[]): ServiceNode[] {\n  return nodes.filter(\n    (n): n is ServiceNode =>\n      n.type === NodeType.ServiceNode &&\n      Array.isArray((n as ServiceNode).incompatibilities) &&\n      ((n as ServiceNode).incompatibilities ?? []).length > 0,\n  )\n}\n\n// Services that show up in the EXTRACTED graph but have no OBSERVED edge\n// pointing at or out of them. The thesis says: when the OBSERVED layer is\n// silent on a service, the gap is a load-bearing signal for the operator.\nfunction servicesWithoutObserved(nodes: GraphNode[], edges: GraphEdge[]): ServiceNode[] {\n  const seen = new Set<string>()\n  for (const e of edges) {\n    if (e.provenance === Provenance.OBSERVED) {\n      seen.add(e.source)\n      seen.add(e.target)\n    }\n  }\n  return nodes.filter(\n    (n): n is ServiceNode => n.type === NodeType.ServiceNode && !seen.has(n.id),\n  )\n}\n\nfunction formatDivergence(d: Divergence): string {\n  // Short, scannable, one-line-per-finding. The reason field already carries\n  // the load-bearing detail; the recommendation rides on a second indent.\n  const conf = d.confidence.toFixed(2)\n  return `  [${conf}] ${d.type} ${d.source} → ${d.target} — ${d.reason}`\n}\n\n// ── Static coverage by language (#1174, part of #1158) ─────────────────────\n//\n// Symbol grain, server routes, and the ORM data axis extract for many\n// languages; outbound HTTP client call recognition (calls/http.ts,\n// calls/route-match.ts) reads JS/TS only. So a caller written in any other\n// language mints no client→route CALLS edge, and its cross-service topology\n// comes from the OBSERVED layer instead. That degradation is graceful but\n// silent — a reader can't tell \"thin because no such calls\" from \"thin\n// because the recognizer skipped this language\". This block names it: per\n// service language present in the scan, which static axes actually produced\n// output, so the boundary reads as a stated limit rather than a low count.\nconst JS_TS_LANGUAGES = new Set(['javascript', 'typescript'])\n\ninterface LanguageCoverage {\n  symbols: boolean\n  routes: boolean\n  data: boolean\n  crossServiceCalls: boolean\n}\n\nconst COVERAGE_COLUMNS: ReadonlyArray<{ key: keyof LanguageCoverage; label: string }> = [\n  { key: 'symbols', label: 'symbols' },\n  { key: 'routes', label: 'routes' },\n  { key: 'data', label: 'data' },\n  { key: 'crossServiceCalls', label: 'cross-service calls' },\n]\n\n// A table InfraNode is the data-axis target — `sql-table`, `supabase-table`,\n// `firestore-collection`. Kept to the shared suffixes so a new table-shaped\n// kind lands here without a code change.\nfunction isTableInfra(kind: string | undefined): boolean {\n  return kind !== undefined && /(table|collection)$/.test(kind)\n}\n\n// Reads which static axes produced output for each service language. Counts\n// only what static extraction actually minted: EXTRACTED CALLS edges (an\n// OBSERVED edge into a route would otherwise mask the very gap this surfaces)\n// and symbols/routes that aren't OBSERVED-only placeholders.\nfunction computeLanguageCoverage(\n  nodes: GraphNode[],\n  edges: GraphEdge[],\n): Map<string, LanguageCoverage> {\n  const serviceLang = new Map<string, string>()\n  const fileService = new Map<string, string>()\n  const nodeById = new Map<string, GraphNode>()\n  for (const n of nodes) {\n    nodeById.set(n.id, n)\n    if (n.type === NodeType.ServiceNode) serviceLang.set((n as ServiceNode).name, (n as ServiceNode).language)\n    else if (n.type === NodeType.FileNode) fileService.set(n.id, (n as FileNode).service)\n  }\n\n  const cov = new Map<string, LanguageCoverage>()\n  const ensure = (lang: string): LanguageCoverage => {\n    let c = cov.get(lang)\n    if (!c) {\n      c = { symbols: false, routes: false, data: false, crossServiceCalls: false }\n      cov.set(lang, c)\n    }\n    return c\n  }\n  // Every present service language gets a row, even one that produced nothing.\n  for (const lang of serviceLang.values()) ensure(lang)\n\n  for (const n of nodes) {\n    if (n.type === NodeType.SymbolNode) {\n      if ((n as SymbolNode).discoveredVia === 'otel') continue\n      const lang = serviceLang.get((n as SymbolNode).service)\n      if (lang) ensure(lang).symbols = true\n    } else if (n.type === NodeType.RouteNode) {\n      if ((n as RouteNode).discoveredVia === 'otel') continue\n      const lang = serviceLang.get((n as RouteNode).service)\n      if (lang) ensure(lang).routes = true\n    }\n  }\n\n  for (const e of edges) {\n    if (e.type !== EdgeType.CALLS || e.provenance !== Provenance.EXTRACTED) continue\n    // File-first: a CALLS edge originates from the FileNode of its call site.\n    const svc = fileService.get(e.source)\n    const lang = svc ? serviceLang.get(svc) : undefined\n    if (!lang) continue\n    const target = nodeById.get(e.target)\n    if (!target) continue\n    if (target.type === NodeType.RouteNode) ensure(lang).crossServiceCalls = true\n    else if (target.type === NodeType.InfraNode && isTableInfra((target as InfraNode).kind)) ensure(lang).data = true\n  }\n\n  return cov\n}\n\nfunction renderLanguageCoverage(nodes: GraphNode[], edges: GraphEdge[]): string[] {\n  const cov = computeLanguageCoverage(nodes, edges)\n  const langs = [...cov.keys()]\n  // The boundary is only worth stating off the JS/TS island — a pure JS/TS\n  // scan has nothing to disclose here, so the block earns its place only when\n  // a non-JS/TS service is present.\n  if (!langs.some((l) => !JS_TS_LANGUAGES.has(l))) return []\n\n  const glyph = (on: boolean): string => (on ? style.ok(style.sym.ok) : style.dim('—'))\n  const header = ['', ...COVERAGE_COLUMNS.map((c) => c.label)]\n  const rows: string[][] = [header]\n  for (const lang of [...langs].sort()) {\n    const c = cov.get(lang) as LanguageCoverage\n    rows.push([lang, ...COVERAGE_COLUMNS.map((col) => glyph(c[col.key]))])\n  }\n\n  const lines: string[] = ['static coverage by language (this scan):']\n  for (const row of style.table(rows)) lines.push(`  ${row}`)\n  lines.push(\n    `  ${style.sym.arrow} cross-service call recognition is JS/TS-only today (#1158); non-JS/TS callers rely on OBSERVED for cross-service topology.`,\n  )\n  lines.push('')\n  return lines\n}\n\nexport function renderValueForwardSummary(input: SummaryInput): string {\n  const { graph, divergences, verbose } = input\n  const nodes: GraphNode[] = []\n  graph.forEachNode((_id, attrs) => nodes.push(attrs))\n  const edges: GraphEdge[] = []\n  graph.forEachEdge((_id, attrs) => edges.push(attrs))\n\n  const lines: string[] = []\n  lines.push(style.heading('neat · findings'))\n  lines.push('')\n\n  // ── Compat violations (driver/engine mismatches) ───────────────────────\n  const incompatServices = findIncompatServices(nodes)\n  const totalIncompats = incompatServices.reduce(\n    (acc, s) => acc + (s.incompatibilities?.length ?? 0),\n    0,\n  )\n  lines.push(`compat violations: ${totalIncompats}`)\n  for (const svc of incompatServices) {\n    for (const inc of svc.incompatibilities ?? []) {\n      const detail = formatIncompat(inc)\n      lines.push(`  ${svc.name}: ${detail}`)\n    }\n  }\n  lines.push('')\n\n  // ── Top divergences (top 3 by confidence desc) ─────────────────────────\n  const top = [...divergences].sort((a, b) => b.confidence - a.confidence).slice(0, 3)\n  lines.push(`top divergences: ${divergences.length} total${top.length > 0 ? ', top 3:' : ''}`)\n  for (const d of top) lines.push(formatDivergence(d))\n  lines.push('')\n\n  // ── Services missing OBSERVED coverage ─────────────────────────────────\n  const noObserved = servicesWithoutObserved(nodes, edges)\n  if (noObserved.length > 0) {\n    lines.push(`services without OBSERVED coverage: ${noObserved.length}`)\n    for (const svc of noObserved) lines.push(`  ${svc.name}`)\n    lines.push('  → run your services with the generated otel-init to populate OBSERVED edges.')\n    lines.push('')\n  }\n\n  // ── Static coverage by language (#1174) ────────────────────────────────\n  for (const line of renderLanguageCoverage(nodes, edges)) lines.push(line)\n\n  // ── OTel env-vars block (static; `neat deploy` substitutes real values)\n  lines.push(renderOtelEnvBlock())\n  lines.push('')\n\n  // ── --verbose: per-type node/edge counts ──────────────────────────────\n  if (verbose) {\n    const byNode = new Map<string, number>()\n    for (const n of nodes) byNode.set(n.type, (byNode.get(n.type) ?? 0) + 1)\n    const byEdge = new Map<string, number>()\n    for (const e of edges) byEdge.set(e.type, (byEdge.get(e.type) ?? 0) + 1)\n    lines.push('=== graph (verbose) ===')\n    lines.push(`total: ${graph.order} nodes, ${graph.size} edges`)\n    lines.push('nodes:')\n    for (const [t, c] of [...byNode.entries()].sort()) lines.push(`  ${t}: ${c}`)\n    lines.push('edges:')\n    for (const [t, c] of [...byEdge.entries()].sort()) lines.push(`  ${t}: ${c}`)\n    lines.push('')\n  }\n\n  return lines.join('\\n')\n}\n\nfunction formatIncompat(inc: NonNullable<ServiceNode['incompatibilities']>[number]): string {\n  if (inc.kind === 'node-engine') {\n    const range = inc.declaredNodeEngine ? ` (engines.node=\"${inc.declaredNodeEngine}\")` : ''\n    return `${inc.package}@${inc.packageVersion ?? '?'} requires Node ${inc.requiredNodeVersion}${range} — ${inc.reason}`\n  }\n  if (inc.kind === 'package-conflict') {\n    const found = inc.foundVersion ? `@${inc.foundVersion}` : ' (missing)'\n    return `${inc.package}@${inc.packageVersion ?? '?'} requires ${inc.requires.name}>=${inc.requires.minVersion}; found ${inc.requires.name}${found} — ${inc.reason}`\n  }\n  if (inc.kind === 'deprecated-api') {\n    return `${inc.package}@${inc.packageVersion ?? '?'} is deprecated — ${inc.reason}`\n  }\n  return `${inc.driver}@${inc.driverVersion} vs ${inc.engine} ${inc.engineVersion} — ${inc.reason}`\n}\n","// The OTLP bearer header, in the form OTEL_EXPORTER_OTLP_HEADERS requires.\n//\n// Header values in that variable are URL-encoded (OTLP exporter spec, W3C\n// Baggage syntax), so the space after `Bearer` is `%20`. Lenient parsers accept\n// a raw space; a strict one (`parse_env_headers(…, liberal=False)` in the Python\n// SDK, older Python SDKs by default) drops the whole header, the exporter sends\n// no Authorization, and the daemon answers 401 with nothing in the app saying\n// why (#1339). The token is encoded too, so a `+`, `/` or `=` survives; every\n// parser decodes it back.\n\nexport const OTLP_BEARER_PREFIX = 'Authorization=Bearer%20'\n\n/** `Authorization=Bearer%20<token>`, ready for OTEL_EXPORTER_OTLP_HEADERS. */\nexport function otlpBearerHeader(token: string): string {\n  return OTLP_BEARER_PREFIX + encodeURIComponent(token)\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport chokidar, { type FSWatcher } from 'chokidar'\nimport type { FastifyInstance } from 'fastify'\nimport type { NeatGraph } from './graph.js'\nimport { buildApi } from './api.js'\nimport { assertBindAuthority, readAuthEnv } from './auth.js'\nimport { ensureCompatLoaded } from './compat.js'\nimport { discoverServices, addServiceNodes } from './extract/services.js'\nimport { addServiceAliases } from './extract/aliases.js'\nimport { addFiles } from './extract/files.js'\nimport { addSymbols } from './extract/symbols.js'\nimport { addImports } from './extract/imports.js'\nimport { addDatabasesAndCompat } from './extract/databases/index.js'\nimport { addConfigNodes } from './extract/configs.js'\nimport { addFlagStores } from './extract/flags.js'\nimport { SERVICE_FILE_EXTENSIONS } from './extract/shared.js'\nimport { addRoutes } from './extract/routes.js'\nimport { addCallEdges } from './extract/calls/index.js'\nimport { addInfra } from './extract/infra/index.js'\nimport { retireEdgesByFile } from './extract/retire.js'\nimport {\n  makeErrorSpanWriter,\n  makeSpanHandler,\n  promoteFrontierNodes,\n  startStalenessLoop,\n} from './ingest.js'\nimport { reconcileFrontierSurfaces } from './hang-sensor.js'\nimport {\n  evaluateAllPolicies,\n  loadPolicyFile,\n  PolicyViolationsLog,\n} from './policy.js'\nimport type { Policy } from '@neat.is/types'\nimport { buildOtelReceiver, listenSteppingOtlp } from './otel.js'\nimport { startConnectorPolling } from './connectors/registry.js'\nimport { startK8sSubstratePolling } from './connectors/kubernetes/index.js'\nimport { startFlagStorePolling } from './flag-stores/index.js'\nimport {\n  clearDaemonRecord,\n  portFromListenAddress,\n  resolveNeatVersion,\n  writeDaemonRecord,\n  type DaemonRecord,\n} from './daemon.js'\nimport { startOtelGrpcReceiver } from './otel-grpc.js'\nimport { loadGraphFromDisk, startPersistLoop } from './persist.js'\nimport { buildSearchIndex, searchProviderFromEnv, type SearchIndex } from './search.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { Projects, pathsForProject } from './projects.js'\nimport { attachGraphToEventBus, emitNeatEvent } from './events.js'\n\nexport type ExtractPhase =\n  | 'services'\n  | 'aliases'\n  | 'files'\n  | 'symbols'\n  | 'imports'\n  | 'databases'\n  | 'configs'\n  | 'flags'\n  | 'routes'\n  | 'calls'\n  | 'infra'\n\n// Phase order mirrors extractFromDirectory (extract/index.ts). Load-bearing\n// ordering: symbols runs after files (the FileNodes it hangs SymbolNodes off\n// must exist) and before calls; routes runs after configs and before calls, so\n// the RouteNode table is populated when addCallEdges' cross-service matcher\n// (route-match.ts, ADR-119) resolves client call sites to server routes.\nconst ALL_PHASES: ExtractPhase[] = [\n  'services',\n  'aliases',\n  'files',\n  'symbols',\n  'imports',\n  'databases',\n  'configs',\n  'flags',\n  'routes',\n  'calls',\n  'infra',\n]\n\n// Map a changed path to the phases that need re-running. Anything not matched\n// here falls back to a full re-extract — better an extra ~50ms of work than a\n// missed update because the path didn't fit a regex.\n//\n// Mapping:\n//   package.json / requirements.txt / pyproject.toml → services + aliases + databases\n//     (deps drive compat; aliases pull from manifest fields)\n//   .env / *.env.* / prisma / knex / ormconfig → databases + configs\n//   docker-compose / Dockerfile / *.tf / k8s yaml → infra + aliases\n//     (compose labels and Dockerfile labels feed alias discovery)\n//   *.js / *.ts / *.tsx / *.py / *.jsx / *.mjs / *.cjs → files + symbols +\n//     imports + routes + calls\n//     (a source edit can shift its IMPORTS, CALLS, SymbolNodes and RouteNodes;\n//     symbols/routes re-run for the same reason and are idempotent no-ops when\n//     the edited file defines neither. Routes must precede calls so the\n//     cross-service matcher sees the fresh route table; the shared\n//     evidence.file retirement mechanism — static-extraction.md §Ghost-edge\n//     cleanup — drops the stale ones from either producer before re-running.\n//     The `files` phase re-enumerates FileNodes first: retiring an edited\n//     file's edges also drops its CONTAINS edge — whose evidence.file is the\n//     file itself — and can orphan the FileNode, so Phase 1 has to rebuild it\n//     before imports/calls originate edges from it, or addImports emits from a\n//     node that no longer exists.)\n//   *.yaml / *.yml that isn't compose → databases + configs (ORM yaml fallbacks)\n//   *.json / any source file → flags (ADR-242: a flag file's definitions, and a\n//     source edit can add or drop a literal that reads a flag key)\nexport function classifyChange(relPath: string): Set<ExtractPhase> {\n  const phases = new Set<ExtractPhase>()\n  const base = path.basename(relPath).toLowerCase()\n  const segments = relPath.split(path.sep).map((s) => s.toLowerCase())\n\n  if (\n    base === 'package.json' ||\n    base === 'requirements.txt' ||\n    base === 'pyproject.toml' ||\n    base === 'setup.py'\n  ) {\n    phases.add('services')\n    phases.add('aliases')\n    phases.add('databases')\n  }\n\n  if (\n    base === '.env' ||\n    base.startsWith('.env.') ||\n    base === 'schema.prisma' ||\n    /^knexfile\\.(?:js|ts|cjs|mjs)$/.test(base) ||\n    /^ormconfig\\.(?:js|ts|json|ya?ml)$/.test(base)\n  ) {\n    phases.add('databases')\n    phases.add('configs')\n  }\n\n  if (\n    base === 'dockerfile' ||\n    /^docker-compose.*\\.ya?ml$/.test(base) ||\n    base.endsWith('.tf') ||\n    segments.includes('k8s') ||\n    segments.includes('kustomize') ||\n    segments.includes('manifests')\n  ) {\n    phases.add('infra')\n    phases.add('aliases')\n  }\n\n  if (/\\.(?:js|jsx|mjs|cjs|ts|tsx|py)$/.test(base)) {\n    phases.add('files')\n    phases.add('symbols')\n    phases.add('imports')\n    phases.add('routes')\n    phases.add('calls')\n  }\n\n  // Flag grain (ADR-242): a flag file is `.json`, and a reader is a literal in\n  // any walked source language.\n  const isFlagFileCandidate =\n    base.endsWith('.json') &&\n    base !== 'package.json' &&\n    !/^(?:package-lock|composer|tsconfig.*|ormconfig|jsconfig.*)\\.json$/.test(base)\n  if (isFlagFileCandidate || SERVICE_FILE_EXTENSIONS.has(path.extname(base))) {\n    phases.add('flags')\n  }\n\n  if (/\\.ya?ml$/.test(base) && !/^docker-compose.*\\.ya?ml$/.test(base)) {\n    // Generic yaml — could be an ORM file, k8s manifest, or random config.\n    // Cheap to run databases + configs; if it was infra, the dir-name check\n    // above already added that phase.\n    phases.add('databases')\n    phases.add('configs')\n  }\n\n  return phases\n}\n\ninterface RunPhasesResult {\n  phases: ExtractPhase[]\n  nodesAdded: number\n  edgesAdded: number\n  frontiersPromoted: number\n  durationMs: number\n}\n\nexport async function runExtractPhases(\n  graph: NeatGraph,\n  scanPath: string,\n  phases: Set<ExtractPhase>,\n  // Project tag passed through for the runtime event bus (ADR-051) — not\n  // required for extraction logic itself but threaded for parity with\n  // extractFromDirectory's project option.\n  project: string = DEFAULT_PROJECT,\n): Promise<RunPhasesResult> {\n  void project\n  const started = Date.now()\n  await ensureCompatLoaded()\n  // Discovery is cheap and every phase needs the same DiscoveredService list,\n  // so we always re-walk. If the user moved a service directory, this is also\n  // the path that picks it up.\n  const services = await discoverServices(scanPath)\n\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  if (phases.has('services')) {\n    nodesAdded += addServiceNodes(graph, services)\n  }\n  if (phases.has('aliases')) {\n    await addServiceAliases(graph, scanPath, services)\n  }\n  // Phase 1 — file enumeration runs before imports/calls (file-awareness.md §1).\n  // Both of those producers originate edges from FileNodes; a re-extract driven\n  // by a source edit has already retired that file's CONTAINS edge (its\n  // evidence.file is the file itself) and may have swept the now-orphaned\n  // FileNode, so rebuilding it here is what keeps addImports from emitting an\n  // edge off a missing node. Idempotent — an unchanged tree is a no-op.\n  if (phases.has('files')) {\n    const r = await addFiles(graph, services)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  // Symbol grain (ADR-158). Runs after files so the FileNodes each SymbolNode\n  // hangs off already exist, mirroring extractFromDirectory. Idempotent — a\n  // re-extract that already retired a changed file's edges re-mints them here.\n  if (phases.has('symbols')) {\n    const r = await addSymbols(graph, services)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  if (phases.has('imports')) {\n    const r = await addImports(graph, services)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  if (phases.has('databases')) {\n    const r = await addDatabasesAndCompat(graph, services, scanPath)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  if (phases.has('configs')) {\n    const r = await addConfigNodes(graph, services, scanPath)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  // Flag grain (ADR-242): the committed flag definitions and the code that reads\n  // each key, after configs as in extractFromDirectory.\n  if (phases.has('flags')) {\n    const r = await addFlagStores(graph, services, scanPath)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  // Route extraction (ADR-119) runs before calls so the RouteNodes exist when\n  // addCallEdges' cross-service matcher (route-match.ts) looks them up —\n  // including the ADR-160 cross-file mount-prefix composition. Mirrors\n  // extractFromDirectory's ordering.\n  if (phases.has('routes')) {\n    const r = await addRoutes(graph, services)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  if (phases.has('calls')) {\n    const r = await addCallEdges(graph, services)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  if (phases.has('infra')) {\n    const r = await addInfra(graph, scanPath, services)\n    nodesAdded += r.nodesAdded\n    edgesAdded += r.edgesAdded\n  }\n  const frontiersPromoted = promoteFrontierNodes(graph)\n\n  return {\n    phases: ALL_PHASES.filter((p) => phases.has(p)),\n    nodesAdded,\n    edgesAdded,\n    frontiersPromoted,\n    durationMs: Date.now() - started,\n  }\n}\n\n// The canonical dashboard port recorded in daemon.json. `neat watch` binds no\n// dashboard of its own, but the DaemonRecord shape requires a web port; only\n// ports.otlp is load-bearing for the OBSERVED endpoint resolution this record\n// exists to serve. Mirrors DEFAULT_WEB_PORT in web-spawn.ts.\nconst DEFAULT_WATCH_WEB_PORT = 6328\n\nexport interface WatchOptions {\n  scanPath: string\n  outPath: string\n  errorsPath: string\n  staleEventsPath: string\n  embeddingsCachePath?: string\n  // Project name this watch instance owns. Defaults to `default` for the\n  // single-project workflow that's been the only one until #83.\n  project?: string\n  host?: string\n  port?: number\n  otelPort?: number\n  otelGrpc?: boolean\n  otelGrpcPort?: number\n  debounceMs?: number\n  // Resolved NEAT_HOME, so `neat watch` polls the connectors added to\n  // `~/.neat/connectors.json` the same way the multi-project daemon does\n  // (#871). Absent → no file connectors are loaded (the pre-#871 behaviour),\n  // which keeps a bare startWatch (tests, embedders) from reading real config.\n  neatHome?: string\n}\n\nexport interface WatchHandle {\n  api: FastifyInstance\n  stop: () => Promise<void>\n}\n\n// Anymatch-compatible ignore set passed to chokidar (#233). The earlier\n// implementation passed a function alone, which forced chokidar to descend\n// into every subdirectory before testing the path. On macOS with kqueue\n// (chokidar 4 dropped fsevents in favour of kqueue), each subdir under the\n// scan root opens a watch handle; nested `node_modules` blew through the\n// per-process kqueue cap with EMFILE before the function-based ignore ever\n// fired. Globs let chokidar prune at descent time — the dirs are never\n// opened in the first place.\nconst IGNORED_WATCH_GLOBS = [\n  '**/node_modules/**',\n  '**/.git/**',\n  '**/dist/**',\n  '**/build/**',\n  '**/.turbo/**',\n  '**/.next/**',\n  '**/neat-out/**',\n  // Python venv shapes (issue #344). chokidar opens one watch handle per\n  // descended dir; a CPython venv carries 20k+ files and trivially blows\n  // through the macOS kqueue cap before extraction even runs.\n  '**/.venv/**',\n  '**/venv/**',\n  '**/__pypackages__/**',\n  '**/.tox/**',\n  '**/site-packages/**',\n  '**/.DS_Store',\n]\n\n// Backstop regex set — covers anything chokidar surfaces post-descent that\n// the globs missed (e.g. a path containing one of these segments at an\n// unexpected depth). Same shape as before; the globs are the load-bearing\n// pruning, this is defence in depth.\nconst IGNORED_WATCH_PATHS = [\n  /(?:^|[\\\\/])node_modules[\\\\/]/,\n  /(?:^|[\\\\/])\\.git[\\\\/]/,\n  /(?:^|[\\\\/])dist[\\\\/]/,\n  /(?:^|[\\\\/])build[\\\\/]/,\n  /(?:^|[\\\\/])\\.turbo[\\\\/]/,\n  /(?:^|[\\\\/])\\.next[\\\\/]/,\n  /(?:^|[\\\\/])neat-out[\\\\/]/,\n  /(?:^|[\\\\/])\\.venv[\\\\/]/,\n  /(?:^|[\\\\/])venv[\\\\/]/,\n  /(?:^|[\\\\/])__pypackages__[\\\\/]/,\n  /(?:^|[\\\\/])\\.tox[\\\\/]/,\n  /(?:^|[\\\\/])site-packages[\\\\/]/,\n  /[\\\\/]?\\.DS_Store$/,\n]\n\nfunction shouldIgnore(absPath: string): boolean {\n  return IGNORED_WATCH_PATHS.some((re) => re.test(absPath))\n}\n\n// Roughly the number of immediate, non-ignored subdirectories in the scan\n// root above which `neat watch` should fall back to polling on darwin. kqueue\n// opens one handle per watched dir; macOS's per-process file-descriptor cap\n// is typically 256 (soft) / unlimited (hard) but raising the hard cap doesn't\n// help with the kqueue-specific limits. Empirically anything north of ~500\n// non-ignored dirs starts to flirt with EMFILE. Threshold sits comfortably\n// under that.\nconst DARWIN_POLLING_DIR_THRESHOLD = 400\n\n// Fast non-recursive count: walk top-level entries only, descending one\n// level into non-ignored subdirs to capture the medusa-shaped case where\n// `packages/*` itself looks small but each contains a heavy `node_modules`.\n// Returns early once it crosses the threshold so we don't waste time on huge\n// repos.\nfunction countWatchableDirs(scanPath: string, limit: number): number {\n  let count = 0\n  const visit = (dir: string, depth: number): void => {\n    if (count >= limit) return\n    let entries: fs.Dirent[]\n    try {\n      entries = fs.readdirSync(dir, { withFileTypes: true })\n    } catch {\n      return\n    }\n    for (const e of entries) {\n      if (count >= limit) return\n      if (!e.isDirectory()) continue\n      if (IGNORED_WATCH_PATHS.some((re) => re.test(path.join(dir, e.name) + path.sep))) continue\n      count++\n      // One level deeper — enough to surface nested `node_modules` shapes\n      // without traversing the whole tree.\n      if (depth < 2) visit(path.join(dir, e.name), depth + 1)\n    }\n  }\n  visit(scanPath, 0)\n  return count\n}\n\n// Darwin heuristic (#233). Forces chokidar onto polling when the scan root\n// is large enough that kqueue would EMFILE. Override via NEAT_WATCH_POLLING:\n//   - \"1\" / \"true\"  → force polling regardless of platform/threshold\n//   - \"0\" / \"false\" → never poll (matches pre-#233 behaviour)\n//   - unset         → auto-detect on darwin\nfunction shouldUsePolling(scanPath: string): boolean {\n  const env = process.env.NEAT_WATCH_POLLING\n  if (env === '1' || env === 'true') return true\n  if (env === '0' || env === 'false') return false\n  if (process.platform !== 'darwin') return false\n  return countWatchableDirs(scanPath, DARWIN_POLLING_DIR_THRESHOLD) >= DARWIN_POLLING_DIR_THRESHOLD\n}\n\nexport async function startWatch(\n  graph: NeatGraph,\n  opts: WatchOptions,\n): Promise<WatchHandle> {\n  const debounceMs = opts.debounceMs ?? 1000\n  const projectName = opts.project ?? DEFAULT_PROJECT\n\n  await loadGraphFromDisk(graph, opts.outPath)\n\n  // Wire graph mutations into the event bus (ADR-051) before extract begins\n  // so the initial pass also produces node/edge events. Detached on stop().\n  const detachEventBus = attachGraphToEventBus(graph, { project: projectName })\n\n  // Load policies + open the violations log once at startup. policy.json\n  // lives at the project root per ADR-042 §File location; absent file is\n  // a perfectly fine state (loadPolicyFile returns []). Reload-on-change\n  // is queued for v0.2.5 — the kickoff doc tracks it.\n  const policyFilePath = path.join(opts.scanPath, 'policy.json')\n  const policyViolationsPath = path.join(path.dirname(opts.outPath), 'policy-violations.ndjson')\n  let policies: Policy[] = []\n  try {\n    policies = await loadPolicyFile(policyFilePath)\n    if (policies.length > 0) {\n      console.log(`policies: loaded ${policies.length} from ${policyFilePath}`)\n    }\n  } catch (err) {\n    console.warn(`policies: failed to load ${policyFilePath} — ${(err as Error).message}`)\n  }\n  const policyLog = new PolicyViolationsLog(policyViolationsPath, projectName)\n\n  // Single shared trigger callback wired into post-ingest, post-extract, and\n  // post-stale per ADR-043. Failures append to console.warn but don't kill\n  // the daemon — a malformed evaluator shouldn't take down ingest.\n  const onPolicyTrigger = async (g: NeatGraph): Promise<void> => {\n    if (policies.length === 0) return\n    try {\n      const violations = evaluateAllPolicies(g, policies, { now: () => Date.now() })\n      for (const v of violations) await policyLog.append(v)\n    } catch (err) {\n      console.warn(`policies: evaluation failed — ${(err as Error).message}`)\n    }\n  }\n\n  // The post-extract trigger fires from extractFromDirectory via opts.\n  // For the initial extract here we run it inline so violations land on\n  // startup before the receiver opens. Subsequent watch-driven re-extract\n  // passes go through runExtractPhases which doesn't take the hook directly\n  // — we run it after each flush() instead.\n  const initial = await runExtractPhases(\n    graph,\n    opts.scanPath,\n    new Set(ALL_PHASES),\n    projectName,\n  )\n  console.log(\n    `extract: ${initial.nodesAdded} new nodes, ${initial.edgesAdded} new edges (graph total ${graph.order}/${graph.size})`,\n  )\n  // extraction-complete for the initial pass (ADR-051). runExtractPhases\n  // doesn't emit on its own — the event lives at the watch / orchestrator\n  // boundary so the daemon can swap in its own emission shape.\n  emitNeatEvent({\n    type: 'extraction-complete',\n    project: projectName,\n    payload: {\n      project: projectName,\n      fileCount: 0,\n      nodesAdded: initial.nodesAdded,\n      edgesAdded: initial.edgesAdded,\n    },\n  })\n  await onPolicyTrigger(graph)\n\n  const stopPersist = startPersistLoop(graph, opts.outPath)\n  const stopStaleness = startStalenessLoop(graph, {\n    staleEventsPath: opts.staleEventsPath,\n    project: projectName,\n    onPolicyTrigger,\n    // Graduate FRONTIER surfaces whose twin arrived + stage surfaces for current\n    // hangs (ADR-226), each post-ingest tick.\n    onReconcile: (g) => reconcileFrontierSurfaces(g, opts.errorsPath),\n  })\n\n  // Connectors plane (docs/contracts/connectors.md, ADR-124; on-ramp ADR-130) —\n  // poll every project-matched entry in `~/.neat/connectors.json` on its own\n  // loop, the same shared path the multi-project daemon uses. Only runs when the\n  // caller resolved a home (the CLI does); a bare startWatch reads no config, so\n  // a connector env-ref stays in memory and never reaches the snapshot\n  // (connector-config.md §6). A bad entry is skipped with a warning, never fatal.\n  const stopConnectors = await startConnectorPolling({\n    project: projectName,\n    graph,\n    projectDir: opts.scanPath,\n    // Incident ledger for an incident-emitting connector (ADR-185), same path\n    // `neat watch`'s own error-span writer already uses.\n    errorsPath: opts.errorsPath,\n    ...(opts.neatHome ? { home: opts.neatHome } : {}),\n    onSkip: (skipped, reason) =>\n      console.warn(\n        `neat watch: connector \"${skipped.id}\" (${skipped.provider}) skipped for project \"${projectName}\" — ${reason}`,\n      ),\n  })\n\n  // The k8s deployment substrate (ADR-224/225) — the observed cluster-state reader,\n  // enabled off `~/.neat/k8s.json` rather than the `neat connector` vendor surface.\n  // Wired here alongside the connector poll loops so `neat watch` stamps observed\n  // deploy state and the deploy-mismatch divergence fires, exactly as the\n  // multi-project daemon's `bootstrapProject` does (the same #873 gap, for the\n  // substrate this time).\n  const stopK8sSubstrate = await startK8sSubstratePolling({\n    project: projectName,\n    graph,\n    projectDir: opts.scanPath,\n    errorsPath: opts.errorsPath,\n    ...(opts.neatHome ? { home: opts.neatHome } : {}),\n    onSkip: (skipped, reason) =>\n      console.warn(`neat watch: k8s substrate \"${skipped.id}\" skipped for project \"${projectName}\" — ${reason}`),\n  })\n\n  // The flag-store reader (ADR-242), same enable path as the daemon slot.\n  const stopFlagStores = await startFlagStorePolling({\n    project: projectName,\n    graph,\n    ...(opts.neatHome ? { home: opts.neatHome } : {}),\n    onSkip: (skipped, reason) =>\n      console.warn(`neat watch: flag store \"${skipped.id}\" skipped for project \"${projectName}\" — ${reason}`),\n  })\n\n  // ADR-073 §3/§4 + issue #341 — `neat watch` follows the same bind discipline\n  // as the daemon: an explicit host wins; otherwise loopback-only without a\n  // token (laptop dev), public bind once `NEAT_AUTH_TOKEN` is set. buildApi\n  // mounts the bearer gate from the same env, so a token-protected watch\n  // returns 401 to unauthenticated callers exactly as `neatd` does.\n  const auth = readAuthEnv()\n  const host = opts.host ?? (auth.authToken ? '0.0.0.0' : '127.0.0.1')\n  assertBindAuthority(host, auth.authToken)\n  const port = opts.port ?? 8080\n  const otelPort = opts.otelPort ?? 4318\n\n  const cachePath =\n    opts.embeddingsCachePath ?? path.join(path.dirname(opts.outPath), 'embeddings.json')\n  const forceProvider = searchProviderFromEnv()\n  let searchIndex: SearchIndex | undefined\n  try {\n    searchIndex = await buildSearchIndex(graph, { cachePath, forceProvider })\n    console.log(`semantic_search: ${searchIndex.provider} provider`)\n  } catch (err) {\n    console.warn(\n      `semantic_search: index build failed (${(err as Error).message}); falling back to inline substring`,\n    )\n  }\n\n  const registry = new Projects()\n  registry.set(projectName, {\n    graph,\n    scanPath: opts.scanPath,\n    paths: {\n      // Paths are derived from the explicit options the watch caller passes\n      // — pathsForProject is only used to fill in the embeddings/snapshot\n      // fields so the registry shape is complete.\n      ...pathsForProject(projectName, path.dirname(opts.outPath)),\n      snapshotPath: opts.outPath,\n      errorsPath: opts.errorsPath,\n      staleEventsPath: opts.staleEventsPath,\n    },\n    searchIndex,\n  })\n\n  const api = await buildApi({ projects: registry })\n  const restAddress = await api.listen({ port, host })\n  console.log(`neat-core listening on http://${host}:${port}`)\n  console.log(`  scan path:     ${opts.scanPath} (watching for changes)`)\n  console.log(`  snapshot path: ${opts.outPath}`)\n  console.log(`  errors log:    ${opts.errorsPath}`)\n\n  // The receiver writes ErrorEvents synchronously before reply (durability).\n  // makeSpanHandler runs on the async queue and skips the inline write\n  // because the receiver already handled it. Ad-hoc callers that bypass the\n  // receiver (CLI tests, fixtures) leave writeErrorEventInline at its default\n  // and get the in-handleSpan write. ADR-033 §Error events.\n  const onSpan = makeSpanHandler({\n    graph,\n    errorsPath: opts.errorsPath,\n    scanPath: opts.scanPath,\n    project: projectName,\n    writeErrorEventInline: false,\n    onPolicyTrigger,\n  })\n  const onErrorSpanSync = makeErrorSpanWriter(opts.errorsPath, graph, opts.scanPath, projectName)\n  const otelHttp = await buildOtelReceiver({ onSpan, onErrorSpanSync })\n  // A held OTLP port steps to the next free one rather than crashing the watch\n  // process (daemon.md §Binding). The real bound port is what daemon.json\n  // records below, so the instrumented app's otel-init resolves the right one.\n  const otelAddress = await listenSteppingOtlp(otelHttp, otelPort, host)\n  const boundOtelPort = portFromListenAddress(otelAddress, otelPort)\n  console.log(`neat-core OTLP receiver on ${otelAddress}/v1/traces`)\n\n  // Self-description (project-daemon §2). `neat watch` is a per-project daemon\n  // in the dev loop: the generated otel-init resolves its OTLP endpoint from\n  // `<project>/neat-out/daemon.json` `ports.otlp`, so an app instrumented\n  // against a watch bound to a non-default (or stepped) OTLP port would fall\n  // back to `:4318` and dark OBSERVED without this record.\n  const boundRestPort = portFromListenAddress(restAddress, port)\n  const daemonRecord: DaemonRecord = {\n    project: projectName,\n    projectPath: opts.scanPath,\n    pid: process.pid,\n    status: 'running',\n    ports: {\n      rest: boundRestPort,\n      otlp: boundOtelPort,\n      // watch serves no dashboard of its own; record the canonical web port so\n      // the record shape is valid. Only ports.otlp is load-bearing here.\n      web: DEFAULT_WATCH_WEB_PORT,\n    },\n    startedAt: new Date().toISOString(),\n    neatVersion: resolveNeatVersion(),\n  }\n  try {\n    await writeDaemonRecord(daemonRecord)\n    console.log(\n      `neat watch: wrote daemon.json (REST ${boundRestPort} / OTLP ${boundOtelPort})`,\n    )\n  } catch (err) {\n    // The record is load-bearing for the OBSERVED layer; without it the app\n    // silently falls back to :4318. Fail loud rather than run half-dark.\n    await api.close().catch(() => {})\n    await otelHttp.close().catch(() => {})\n    throw new Error(\n      `neat watch: failed to write daemon.json — ${(err as Error).message}`,\n    )\n  }\n\n  let grpcReceiver: { stop: () => Promise<void> } | null = null\n  if (opts.otelGrpc) {\n    const grpcPort = opts.otelGrpcPort ?? 4317\n    // gRPC handler keeps the inline ErrorEvent write — the gRPC receiver\n    // awaits onSpan synchronously (otel-grpc.ts), so the same durability\n    // guarantee is met without a separate sync hook. Non-blocking gRPC\n    // ingest is out of scope for the v0.2.2 batch.\n    const onSpanGrpc = makeSpanHandler({\n      graph,\n      errorsPath: opts.errorsPath,\n      scanPath: opts.scanPath,\n      project: projectName,\n      onPolicyTrigger,\n    })\n    const r = await startOtelGrpcReceiver({ onSpan: onSpanGrpc, host, port: grpcPort })\n    console.log(`neat-core OTLP/gRPC receiver on ${r.address}`)\n    grpcReceiver = r\n  }\n\n  // Coalesce bursts of changes into a single re-extract. chokidar fires one\n  // event per affected path; an editor save can produce 3+ events on the same\n  // file in <50ms.\n  const pending = new Set<ExtractPhase>()\n  const pendingPaths = new Set<string>()\n  let timer: NodeJS.Timeout | null = null\n  let inflight: Promise<void> | null = null\n\n  const flush = async (): Promise<void> => {\n    if (pending.size === 0) return\n    const phases = new Set(pending)\n    const paths = new Set(pendingPaths)\n    pending.clear()\n    pendingPaths.clear()\n    try {\n      // Drop EXTRACTED edges keyed to changed paths first, so the producer's\n      // idempotent re-extract recreates only the edges that still apply.\n      // Without this, edges from deleted code would survive forever\n      // (docs/contracts/static-extraction.md §Ghost-edge cleanup).\n      let retired = 0\n      for (const p of paths) retired += retireEdgesByFile(graph, p)\n      const result = await runExtractPhases(graph, opts.scanPath, phases, projectName)\n      console.log(\n        `[watch] re-extract phases=${result.phases.join(',')} retired=${retired} +${result.nodesAdded}n/+${result.edgesAdded}e in ${result.durationMs}ms`,\n      )\n      // extraction-complete after every re-extract pass (ADR-051). fileCount\n      // is the number of paths that drove the pass — closest signal we have\n      // for \"how much source moved\" without per-phase accounting.\n      emitNeatEvent({\n        type: 'extraction-complete',\n        project: projectName,\n        payload: {\n          project: projectName,\n          fileCount: paths.size,\n          nodesAdded: result.nodesAdded,\n          edgesAdded: result.edgesAdded,\n        },\n      })\n      if (searchIndex) {\n        try {\n          await searchIndex.refresh(graph)\n        } catch (err) {\n          console.warn('[watch] semantic_search refresh failed', err)\n        }\n      }\n      // Post-extract policy trigger (ADR-043). The runExtractPhases call\n      // doesn't take the hook directly — it runs through promoteFrontierNodes\n      // for FRONTIER → OBSERVED upgrades but doesn't load policies itself.\n      // Firing the evaluator here keeps the trigger surface symmetric across\n      // ingest / extract / stale paths.\n      await onPolicyTrigger(graph)\n    } catch (err) {\n      console.error('[watch] re-extract failed', err)\n    }\n  }\n\n  const schedule = (): void => {\n    if (timer) clearTimeout(timer)\n    timer = setTimeout(() => {\n      timer = null\n      // Serialise re-extracts so two flushes can't interleave on the graph.\n      inflight = (inflight ?? Promise.resolve()).then(flush)\n    }, debounceMs)\n  }\n\n  const onPath = (absPath: string): void => {\n    if (shouldIgnore(absPath)) return\n    const rel = path.relative(opts.scanPath, absPath)\n    if (!rel || rel.startsWith('..')) return\n    pendingPaths.add(rel.split(path.sep).join('/'))\n    const phases = classifyChange(rel)\n    if (phases.size === 0) {\n      // Unknown file kind — fall back to full re-extract rather than silently\n      // miss it. Cheaper than the user wondering why their change didn't show.\n      for (const p of ALL_PHASES) pending.add(p)\n    } else {\n      for (const p of phases) pending.add(p)\n    }\n    schedule()\n  }\n\n  const usePolling = shouldUsePolling(opts.scanPath)\n  if (usePolling) {\n    const reason =\n      process.env.NEAT_WATCH_POLLING === '1' || process.env.NEAT_WATCH_POLLING === 'true'\n        ? 'NEAT_WATCH_POLLING env override'\n        : 'darwin heuristic — large scan root, kqueue cap risk'\n    console.log(`[${projectName}] watch: usePolling=true (${reason})`)\n  }\n  const watcher: FSWatcher = chokidar.watch(opts.scanPath, {\n    ignoreInitial: true,\n    // Glob array prunes at descent time (#233) so chokidar never opens a\n    // kqueue handle for `node_modules` and friends. The function backstop\n    // catches any path that slipped through and matches the regex set.\n    ignored: [...IGNORED_WATCH_GLOBS, (p: string) => shouldIgnore(p)],\n    persistent: true,\n    usePolling,\n    awaitWriteFinish: { stabilityThreshold: 200, pollInterval: 50 },\n  })\n  watcher.on('add', onPath)\n  watcher.on('change', onPath)\n  watcher.on('unlink', onPath)\n  watcher.on('addDir', onPath)\n  watcher.on('unlinkDir', onPath)\n\n  let stopped = false\n  const stop = async (): Promise<void> => {\n    if (stopped) return\n    stopped = true\n    if (timer) clearTimeout(timer)\n    timer = null\n    if (inflight) {\n      try {\n        await inflight\n      } catch {\n        // surfaced already in flush()\n      }\n    }\n    await watcher.close()\n    stopConnectors()\n    stopK8sSubstrate()\n    stopFlagStores()\n    stopStaleness()\n    stopPersist()\n    detachEventBus()\n    await api.close()\n    await otelHttp.close()\n    if (grpcReceiver) await grpcReceiver.stop()\n    // Reconcile the self-description on shutdown (project-daemon §2) so a\n    // stopped watch never leaves a `running` record pointing an app at a\n    // receiver nothing is listening on.\n    await clearDaemonRecord(daemonRecord).catch(() => {})\n  }\n\n  return { api, stop }\n}\n","import Fastify, {\n  type FastifyInstance,\n  type FastifyReply,\n  type FastifyRequest,\n} from 'fastify'\nimport { timingSafeEqual } from 'node:crypto'\nimport cors from '@fastify/cors'\nimport type {\n  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  Policy,\n  PolicyViolation,\n  ProjectListEntry,\n} from '@neat.is/types'\nimport { DivergenceTypeSchema, PoliciesCheckBodySchema, PolicySeveritySchema } from '@neat.is/types'\nimport type { DivergenceType } from '@neat.is/types'\nimport {\n  applyExtension,\n  describeProjectInstrumentation,\n  dryRunExtension,\n  listUninstrumented,\n  lookupInstrumentation,\n  rollbackExtension,\n} from './extend/index.js'\nimport { computeDivergences } from './divergences.js'\nimport {\n  LOGS_QUERY_DEFAULT_LIMIT,\n  LOGS_QUERY_MAX_LIMIT,\n  queryLogEntries,\n} from './logs-store.js'\nimport {\n  evaluateAllPolicies,\n  loadPolicyFile,\n  PolicyViolationsLog,\n  selectApplicablePolicies,\n} from './policy.js'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { readSourceBaselines, type SourceBaseline } from './extract/source-baseline.js'\nimport { readExtractionHealth, extractionHealthPathFor } from './extract/errors.js'\nimport { readErrorEventById, readErrorEvents, readStaleEvents } from './ingest.js'\nimport {\n  expandNode,\n  getBlastRadius,\n  getObservedDependencies,\n  getRootCause,\n  getTransitiveDependencies,\n  relate,\n  TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n  TRANSITIVE_DEPENDENCIES_MAX_DEPTH,\n} from './traverse.js'\nimport { buildIncidentCard, composeNodeCard } from './goodybag.js'\nimport { askGraph } from './ask.js'\nimport { computeGraphDiff, loadSnapshotForDiff } from './diff.js'\nimport { mergeSnapshot, SnapshotValidationError } from './ingest.js'\nimport { SCHEMA_VERSION, migrateSnapshot, type PersistedGraph } from './persist.js'\nimport type { SearchIndex } from './search.js'\nimport type { Projects, ProjectContext } from './projects.js'\nimport { Projects as ProjectsClass, pathsForProject } from './projects.js'\nimport {\n  findDaemonByProject,\n  getProject as getRegistryProject,\n  listProjects as listRegistryProjects,\n} from './registry.js'\nimport { handleSse, loadIncidentReplay } from './streaming.js'\nimport { BEARER_DELEGATED, mountBearerAuth, readAuthEnv } from './auth.js'\nimport type { RepoSyncRequestResult } from './connectors/hosted-repos.js'\nimport {\n  createPrVerdictRunner,\n  parsePrVerdictRequest,\n  PrVerdictError,\n  type PrVerdictRunner,\n} from './pr-verdict.js'\nimport {\n  connectorMatchesProject,\n  readConnectorsConfig,\n  redactCredentialRef,\n} from './connectors-config.js'\nimport { getConnectorStatus, recordConnectorPoll, sanitizePollError } from './connectors/status.js'\nimport { runConnectorPoll } from './connectors/index.js'\nimport { buildRegistration } from './connectors/registry.js'\n\n// Incident-list bounding (#1083). The incident store is unbounded, so both\n// `/incidents` and `/incidents/:nodeId` must slice before serializing or a busy\n// service's history blows past V8's string ceiling and 500s. Default keeps the\n// response small; the cap is the most a caller can ask for in one page.\nconst INCIDENT_LIST_DEFAULT_LIMIT = 50\nconst INCIDENT_LIST_MAX_LIMIT = 200\n\nexport interface BuildApiOptions {\n  // Multi-project shape. Optional — when absent we synthesise a single-\n  // project registry from the legacy fields below so existing callers\n  // (mainly tests) keep working unchanged.\n  projects?: Projects\n  startedAt?: number\n\n  // Legacy single-project shape. Mapped to project=`default` if `projects`\n  // isn't provided.\n  graph?: NeatGraph\n  scanPath?: string\n  errorsPath?: string\n  staleEventsPath?: string\n  searchIndex?: SearchIndex\n\n  // ADR-073 §3 — bearer token required on `/api/*` and `/events`. Undefined\n  // leaves the middleware off (loopback-only callers; the bind-authority\n  // gate in startDaemon refuses to bind publicly without one).\n  authToken?: string\n  // A separate read credential for the source-free hosted incident stream.\n  // Never give its bridge the general daemon bearer, which can read graphs.\n  incidentStreamToken?: string\n  /** Set only after the hosted substrate restores the complete errors ledger before boot. */\n  incidentReplayDurable?: boolean\n  // ADR-073 §3 — when the operator runs behind a reverse proxy that already\n  // authenticates the request, the daemon-side check is bypassed.\n  trustProxy?: boolean\n  // ADR-073 §3 amendment — public-read mode. When `true`, GET / HEAD / OPTIONS\n  // bypass the bearer check; writes still require it. OTLP ingest is gated\n  // independently and is unaffected by this flag.\n  publicRead?: boolean\n  // The OTLP receiver, when its routes should also answer on this listener.\n  // A host that routes one port per service (Cloud Run) can only reach REST,\n  // so `/v1/traces` has to be here for a tenant app's spans to arrive at all.\n  // A getter because the receiver is built after this app is listening; until\n  // it exists the routes answer 503, which an OTLP exporter retries.\n  otlpReceiver?: () => FastifyInstance | undefined\n  // Issue #340 — per-project bootstrap status. When provided, project-scoped\n  // routes for projects still extracting return 503 with `{ready: false}`\n  // instead of 404.\n  bootstrap?: {\n    status: (name: string) => 'bootstrapping' | 'active' | 'broken' | undefined\n    list: () => Array<{ name: string; status: 'bootstrapping' | 'active' | 'broken'; elapsedMs: number }>\n  }\n  // ADR-096 §4/§5 — the per-project daemon's identity. When set, this daemon\n  // serves exactly this one project: `GET /projects` reports only it (the\n  // dashboard pins to \"the project this daemon serves,\" not a machine-wide\n  // list), and the daemon-wide `/health` carries it at the top level for the\n  // spawn-reuse identity check. Absent → the legacy multi-project daemon, whose\n  // `/projects` is the machine-wide registry passthrough.\n  singleProject?: { name: string; path: string }\n\n  // ADR-136 — the resolved NEAT_HOME the connector-status endpoint\n  // (`GET /:project/connectors`) reads `~/.neat/connectors.json` from. The\n  // daemon passes the same home its slot bootstrap read the file from. Absent\n  // falls back to the env-based resolution in connectors-config.ts (the CLI /\n  // test path), so callers that never touch connectors need not set it.\n  connectorsHome?: string\n  // #1293 — the hosted repo-sync trigger for a project, when one is running.\n  // Returns undefined for a project with no repo-sync (every local daemon), and\n  // the `repo-sync` route answers 404. Called per request, so a slot that comes\n  // up after the listener binds is still found.\n  repoSync?: (project: string) => (() => RepoSyncRequestResult) | undefined\n  // ADR-235 — test seam for the PR-verdict runner (`POST /pr-verdict`). Absent,\n  // the route uses the real one: isomorphic-git clones and the real extractor.\n  prVerdict?: PrVerdictRunner\n  // #871 — test seam for the manual poll trigger (POST /connectors/:id/poll).\n  // Defaults to runConnectorPoll; tests inject a stub so the trigger's wiring\n  // is verifiable without a live provider round-trip.\n  runPoll?: typeof runConnectorPoll\n}\n\ninterface SerializedGraph {\n  nodes: GraphNode[]\n  edges: GraphEdge[]\n  sourceBaselines: SourceBaseline[]\n}\n\nfunction serializeGraph(graph: NeatGraph): SerializedGraph {\n  const nodes: GraphNode[] = []\n  graph.forEachNode((_id, attrs) => {\n    nodes.push(attrs)\n  })\n  const edges: GraphEdge[] = []\n  graph.forEachEdge((_id, attrs) => {\n    edges.push(attrs)\n  })\n  return { nodes, edges, sourceBaselines: readSourceBaselines(graph) }\n}\n\nfunction projectFromReq(\n  req: FastifyRequest,\n  singleProject?: string,\n  registry?: Projects,\n): string {\n  // `:project` is optional in the URL — the request hits either\n  // /projects/:project/X or the unprefixed /X.\n  const params = req.params as { project?: string }\n  const named = params.project\n  // ADR-096 §4 — \"the daemon is the project.\" On a per-project daemon a bare\n  // /X needs no project name to disambiguate: it means this daemon's one\n  // project. The legacy `default` alias maps to it too, so an agent wired with\n  // only NEAT_CORE_URL (no project arg, no NEAT_DEFAULT_PROJECT) reaches the\n  // real project without naming it. An explicit real name still routes as\n  // given.\n  if (singleProject) {\n    return named === undefined || named === DEFAULT_PROJECT ? singleProject : named\n  }\n  if (named !== undefined) return named\n  // Unprefixed against a registry daemon (ADR-229 §4). The same reading holds\n  // whenever there is only one project to mean: a daemon hosting exactly one\n  // resolves a bare /X to it, rather than to the `default` literal — which\n  // answers \"project not found\" to a caller that named no project (#1157).\n  // Several hosted, and the `default` coercion stands, so an explicitly\n  // registered `default` still wins where one exists.\n  const hosted = registry?.list() ?? []\n  return hosted.length === 1 ? hosted[0]! : DEFAULT_PROJECT\n}\n\nfunction resolveProject(\n  registry: Projects,\n  req: FastifyRequest,\n  reply: FastifyReply,\n  bootstrap?: BuildApiOptions['bootstrap'],\n  singleProject?: string,\n): ProjectContext | null {\n  const name = projectFromReq(req, singleProject, registry)\n  const ctx = registry.get(name)\n  if (!ctx) {\n    // Issue #340 — registered but still bootstrapping: surface 503 so the\n    // probe consumer knows the project is real and incoming, not missing.\n    const phase = bootstrap?.status(name)\n    if (phase === 'bootstrapping') {\n      void reply.code(503).send({ ready: false, project: name, status: 'bootstrapping' })\n      return null\n    }\n    if (phase === 'broken') {\n      void reply.code(503).send({ ready: false, project: name, status: 'broken' })\n      return null\n    }\n    // The project isn't in this daemon's hosted set. The shared machine-wide\n    // registry may still know it because another daemon serves it — so a bare\n    // \"project not found\" reads as \"no such project\" when the truth is \"not\n    // here.\" GET /projects marks which projects this core hosts (`hostedHere`);\n    // point the caller there rather than let it trust the wrong daemon (#884).\n    // An unprefixed request that landed on the `default` coercion never named a\n    // project, so \"does not host that project\" describes a name the caller\n    // didn't choose. Where several are hosted and none is `default`, name them\n    // (ADR-229 §4) rather than send the caller to GET /projects to find out.\n    const unnamed = (req.params as { project?: string }).project === undefined\n    const hosted = registry.list()\n    const hint =\n      unnamed && name === DEFAULT_PROJECT && hosted.length > 1\n        ? `This daemon hosts ${hosted.length} projects and none is named \\`default\\`: ${hosted.join(', ')}. Name one as /projects/<name>/… , or reach that project's own daemon.`\n        : 'This daemon does not host that project. GET /projects lists what it serves (see hostedHere).'\n    void reply.code(404).send({\n      error: 'project not found',\n      project: name,\n      hint,\n    })\n    return null\n  }\n  return ctx\n}\n\nfunction buildLegacyRegistry(opts: BuildApiOptions): Projects {\n  if (opts.projects) return opts.projects\n  if (!opts.graph) {\n    throw new Error('buildApi: either `projects` or `graph` must be provided')\n  }\n  const registry = new ProjectsClass()\n  // pathsForProject only matters here for the snapshot/embeddings paths\n  // routes never read; the ingest paths come from explicit options below.\n  const paths = pathsForProject(DEFAULT_PROJECT, '')\n  registry.set(DEFAULT_PROJECT, {\n    graph: opts.graph,\n    scanPath: opts.scanPath,\n    paths: {\n      snapshotPath: paths.snapshotPath,\n      errorsPath: opts.errorsPath ?? paths.errorsPath,\n      staleEventsPath: opts.staleEventsPath ?? paths.staleEventsPath,\n      embeddingsCachePath: paths.embeddingsCachePath,\n      policyViolationsPath: paths.policyViolationsPath,\n    },\n    searchIndex: opts.searchIndex,\n  })\n  return registry\n}\n\ninterface RouteContext {\n  registry: Projects\n  startedAt: number\n  incidentStreamToken?: string\n  incidentReplayDurable: boolean\n  generalAuthToken?: string\n  // Where the routes are getting mounted. `'root'` is the legacy unprefixed\n  // mount that historically resolved every request to the `default` project;\n  // `'project'` is the `/projects/:project` plugin scope where the project\n  // segment is always present. The /health handler branches on this so the\n  // root mount can answer daemon-wide while the scoped mount stays\n  // per-project (issue #343).\n  scope: 'root' | 'project'\n  // Legacy callers passed `errorsPath`/`staleEventsPath` explicitly and\n  // expected absent values to disable the read. Track that intent so the\n  // /incidents handlers don't accidentally read a phantom file.\n  errorsPathFor: (ctx: ProjectContext) => string | undefined\n  staleEventsPathFor: (ctx: ProjectContext) => string | undefined\n  // policy.json lives at the project root (per ADR-042 §File location), not\n  // under neat-out/. Routes that read it map a project context to the path.\n  policyFilePathFor: (ctx: ProjectContext) => string | undefined\n  // Issue #340 — flips per-project routes from 404 to 503 while a slot is\n  // still extracting.\n  bootstrap?: BuildApiOptions['bootstrap']\n  // ADR-096 §4 — the per-project daemon's one project. When set, unprefixed\n  // (and `default`-named) requests resolve to it instead of the `default`\n  // project. Absent for the legacy multi-project daemon.\n  singleProject?: string\n  // #1293 — the on-demand repo-sync trigger for a project, when it has one.\n  repoSync?: BuildApiOptions['repoSync']\n  // ADR-235 — computes a PR verdict. One runner for the whole daemon, shared by\n  // both mounts, so its one-at-a-time limit holds across them.\n  prVerdict: PrVerdictRunner\n  // ADR-136 — where the connector-status route reads connectors.json from.\n  // Undefined uses connectors-config.ts's env-based home resolution.\n  connectorsHome?: string\n  // #871 — the poll executor the manual trigger runs; defaults to\n  // runConnectorPoll, overridable for tests.\n  runPoll: typeof runConnectorPoll\n}\n\n// Registers every project-scoped route on `scope`. Called twice from\n// buildApi: once on the root app (so /graph etc. land at default), once\n// inside a `register(_, { prefix: '/projects/:project' })` plugin so the\n// same handlers run when the URL names a project explicitly.\nfunction registerRoutes(scope: FastifyInstance, ctx: RouteContext): void {\n  const { registry, startedAt, errorsPathFor, staleEventsPathFor } = ctx\n\n  // SSE event stream (ADR-051 #1). Dual-mounted: hits /events for default\n  // project and /projects/:project/events when scoped. The handler keeps\n  // the connection open and writes one frame per bus envelope whose\n  // `project` matches.\n  scope.get<{ Params: { project?: string } }>('/events', (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    handleSse(req, reply, { project: proj.name })\n  })\n\n  // Hosted Sniper consumes only the lean incident trigger. This route has its\n  // own bearer check, including when ordinary graph GETs are public-read or\n  // authenticated by a proxy. The general /events stream can carry graph\n  // attributes and must never be used by an external trigger bridge.\n  scope.get<{ Params: { project?: string } }>(\n    '/incident-triggers',\n    { config: BEARER_DELEGATED },\n    (req, reply) => {\n      const token = ctx.incidentStreamToken\n      if (!token || Buffer.byteLength(token, 'utf8') < 32 || token === ctx.generalAuthToken || !ctx.incidentReplayDurable) {\n        return reply.code(503).send({ error: 'incident trigger stream unavailable' })\n      }\n      const header = req.headers.authorization\n      const supplied = typeof header === 'string' && header.startsWith('Bearer ')\n        ? Buffer.from(header.slice('Bearer '.length), 'utf8')\n        : undefined\n      const expected = Buffer.from(token, 'utf8')\n      if (!supplied || supplied.length !== expected.length || !timingSafeEqual(supplied, expected)) {\n        return reply.code(401).send({ error: 'unauthorized' })\n      }\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const errorsPath = errorsPathFor(proj)\n      if (!errorsPath) return reply.code(503).send({ error: 'incident replay unavailable' })\n      let replay: ReturnType<typeof loadIncidentReplay>\n      try {\n        const cursor = req.headers['last-event-id']\n        if (Array.isArray(cursor)) throw new Error('invalid cursor')\n        replay = loadIncidentReplay(errorsPath, cursor)\n      } catch { return reply.code(409).send({ error: 'incident replay unavailable' }) }\n      handleSse(req, reply, { project: proj.name, incidentOnly: true, incidentReplay: replay })\n    },\n  )\n\n  // Per-project /health stays scoped. The unscoped `/health` at the root\n  // mount is handled by the daemon-wide handler below (issue #343) —\n  // daemon-wide readiness mustn't pivot on whether the `default` project\n  // exists. The scoped variant carries the bootstrap-aware shape from\n  // issue #340.\n  if (ctx.scope === 'project') {\n    scope.get<{ Params: { project?: string } }>('/health', async (req, reply) => {\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const uptimeMs = Date.now() - startedAt\n      // #883 — surface the most recent extraction pass's coverage so a caller\n      // can tell the graph is partial. Best-effort: absent sidecar → no field,\n      // never an error.\n      const coverage = await readExtractionHealth(\n        extractionHealthPathFor(proj.paths.errorsPath),\n      )\n      return {\n        ok: true,\n        project: proj.name,\n        uptimeMs,\n        // Legacy fields kept additively. The web shell's StatusBar reads\n        // nodeCount / edgeCount; ADR-061's HealthResponseSchema validates\n        // the canonical triple and lets the extras pass through.\n        uptime: Math.floor(uptimeMs / 1000),\n        nodeCount: proj.graph.order,\n        edgeCount: proj.graph.size,\n        lastUpdated: new Date().toISOString(),\n        ...(coverage ? { coverage } : {}),\n      }\n    })\n  }\n\n  scope.get<{ Params: { project?: string } }>('/graph', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    return serializeGraph(proj.graph)\n  })\n\n  scope.get<{ Params: { project?: string; id: string } }>(\n    '/graph/node/:id',\n    async (req, reply) => {\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const { id } = req.params\n      if (!proj.graph.hasNode(id)) {\n        return reply.code(404).send({ error: 'node not found', id })\n      }\n      return { node: proj.graph.getNodeAttributes(id) as GraphNode }\n    },\n  )\n\n  scope.get<{ Params: { project?: string; id: string } }>(\n    '/graph/edges/:id',\n    async (req, reply) => {\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const { id } = req.params\n      if (!proj.graph.hasNode(id)) {\n        return reply.code(404).send({ error: 'node not found', id })\n      }\n      const inbound = proj.graph\n        .inboundEdges(id)\n        .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n      const outbound = proj.graph\n        .outboundEdges(id)\n        .map((e) => proj.graph.getEdgeAttributes(e) as GraphEdge)\n      return { inbound, outbound }\n    },\n  )\n\n  // Transitive dependencies (issue #144). BFS outbound to depth N, returning\n  // a flat list with distance + edgeType + provenance per dependency.\n  // Default depth 3, max 10. The MCP get_dependencies tool calls this.\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { depth?: string }\n  }>('/graph/dependencies/:nodeId', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { nodeId } = req.params\n    if (!proj.graph.hasNode(nodeId)) {\n      return reply.code(404).send({ error: 'node not found', id: nodeId })\n    }\n    const depth = req.query.depth ? Number(req.query.depth) : TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH\n    if (!Number.isFinite(depth) || depth < 1 || depth > TRANSITIVE_DEPENDENCIES_MAX_DEPTH) {\n      return reply.code(400).send({\n        error: `depth must be an integer in [1, ${TRANSITIVE_DEPENDENCIES_MAX_DEPTH}]`,\n      })\n    }\n    return getTransitiveDependencies(proj.graph, nodeId, depth)\n  })\n\n  // Observed-only dependencies (issue #578). The runtime CALLS a node makes,\n  // file-grained — and, for a ServiceNode, the OBSERVED edges of the files it\n  // owns, since the call-site processor lands them on files, not the service\n  // root. REST parity for the MCP get_observed_dependencies tool (issue #593);\n  // the CLI observed-dependencies verb reads it too.\n  scope.get<{ Params: { project?: string; nodeId: string } }>(\n    '/graph/observed-dependencies/:nodeId',\n    async (req, reply) => {\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const { nodeId } = req.params\n      if (!proj.graph.hasNode(nodeId)) {\n        return reply.code(404).send({ error: 'node not found', id: nodeId })\n      }\n      return getObservedDependencies(proj.graph, nodeId)\n    },\n  )\n\n  // Divergence query — the thesis surface (ADR-060). Read-only, derived,\n  // dual-mounted via registerRoutes. Query params filter the result set;\n  // body shape is DivergenceResult.\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { type?: string; minConfidence?: string; node?: string }\n  }>('/graph/divergences', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    let typeFilter: Set<DivergenceType> | undefined\n    if (req.query.type) {\n      const candidates = req.query.type\n        .split(',')\n        .map((s) => s.trim())\n        .filter((s) => s.length > 0)\n      const parsed: DivergenceType[] = []\n      for (const c of candidates) {\n        const r = DivergenceTypeSchema.safeParse(c)\n        if (!r.success) {\n          return reply.code(400).send({\n            error: `unknown divergence type \"${c}\"`,\n            allowed: DivergenceTypeSchema.options,\n          })\n        }\n        parsed.push(r.data)\n      }\n      typeFilter = new Set(parsed)\n    }\n    let minConfidence: number | undefined\n    if (req.query.minConfidence !== undefined) {\n      const n = Number(req.query.minConfidence)\n      if (!Number.isFinite(n) || n < 0 || n > 1) {\n        return reply.code(400).send({\n          error: 'minConfidence must be a number in [0, 1]',\n        })\n      }\n      minConfidence = n\n    }\n    // Symbol/field-grain divergence (ADR-215) fuses the recorded incidents with\n    // the graph, so read the sidecar and hand the array in. The read stays here\n    // at the call site; computeDivergences stays pure. Absent/empty leaves the\n    // edge-grain result identical.\n    const epath = errorsPathFor(proj)\n    const incidents = epath ? await readErrorEvents(epath) : []\n    return computeDivergences(proj.graph, {\n      ...(typeFilter ? { type: typeFilter } : {}),\n      ...(minConfidence !== undefined ? { minConfidence } : {}),\n      ...(req.query.node ? { node: req.query.node } : {}),\n      incidents,\n    })\n  })\n\n  // ADR-061 envelope rule: list endpoints return { count, total, events }.\n  // `total` is the size of the underlying collection; `count` is the size of\n  // the slice we're handing back. The web shell counts on both.\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { limit?: string; since?: string }\n  }>('/incidents', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const epath = errorsPathFor(proj)\n    if (!epath) return { count: 0, total: 0, events: [] }\n    // `since` (ISO8601) keeps the incidents stamped at or after it, before the\n    // limit applies, so a caller asking \"anything live?\" sees the newest ones\n    // however long the ledger is (ADR-261). An unparseable value is a 400.\n    let events = await readErrorEvents(epath)\n    if (req.query.since !== undefined) {\n      const sinceMs = Date.parse(req.query.since)\n      if (!Number.isFinite(sinceMs)) {\n        return reply.code(400).send({ error: 'since must be an ISO8601 timestamp' })\n      }\n      events = events.filter((e) => {\n        const t = Date.parse(e.timestamp)\n        return Number.isFinite(t) && t >= sinceMs\n      })\n    }\n    const total = events.length\n    const limit = req.query.limit ? Number(req.query.limit) : INCIDENT_LIST_DEFAULT_LIMIT\n    const safeLimit =\n      Number.isFinite(limit) && limit > 0\n        ? Math.min(limit, INCIDENT_LIST_MAX_LIMIT)\n        : INCIDENT_LIST_DEFAULT_LIMIT\n    const sliced = events.slice(0, safeLimit)\n    const omitted = total - sliced.length\n    return { count: sliced.length, total, events: sliced, ...(omitted > 0 ? { omitted } : {}) }\n  })\n\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { limit?: string; edgeType?: string }\n  }>('/stale-events', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const spath = staleEventsPathFor(proj)\n    if (!spath) return { count: 0, total: 0, events: [] }\n    const events = await readStaleEvents(spath)\n    const filtered = req.query.edgeType\n      ? events.filter((e) => e.edgeType === req.query.edgeType)\n      : events\n    const ordered = [...filtered].reverse()\n    const total = ordered.length\n    const limit = req.query.limit ? Number(req.query.limit) : 50\n    const sliced = ordered.slice(0, Number.isFinite(limit) && limit > 0 ? limit : 50)\n    return { count: sliced.length, total, events: sliced }\n  })\n\n  // Logs surface (docs/contracts/logs.md, ADR-132). Reads the bounded\n  // per-(project, source) ring buffer in logs-store.ts — the only REST\n  // surface allowed to; MCP's get_logs and the CLI's `neat logs` are meant\n  // to call this endpoint rather than the store directly. `source` is\n  // repeatable (?source=supabase&source=railway); `service`/`since` filter\n  // before the `limit` cap, so `total` reflects the filtered-but-unlimited\n  // size per the ADR-061 envelope rule.\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { source?: string | string[]; service?: string; limit?: string; since?: string }\n  }>('/logs', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const rawSource = req.query.source\n    const sources =\n      rawSource === undefined ? undefined : Array.isArray(rawSource) ? rawSource : [rawSource]\n    const filtered = queryLogEntries({\n      projectName: proj.name,\n      ...(sources && sources.length > 0 ? { source: sources } : {}),\n      ...(req.query.service ? { service: req.query.service } : {}),\n      ...(req.query.since ? { since: req.query.since } : {}),\n    })\n    const total = filtered.length\n    const limit = req.query.limit ? Number(req.query.limit) : LOGS_QUERY_DEFAULT_LIMIT\n    const safeLimit =\n      Number.isFinite(limit) && limit > 0\n        ? Math.min(limit, LOGS_QUERY_MAX_LIMIT)\n        : LOGS_QUERY_DEFAULT_LIMIT\n    const sliced = filtered.slice(0, safeLimit)\n    return { count: sliced.length, total, logs: sliced }\n  })\n\n  // Connector status (docs/contracts/rest-api.md, connectors.md §8, ADR-136).\n  // Read-only view backing the web GUI's connector view: the connectors\n  // configured for this project in ~/.neat/connectors.json, each with its\n  // credential redacted to the env-ref pointer (never a resolved secret) and\n  // the live poll health the in-process status tracker recorded. Reads the live\n  // config file, never the graph; dual-mounted per ADR-026 like every route.\n  scope.get<{ Params: { project?: string } }>('/connectors', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    let entries\n    try {\n      entries = (await readConnectorsConfig(ctx.connectorsHome)).connectors\n    } catch (err) {\n      return reply.code(500).send({\n        error: 'connectors.json failed to read',\n        details: (err as Error).message,\n      })\n    }\n    const connectors = entries\n      .filter((entry) => connectorMatchesProject(entry, proj.name))\n      .map((entry) => ({\n        id: entry.id,\n        provider: entry.provider,\n        credentialRef: redactCredentialRef(entry.credential),\n        status: getConnectorStatus(entry.id),\n      }))\n    return { connectors }\n  })\n\n  // #871 — trigger one poll of a connector on demand. An operator verifying a\n  // freshly-added connector shouldn't have to wait a full interval (and, before\n  // the poll loop wired up under `neat watch`, waited forever with no way to\n  // force or diagnose a tick). Reuses the exact buildRegistration + runConnectorPoll\n  // the background loop uses, against this project's live graph; the outcome lands\n  // in the same status tracker GET /connectors reads, so the two surfaces agree.\n  scope.post<{ Params: { project?: string; id: string } }>(\n    '/connectors/:id/poll',\n    async (req, reply) => {\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const { id } = req.params\n      let entries\n      try {\n        entries = (await readConnectorsConfig(ctx.connectorsHome)).connectors\n      } catch (err) {\n        return reply\n          .code(500)\n          .send({ error: 'connectors.json failed to read', details: (err as Error).message })\n      }\n      const entry = entries.find((e) => e.id === id && connectorMatchesProject(e, proj.name))\n      if (!entry) {\n        return reply.code(404).send({ error: 'connector not found', id, project: proj.name })\n      }\n      const built = buildRegistration(entry, proj.graph, process.env)\n      if (!built.ok) {\n        // A push provider (Vercel) has nothing to poll — its data arrives via\n        // the OTLP receiver — so that's a 409, distinct from a genuinely broken\n        // entry (unknown provider / missing field / unresolved credential) → 400.\n        return reply\n          .code(built.push ? 409 : 400)\n          .send({ error: built.reason, id, push: built.push ?? false })\n      }\n      const reg = built.registration\n      const at = new Date().toISOString()\n      // Same incident ledger the background poll loop writes to (ADR-185), so a\n      // manual poll of an incident-emitting connector lands its build-failure\n      // incident too rather than dropping it.\n      const incidentsPath = errorsPathFor(proj)\n      try {\n        const result = await ctx.runPoll(\n          reg.connector,\n          {\n            projectDir: proj.scanPath ?? '',\n            project: proj.name,\n            credentials: reg.credentials,\n            ...(incidentsPath ? { errorsPath: incidentsPath } : {}),\n          },\n          proj.graph,\n          reg.resolveTarget,\n        )\n        recordConnectorPoll(id, { outcome: 'ok', at, signalsLastPoll: result.signalCount })\n        return { id, outcome: 'ok', signalsLastPoll: result.signalCount, status: getConnectorStatus(id) }\n      } catch (err) {\n        const error = sanitizePollError(err)\n        recordConnectorPoll(id, { outcome: 'error', at, error })\n        return reply.code(502).send({ id, outcome: 'error', error, status: getConnectorStatus(id) })\n      }\n    },\n  )\n\n  // One handler, two paths: `/incidents/:nodeId` is the original REST name and\n  // `/graph/incident-history/:nodeId` mirrors the MCP get_incident_history tool\n  // so the two surfaces answer under matching names (issue #593).\n  const incidentHistoryHandler = async (\n    req: FastifyRequest<{\n      Params: { project?: string; nodeId: string }\n      Querystring: { limit?: string }\n    }>,\n    reply: FastifyReply,\n  ): Promise<\n    { count: number; total: number; events: ErrorEvent[]; omitted?: number } | undefined\n  > => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { nodeId } = req.params\n    if (!proj.graph.hasNode(nodeId)) {\n      reply.code(404).send({ error: 'node not found', id: nodeId })\n      return\n    }\n    const epath = errorsPathFor(proj)\n    if (!epath) return { count: 0, total: 0, events: [] }\n    // Bounded read + bounded slice (#1083). A busy service accumulates far more\n    // incidents than any caller needs; serializing the whole filtered set is what\n    // 500'd get_incident_history on a long-running daemon. Return the most-recent\n    // page and mark how many older ones we held back.\n    const events = await readErrorEvents(epath)\n    const filtered = events.filter(\n      (e) =>\n        e.affectedNode === nodeId || e.service === nodeId.replace(/^service:/, ''),\n    )\n    const total = filtered.length\n    const limit = req.query.limit ? Number(req.query.limit) : INCIDENT_LIST_DEFAULT_LIMIT\n    const safeLimit =\n      Number.isFinite(limit) && limit > 0\n        ? Math.min(limit, INCIDENT_LIST_MAX_LIMIT)\n        : INCIDENT_LIST_DEFAULT_LIMIT\n    // Newest first — \"recent ErrorEvents filtered to a node\" per the REST contract.\n    const recent = [...filtered]\n      .sort((a, b) => (b.timestamp ?? '').localeCompare(a.timestamp ?? ''))\n      .slice(0, safeLimit)\n    const omitted = total - recent.length\n    return {\n      count: recent.length,\n      total,\n      events: recent,\n      ...(omitted > 0 ? { omitted } : {}),\n    }\n  }\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { limit?: string }\n  }>('/incidents/:nodeId', incidentHistoryHandler)\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { limit?: string }\n  }>('/graph/incident-history/:nodeId', incidentHistoryHandler)\n\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { errorId?: string }\n  }>('/graph/root-cause/:nodeId', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { nodeId } = req.params\n    if (!proj.graph.hasNode(nodeId)) {\n      return reply.code(404).send({ error: 'node not found', id: nodeId })\n    }\n    // Load the incident store so root-cause can localize an in-process failure\n    // that never crossed a graph edge (#584). When errorId is supplied the\n    // named incident colours the reason; the full set is the fallback the graph\n    // walk consults when no edge carried an incompatibility.\n    const epath = errorsPathFor(proj)\n    const incidents = epath ? await readErrorEvents(epath) : []\n    let errorEvent: ErrorEvent | undefined\n    if (req.query.errorId) {\n      errorEvent = incidents.find((e) => e.id === req.query.errorId)\n      if (!errorEvent) {\n        return reply\n          .code(404)\n          .send({ error: 'error event not found', id: req.query.errorId })\n      }\n    }\n    const result = getRootCause(proj.graph, nodeId, errorEvent, incidents)\n    if (!result) return reply.code(404).send({ error: 'no root cause found', id: nodeId })\n    return result\n  })\n\n  // The incident card (ADR-221, incident-card.md) — one composed work order for\n  // an incident on this node. Backs both the get_incident_card MCP tool (pull)\n  // and the monitor's incident fact kind (push, which passes ?errorId= for the\n  // exact incident its bus event carried). Default (no errorId) is the node's\n  // most-recent incident, and a node with none gets the same card composed from\n  // the graph (ADR-244) rather than a 404. The incident read is tail-bounded in readErrorEvents\n  // (#1083); the response is a single card, never the incident store.\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { errorId?: string }\n  }>('/graph/incident-card/:nodeId', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { nodeId } = req.params\n    if (!proj.graph.hasNode(nodeId)) {\n      return reply.code(404).send({ error: 'node not found', id: nodeId })\n    }\n    const epath = errorsPathFor(proj)\n    const incidents = epath ? await readErrorEvents(epath) : []\n    let errorEvent: ErrorEvent | undefined\n    if (req.query.errorId) {\n      errorEvent = incidents.find((e) => e.id === req.query.errorId)\n        ?? (epath ? await readErrorEventById(epath, req.query.errorId) : undefined)\n      if (!errorEvent) {\n        return reply.code(404).send({ error: 'error event not found', id: req.query.errorId })\n      }\n    } else {\n      // The node's most-recent incident (newest timestamp), matched the same way\n      // the incident-history handler matches: the affected node, or a service id.\n      const svc = nodeId.replace(/^service:/, '')\n      errorEvent = [...incidents]\n        .filter((e) => e.affectedNode === nodeId || e.service === svc)\n        .sort((a, b) => (b.timestamp ?? '').localeCompare(a.timestamp ?? ''))[0]\n      // No recorded incident: the same card, composed from the graph (ADR-244).\n    }\n    // Applicable policies ride into the card as context (soft guardrail, ADR-108).\n    // A malformed policy file degrades to no policies rather than failing the card.\n    const policyPath = ctx.policyFilePathFor(proj)\n    let policies: Policy[] = []\n    if (policyPath) {\n      try {\n        policies = await loadPolicyFile(policyPath)\n      } catch {\n        policies = []\n      }\n    }\n    return errorEvent\n      ? buildIncidentCard(proj.graph, errorEvent, incidents, policies)\n      : composeNodeCard(proj.graph, nodeId, incidents, policies)\n  })\n\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { depth?: string }\n  }>('/graph/blast-radius/:nodeId', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { nodeId } = req.params\n    if (!proj.graph.hasNode(nodeId)) {\n      return reply.code(404).send({ error: 'node not found', id: nodeId })\n    }\n    const depth = req.query.depth ? Number(req.query.depth) : undefined\n    if (depth !== undefined && (!Number.isFinite(depth) || depth < 0)) {\n      return reply.code(400).send({ error: 'depth must be a non-negative number' })\n    }\n    return getBlastRadius(proj.graph, nodeId, depth)\n  })\n\n  // Expand — one bidirectional navigation step (ADR-189). up = inbound\n  // (callers/dependents), down = outbound (callees/dependencies). Incidents\n  // sharpen the per-node classification, same store the root-cause route loads.\n  scope.get<{\n    Params: { project?: string; nodeId: string }\n    Querystring: { direction?: string }\n  }>('/graph/expand/:nodeId', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { nodeId } = req.params\n    if (!proj.graph.hasNode(nodeId)) {\n      return reply.code(404).send({ error: 'node not found', id: nodeId })\n    }\n    const direction = req.query.direction\n    if (direction !== 'up' && direction !== 'down') {\n      return reply.code(400).send({ error: 'direction must be \"up\" or \"down\"' })\n    }\n    const epath = errorsPathFor(proj)\n    const incidents = epath ? await readErrorEvents(epath) : []\n    return expandNode(proj.graph, nodeId, direction, incidents)\n  })\n\n  // Relate — pairwise directed link-confirmation (ADR-189). Does a path run\n  // between a and b, which way, and does it carry the failure end to end.\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { a?: string; b?: string; maxDepth?: string }\n  }>('/graph/relate', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { a, b } = req.query\n    if (!a || !b) {\n      return reply.code(400).send({ error: 'both a and b query params are required' })\n    }\n    const maxDepth = req.query.maxDepth ? Number(req.query.maxDepth) : undefined\n    if (maxDepth !== undefined && (!Number.isFinite(maxDepth) || maxDepth < 1)) {\n      return reply.code(400).send({ error: 'maxDepth must be a positive integer' })\n    }\n    return relate(proj.graph, a, b, maxDepth)\n  })\n\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { q?: string; limit?: string }\n  }>('/search', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const raw = (req.query.q ?? '').trim()\n    if (!raw) return reply.code(400).send({ error: 'query parameter `q` is required' })\n    const limit = req.query.limit ? Number(req.query.limit) : undefined\n    const safeLimit =\n      limit !== undefined && Number.isFinite(limit) && limit > 0 ? limit : undefined\n    if (proj.searchIndex) {\n      const result = await proj.searchIndex.search(raw, safeLimit)\n      return {\n        query: result.query,\n        provider: result.provider,\n        matches: result.matches.map((m) => ({ ...m.node, score: m.score })),\n      }\n    }\n    const q = raw.toLowerCase()\n    const matches: (GraphNode & { score: number })[] = []\n    proj.graph.forEachNode((id, attrs) => {\n      const name = (attrs as { name?: string }).name ?? ''\n      if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n        matches.push({ ...(attrs as GraphNode), score: 1 })\n      }\n    })\n    return {\n      query: q,\n      provider: 'substring' as const,\n      matches: matches.slice(0, safeLimit),\n    }\n  })\n\n  // ask — the plain-language door (ADR-198). Resolves the question to nodes and\n  // routes it to the existing traversals, answering with one compact,\n  // provenance-tagged payload. It reads the same search index the /search route\n  // holds (so entity resolution gets the embedder) and the same incident store\n  // root-cause reads. Deterministic — no LLM (llm-policy.md); the agent that\n  // calls it is the only model.\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { q?: string }\n  }>('/graph/ask', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const question = (req.query.q ?? '').trim()\n    if (!question) return reply.code(400).send({ error: 'query parameter `q` is required' })\n    const epath = errorsPathFor(proj)\n    const incidents = epath ? await readErrorEvents(epath) : []\n    return askGraph(proj.graph, question, {\n      ...(proj.searchIndex ? { searchIndex: proj.searchIndex } : {}),\n      incidents,\n    })\n  })\n\n  scope.get<{ Params: { project?: string }; Querystring: { against?: string } }>(\n    '/graph/diff',\n    async (req, reply) => {\n      const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n      if (!proj) return\n      const against = req.query.against\n      if (!against) {\n        return reply.code(400).send({ error: 'query parameter `against` is required' })\n      }\n      // Security (#693): `against` used to be handed straight to\n      // `loadSnapshotForDiff`, which `fetch()`es any `http(s)` URL and\n      // otherwise reads whatever filesystem path it's given — a live\n      // SSRF/LFI vector once this route is reachable without auth (public-read\n      // mode). `against` now only ever resolves to a snapshot the server\n      // already manages: `self` (this project's own on-disk snapshot, written\n      // by the persist loop / `neat sync`) or the name of another project\n      // this same daemon is tracking. Either way the string is looked up in\n      // the registry map, never concatenated into a path or handed to\n      // `fetch()` — anything that doesn't match a known project is a 400.\n      const targetProjectName = against === 'self' ? proj.name : against\n      const targetProject = registry.get(targetProjectName)\n      if (!targetProject) {\n        return reply.code(400).send({\n          error:\n            'unknown snapshot id — `against` must be `self` or the name of a project this server has a snapshot for',\n          against,\n        })\n      }\n      try {\n        const snapshot = await loadSnapshotForDiff(targetProject.paths.snapshotPath)\n        return computeGraphDiff(proj.graph, snapshot)\n      } catch (err) {\n        return reply\n          .code(400)\n          .send({ error: 'failed to load snapshot', against, detail: (err as Error).message })\n      }\n    },\n  )\n\n  // Snapshot push (ADR-074 §1). `neat sync` POSTs a snapshot here; we merge\n  // it into the live graph through `mergeSnapshot`, which preserves any\n  // accumulated OBSERVED edges per the Rule 2 coexistence contract. Body\n  // shape is the same JSON `persist.ts` writes to disk. Dual-mounted at\n  // `/snapshot` and `/projects/:project/snapshot` via registerRoutes.\n  scope.post<{\n    Params: { project?: string }\n    Body: { snapshot?: PersistedGraph }\n  }>('/snapshot', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const body = req.body\n    if (!body || typeof body !== 'object' || !body.snapshot) {\n      return reply\n        .code(400)\n        .send({ error: 'request body must be { snapshot: <persisted-graph> }' })\n    }\n    const snap = body.snapshot\n    if (typeof snap.schemaVersion !== 'number') {\n      return reply.code(400).send({\n        error: `unsupported snapshot schemaVersion ${snap.schemaVersion} (expected ${SCHEMA_VERSION})`,\n      })\n    }\n    // Bring an older push forward the same way a snapshot read off disk is\n    // brought forward (#1307). This used to demand exact equality, so a single\n    // schema bump made `neat sync --to` answer 400 for every CLI already\n    // published — the hosted push route included, which is the one a user is\n    // handed right after `neat login`. The migrations were sitting in\n    // `persist.ts` the whole time; the endpoint just had no way to reach them.\n    //\n    // A snapshot NEWER than this daemon still fails: there is nothing to migrate\n    // down to, and merging a shape this build doesn't know would be a guess.\n    let migrated: PersistedGraph\n    try {\n      migrated = migrateSnapshot(snap)\n    } catch {\n      return reply.code(400).send({\n        error: `unsupported snapshot schemaVersion ${snap.schemaVersion} (expected ${SCHEMA_VERSION})`,\n      })\n    }\n    try {\n      const result = mergeSnapshot(proj.graph, migrated)\n      return {\n        project: proj.name,\n        nodesAdded: result.nodesAdded,\n        edgesAdded: result.edgesAdded,\n        nodeCount: proj.graph.order,\n        edgeCount: proj.graph.size,\n      }\n    } catch (err) {\n      // A malformed node/edge (wrong `type` literal, missing required field,\n      // ...) fails GraphNodeSchema/GraphEdgeSchema validation inside\n      // mergeSnapshot and rejects the whole snapshot rather than merging the\n      // valid entries and silently dropping the rest. `issues` carries one\n      // entry per invalid node/edge so the caller can see exactly what was\n      // wrong instead of guessing from a single summary string.\n      if (err instanceof SnapshotValidationError) {\n        return reply.code(400).send({\n          error: 'snapshot merge failed',\n          details: err.message,\n          issues: err.issues,\n        })\n      }\n      return reply.code(400).send({\n        error: 'snapshot merge failed',\n        details: (err as Error).message,\n      })\n    }\n  })\n\n  // Run a hosted repo-sync pass now (#1293). The daemon syncs its bound repos at\n  // boot and on a timer; this is what the control plane calls after a bind, a\n  // Resync or a push so none of them waits for the timer. It answers at once —\n  // a clone and an extraction can run for minutes — with whether a pass started\n  // or was queued behind the one running, and how the last finished pass went.\n  // The request itself is also what wakes a tenant that has scaled to zero.\n  scope.post<{ Params: { project?: string } }>('/repo-sync', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const syncNow = ctx.repoSync?.(proj.name)\n    if (!syncNow) {\n      return reply.code(404).send({\n        error: 'repo-sync is not running for this project',\n        project: proj.name,\n        hint: 'Only a hosted daemon syncs bound repos. On a local daemon, POST /graph/scan re-extracts the project path.',\n      })\n    }\n    return reply.code(202).send({ project: proj.name, ...syncNow() })\n  })\n\n  // The PR verdict (ADR-235). Given a pull request's base and head commits for\n  // a repo, clone both, extract each into a scratch graph, diff them, read the\n  // OBSERVED half from this project's live graph, and return the comment the\n  // Action would post — rendered by the Action's own code. This is how the\n  // hosted GitHub App gets a verdict without an engine in the control plane.\n  // It answers when the work is done; the live graph is only read.\n  scope.post<{ Params: { project?: string } }>('/pr-verdict', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    try {\n      const request = parsePrVerdictRequest(req.body)\n      const epath = errorsPathFor(proj)\n      const incidents = epath ? await readErrorEvents(epath) : []\n      const verdict = await ctx.prVerdict(request, { liveGraph: proj.graph, incidents })\n      return { project: proj.name, ...verdict }\n    } catch (err) {\n      if (!(err instanceof PrVerdictError)) throw err\n      if (err.status === 429) void reply.header('retry-after', '30')\n      return reply.code(err.status).send({\n        error: err.message,\n        project: proj.name,\n        ...(err.stage ? { stage: err.stage } : {}),\n        ...(err.details !== undefined ? { details: err.details } : {}),\n      })\n    }\n  })\n\n  scope.post<{ Params: { project?: string } }>('/graph/scan', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      return reply\n        .code(409)\n        .send({ error: 'scan path not configured for this project', project: proj.name })\n    }\n    const result = await extractFromDirectory(proj.graph, proj.scanPath)\n    return {\n      project: proj.name,\n      scanned: proj.scanPath,\n      nodesAdded: result.nodesAdded,\n      edgesAdded: result.edgesAdded,\n      nodeCount: proj.graph.order,\n      edgeCount: proj.graph.size,\n    }\n  })\n\n  // Policy surface (ADR-045 / contract #18). /policies returns the parsed\n  // policy.json; /policies/violations is the persistent log; /policies/check\n  // is dry-run evaluation. All dual-mounted via registerRoutes.\n  scope.get<{ Params: { project?: string } }>('/policies', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const policyPath = ctx.policyFilePathFor(proj)\n    if (!policyPath) {\n      // No policy file configured for this project — return the empty file\n      // shape so consumers don't have to special-case \"no policies yet.\"\n      return { version: 1, policies: [] }\n    }\n    try {\n      const policies = await loadPolicyFile(policyPath)\n      return { version: 1, policies }\n    } catch (err) {\n      return reply.code(400).send({\n        error: 'policy.json failed to parse',\n        details: (err as Error).message,\n      })\n    }\n  })\n\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { severity?: string; policyId?: string }\n  }>('/policies/violations', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const log = new PolicyViolationsLog(proj.paths.policyViolationsPath)\n    let violations = await log.readAll()\n    if (req.query.severity) {\n      const sev = PolicySeveritySchema.safeParse(req.query.severity)\n      if (!sev.success) {\n        return reply.code(400).send({\n          error: 'invalid severity',\n          details: sev.error.format(),\n        })\n      }\n      violations = violations.filter((v) => v.severity === sev.data)\n    }\n    if (req.query.policyId) {\n      violations = violations.filter((v) => v.policyId === req.query.policyId)\n    }\n    return { violations }\n  })\n\n  // Soft guardrail read path (ADR-108 / policies-soft-guardrail.md). Returns\n  // the policies APPLICABLE to a node — the rules an agent should be aware of\n  // while working there. This INFORMS; it never blocks and carries no verdict.\n  // Matching is a direct subject/region match (see selectApplicablePolicies),\n  // not the full overlay traversal (ADR-105 §5), which is still unbuilt.\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { node?: string }\n  }>('/policies/applicable', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const nodeId = req.query.node\n    if (!nodeId) {\n      return reply.code(400).send({ error: 'missing required query param \"node\"' })\n    }\n    const policyPath = ctx.policyFilePathFor(proj)\n    let policies: Policy[] = []\n    if (policyPath) {\n      try {\n        policies = await loadPolicyFile(policyPath)\n      } catch (err) {\n        return reply.code(400).send({\n          error: 'policy.json failed to parse',\n          details: (err as Error).message,\n        })\n      }\n    }\n    const applicable = selectApplicablePolicies(proj.graph, policies, nodeId)\n    return { node: nodeId, applicable }\n  })\n\n  scope.post<{\n    Params: { project?: string }\n    Body: { hypotheticalAction?: unknown }\n  }>('/policies/check', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const parsed = PoliciesCheckBodySchema.safeParse(req.body ?? {})\n    if (!parsed.success) {\n      return reply.code(400).send({\n        error: 'invalid /policies/check body',\n        details: parsed.error.format(),\n      })\n    }\n\n    const policyPath = ctx.policyFilePathFor(proj)\n    let policies: Policy[] = []\n    if (policyPath) {\n      try {\n        policies = await loadPolicyFile(policyPath)\n      } catch (err) {\n        return reply.code(400).send({\n          error: 'policy.json failed to parse',\n          details: (err as Error).message,\n        })\n      }\n    }\n\n    // No hypothetical → return current violations against the live graph.\n    // With a hypothetical → simulate the action against a deep-copy graph\n    // (avoids mutation authority concerns), evaluate, return the delta.\n    const evalCtx = { now: () => Date.now() }\n    if (!parsed.data.hypotheticalAction) {\n      const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n      const blocking = violations.filter((v) => v.onViolation === 'block')\n      return { allowed: blocking.length === 0, violations }\n    }\n\n    // For now the dry-run simulation re-uses evaluateAllPolicies on the\n    // current graph. Full hypothetical simulation (e.g. \"what if I added\n    // this OBSERVED edge?\") is the v0.2.4-δ scope; #117 ships the surface,\n    // #118 fills in the action shapes' simulation logic.\n    const violations = evaluateAllPolicies(proj.graph, policies, evalCtx)\n    const blocking = violations.filter((v) => v.onViolation === 'block')\n    return {\n      allowed: blocking.length === 0,\n      hypotheticalAction: parsed.data.hypotheticalAction,\n      violations,\n    } as { allowed: boolean; hypotheticalAction: unknown; violations: PolicyViolation[] }\n  })\n\n  // ── /extend — surgical instrumentation tools (ADR-081, ADR-086) ─────────\n  // Six routes. Three read-only (list-uninstrumented, lookup, describe),\n  // three operative (apply, dry-run, rollback). File-scope restricted per\n  // the extend-skill contract: only instrumentation/otel-init files and\n  // package.json. Dual-mounted via registerRoutes.\n\n  scope.get<{ Params: { project?: string } }>('/extend/list-uninstrumented', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n    }\n    try {\n      const results = await listUninstrumented({ project: proj.name, scanPath: proj.scanPath })\n      return { libraries: results }\n    } catch (err) {\n      return reply.code(500).send({ error: (err as Error).message })\n    }\n  })\n\n  scope.get<{\n    Params: { project?: string }\n    Querystring: { library?: string; version?: string }\n  }>('/extend/lookup', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    const { library, version } = req.query\n    if (!library) {\n      return reply.code(400).send({ error: 'query parameter `library` is required' })\n    }\n    const result = lookupInstrumentation(library, version)\n    if (!result) {\n      return reply.code(404).send({ error: 'library not found in registry', library })\n    }\n    return result\n  })\n\n  scope.get<{ Params: { project?: string } }>('/extend/describe', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n    }\n    try {\n      const state = await describeProjectInstrumentation({ project: proj.name, scanPath: proj.scanPath })\n      return state\n    } catch (err) {\n      return reply.code(500).send({ error: (err as Error).message })\n    }\n  })\n\n  // GET /instrumentation — the web ObservedOverlay's honesty probe (#823).\n  //\n  // The overlay (packages/web/app/components/ObservedOverlay.tsx), through its\n  // proxy (packages/web/app/api/instrumentation/route.ts), reads the daemon\n  // ROOT `/instrumentation` to pick Mode A (instrumentation wired, idle — run\n  // your app) vs Mode B (didn't engage — here's the one fix) and to pull the\n  // specific Mode B diagnosis. This fuses the static hook state\n  // (describeProjectInstrumentation: hook files + installed OTel deps) with the\n  // registry-driven coverage gaps (listUninstrumented) and answers the overlay's\n  // contract shape: `{ engaged, diagnosis? }`.\n  //\n  // Honesty (web-completeness #26): never a fabricated cause. Wired with nothing\n  // diagnosably missing → `engaged: true` (Mode A). Can't tell — no scan path or\n  // an unreadable package.json → `engaged: null` (neutral; the overlay stays\n  // Mode A rather than wrongly accusing a healthy idle setup). Only a real, named\n  // gap yields `engaged: false` with a diagnosis. Dual-mounted via registerRoutes\n  // like every route (ADR-026), so the web proxy's root-path hit resolves.\n  scope.get<{ Params: { project?: string } }>('/instrumentation', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      // No scan path configured — we genuinely can't diagnose. Neutral.\n      return { engaged: null }\n    }\n    try {\n      const state = await describeProjectInstrumentation({ project: proj.name, scanPath: proj.scanPath })\n      const uninstrumented = await listUninstrumented({ project: proj.name, scanPath: proj.scanPath })\n\n      // Not wired at all: NEAT never wrote an OTel init hook for this project.\n      if (state.hookFiles.length === 0) {\n        return {\n          engaged: false,\n          diagnosis: {\n            reason:\n              \"No instrumented entry point found — NEAT hasn't written an OTel init hook for this project.\",\n            fixCommand: 'neat init',\n            detail:\n              'Run `neat init` so NEAT writes the instrumentation hook next to your entry point, then run your app.',\n          },\n        }\n      }\n\n      // Wired, but a library on the hot path isn't in the auto-instrumentation\n      // set — its spans won't reach the graph until it's extended.\n      if (uninstrumented.length > 0) {\n        const names = uninstrumented.map((u) => u.library)\n        const more = names.length > 1 ? ` (and ${names.length - 1} more)` : ''\n        return {\n          engaged: false,\n          diagnosis: {\n            reason: `\\`${names[0]}\\`${more} isn't in the auto-instrumentation set, so spans from it won't reach the graph.`,\n            fixCommand: 'neat extend',\n            detail: `Uninstrumented on your hot path: ${names.join(', ')}. Run \\`neat extend\\` to wire the missing instrumentation.`,\n          },\n        }\n      }\n\n      // Hook files present and no known coverage gaps: the static picture is\n      // healthy. Whether traffic has actually flowed is an OBSERVED question the\n      // graph answers — from here the honest read is \"wired, waiting to engage.\"\n      return { engaged: true }\n    } catch {\n      // Unreadable package.json / other read error — we can't tell. Neutral,\n      // never a fabricated cause.\n      return { engaged: null }\n    }\n  })\n\n  scope.post<{\n    Params: { project?: string }\n    Body: { library?: string; instrumentation_package?: string; version?: string; registration_snippet?: string }\n  }>('/extend/apply', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n    }\n    const { library, instrumentation_package, version, registration_snippet } = req.body ?? {}\n    if (!library || !instrumentation_package || !version || !registration_snippet) {\n      return reply.code(400).send({ error: 'body must include library, instrumentation_package, version, registration_snippet' })\n    }\n    try {\n      const result = await applyExtension(\n        { project: proj.name, scanPath: proj.scanPath },\n        { library, instrumentation_package, version, registration_snippet },\n      )\n      return result\n    } catch (err) {\n      return reply.code(500).send({ error: (err as Error).message })\n    }\n  })\n\n  scope.post<{\n    Params: { project?: string }\n    Body: { library?: string; instrumentation_package?: string; version?: string; registration_snippet?: string }\n  }>('/extend/dry-run', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n    }\n    const { library, instrumentation_package, version, registration_snippet } = req.body ?? {}\n    if (!library || !instrumentation_package || !version || !registration_snippet) {\n      return reply.code(400).send({ error: 'body must include library, instrumentation_package, version, registration_snippet' })\n    }\n    try {\n      const result = await dryRunExtension(\n        { project: proj.name, scanPath: proj.scanPath },\n        { library, instrumentation_package, version, registration_snippet },\n      )\n      return result\n    } catch (err) {\n      return reply.code(500).send({ error: (err as Error).message })\n    }\n  })\n\n  scope.post<{\n    Params: { project?: string }\n    Body: { library?: string }\n  }>('/extend/rollback', async (req, reply) => {\n    const proj = resolveProject(registry, req, reply, ctx.bootstrap, ctx.singleProject)\n    if (!proj) return\n    if (!proj.scanPath) {\n      return reply.code(409).send({ error: 'scan path not configured for this project', project: proj.name })\n    }\n    const { library } = req.body ?? {}\n    if (!library) {\n      return reply.code(400).send({ error: 'body must include library' })\n    }\n    try {\n      const result = await rollbackExtension(\n        { project: proj.name, scanPath: proj.scanPath },\n        { library },\n      )\n      return result\n    } catch (err) {\n      return reply.code(500).send({ error: (err as Error).message })\n    }\n  })\n}\n\n// The same ceiling the OTLP receiver applies to a batch (otel.ts).\nconst OTLP_BODY_LIMIT = 16 * 1024 * 1024\n\n// Serve the OTLP receiver's routes on the REST listener (otel-ingest.md\n// §One receiver, two doors).\n//\n// The routes carry no ingest logic. Each hands the request — raw bytes and\n// headers, untouched — to the receiver itself and relays its answer, so the\n// bearer check against the ingest token, gzip, protobuf, the project-scoped\n// 404, and partialSuccess are the receiver's own on both doors and cannot\n// disagree. That is also why the body is taken as a buffer for every content\n// type here: parsing belongs to the receiver.\n//\n// Encapsulated, so the buffer parser applies to these routes and nothing else.\nfunction otlpOnRest(getReceiver: () => FastifyInstance | undefined) {\n  return async function plugin(scope: FastifyInstance): Promise<void> {\n    scope.removeAllContentTypeParsers()\n    scope.addContentTypeParser(\n      '*',\n      { parseAs: 'buffer', bodyLimit: OTLP_BODY_LIMIT },\n      (_req, body, done) => done(null, body),\n    )\n\n    const relay = async (req: FastifyRequest, reply: FastifyReply): Promise<unknown> => {\n      const receiver = getReceiver()\n      if (!receiver) {\n        // Still starting. 503 is retryable for an OTLP exporter; a 404 is not.\n        return reply.code(503).header('retry-after', '1').send({ error: 'OTLP receiver is starting' })\n      }\n      // The body arrives here already de-chunked and whole, so the framing\n      // headers describe a request that no longer exists; the receiver gets a\n      // content-length computed from the bytes it is actually handed.\n      const headers = { ...req.headers }\n      delete headers['content-length']\n      delete headers['transfer-encoding']\n      delete headers.connection\n      const res = await receiver.inject({\n        method: 'POST',\n        url: req.url,\n        headers,\n        payload: req.body as Buffer | undefined,\n      })\n      const contentType = res.headers['content-type']\n      if (contentType !== undefined) void reply.header('content-type', contentType)\n      return reply.code(res.statusCode).send(res.rawPayload)\n    }\n\n    const route = { config: BEARER_DELEGATED, bodyLimit: OTLP_BODY_LIMIT }\n    scope.post('/v1/traces', route, relay)\n    scope.post('/projects/:project/v1/traces', route, relay)\n  }\n}\n\nexport async function buildApi(opts: BuildApiOptions): Promise<FastifyInstance> {\n  // Node ids are how the graph is addressed over REST, and under file-awareness\n  // (ADR-087) an id is `code:<filepath>:<symbol>` — which the CLI and MCP\n  // clients URL-encode (every `/` becomes `%2F`) before it lands in a `:id` /\n  // `:nodeId` path param. Fastify's default maxParamLength of 100 then rejects\n  // any realistic file-grained id at the router, before the handler runs, with\n  // a generic \"Route not found\" 404. To an agent querying blast-radius /\n  // dependencies / root-cause for a real node, that reads as a broken endpoint\n  // rather than \"that node isn't in the graph\" — the handler's actionable\n  // `{ error: 'node not found', id }` never gets a chance to answer. Raise the\n  // cap so a long-but-real id reaches the handler; 1024 clears any realistic\n  // path + symbol while still bounding a pathological multi-kilobyte URL.\n  const app = Fastify({ logger: false, routerOptions: { maxParamLength: 1024 } })\n  await app.register(cors, { origin: true })\n\n  // ADR-073 §3/§4 — `buildApi` owns auth enforcement so every listener that\n  // serves the REST surface gets the same gate, whoever builds it. When a\n  // caller doesn't pass auth options explicitly, they resolve from the\n  // environment (`NEAT_AUTH_TOKEN` / `NEAT_AUTH_PROXY` / `NEAT_PUBLIC_READ`)\n  // through the single `readAuthEnv` reader. A caller that does pass them\n  // wins, so the daemon and `serve` keep their explicit wiring; a caller that\n  // omits them — `neat watch` — inherits the same token rather than serving\n  // open by omission. The bind-host loopback refusal stays with the binding\n  // caller via `assertBindAuthority`, which reads the same env.\n  const env = readAuthEnv()\n  const authToken = opts.authToken ?? env.authToken\n  const trustProxy = opts.trustProxy ?? env.trustProxy\n  const publicRead = opts.publicRead ?? env.publicRead\n  const incidentStreamToken = opts.incidentStreamToken ?? process.env.NEAT_INCIDENT_STREAM_TOKEN\n  const incidentReplayDurable = opts.incidentReplayDurable ??\n    (process.env.NEAT_INCIDENT_REPLAY_DURABLE === '1' &&\n      Buffer.byteLength(process.env.NEAT_INCIDENT_DURABLE_TOKEN ?? '', 'utf8') >= 32)\n\n  // ADR-073 §3 — bearer middleware sits ahead of every route handler. No-op\n  // when the resolved token is undefined; loopback-only callers (the laptop\n  // dev path) hit that branch. `publicRead` opens GET / HEAD / OPTIONS to\n  // anonymous callers while keeping writes gated.\n  mountBearerAuth(app, {\n    token: authToken,\n    trustProxy,\n    publicRead,\n  })\n\n  // ADR-073 §3a / ADR-139 — `/api/config` is always unauthenticated. The web\n  // shell hits it before any bearer-carrying request to learn which mode the\n  // daemon is in. Exposes exactly three booleans — `publicRead`, `authProxy`,\n  // and `requiresAuth` — and nothing else; no project list, no version, no env.\n  //\n  // `requiresAuth` is true iff this daemon actually mounts a bearer hook, which\n  // is exactly `mountBearerAuth`'s own condition: a token is set and we're not\n  // trusting an upstream proxy. A tokenless daemon (the loopback dev path) and\n  // a proxy-terminated one both serve every request anonymously — there is no\n  // bearer to log in with — so the web gate must not bounce them to /login.\n  // This is distinct from `publicRead`: a public-read reference deployment\n  // still requires auth for writes and renders read-only, while a tokenless\n  // local daemon requires no auth at all and stays fully writable.\n  const requiresAuth = authToken !== undefined && authToken.length > 0 && trustProxy !== true\n  app.get('/api/config', async () => ({\n    publicRead: publicRead === true,\n    authProxy: trustProxy === true,\n    requiresAuth,\n  }))\n\n  if (opts.otlpReceiver) await app.register(otlpOnRest(opts.otlpReceiver))\n\n  const startedAt = opts.startedAt ?? Date.now()\n  const registry = buildLegacyRegistry(opts)\n\n  const legacyErrorsExplicit = !opts.projects && opts.errorsPath !== undefined\n  const legacyStaleExplicit = !opts.projects && opts.staleEventsPath !== undefined\n\n  const errorsPathFor = (proj: ProjectContext): string | undefined => {\n    if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n      return legacyErrorsExplicit ? opts.errorsPath : undefined\n    }\n    return proj.paths.errorsPath\n  }\n  const staleEventsPathFor = (proj: ProjectContext): string | undefined => {\n    if (proj.name === DEFAULT_PROJECT && !opts.projects) {\n      return legacyStaleExplicit ? opts.staleEventsPath : undefined\n    }\n    return proj.paths.staleEventsPath\n  }\n\n  // policy.json lives at the project's scanPath root per ADR-042. Without a\n  // scanPath we have nowhere to read it from — those projects show as\n  // \"no policies configured\" via the empty-file response.\n  const policyFilePathFor = (proj: ProjectContext): string | undefined => {\n    if (!proj.scanPath) return undefined\n    return `${proj.scanPath}/policy.json`\n  }\n\n  const routeCtx: RouteContext = {\n    registry,\n    startedAt,\n    incidentStreamToken,\n    incidentReplayDurable,\n    generalAuthToken: authToken,\n    scope: 'root',\n    errorsPathFor,\n    staleEventsPathFor,\n    policyFilePathFor,\n    bootstrap: opts.bootstrap,\n    singleProject: opts.singleProject?.name,\n    connectorsHome: opts.connectorsHome,\n    repoSync: opts.repoSync,\n    prVerdict: opts.prVerdict ?? createPrVerdictRunner(),\n    runPoll: opts.runPoll ?? runConnectorPoll,\n  }\n\n  // Daemon-wide /health (issue #343). Per ADR-049 the daemon is the unit of\n  // readiness; the response answers \"is this process up and what's it\n  // currently serving?\" without depending on a `default` project. Probes —\n  // orchestrator, kubelet readiness, systemd, supervisors — read this.\n  //\n  // The `projects` array surfaces every slot the daemon knows about. When\n  // the bootstrap tracker is wired (issue #340), the per-entry `status`\n  // and `elapsedMs` come from there so the orchestrator's wait loop can\n  // tell `bootstrapping` apart from `active` without per-project probes.\n  app.get('/health', async () => {\n    const uptimeMs = Date.now() - startedAt\n    const bootstrapList = opts.bootstrap?.list() ?? []\n    const byName = new Map(bootstrapList.map((p) => [p.name, p]))\n    const names = new Set<string>([\n      ...registry.list(),\n      ...bootstrapList.map((p) => p.name),\n    ])\n    const projects = [...names].sort().map((name) => {\n      const proj = registry.get(name)\n      const tracked = byName.get(name)\n      return {\n        name,\n        nodeCount: proj?.graph.order ?? 0,\n        edgeCount: proj?.graph.size ?? 0,\n        ...(tracked ? { status: tracked.status, elapsedMs: tracked.elapsedMs } : {}),\n      }\n    })\n    return {\n      ok: true,\n      uptimeMs,\n      // ADR-096 §7 — a per-project daemon carries its project at the top level\n      // so a spawn can confirm a daemon found on a reused port is serving THIS\n      // project before reusing it. The legacy multi-project daemon omits it and\n      // is matched against the `projects` array instead.\n      ...(opts.singleProject ? { project: opts.singleProject.name } : {}),\n      projects,\n    }\n  })\n\n  // ADR-096 §4 — \"the daemon is the project.\" A per-project daemon reports only\n  // its own project here, so the dashboard pins to the project this daemon\n  // serves rather than to whichever machine-registered project happens to be\n  // active. The legacy multi-project daemon hands back the machine-level\n  // registry (ADR-048) — the one documented bare-array GET. Either way the\n  // response is `Array<ProjectListEntry>` — a RegistryEntry plus `hostedHere`\n  // (#884) — which the dashboard and the CLI's bare-verb resolver treat as a\n  // list primitive.\n  app.get('/projects', async (_req, reply) => {\n    if (opts.singleProject) {\n      const phase = opts.bootstrap?.status(opts.singleProject.name)\n      const entry: ProjectListEntry = {\n        name: opts.singleProject.name,\n        path: opts.singleProject.path,\n        registeredAt: new Date(startedAt).toISOString(),\n        languages: [],\n        // The daemon is serving this project, so it's active unless its\n        // bootstrap broke. ('bootstrapping' still reads as active — the project\n        // is the one to land on; its graph route answers 503 until ready.)\n        status: phase === 'broken' ? 'broken' : 'active',\n        hostedHere: true,\n      }\n      return [entry]\n    }\n    try {\n      // The registry is shared machine-wide, so it lists projects this daemon\n      // doesn't serve (another daemon owns them). Mark which ones this core\n      // actually hosts so a caller doesn't trust per-project answers from the\n      // wrong daemon (#884). `registry` is this daemon's in-memory hosted set.\n      const entries = await listRegistryProjects()\n      return entries.map<ProjectListEntry>((entry) => ({\n        ...entry,\n        hostedHere: registry.has(entry.name),\n      }))\n    } catch (err) {\n      return reply.code(500).send({\n        error: 'failed to read project registry',\n        details: (err as Error).message,\n      })\n    }\n  })\n\n  // Singular project lookup (ADR-061 #7). Distinct route from the\n  // `/projects/:project/...` dual-mount prefix because Fastify matches on\n  // the full path; the trailing-segment-less request lands here.\n  app.get<{ Params: { project: string } }>('/projects/:project', async (req, reply) => {\n    try {\n      const entry = await getRegistryProject(req.params.project)\n      if (!entry) {\n        return reply\n          .code(404)\n          .send({ error: 'project not found', project: req.params.project })\n      }\n      // The registry knows the project, but this daemon may not host it. Say so,\n      // and when another daemon owns it, name where it lives so the caller can\n      // repoint rather than read a 200 as \"this core serves it\" (#884).\n      const hostedHere = registry.has(entry.name)\n      if (!hostedHere) {\n        const owner = await findDaemonByProject(entry.name).catch(() => undefined)\n        if (owner) {\n          return {\n            project: { ...entry, hostedHere },\n            servedBy: {\n              path: owner.record.projectPath,\n              restPort: owner.record.ports.rest,\n              live: owner.live,\n            },\n          }\n        }\n      }\n      return { project: { ...entry, hostedHere } }\n    } catch (err) {\n      return reply.code(500).send({\n        error: 'failed to read project registry',\n        details: (err as Error).message,\n      })\n    }\n  })\n\n  // Default mount: /graph, /incidents, etc. resolve to project=default.\n  // `/health` at this scope is the daemon-wide handler registered above,\n  // not the per-project one (issue #343).\n  registerRoutes(app, routeCtx)\n\n  // Project-scoped mount: same handlers, URL params include `:project`,\n  // and `/health` answers per project.\n  await app.register(\n    async (scope) => {\n      registerRoutes(scope, { ...routeCtx, scope: 'project' })\n    },\n    { prefix: '/projects/:project' },\n  )\n\n  return app\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { resolve as registryResolve, list as registryList } from '@neat.is/instrumentation-registry'\nimport {\n  detectPackageManager,\n  runPackageManagerInstall,\n} from '../installers/package-manager.js'\n\nexport interface ExtendContext {\n  project: string\n  scanPath: string\n}\n\nexport interface LibraryCoverageResult {\n  library: string\n  coverage: 'bundled' | 'first-party' | 'third-party' | 'http-only' | 'gap'\n  installedVersion?: string\n  instrumentation_package?: string\n  package_version?: string\n  registration?: string\n  notes?: string\n}\n\nexport interface ProjectInstrumentationState {\n  hookFiles: string[]\n  envNeat: boolean\n  installedDeps: Record<string, string>\n}\n\nexport interface ExtensionApplyResult {\n  library: string\n  filesTouched: string[]\n  depsAdded: string[]\n  installOutput: string\n  alreadyApplied: boolean\n}\n\nexport interface ExtensionDiff {\n  library: string\n  filesTouched: string[]\n  depsToAdd: string[]\n  packageJsonPatch: object\n  templatePatch: string\n}\n\ninterface PackageJson {\n  name?: string\n  dependencies?: Record<string, string>\n  devDependencies?: Record<string, string>\n  [key: string]: unknown\n}\n\ninterface ExtendLogEntry {\n  timestamp: string\n  project: string\n  library: string\n  instrumentation_package: string\n  version: string\n  registration_snippet: string\n  filesTouched: string[]\n  depsAdded: string[]\n  installOutput: string\n}\n\nasync function fileExists(p: string): Promise<boolean> {\n  try {\n    await fs.access(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\nasync function readPackageJson(scanPath: string): Promise<PackageJson> {\n  const pkgPath = path.join(scanPath, 'package.json')\n  const raw = await fs.readFile(pkgPath, 'utf8')\n  return JSON.parse(raw) as PackageJson\n}\n\n// Directories the hook-file walk never descends into: dependency trees, VCS\n// metadata, build output, and NEAT's own output dir. None can hold a user's\n// instrumentation hook, and node_modules especially would make the walk crawl.\n// Every dot-prefixed directory (`.git`, `.next`, `.turbo`, `.vercel`, …) is\n// skipped too — a generated hook never lands in one.\nconst HOOK_WALK_SKIP_DIRS = new Set([\n  'node_modules',\n  'dist',\n  'build',\n  'out',\n  'coverage',\n  'neat-out',\n])\n\n// Locate every OTel init hook in the project: a file whose basename starts with\n// `instrumentation` or `otel-init` in any JS/TS module flavor (js/ts/cjs/mjs).\n// The orchestrator writes the hook adjacent to the resolved entry — commonly a\n// subdirectory like `src/otel-init.cjs` for an app whose entry is\n// `src/index.js` — and the Next branch writes `instrumentation.node.{ts,js}`\n// under `src/` for --src-dir layouts, so the search walks the whole tree rather\n// than reading the root alone (#823). Paths come back relative to scanPath;\n// every caller re-joins them with `path.join(scanPath, file)`.\nasync function findHookFiles(scanPath: string): Promise<string[]> {\n  const found: string[] = []\n  const walk = async (dir: string): Promise<void> => {\n    const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => [])\n    for (const entry of entries) {\n      if (entry.isDirectory()) {\n        if (entry.name.startsWith('.') || HOOK_WALK_SKIP_DIRS.has(entry.name)) continue\n        await walk(path.join(dir, entry.name))\n      } else if (entry.isFile()) {\n        if (\n          (entry.name.startsWith('instrumentation') || entry.name.startsWith('otel-init')) &&\n          /\\.(ts|js|cjs|mjs)$/.test(entry.name)\n        ) {\n          const rel = path.relative(scanPath, path.join(dir, entry.name))\n          // Normalise to forward slashes so the returned path is stable across\n          // platforms and re-joins cleanly (path.join accepts `/` everywhere).\n          found.push(rel.split(path.sep).join('/'))\n        }\n      }\n    }\n  }\n  await walk(scanPath)\n  return found.sort()\n}\n\n// Choose which hook file the registration snippet splices into. A project can\n// carry several (Next writes instrumentation.{,node,edge}.{ts,js}; a monorepo\n// may keep one per package), but only the file that constructs the SDK has an\n// insertion point — the edge file registers via `@vercel/otel` and sorts first\n// alphabetically, so `hookFiles[0]` would be the wrong target. Prefer the first\n// hook file that splices cleanly and hand back its patched contents; fall back\n// to the first hook file so the caller still emits a precise \"no insertion\n// point\" error naming a real file.\nasync function pickPrimaryHookFile(\n  scanPath: string,\n  hookFiles: string[],\n  snippet: string,\n): Promise<{ file: string; content: string; patched: string | null }> {\n  let fallback: { file: string; content: string } | null = null\n  for (const file of hookFiles) {\n    const content = await fs.readFile(path.join(scanPath, file), 'utf8')\n    const patched = splicedContent(content, snippet)\n    if (patched !== null) return { file, content, patched }\n    if (fallback === null) fallback = { file, content }\n  }\n  return { file: fallback!.file, content: fallback!.content, patched: null }\n}\n\nfunction extendLogPath(): string {\n  return process.env.NEAT_EXTEND_LOG ?? path.join(os.homedir(), '.neat', 'extend-log.ndjson')\n}\n\nasync function appendExtendLog(entry: ExtendLogEntry): Promise<void> {\n  const logPath = extendLogPath()\n  await fs.mkdir(path.dirname(logPath), { recursive: true })\n  await fs.appendFile(logPath, JSON.stringify(entry) + '\\n', 'utf8')\n}\n\n// Insert `snippet` into `fileContent` at the instrumentation array.\n// Tries __INSTRUMENTATION_BLOCK__ first, then last instrumentations.push(,\n// then before new NodeSDK(. Returns null if no insertion point is found.\nfunction splicedContent(fileContent: string, snippet: string): string | null {\n  if (fileContent.includes('__INSTRUMENTATION_BLOCK__')) {\n    return fileContent.replace('__INSTRUMENTATION_BLOCK__', `${snippet}\\n__INSTRUMENTATION_BLOCK__`)\n  }\n\n  const lines = fileContent.split('\\n')\n\n  let lastPushIdx = -1\n  for (let i = 0; i < lines.length; i++) {\n    if (lines[i].includes('instrumentations.push(')) lastPushIdx = i\n  }\n  if (lastPushIdx >= 0) {\n    lines.splice(lastPushIdx + 1, 0, snippet)\n    return lines.join('\\n')\n  }\n\n  for (let i = 0; i < lines.length; i++) {\n    if (lines[i].includes('new NodeSDK(')) {\n      lines.splice(i, 0, snippet)\n      return lines.join('\\n')\n    }\n  }\n\n  return null\n}\n\nexport async function listUninstrumented(ctx: ExtendContext): Promise<LibraryCoverageResult[]> {\n  const pkg = await readPackageJson(ctx.scanPath)\n  const allDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n\n  const results: LibraryCoverageResult[] = []\n  for (const [library, installedVersion] of Object.entries(allDeps)) {\n    const entry = registryResolve(library, installedVersion)\n    if (!entry) continue\n    if (entry.coverage === 'bundled' || entry.coverage === 'http-only') continue\n    results.push({\n      library,\n      coverage: entry.coverage,\n      installedVersion,\n      instrumentation_package: entry.instrumentation_package,\n      package_version: entry.package_version,\n      registration: entry.registration,\n      notes: entry.notes,\n    })\n  }\n  return results\n}\n\nexport function lookupInstrumentation(\n  library: string,\n  installedVersion?: string,\n): LibraryCoverageResult | null {\n  const entry = registryResolve(library, installedVersion)\n  if (!entry) return null\n  return {\n    library: entry.library,\n    coverage: entry.coverage,\n    instrumentation_package: entry.instrumentation_package,\n    package_version: entry.package_version,\n    registration: entry.registration,\n    notes: entry.notes,\n  }\n}\n\nexport async function describeProjectInstrumentation(\n  ctx: ExtendContext,\n): Promise<ProjectInstrumentationState> {\n  const hookFiles = await findHookFiles(ctx.scanPath)\n  const envNeat = await fileExists(path.join(ctx.scanPath, '.env.neat'))\n\n  const registryInstrPackages = new Set<string>(\n    registryList()\n      .map((e) => e.instrumentation_package)\n      .filter((p): p is string => !!p),\n  )\n\n  const pkg = await readPackageJson(ctx.scanPath)\n  const allDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n\n  const installedDeps: Record<string, string> = {}\n  for (const [key, version] of Object.entries(allDeps)) {\n    if (key.startsWith('@opentelemetry/') || registryInstrPackages.has(key)) {\n      installedDeps[key] = version\n    }\n  }\n\n  return { hookFiles, envNeat, installedDeps }\n}\n\nexport async function applyExtension(\n  ctx: ExtendContext,\n  args: {\n    library: string\n    instrumentation_package: string\n    version: string\n    registration_snippet: string\n  },\n  options?: {\n    runInstall?: typeof runPackageManagerInstall\n  },\n): Promise<ExtensionApplyResult> {\n  const hookFiles = await findHookFiles(ctx.scanPath)\n\n  if (hookFiles.length === 0) {\n    throw new Error(\n      `No instrumentation hook files found in ${ctx.scanPath}. Run \\`neat init\\` first.`,\n    )\n  }\n\n  // Idempotency check: scan all hook files for the snippet\n  for (const file of hookFiles) {\n    const content = await fs.readFile(path.join(ctx.scanPath, file), 'utf8')\n    if (content.includes(args.registration_snippet)) {\n      return { library: args.library, filesTouched: [], depsAdded: [], installOutput: '', alreadyApplied: true }\n    }\n  }\n\n  // Resolve the hook file to splice into, and confirm it has an insertion point\n  // BEFORE touching package.json — otherwise a snippet that can't splice would\n  // leave a dep added with no matching registration.\n  const primary = await pickPrimaryHookFile(ctx.scanPath, hookFiles, args.registration_snippet)\n  if (primary.patched === null) {\n    throw new Error(\n      `Could not find instrumentation insertion point in ${hookFiles.join(', ')}. ` +\n        'Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.',\n    )\n  }\n  const primaryFile = primary.file\n  const primaryPath = path.join(ctx.scanPath, primaryFile)\n  const filesTouched: string[] = []\n  const depsAdded: string[] = []\n\n  // 1. Add dep to package.json if not already present\n  const pkgPath = path.join(ctx.scanPath, 'package.json')\n  const pkg = await readPackageJson(ctx.scanPath)\n  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {\n    pkg.dependencies = { ...(pkg.dependencies ?? {}), [args.instrumentation_package]: args.version }\n    await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\\n', 'utf8')\n    filesTouched.push('package.json')\n    depsAdded.push(`${args.instrumentation_package}@${args.version}`)\n  }\n\n  // 2. Splice registration snippet into the resolved hook file\n  await fs.writeFile(primaryPath, primary.patched, 'utf8')\n  filesTouched.push(primaryFile)\n\n  // 3. Run package manager install\n  const cmd = await detectPackageManager(ctx.scanPath)\n  const installer = options?.runInstall ?? runPackageManagerInstall\n  const install = await installer(cmd)\n  const installOutput =\n    install.exitCode === 0\n      ? `${cmd.pm} install succeeded`\n      : install.stderr || `${cmd.pm} install failed (exit ${install.exitCode})`\n\n  // 4. Log the apply\n  await appendExtendLog({\n    timestamp: new Date().toISOString(),\n    project: ctx.project,\n    library: args.library,\n    instrumentation_package: args.instrumentation_package,\n    version: args.version,\n    registration_snippet: args.registration_snippet,\n    filesTouched,\n    depsAdded,\n    installOutput,\n  })\n\n  return { library: args.library, filesTouched, depsAdded, installOutput, alreadyApplied: false }\n}\n\nexport async function dryRunExtension(\n  ctx: ExtendContext,\n  args: {\n    library: string\n    instrumentation_package: string\n    version: string\n    registration_snippet: string\n  },\n): Promise<ExtensionDiff> {\n  const hookFiles = await findHookFiles(ctx.scanPath)\n\n  if (hookFiles.length === 0) {\n    return {\n      library: args.library,\n      filesTouched: [],\n      depsToAdd: [],\n      packageJsonPatch: {},\n      templatePatch: \"No hook files found. Run 'neat init' first.\",\n    }\n  }\n\n  for (const file of hookFiles) {\n    const content = await fs.readFile(path.join(ctx.scanPath, file), 'utf8')\n    if (content.includes(args.registration_snippet)) {\n      return {\n        library: args.library,\n        filesTouched: [],\n        depsToAdd: [],\n        packageJsonPatch: {},\n        templatePatch: 'Already applied — no changes would be made.',\n      }\n    }\n  }\n\n  const primary = await pickPrimaryHookFile(ctx.scanPath, hookFiles, args.registration_snippet)\n  const filesTouched: string[] = []\n  const depsToAdd: string[] = []\n  let packageJsonPatch: object = {}\n  let templatePatch = ''\n\n  const pkg = await readPackageJson(ctx.scanPath)\n  if (!(pkg.dependencies ?? {})[args.instrumentation_package]) {\n    packageJsonPatch = { dependencies: { [args.instrumentation_package]: args.version } }\n    depsToAdd.push(`${args.instrumentation_package}@${args.version}`)\n    filesTouched.push('package.json')\n  }\n\n  if (primary.patched !== null) {\n    filesTouched.push(primary.file)\n    templatePatch = `+ ${args.registration_snippet}`\n  } else {\n    templatePatch = 'Could not find insertion point in hook file.'\n  }\n\n  return { library: args.library, filesTouched, depsToAdd, packageJsonPatch, templatePatch }\n}\n\nexport async function rollbackExtension(\n  ctx: ExtendContext,\n  args: { library: string },\n): Promise<{ undone: boolean; message: string }> {\n  const logPath = extendLogPath()\n\n  if (!(await fileExists(logPath))) {\n    return { undone: false, message: 'no apply found for library' }\n  }\n\n  const raw = await fs.readFile(logPath, 'utf8')\n  const entries: ExtendLogEntry[] = raw\n    .trim()\n    .split('\\n')\n    .filter(Boolean)\n    .map((line) => JSON.parse(line) as ExtendLogEntry)\n\n  const match = [...entries]\n    .reverse()\n    .find((e) => e.project === ctx.project && e.library === args.library)\n\n  if (!match) {\n    return { undone: false, message: 'no apply found for library' }\n  }\n\n  // Remove dep from package.json\n  const pkgPath = path.join(ctx.scanPath, 'package.json')\n  if (await fileExists(pkgPath)) {\n    const pkg = await readPackageJson(ctx.scanPath)\n    if (pkg.dependencies?.[match.instrumentation_package]) {\n      const { [match.instrumentation_package]: _removed, ...rest } = pkg.dependencies\n      pkg.dependencies = rest\n      await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\\n', 'utf8')\n    }\n  }\n\n  // Remove the registration snippet from hook files (no re-install — user owns the lockfile)\n  const hookFiles = await findHookFiles(ctx.scanPath)\n  for (const file of hookFiles) {\n    const filePath = path.join(ctx.scanPath, file)\n    const content = await fs.readFile(filePath, 'utf8')\n    if (content.includes(match.registration_snippet)) {\n      const filtered = content\n        .split('\\n')\n        .filter((line) => !line.includes(match.registration_snippet))\n        .join('\\n')\n      await fs.writeFile(filePath, filtered, 'utf8')\n      break\n    }\n  }\n\n  return {\n    undone: true,\n    message: `rolled back ${match.library} (${match.instrumentation_package})`,\n  }\n}\n","/**\n * Package-manager detection + install invocation.\n *\n * Issue #381 — the apply phase adds dependencies to package.json but\n * relies on the operator to run `npm install` afterwards. The v0.4.5\n * smoke surfaced this as a hard regression on Brief: the installer\n * adds `@opentelemetry/sdk-node` (and `@prisma/instrumentation` when\n * Prisma is in deps) and the next `npm run dev` fails with\n * `Cannot find module '@opentelemetry/sdk-node'` before the OTel SDK\n * even gets a chance to load.\n *\n * ADR-046's \"lockfiles never touched\" rule is about NEAT not directly\n * editing lockfile contents; letting the user's own package manager\n * update them as a side effect of `<pm> install` is consistent with\n * that contract. The clarification is documented in\n * docs/contracts/sdk-install.md.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\n\nexport type PackageManager = 'bun' | 'pnpm' | 'yarn' | 'npm'\n\nexport interface PackageManagerCommand {\n  pm: PackageManager\n  // The directory the install command runs in. Monorepo workspaces install\n  // from the lockfile root, not the per-package directory, so detection\n  // walks up from `serviceDir` and reports the lockfile-owning parent.\n  cwd: string\n  // The argv passed to spawn(). Each entry is one positional token. Selected\n  // to keep install output quiet on the happy path; failures still print\n  // because stderr is streamed verbatim.\n  args: string[]\n}\n\n// Lockfile basename → package manager + the install args we run for it.\n// Priority order — first match wins when multiple lockfiles coexist (rare,\n// but `package-lock.json` alongside `pnpm-lock.yaml` happens during a\n// migration). Bun leads because a project that opted into Bun deliberately\n// rejects npm; pnpm and yarn follow for similar reasons; npm is the default\n// when nothing else applies.\nconst LOCKFILE_PRIORITY: ReadonlyArray<{\n  lockfile: string\n  pm: PackageManager\n  args: string[]\n}> = [\n  { lockfile: 'bun.lockb', pm: 'bun', args: ['install', '--no-summary'] },\n  { lockfile: 'pnpm-lock.yaml', pm: 'pnpm', args: ['install', '--no-summary'] },\n  { lockfile: 'yarn.lock', pm: 'yarn', args: ['install', '--silent'] },\n  {\n    lockfile: 'package-lock.json',\n    pm: 'npm',\n    args: ['install', '--no-audit', '--no-fund', '--prefer-offline'],\n  },\n]\n\n// Default when no lockfile is present anywhere in the ancestor chain — a\n// fresh project the operator hasn't installed yet. npm is the safe pick:\n// it's available on every Node install and produces a `package-lock.json`\n// the user can later swap out for pnpm/yarn/bun without losing fidelity.\nconst NPM_FALLBACK_ARGS = ['install', '--no-audit', '--no-fund', '--prefer-offline']\n\nasync function exists(p: string): Promise<boolean> {\n  try {\n    await fs.access(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\n// Resolve the package-manager command for a service directory. Walks up from\n// `serviceDir` looking for a lockfile — the first ancestor that has one\n// owns the install. Monorepos (npm/pnpm/yarn workspaces, Bun workspaces)\n// land their lockfile at the workspace root, so this returns the root cwd\n// even when `serviceDir` is a per-package subdir.\n//\n// No lockfile anywhere → npm at the service dir. A fresh `create-next-app`\n// run sits in this bucket (no install yet, no lockfile to read).\nexport async function detectPackageManager(\n  serviceDir: string,\n): Promise<PackageManagerCommand> {\n  let dir = path.resolve(serviceDir)\n  const stops = new Set<string>()\n  for (let i = 0; i < 64; i++) {\n    if (stops.has(dir)) break\n    stops.add(dir)\n    for (const candidate of LOCKFILE_PRIORITY) {\n      const lockPath = path.join(dir, candidate.lockfile)\n      if (await exists(lockPath)) {\n        return { pm: candidate.pm, cwd: dir, args: [...candidate.args] }\n      }\n    }\n    const parent = path.dirname(dir)\n    if (parent === dir) break\n    dir = parent\n  }\n  return { pm: 'npm', cwd: path.resolve(serviceDir), args: [...NPM_FALLBACK_ARGS] }\n}\n\nexport interface PackageManagerInvocation {\n  pm: PackageManager\n  cwd: string\n  args: string[]\n  // 0 → success; non-zero → install failed. Reported in the orchestrator\n  // summary so the operator can act before the daemon goes hunting for\n  // spans that never arrive.\n  exitCode: number\n  // Stderr captured from the child process, trimmed. Empty on success.\n  // Surfaces the underlying failure cause without dumping the entire\n  // install log into the summary.\n  stderr: string\n}\n\n// Run the install command and resolve with the outcome. Stdout is dropped\n// (`<pm> install --silent`-style flags already keep it short); stderr is\n// captured so a failure can be relayed up to the orchestrator's summary.\nexport async function runPackageManagerInstall(\n  cmd: PackageManagerCommand,\n): Promise<PackageManagerInvocation> {\n  return new Promise((resolve) => {\n    const child = spawn(cmd.pm, cmd.args, {\n      cwd: cmd.cwd,\n      // Inherit PATH + HOME so the user's installed managers resolve.\n      env: process.env,\n      // `false` keeps the parent in control of cleanup if the orchestrator\n      // exits before install finishes. Cross-platform-safe.\n      shell: false,\n      stdio: ['ignore', 'ignore', 'pipe'],\n    })\n    let stderr = ''\n    child.stderr?.on('data', (chunk: Buffer) => {\n      stderr += chunk.toString('utf8')\n    })\n    child.on('error', (err) => {\n      resolve({\n        pm: cmd.pm,\n        cwd: cmd.cwd,\n        args: cmd.args,\n        exitCode: 127,\n        stderr: stderr + `\\n${err.message}`,\n      })\n    })\n    child.on('close', (code) => {\n      resolve({\n        pm: cmd.pm,\n        cwd: cmd.cwd,\n        args: cmd.args,\n        exitCode: code ?? 1,\n        stderr: stderr.trim(),\n      })\n    })\n  })\n}\n","import type { LogEntry } from '@neat.is/types'\n\n// Bounded per-(projectName, source) ring buffer for LogEntry records\n// (docs/contracts/logs.md Rule 4, ADR-132). Fully in-memory, no\n// persistence — a daemon restart loses the buffer, the same trade-off NEAT\n// already accepts for the live graph between snapshots. Every pair owns its\n// own array, so a burst from one source can never evict another pair's\n// entries.\n\n// Default cap: the last 1,000 entries, and nothing older than 24h — both\n// bounds apply independently (see `prune` below), whichever trips first for\n// a given entry.\nexport const LOGS_STORE_MAX_ENTRIES = 1000\nexport const LOGS_STORE_MAX_AGE_MS = 24 * 60 * 60 * 1000\n\n// GET /logs query-param defaults. Exported so the REST route (api.ts) and\n// any future direct caller (MCP's get_logs) share one definition of \"sane\n// max\" rather than each picking their own number.\nexport const LOGS_QUERY_DEFAULT_LIMIT = 100\nexport const LOGS_QUERY_MAX_LIMIT = 1000\n\nconst buffers = new Map<string, LogEntry[]>()\n\n// Separator chosen so an ordinary project name or source string can't\n// collide two distinct (projectName, source) pairs onto the same key —\n// neither a NEAT project name nor a `source` value (logs.md Rule 1's fixed\n// set, extended one string per future connector) is expected to contain it.\nconst KEY_SEP = '::'\n\nfunction bufferKey(projectName: string, source: string): string {\n  return `${projectName}${KEY_SEP}${source}`\n}\n\nfunction sourcesForProject(projectName: string): string[] {\n  const prefix = `${projectName}${KEY_SEP}`\n  const sources: string[] = []\n  for (const key of buffers.keys()) {\n    if (key.startsWith(prefix)) sources.push(key.slice(prefix.length))\n  }\n  return sources\n}\n\n// Drops entries older than the age cap, then trims to the count cap. Both\n// run every append so a buffer never grows past 1,000 elements even\n// mid-burst, and a slow, quiet source still ages its old entries out even\n// though it never fills the count cap.\nfunction prune(entries: LogEntry[], now: number): LogEntry[] {\n  const cutoff = now - LOGS_STORE_MAX_AGE_MS\n  let pruned = entries.filter((e) => {\n    const t = Date.parse(e.timestamp)\n    // A timestamp that fails to parse can't be judged stale — fail open\n    // rather than silently dropping a malformed-but-real entry.\n    return Number.isNaN(t) || t >= cutoff\n  })\n  if (pruned.length > LOGS_STORE_MAX_ENTRIES) {\n    pruned = pruned.slice(pruned.length - LOGS_STORE_MAX_ENTRIES)\n  }\n  return pruned\n}\n\nexport function appendLogEntry(entry: LogEntry): void {\n  const key = bufferKey(entry.projectName, entry.source)\n  const existing = buffers.get(key) ?? []\n  existing.push(entry)\n  buffers.set(key, prune(existing, Date.now()))\n}\n\nexport interface QueryLogEntriesOptions {\n  projectName: string\n  // Repeatable per logs.md §5 — when omitted, every source this project has\n  // ever written an entry under is included.\n  source?: string[]\n  service?: string\n  limit?: number\n  // ISO8601 lower bound, inclusive, matched against each entry's own\n  // `timestamp` (not append time).\n  since?: string\n}\n\n// Newest-first, merged across every matching source bucket for the\n// project, then service/since filtered. `limit` is applied last so a\n// direct caller (a future MCP get_logs, or a test) can ask for a bounded\n// slice without redoing the REST layer's separate total/count bookkeeping;\n// the REST route itself calls this once unlimited (for `total`) and slices\n// the result itself so `total` reflects the filtered-but-unlimited size.\nexport function queryLogEntries(opts: QueryLogEntriesOptions): LogEntry[] {\n  const { projectName, source, service, since, limit } = opts\n  const sources = source && source.length > 0 ? source : sourcesForProject(projectName)\n\n  let merged: LogEntry[] = []\n  for (const src of sources) {\n    const buf = buffers.get(bufferKey(projectName, src))\n    if (buf) merged = merged.concat(buf)\n  }\n\n  if (service) {\n    merged = merged.filter((e) => e.serviceName === service)\n  }\n\n  if (since) {\n    const sinceMs = Date.parse(since)\n    if (!Number.isNaN(sinceMs)) {\n      merged = merged.filter((e) => {\n        const t = Date.parse(e.timestamp)\n        return Number.isNaN(t) || t >= sinceMs\n      })\n    }\n  }\n\n  merged.sort((a, b) => Date.parse(b.timestamp) - Date.parse(a.timestamp))\n\n  if (typeof limit === 'number' && Number.isFinite(limit) && limit >= 0) {\n    return merged.slice(0, limit)\n  }\n  return merged\n}\n\n// Test seam. The store is a module-level singleton with no persistence —\n// tests that append fixture entries need a way back to empty between\n// cases, the same shape `resetGraph()` gives the in-memory graph.\nexport function resetLogsStore(): void {\n  buffers.clear()\n}\n","// The incident-card assembler (ADR-221, docs/contracts/incident-card.md). One\n// self-sufficient work order per incident, composed so an agent reads its\n// context instead of grepping for it: the incident fused with its root-cause\n// chain, blast radius, governing policies, and node divergence — each claim\n// carrying its own provenance.\n//\n// `buildIncidentCard` is a PURE function over the graph and the incident set:\n// no I/O, no mutation, fully synchronous. It composes surface that already ships and\n// computes nothing new (§1). The read of the append-only incident sidecar and\n// the policy file stays at the REST call site; this function never touches disk.\n// It is zero-fabrication (§2): a missing locus is null, a missing cause is null,\n// and each chain hop carries its own provenance rather than a single flattened\n// confidence.\n\nimport {\n  IncidentCardSchema,\n  Provenance,\n  incidentKindOf,\n  type ErrorEvent,\n  type IncidentCard,\n  type IncidentChainHop,\n  type IncidentDeployContext,\n  type IncidentGrade,\n  type IncidentGradeFactor,\n  type IncidentLocus,\n  type Policy,\n  type ProvenanceValue,\n  ObservedDeployContextSchema,\n} from '@neat.is/types'\nimport type { Divergence } from '@neat.is/types'\nimport { flagMismatchPhrase } from './incidents-render.js'\nimport type { NeatGraph } from './graph.js'\nimport { getBlastRadius, getRootCause } from './traverse.js'\nimport { selectApplicablePolicies } from './policy.js'\nimport { computeDivergences } from './divergences.js'\n\nconst CODE_FILEPATH_ATTR = 'code.filepath'\nconst CODE_LINENO_ATTR = 'code.lineno'\nconst BLAST_NEAREST_LIMIT = 5\n\n// The faulted workload's deploy/process/config context (ADR-237/239), read off the\n// workload node where ingest fused it (ADR-243). Shown on the card of the incident it\n// was observed with; any other incident, and every non-k8s one, grows nothing. A\n// card composed for a node with no incident (ADR-244) has no incident to match, so\n// it shows the node's context as it stands (`incidentId` null).\nfunction deployContextOf(\n  graph: NeatGraph,\n  nodeId: string,\n  incidentId: string | null,\n): IncidentDeployContext | undefined {\n  if (!graph.hasNode(nodeId)) return undefined\n  const observed = (graph.getNodeAttributes(nodeId) as { observedDeployContext?: unknown })\n    .observedDeployContext\n  const parsed = ObservedDeployContextSchema.safeParse(observed)\n  if (!parsed.success) return undefined\n  if (incidentId !== null && parsed.data.incidentId !== incidentId) return undefined\n  const { incidentId: _incidentId, observedAt: _observedAt, ...context } = parsed.data\n  return Object.keys(context).length > 0 ? context : undefined\n}\n\n// The node's own grain — read from its `type` attribute, falling back to the id\n// prefix (`service:foo` → `service`) when the node isn't in the graph.\n// Normalized to the grain vocabulary (`SymbolNode` → `symbol`, `FileNode` →\n// `file`) so grain reads the same whichever source it came from.\nfunction grainOf(graph: NeatGraph, nodeId: string): string {\n  if (graph.hasNode(nodeId)) {\n    const t = (graph.getNodeAttributes(nodeId) as { type?: string }).type\n    if (typeof t === 'string' && t.length > 0) {\n      return (t.endsWith('Node') ? t.slice(0, -4) : t).toLowerCase()\n    }\n  }\n  const colon = nodeId.indexOf(':')\n  return colon > 0 ? nodeId.slice(0, colon) : 'unknown'\n}\n\n// The declaring file:line, recovered from the incident's own code.* attributes\n// (ADR-215/216). Null — never fabricated — when the span carried no locus.\nfunction locusOf(graph: NeatGraph, ev: ErrorEvent): IncidentLocus | null {\n  const file = ev.attributes?.[CODE_FILEPATH_ATTR]\n  if (typeof file !== 'string' || file.length === 0) return null\n  const rawLine = ev.attributes?.[CODE_LINENO_ATTR]\n  const line = typeof rawLine === 'number' ? rawLine : Number(rawLine)\n  const node = graph.hasNode(ev.affectedNode)\n    ? (graph.getNodeAttributes(ev.affectedNode) as { type?: string; qualname?: string; service?: string })\n    : undefined\n  // Only a SymbolNode names a symbol, by its `qualname`. An incident whose call\n  // site didn't land on a file falls back to the ServiceNode while keeping its\n  // code.* attributes; that node's `name` is the service, not a symbol, and\n  // reading it would mislabel a file-grain locus as symbol grain.\n  const symbol = node?.type === 'SymbolNode' ? node.qualname : undefined\n  return {\n    file,\n    ...(Number.isFinite(line) ? { lineStart: line, lineEnd: line } : {}),\n    ...(symbol ? { symbol } : {}),\n    service: node?.service ?? ev.service,\n    provenance: Provenance.OBSERVED,\n  }\n}\n\n// The declared file:line a node itself carries — a SymbolNode's `relPath` +\n// definition `span`, or a FileNode's `path`. Used to promote a root-cause locus\n// onto a victim-surfaced card (#1111). Null when the node carries no file — never\n// synthesized.\nfunction locusFromNode(graph: NeatGraph, nodeId: string): IncidentLocus | null {\n  if (!graph.hasNode(nodeId)) return null\n  const n = graph.getNodeAttributes(nodeId) as {\n    relPath?: string\n    path?: string\n    service?: string\n    qualname?: string\n    span?: { startLine?: number; endLine?: number }\n  }\n  const file = n.relPath ?? n.path\n  if (typeof file !== 'string' || file.length === 0) return null\n  const start = n.span?.startLine\n  const end = n.span?.endLine\n  return {\n    file,\n    ...(typeof start === 'number' ? { lineStart: start } : {}),\n    ...(typeof end === 'number' ? { lineEnd: end } : {}),\n    ...(n.qualname ? { symbol: shortLabel(graph, nodeId) } : {}),\n    ...(n.service ? { service: n.service } : {}),\n    provenance: Provenance.INFERRED,\n  }\n}\n\n// #1111: a victim-surfaced incident (a frontend 5xx / gRPC error) carries no code\n// locus of its own, but the resolved root cause does. Surface the cause's locus\n// so the card still points the agent at the code instead of `null`. Prefer the\n// exact failing line from a native incident recorded AT the cause node; else the\n// cause node's own declared definition. Always INFERRED — it names the cause, not\n// the observed surface. Zero-fabrication: only a locus that actually exists.\nfunction promoteCauseLocus(\n  graph: NeatGraph,\n  causeNode: string,\n  incidents: readonly ErrorEvent[],\n): IncidentLocus | null {\n  const native = incidents.find(\n    (e) => e.affectedNode === causeNode && typeof e.attributes?.[CODE_FILEPATH_ATTR] === 'string',\n  )\n  if (native) {\n    const l = locusOf(graph, native)\n    if (l) return { ...l, symbol: shortLabel(graph, causeNode), provenance: Provenance.INFERRED }\n  }\n  return locusFromNode(graph, causeNode)\n}\n\n// A short, union-safe summary for a divergence at the node — `source/target`\n// (and `table.column` when present) are on every variant, so this never trips\n// on a variant-specific field. The `type` carries the semantic. A symbol-grain\n// mismatch (ADR-215) carries the code node as both endpoints, so it names the\n// member and where it's read instead of `X → X` (#1113).\nexport function divergenceSummary(d: Divergence): string {\n  if (d.type === 'flag-mismatch') return flagMismatchPhrase(d)\n  if (d.type === 'observed-symbol-mismatch' || d.source === d.target) {\n    const symbol = 'symbol' in d && d.symbol ? d.symbol : d.source\n    const at = 'location' in d && d.location ? ` at ${d.location}` : ''\n    return `${symbol}${at}`\n  }\n  const column = 'column' in d && d.column ? `.${d.column}` : ''\n  const label = 'table' in d && d.table ? `${d.table}${column}` : `${d.source} → ${d.target}`\n  return label\n}\n\n// The file's base name — the headline stays readable while the structured\n// `locus.file` keeps the absolute path the agent opens. A pure string split, so\n// the assembler's no-I/O purity holds (no `node:path` import).\nfunction baseName(p: string): string {\n  const parts = p.split(/[\\\\/]/)\n  return parts[parts.length - 1] || p\n}\n\n// A short human label for a node id — the graph node's `name`, else the id's\n// terminal segment (after `#`, then after the last `:`). Never the raw id.\nfunction shortLabel(graph: NeatGraph, nodeId: string): string {\n  if (graph.hasNode(nodeId)) {\n    const name = (graph.getNodeAttributes(nodeId) as { name?: string }).name\n    if (typeof name === 'string' && name.length > 0) return name\n  }\n  const afterHash = nodeId.includes('#') ? nodeId.slice(nodeId.lastIndexOf('#') + 1) : nodeId\n  return afterHash.includes(':') ? afterHash.slice(afterHash.lastIndexOf(':') + 1) : afterHash\n}\n\n// The one-line sentence (ADR-221) — a human/loose-LLM read over the structured\n// body. Deterministic and total: it renders whatever the card actually carries,\n// using the file's base name and human labels — never an absolute path or a raw\n// node id (the structured fields keep those).\nfunction renderHeadline(\n  graph: NeatGraph,\n  ev: ErrorEvent,\n  locus: IncidentLocus | null,\n  causeNode: string | null,\n): string {\n  const what = ev.exceptionType ? `raised ${ev.exceptionType}` : ev.errorMessage || 'failed'\n  const causeLabel = causeNode && causeNode !== ev.affectedNode ? shortLabel(graph, causeNode) : ''\n  if (locus) {\n    const base = baseName(locus.file)\n    const lines =\n      locus.lineStart != null\n        ? locus.lineEnd && locus.lineEnd !== locus.lineStart\n          ? `LINES ${locus.lineStart}-${locus.lineEnd}`\n          : `LINE ${locus.lineStart}`\n        : ''\n    // Prefer the recovered symbol; else, when the incident lands on a\n    // symbol-grain node, name it from the node id — so a symbol incident reads\n    // as SYMBOL, not FILE.\n    const symbol =\n      locus.symbol ??\n      (grainOf(graph, ev.affectedNode) === 'symbol'\n        ? shortLabel(graph, ev.affectedNode)\n        : undefined)\n    const subject = symbol ? `SYMBOL ${symbol}` : `FILE ${base}`\n    const at = symbol ? `${lines ? `${lines} in ` : ''}${base}` : lines\n    const where = at ? ` at ${at}` : ''\n    // Attribute the file to the service that owns it (the promoted cause may live\n    // in a different service than where the incident surfaced), and drop the\n    // \"→ root cause X\" tail when the subject already names that cause (#1111).\n    const svc = locus.service ?? ev.service\n    const cause = causeLabel && causeLabel !== symbol ? ` → root cause ${causeLabel}` : ''\n    return `${subject}${where} (SERVICE ${svc}) ${what} at ${ev.timestamp}${cause}`\n  }\n  const cause = causeLabel ? ` → root cause ${causeLabel}` : ''\n  return `SERVICE ${ev.service} ${what} at ${ev.timestamp}${cause}`\n}\n\n// The headline of a card composed for a node with no recorded incident\n// (ADR-244). It says so plainly and names the root cause when one resolved;\n// it never states a failure the graph didn't record.\nfunction renderNodeHeadline(\n  graph: NeatGraph,\n  nodeId: string,\n  service: string | null,\n  causeNode: string | null,\n): string {\n  const subject = `${grainOf(graph, nodeId).toUpperCase()} ${shortLabel(graph, nodeId)}`\n  const owner = service && grainOf(graph, nodeId) !== 'service' ? ` (SERVICE ${service})` : ''\n  const cause = causeNode && causeNode !== nodeId ? ` → root cause ${shortLabel(graph, causeNode)}` : ''\n  return `${subject}${owner} has no recorded incident${cause}`\n}\n\n// The service that owns a node: a ServiceNode's own name, else the node's\n// `service`. Null when the graph records none — never guessed from the id.\nfunction serviceOfNode(graph: NeatGraph, nodeId: string): string | null {\n  if (!graph.hasNode(nodeId)) return null\n  const n = graph.getNodeAttributes(nodeId) as { type?: string; name?: string; service?: string }\n  if (n.type === 'ServiceNode' && typeof n.name === 'string' && n.name.length > 0) return n.name\n  return typeof n.service === 'string' && n.service.length > 0 ? n.service : null\n}\n\nexport const NO_INCIDENT_REASON =\n  'composed from the graph; no recorded incident for this node, so the fields only an incident supplies (id, at, incidentKind, message) are null'\n\nexport function buildIncidentCard(\n  graph: NeatGraph,\n  errorEvent: ErrorEvent,\n  incidents: readonly ErrorEvent[],\n  policies: Policy[],\n): IncidentCard {\n  return composeCard(graph, errorEvent.affectedNode, errorEvent, incidents, policies)\n}\n\n/**\n * The same card, composed for a node with no recorded incident (ADR-244): the\n * pull a caller makes to ask \"compose the incident for this node\". Root cause,\n * blast radius, policies and divergence compose as for any card; `id`, `at`,\n * `incidentKind` and `message` are null and `noIncident.reason` says why.\n */\nexport function composeNodeCard(\n  graph: NeatGraph,\n  nodeId: string,\n  incidents: readonly ErrorEvent[],\n  policies: Policy[],\n): IncidentCard {\n  return composeCard(graph, nodeId, null, incidents, policies)\n}\n\nfunction composeCard(\n  graph: NeatGraph,\n  affected: string,\n  errorEvent: ErrorEvent | null,\n  incidents: readonly ErrorEvent[],\n  policies: Policy[],\n): IncidentCard {\n  let locus = errorEvent ? locusOf(graph, errorEvent) : null\n  // The incident may be attributed to a node the live graph no longer carries\n  // (a retired node, or service:unidentified). The graph-walking queries need\n  // the node to exist; when it doesn't, the card degrades to locus + headline\n  // rather than throwing — the same honest degradation as a missing locus.\n  const inGraph = graph.hasNode(affected)\n\n  // Root cause + its chain, each hop stamped with the provenance of the edge\n  // into it. Null when no cause is reachable — the incident still ships.\n  const rc = inGraph ? getRootCause(graph, affected, errorEvent ?? undefined, [...incidents]) : null\n  let rootCause: IncidentCard['rootCause'] = null\n  if (rc) {\n    const provs = rc.edgeProvenances ?? []\n    const chain: IncidentChainHop[] = (rc.traversalPath ?? []).map((node, i) => ({\n      node,\n      grain: grainOf(graph, node),\n      provenance: (provs[i] ??\n        provs[provs.length - 1] ??\n        Provenance.INFERRED) as ProvenanceValue,\n    }))\n    rootCause = {\n      node: rc.rootCauseNode,\n      ...(rc.candidates?.[0]?.classification\n        ? { classification: rc.candidates[0].classification }\n        : {}),\n      reason: rc.rootCauseReason,\n      confidence: rc.confidence,\n      fix: rc.fixRecommendation ?? null,\n      chain,\n    }\n  }\n\n  // #1111: the incident surfaced on a node with no code locus of its own (a\n  // frontend/proxy victim), but the root cause resolved to a node that carries a\n  // file:line. Promote the cause's locus (INFERRED) so the card — and its\n  // headline — still point the agent at the code instead of `null`.\n  if (locus === null && rootCause) {\n    locus = promoteCauseLocus(graph, rootCause.node, incidents)\n  }\n\n  // What a fix at the locus would reach — the total plus the nearest nodes.\n  const blast = inGraph\n    ? getBlastRadius(graph, affected)\n    : { origin: affected, affectedNodes: [], totalAffected: 0 }\n  const nearest = [...blast.affectedNodes]\n    .sort((a, b) => a.distance - b.distance)\n    .slice(0, BLAST_NEAREST_LIMIT)\n    .map((n) => ({ node: n.nodeId, distance: n.distance, provenance: n.edgeProvenance }))\n\n  // The rules that govern the node (soft guardrail, ADR-108).\n  const applicable = inGraph ? selectApplicablePolicies(graph, policies, affected) : []\n  const policyCards = applicable.map((p) => ({\n    policyName: p.policyName,\n    severity: p.severity,\n    message: p.reason,\n    onViolation: p.onViolation,\n  }))\n\n  // Any code↔runtime divergence already standing at the node.\n  const divergences = inGraph\n    ? computeDivergences(graph, { node: affected, incidents }).divergences.map((d) => ({\n        type: d.type,\n        summary: divergenceSummary(d),\n      }))\n    : []\n\n  const service = errorEvent ? errorEvent.service : serviceOfNode(graph, affected)\n  const card: IncidentCard = {\n    kind: 'incident',\n    id: errorEvent ? errorEvent.id : null,\n    at: errorEvent ? errorEvent.timestamp : null,\n    incidentKind: errorEvent ? incidentKindOf(errorEvent) : null,\n    service,\n    affectedNode: affected,\n    message: errorEvent ? errorEvent.errorMessage : null,\n    ...(errorEvent ? {} : { noIncident: { reason: NO_INCIDENT_REASON } }),\n    ...(errorEvent?.exceptionType ? { exceptionType: errorEvent.exceptionType } : {}),\n    ...(errorEvent?.httpStatusCode !== undefined\n      ? { httpStatusCode: errorEvent.httpStatusCode }\n      : {}),\n    ...(errorEvent?.incidentCount !== undefined ? { count: errorEvent.incidentCount } : {}),\n    ...(errorEvent?.firstTimestamp && errorEvent.lastTimestamp\n      ? { window: { first: errorEvent.firstTimestamp, last: errorEvent.lastTimestamp } }\n      : {}),\n    ...(errorEvent?.traceId ? { traceId: errorEvent.traceId } : {}),\n    ...(errorEvent?.spanId ? { spanId: errorEvent.spanId } : {}),\n    locus,\n    rootCause,\n    ...(nearest.length > 0\n      ? { blastRadius: { totalAffected: blast.totalAffected, nearest } }\n      : {}),\n    ...(policyCards.length > 0 ? { policies: policyCards } : {}),\n    ...(divergences.length > 0 ? { divergence: divergences } : {}),\n    ...((): { deployContext?: IncidentDeployContext } => {\n      const dc = deployContextOf(graph, affected, errorEvent?.id ?? null)\n      return dc ? { deployContext: dc } : {}\n    })(),\n    headline: errorEvent\n      ? renderHeadline(graph, errorEvent, locus, rootCause?.node ?? null)\n      : renderNodeHeadline(graph, affected, service, rootCause?.node ?? null),\n  }\n  card.grade = gradeIncidentCard(card)\n\n  // Validate the composed shape before it leaves the assembler (§Enforcement).\n  return IncidentCardSchema.parse(card)\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// The incident grade (ADR-238): G = Γ·C, from the card's own fields only.\n// ──────────────────────────────────────────────────────────────────────────\n\n// The priors from neat-sniper's architecture (\"The incident grade\"). They ship\n// as priors; calibration against labelled incidents comes later and bumps this.\nexport const GRADE_PRIORS_VERSION = 'sniper-architecture-priors-2026-10-08'\nconst GRADE_WEIGHTS = {\n  evidence: 3,\n  locus: 2,\n  tests: 2,\n  reach: 1.5,\n  kind: 1.5,\n  chain: 1,\n  recur: 1,\n  div: 1,\n} as const\nconst PROVENANCE_WEIGHT: Record<string, number> = {\n  OBSERVED: 1,\n  EXTRACTED: 0.8,\n  INFERRED: 0.4,\n  FRONTIER: 0.3,\n  STALE: 0.2,\n}\n// The blast radius at which a fix stops counting as contained. The architecture\n// states F_max in files at Sniper's admission bound; the card carries the\n// blast radius's total node count, so this prior is in nodes.\nconst REACH_NODES_MAX = 50\nconst TIMEOUT = /timeout|timed out|deadline/i\n\nconst round = (n: number): number => Math.round(n * 10_000) / 10_000\n\nfunction factor(\n  name: keyof typeof GRADE_WEIGHTS,\n  value: number | null,\n  evidence: string[],\n  reason?: string,\n): IncidentGradeFactor {\n  return {\n    value: value === null ? null : round(value),\n    weight: GRADE_WEIGHTS[name],\n    evidence,\n    ...(reason ? { reason } : {}),\n  }\n}\n\n/**\n * The incident grade, computed from the card alone — pure, synchronous, total.\n * Every factor names the card fields it read. A factor the card can't support is\n * null with a reason and leaves the weighted mean; the grade never guesses.\n */\nexport function gradeIncidentCard(card: Omit<IncidentCard, 'grade'>): IncidentGrade {\n  const rc = card.rootCause\n  const chain = rc?.chain ?? []\n\n  const gates: IncidentGrade['gates'] = {\n    policyNotBlock: {\n      passed: !(card.policies ?? []).some((p) => p.onViolation === 'block'),\n      evidence: ['policies[].onViolation'],\n    },\n    notSymptomOnly: {\n      passed: rc?.classification !== 'symptom-only',\n      evidence: ['rootCause.classification'],\n    },\n    locusResolves: { passed: card.locus !== null, evidence: ['locus'] },\n  }\n  const gamma = Object.values(gates).every((g) => g.passed) ? 1 : 0\n\n  // A chain is as strong as its least-trusted hop. Hops that say they carry the\n  // signal are the carrying hops; with no such marks, every hop carries it.\n  const carrying = chain.some((h) => h.carriesSignal === true)\n    ? chain.filter((h) => h.carriesSignal === true)\n    : chain\n  const hopWeights = carrying.map((h) => PROVENANCE_WEIGHT[h.provenance])\n  const evidence =\n    hopWeights.length === 0\n      ? factor('evidence', null, ['rootCause.chain[].provenance'], 'no root-cause chain on the card')\n      : hopWeights.some((w) => w === undefined)\n        ? factor('evidence', null, ['rootCause.chain[].provenance'], 'a chain hop has a provenance with no weight')\n        : factor('evidence', Math.min(...(hopWeights as number[])), ['rootCause.chain[].provenance'])\n\n  const locus = card.locus\n    ? factor('locus', card.locus.symbol ? 1 : 0.6, ['locus.symbol', 'locus.file'])\n    : factor('locus', null, ['locus'], 'no locus on the card (the locus gate fails)')\n\n  const tests = factor(\n    'tests',\n    null,\n    [],\n    'the card carries no test-file classification or test-to-symbol edges',\n  )\n\n  const reach = card.blastRadius\n    ? factor(\n        'reach',\n        Math.max(0, 1 - card.blastRadius.totalAffected / REACH_NODES_MAX),\n        ['blastRadius.totalAffected'],\n        `nodes in the blast radius against a prior bound of ${REACH_NODES_MAX}`,\n      )\n    : factor('reach', null, ['blastRadius'], 'no blast radius on the card')\n\n  const timeout = TIMEOUT.test(`${card.exceptionType ?? ''} ${card.message ?? ''}`)\n  const kindValue = card.incidentKind === null\n    ? null\n    : timeout\n    ? 0.3\n    : card.incidentKind === 'exception'\n      ? 1\n      : card.incidentKind === '5xx' || card.incidentKind === 'status-error'\n        ? 0.7\n        : card.incidentKind === 'connector'\n          ? 0.6\n          : 0.4\n  const kind = factor(\n    'kind',\n    kindValue,\n    ['incidentKind', 'exceptionType', 'message'],\n    kindValue === null ? 'no incident on the card' : undefined,\n  )\n\n  const chainFactor = rc\n    ? factor(\n        'chain',\n        1 / (1 + 0.25 * (Math.max(1, chain.length - 1) - 1)),\n        ['rootCause.chain'],\n      )\n    : factor('chain', null, ['rootCause'], 'no root cause on the card')\n\n  const occurrences = card.count ?? 1\n  const recur = card.noIncident\n    ? factor('recur', null, ['count'], 'no incident on the card')\n    : factor(\n        'recur',\n        Math.min(1, Math.log(1 + occurrences) / Math.log(11)),\n        ['count'],\n        card.count === undefined ? 'no coalesced count; one recorded occurrence' : undefined,\n      )\n\n  const div = factor('div', (card.divergence ?? []).length > 0 ? 1 : 0.7, ['divergence'])\n\n  const factors = { evidence, locus, tests, reach, kind, chain: chainFactor, recur, div }\n  let weighted = 0\n  let total = 0\n  for (const f of Object.values(factors)) {\n    if (f.value === null) continue\n    weighted += f.weight * f.value\n    total += f.weight\n  }\n  // div is always computable, so total is never zero.\n  const C = round(weighted / total)\n  const G = round(gamma * C)\n  const band = gamma === 0 || G < 0.5 ? 'out' : G >= 0.75 ? 'full' : 'diagnose-only'\n\n  return {\n    G,\n    gamma,\n    gates,\n    C,\n    factors,\n    band,\n    urgency: {\n      value: null,\n      reason: 'f_fresh needs the time of the last OBSERVED signal at the node, which the card does not carry',\n    },\n    priorsVersion: GRADE_PRIORS_VERSION,\n  }\n}\n","import {\n  ObservedDeployContextSchema,\n  type DeployContext,\n  type ErrorEvent,\n  type FlagMismatchDivergence,\n} from '@neat.is/types'\n\n// The OBSERVED deploy/process/config context of a faulted workload (ADR-237/240),\n// fused onto its node at ingest (ADR-243): the deploy fault, the faulted\n// container's redacted env/args, and its boot-time stdout tail. Rendered compactly\n// so the incident surfaces the wrong host / bad flag / crash traceback inline\n// instead of leaving it to the card.\n//\n// One renderer, every text reader: the CLI `neat incidents` output (cli-client.ts)\n// and the MCP get_incident_history / incident-card tools (packages/mcp) all call\n// this, so they never drift (core #1373 — atomic, no feature mirrors another's\n// fields). Returns [] when there is no context, so those lines read exactly as\n// before.\nexport function deployHintLines(ctx: DeployContext | undefined): string[] {\n  if (!ctx) return []\n  const env = ctx.containerEnv ?? []\n  const args = ctx.containerArgs ?? []\n  const log = ctx.processLog\n  if (!ctx.fault && env.length === 0 && args.length === 0 && !log) return []\n  const out: string[] = []\n  if (ctx.fault) {\n    const bits = [ctx.fault]\n    if (ctx.waitingReason) bits.push(ctx.waitingReason)\n    if (ctx.restartCount !== undefined) bits.push(`restarts=${ctx.restartCount}`)\n    if (ctx.exitCode !== undefined) bits.push(`exit=${ctx.exitCode}`)\n    if (ctx.terminatedReason) bits.push(ctx.terminatedReason)\n    out.push(`deploy: ${bits.join(' ')}`)\n  }\n  const cap = (xs: string[], max: number): string => {\n    const joined = xs.join('  ')\n    return joined.length > max ? `${joined.slice(0, max)}…(+${xs.length} entries)` : joined\n  }\n  if (env.length > 0) out.push(`env: ${cap(env, 700)}`)\n  if (args.length > 0) out.push(`args: ${cap(args, 300)}`)\n  if (log) {\n    const tail = log.split('\\n').filter((l) => l.trim().length > 0).slice(-4)\n    if (tail.length > 0) out.push(`log: ${tail.join(' ⏎ ')}`)\n  }\n  return out\n}\n\n// The deploy context on each incident's workload node, keyed by the incident it\n// was observed with (ADR-243). `readNode` is the caller's own GET /graph/node/:id;\n// it runs once per distinct affected node, and a node that can't be read just\n// shows no context.\nexport async function deployContextsFor(\n  events: ErrorEvent[],\n  readNode: (nodeId: string) => Promise<{ observedDeployContext?: unknown } | undefined>,\n): Promise<Map<string, DeployContext>> {\n  const byIncident = new Map<string, DeployContext>()\n  for (const nodeId of new Set(events.map((e) => e.affectedNode))) {\n    try {\n      const parsed = ObservedDeployContextSchema.safeParse((await readNode(nodeId))?.observedDeployContext)\n      if (!parsed.success) continue\n      const { incidentId, observedAt: _observedAt, ...ctx } = parsed.data\n      byIncident.set(incidentId, ctx)\n    } catch {\n      // The incident list still renders without the context.\n    }\n  }\n  return byIncident\n}\n\n// A flag-grain divergence (ADR-242) in one phrase, the same on every surface that\n// names one: the card's divergence summary, `neat divergences`, MCP\n// get_divergences and the monitor stream. Names the flag, the committed and the\n// running variant, and where the code reads it.\nexport function flagMismatchPhrase(d: FlagMismatchDivergence): string {\n  const q = (v: string | null | undefined): string => (v === null || v === undefined ? 'none' : v)\n  const what = d.changed.includes('defaultVariant')\n    ? `committed ${q(d.declaredVariant)}, running ${q(d.observedVariant)}`\n    : `${d.changed.join(', ')} changed from the committed definition`\n  const at = d.readers && d.readers.length > 0 ? ` (read at ${d.readers.join(', ')})` : ''\n  return `flag ${d.flagKey}: ${what}${at}`\n}\n","// ask (ADR-198) — the plain-language door over the fused graph.\n//\n// NEAT's tools are structured: get_root_cause(nodeId), get_dependencies(nodeId),\n// get_blast_radius(nodeId). To use them an agent has to already know WHICH tool\n// and the exact NODE ID — higher friction than `grep`, so in practice the agent\n// grep-scans source instead of reaching for the graph even when the graph would\n// answer better. `ask` closes that gap: one natural-language question in, one\n// compact provenance-tagged answer out.\n//\n// It is a ROUTER/COMPOSER over the traversals in traverse.ts + the divergence\n// query, not a new engine. Two deterministic steps and then existing walks:\n//\n//   1. Resolve the question's entities to graph nodes — token/label overlap\n//      against node ids + names, plus the semantic_search embedder against node\n//      labels (the graphify vocab-expansion move). NO LLM in the engine\n//      (docs/contracts/llm-policy.md): the calling agent is the only model.\n//   2. Read the question's intent off a fixed English keyword vocabulary — never\n//      a provider / framework / language name, so `ask` stays as agnostic as the\n//      traversal core it composes (docs/contracts/traversal.md).\n//   3. Compose the intent-relevant traversal (leading with get_root_cause's\n//      navigation when the question is root-cause-shaped) plus a compact fused\n//      local context, every fact provenance-tagged + confidence-scored\n//      (docs/contracts/provenance.md).\n\nimport type {\n  AskFact,\n  AskIntent,\n  AskMatch,\n  AskResult,\n  AskSection,\n  Divergence,\n  DivergenceType,\n  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  RootCauseCandidate,\n} from '@neat.is/types'\nimport { AskResultSchema, NodeType, Provenance, serviceId } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport type { SearchIndex } from './search.js'\nimport { computeDivergences } from './divergences.js'\nimport {\n  confidenceForEdge,\n  getBlastRadius,\n  getObservedDependencies,\n  getRootCause,\n  getTransitiveDependencies,\n} from './traverse.js'\n\nexport interface AskOptions {\n  // The embedder-backed node index (semantic_search). When present it widens\n  // entity resolution beyond literal token overlap, the same way graphify's\n  // vocab expansion rescues a wording mismatch. Absent → token/label match only.\n  searchIndex?: SearchIndex\n  // The recorded incident store, so a root-cause / incidents question answers\n  // from OBSERVED failures the graph can't carry on an edge.\n  incidents?: ErrorEvent[]\n  // Clock seam for deterministic tests.\n  now?: number\n  // Cap on how many entities the question resolves to (default 3).\n  maxNodes?: number\n}\n\nconst DEFAULT_MAX_NODES = 3\nconst MAX_FACTS_PER_SECTION = 6\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Intent — a fixed English keyword vocabulary, checked in priority order. The\n// words are question shapes (\"why\", \"depends\", \"weird\"), never provider /\n// framework / language names, so the router never smuggles adapter knowledge in.\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface IntentRule {\n  intent: AskIntent\n  test: RegExp\n}\n\n// Order matters: the first rule that fires wins. Root-cause (a failure question)\n// is the most specific and leads; overview is the catch-all fallback below.\nconst INTENT_RULES: IntentRule[] = [\n  {\n    intent: 'root-cause',\n    test: /\\b(why|root[\\s-]?cause|failing|fail(?:s|ed)?|breaking|broke(?:n)?|crash(?:ing|ed)?|throw(?:ing|s)?|culprit|5\\d\\d)\\b/,\n  },\n  {\n    intent: 'blast-radius',\n    test: /\\b(blast|break[\\s-]?if|breaks[\\s-]?if|impact|downstream|dependents?|redeploy|who\\s+(?:uses|calls|depends(?:\\s+on)?)|what\\s+depends\\s+on|consumers?\\s+of|callers?\\s+of|affect(?:s|ed)?)\\b/,\n  },\n  {\n    // The second branch catches a flag question phrased as a divergence — a flag\n    // the store serves differently from what the flag file committed (ADR-242).\n    // \"flag\" alone is not enough (it would swallow \"what does the flag store call\"\n    // into divergence); it must sit beside a serving/committed/different signal.\n    intent: 'divergence',\n    test: /\\b(diverg\\w*|weird|mismatch|drift|out\\s+of\\s+sync|inconsistent|disagree\\w*|declared\\s+vs|anything\\s+wrong)\\b|(?=[\\s\\S]*\\bflags?\\b)(?=[\\s\\S]*\\b(?:serv\\w*|commit\\w*|different)\\b)/,\n  },\n  {\n    intent: 'incidents',\n    test: /\\b(incidents?|recent\\s+(?:errors?|failures?)|error\\s+history|failure\\s+history)\\b/,\n  },\n  {\n    intent: 'observed',\n    test: /\\b(at\\s+runtime|in\\s+prod(?:uction)?|actually|really\\s+call\\w*|observed|runtime\\s+traffic|slow|latency|p95|timing)\\b/,\n  },\n  {\n    intent: 'dependencies',\n    test: /\\b(depend\\w*|calls?|uses?|imports?|relies\\s+on|needs?|talks?\\s+to|connects?\\s+to|hits?|reads?\\s+from|writes?\\s+to)\\b/,\n  },\n]\n\nexport function classifyIntent(question: string): AskIntent {\n  const q = question.toLowerCase()\n  for (const rule of INTENT_RULES) {\n    if (rule.test.test(q)) return rule.intent\n  }\n  return 'overview'\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Entity resolution — deterministic. Token/label overlap over node ids + names,\n// widened by the embedder when one is available.\n// ─────────────────────────────────────────────────────────────────────────────\n\n// Words that carry no entity signal — dropped from the query so they never match\n// a node. Intent keywords are dropped too (they steer routing, not resolution).\nconst STOPWORDS = new Set([\n  'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been', 'being', 'of',\n  'to', 'in', 'on', 'at', 'by', 'for', 'with', 'and', 'or', 'but', 'if', 'as',\n  'this', 'that', 'these', 'those', 'it', 'its', 'do', 'does', 'did', 'has',\n  'have', 'had', 'what', 'which', 'who', 'whom', 'how', 'when', 'where', 'my',\n  'me', 'i', 'we', 'you', 'they', 'them', 'from', 'into', 'about', 'would',\n  'will', 'can', 'could', 'should', 'anything', 'everything', 'something', 'all',\n  'any', 'some', 'no', 'not', 'so', 'up', 'out', 'over', 'get', 'got', 'show',\n  'tell', 'explain', 'find', 'give', 'happen', 'happens', 'happening', 'here',\n  'there', 'system', 'code', 'service', 'node', 'graph',\n])\n\n// The routing words also carry no entity signal — strip them so \"why is checkout\n// failing\" resolves on \"checkout\", not \"why\"/\"failing\".\nconst INTENT_WORDS = new Set([\n  'why', 'root', 'cause', 'failing', 'fail', 'fails', 'failed', 'breaking',\n  'broke', 'broken', 'crash', 'crashing', 'crashed', 'throw', 'throwing',\n  'throws', 'culprit', 'blast', 'radius', 'break', 'breaks', 'impact',\n  'downstream', 'dependent', 'dependents', 'redeploy', 'affect', 'affects',\n  'affected', 'diverge', 'divergence', 'divergences', 'weird', 'mismatch',\n  'drift', 'inconsistent', 'disagree', 'declared', 'observed', 'incident',\n  'incidents', 'recent', 'errors', 'error', 'failures', 'failure', 'history',\n  'runtime', 'production', 'prod', 'traffic', 'actually', 'really', 'depend',\n  'depends', 'dependency', 'dependencies', 'call', 'calls', 'use', 'uses',\n  'using', 'import', 'imports', 'relies', 'rely', 'needs', 'need', 'sync',\n  'talk', 'talks', 'connect', 'connects', 'hit', 'hits', 'read', 'reads',\n  'write', 'writes', 'consumer', 'consumers', 'caller', 'callers', 'slow',\n  'latency', 'p95', 'timing', 'flag', 'flags', 'committed', 'serving',\n])\n\n// camelCase / kebab / snake / path splitter → lowercase alphanumeric tokens.\nfunction tokens(input: string): string[] {\n  const spaced = input.replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n  return (spaced.toLowerCase().match(/[a-z0-9]+/g) ?? []).filter((t) => t.length >= 2)\n}\n\nfunction queryTokens(question: string): string[] {\n  const seen = new Set<string>()\n  const out: string[] = []\n  for (const t of tokens(question)) {\n    if (STOPWORDS.has(t) || INTENT_WORDS.has(t)) continue\n    if (seen.has(t)) continue\n    seen.add(t)\n    out.push(t)\n  }\n  return out\n}\n\nfunction nodeName(node: GraphNode): string {\n  return (node as { name?: string }).name ?? node.id\n}\n\n// The distinctive part of a node id — everything after its `type:` prefix\n// (`service:checkout` → `checkout`, `database:payments-db` → `payments-db`).\nfunction idBody(id: string): string {\n  const colon = id.indexOf(':')\n  return colon >= 0 ? id.slice(colon + 1) : id\n}\n\ninterface Scored {\n  nodeId: string\n  label: string\n  via: AskMatch['via']\n  score: number\n}\n\nconst TYPE_NOUNS: ReadonlyArray<{ nouns: readonly string[]; type: NodeType }> = [\n  { nouns: ['database', 'db', 'table'], type: NodeType.DatabaseNode },\n  { nouns: ['service', 'api', 'backend'], type: NodeType.ServiceNode },\n  { nouns: ['route', 'endpoint'], type: NodeType.RouteNode },\n  { nouns: ['file'], type: NodeType.FileNode },\n  { nouns: ['config'], type: NodeType.ConfigNode },\n]\n\ninterface EntityResolution {\n  matched: AskMatch[]\n  ambiguousType?: { noun: string; ids: string[] }\n}\n\n// Only an embedder match this similar (or better) is trusted on its own; below\n// it, an embedding-only hit is noise and dropped. Token matches are kept\n// regardless — they are exact overlaps, not similarity guesses.\nconst EMBED_MIN_SCORE = 0.35\n\n// Resolve the question to nodes. Token/label overlap first, then fold in the\n// embedder's matches (semantic_search against node labels) so a wording mismatch\n// still lands. Returns best match first, capped at `maxNodes`.\nasync function resolveEntities(\n  graph: NeatGraph,\n  question: string,\n  searchIndex: SearchIndex | undefined,\n  maxNodes: number,\n): Promise<EntityResolution> {\n  // A word that is a node id verbatim (`database:orders-db`) is an explicit\n  // reference: it resolves to that node and nothing else, before any fuzzy pass\n  // can land on a same-named node of another type (#1051).\n  const verbatim: AskMatch[] = []\n  for (const word of question.split(/\\s+/)) {\n    const id = word.replace(/^[\"'`(<]+|[\"'`)>?!.,;]+$/g, '')\n    if (!id || !graph.hasNode(id) || verbatim.some((m) => m.nodeId === id)) continue\n    const node = graph.getNodeAttributes(id) as GraphNode\n    if (node.type === NodeType.FrontierNode) continue\n    verbatim.push({ nodeId: id, label: nodeName(node), via: 'id', score: 1 })\n  }\n  if (verbatim.length > 0) return { matched: verbatim.slice(0, maxNodes) }\n\n  const qTokens = queryTokens(question)\n  const normalized = question.toLowerCase()\n  const best = new Map<string, Scored>()\n\n  const consider = (cand: Scored): void => {\n    const cur = best.get(cand.nodeId)\n    if (cur?.via === 'id' && cand.via === 'embedding') return\n    if (!cur || cand.score > cur.score) best.set(cand.nodeId, cand)\n  }\n\n  // Pass 1 — token/label overlap over every node.\n  graph.forEachNode((id, attrs) => {\n    const node = attrs as GraphNode\n    if (node.type === NodeType.FrontierNode) return\n    const name = nodeName(node)\n    const body = idBody(id)\n    const labelTokens = new Set([...tokens(body), ...tokens(name)])\n    if (labelTokens.size === 0) return\n\n    let matched = 0\n    for (const t of qTokens) if (labelTokens.has(t)) matched += 1\n    // The node's own distinctive id/name appearing verbatim in the question is\n    // the strongest signal — an explicit reference, not a token coincidence.\n    const named =\n      (body.length >= 2 && normalized.includes(body.toLowerCase())) ||\n      (name.length >= 2 && normalized.includes(name.toLowerCase()))\n    if (matched === 0 && !named) return\n\n    const coverage = qTokens.length > 0 ? matched / qTokens.length : 0\n    const via: AskMatch['via'] = named ? 'id' : matched > 0 && tokens(name).some((t) => qTokens.includes(t)) ? 'label' : 'token'\n    const score = named ? Math.max(0.9, coverage) : Math.min(0.85, 0.3 + 0.7 * coverage)\n    consider({ nodeId: id, label: name, via, score: Math.min(1, score) })\n  })\n\n  // Pass 2 — the embedder. Its cosine score is a genuine semantic match against\n  // the node label; fold it in so a question phrased unlike the code still lands.\n  if (searchIndex) {\n    try {\n      const res = await searchIndex.search(question, 10)\n      // The substring fallback returns a placeholder score of 1 that would swamp\n      // real token overlap — pass 1 already covers substring, so skip that tier.\n      if (res.provider !== 'substring') {\n        for (const m of res.matches) {\n          if (m.node.type === NodeType.FrontierNode) continue\n          if (!graph.hasNode(m.node.id)) continue\n          const already = best.get(m.node.id)\n          if (!already && m.score < EMBED_MIN_SCORE) continue\n          consider({\n            nodeId: m.node.id,\n            label: nodeName(m.node),\n            via: 'embedding',\n            score: Math.max(0, Math.min(1, m.score)),\n          })\n        }\n      }\n    } catch {\n      // A flaky embedder must never sink a query that token matching answered.\n    }\n  }\n\n  // A kind noun is a fallback only after both exact wording and semantic search\n  // have had a chance to find a specific subject. Otherwise \"the API order\n  // processor\" would become an ambiguity even when the index knows the node.\n  if (best.size === 0) {\n    const words = new Set(tokens(question))\n    const kind = TYPE_NOUNS.find((entry) => entry.nouns.some((noun) => words.has(noun)))\n    if (kind) {\n      const ids = graph.filterNodes((_id, attrs) => (attrs as GraphNode).type === kind.type).sort()\n      if (ids.length > 1) {\n        return { matched: [], ambiguousType: { noun: kind.nouns.find((noun) => words.has(noun))!, ids } }\n      }\n      if (ids.length === 1) {\n        const id = ids[0]!\n        return { matched: [{ nodeId: id, label: nodeName(graph.getNodeAttributes(id) as GraphNode), via: 'type', score: 0.6 }].slice(0, maxNodes) }\n      }\n      return { matched: [] }\n    }\n  }\n\n  const viaRank: Record<AskMatch['via'], number> = { id: 4, label: 3, token: 2, type: 1, embedding: 0 }\n  const ranked = [...best.values()].sort(\n    (a, b) =>\n      Number(b.via === 'id') - Number(a.via === 'id') ||\n      b.score - a.score || viaRank[b.via] - viaRank[a.via] || a.nodeId.localeCompare(b.nodeId),\n  )\n  // With a clear primary (an id match at 0.85 or better), secondaries ride along only when they are\n  // close in score or of the same node type — a \"db\" token overlapping \"db-config\" must not sit\n  // beside a 0.90 id hit as if it were a second subject.\n  const primary = ranked[0]\n  const primaryType = primary && graph.getNodeAttributes(primary.nodeId).type\n  const matched = ranked\n    .filter(\n      (candidate) =>\n        !primary || primary.via !== 'id' || primary.score < 0.85 || candidate === primary ||\n        graph.getNodeAttributes(candidate.nodeId).type === primaryType ||\n        (candidate.via !== 'embedding' && candidate.score >= primary.score - 0.2),\n    )\n    .slice(0, maxNodes)\n    .map((s) => ({ nodeId: s.nodeId, label: s.label, via: s.via, score: Number(s.score.toFixed(3)) }))\n  return { matched }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Composition — each builder wraps one existing traversal into a section of\n// provenance-tagged facts. Every fact carries the provenance + confidence the\n// traversal already computed; nothing is synthesized.\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction incidentsForNode(nodeId: string, incidents: ErrorEvent[] | undefined): ErrorEvent[] {\n  if (!incidents || incidents.length === 0) return []\n  const svc = nodeId.replace(/^service:/, '')\n  return incidents.filter((e) => e.affectedNode === nodeId || e.service === svc)\n}\n\nfunction edgeSignalNote(e: GraphEdge): string {\n  const bits: string[] = []\n  if (e.signal) {\n    bits.push(`${e.signal.spanCount} spans`)\n    if (e.signal.errorCount > 0) bits.push(`${e.signal.errorCount} errors`)\n    if (e.signal.latencyMs?.p95 !== undefined) bits.push(`p95 ${Math.round(e.signal.latencyMs.p95)}ms`)\n  } else if (e.callCount !== undefined) {\n    bits.push(`${e.callCount} calls`)\n  }\n  return bits.length ? ` (${bits.join(', ')})` : ''\n}\n\n// Flag-mismatch (ADR-242) and deploy-mismatch (ADR-225) are node-local divergences\n// that stand on their own as a cause, not a downstream symptom: a flag running in a\n// state nobody committed, or a rollout that never took. Both surface with no\n// incident recorded — the service is up, it just behaves wrong — so get_root_cause,\n// which reads the incident store and the failing edges, never sees them. Lift just\n// these two self-standing types off the node's divergence set (the same scoped read\n// buildDivergenceSection does) so a root-cause question doesn't miss NEAT's sharpest\n// finding. Composition only — computeDivergences does the work.\nconst CAUSAL_DIVERGENCE_TYPES: ReadonlySet<DivergenceType> = new Set<DivergenceType>([\n  'flag-mismatch',\n  'deploy-mismatch',\n])\n\nfunction causalDivergences(\n  graph: NeatGraph,\n  node: string,\n  incidents: ErrorEvent[] | undefined,\n): Divergence[] {\n  const result = computeDivergences(graph, {\n    node,\n    type: CAUSAL_DIVERGENCE_TYPES,\n    ...(incidents ? { incidents } : {}),\n  })\n  return result.divergences\n}\n\nfunction buildRootCauseSection(\n  graph: NeatGraph,\n  node: string,\n  incidents: ErrorEvent[] | undefined,\n  now: number,\n): AskSection | null {\n  const result = getRootCause(graph, node, undefined, incidents, { now })\n  // A committed-vs-serving flag or a stuck rollout is a cause the incident-driven\n  // traversal cannot reach, so pull it in alongside whatever get_root_cause found.\n  const causal = causalDivergences(graph, node, incidents)\n  if (!result && causal.length === 0) return null\n\n  const facts: AskFact[] = []\n  if (result) {\n    const lastProv = result.edgeProvenances[result.edgeProvenances.length - 1] ?? Provenance.OBSERVED\n    facts.push({\n      text: `Root cause: ${result.rootCauseNode} — ${result.rootCauseReason}`,\n      provenance: lastProv,\n      confidence: result.confidence,\n    })\n  }\n  // The flag/deploy divergence rides right behind the verdict (or leads when there\n  // is none): when get_root_cause recorded nothing, this IS the cause; when it did,\n  // it is a candidate the agent must still weigh. Rendered with divergenceLine like\n  // every other divergence; the composite EXTRACTED-vs-OBSERVED claim carries no\n  // single provenance, so the fact leaves it unset.\n  for (const d of causal) {\n    facts.push({ text: divergenceLine(d), confidence: d.confidence })\n  }\n  if (result) {\n    // Lead with the ADR-189 navigation: the ranked candidate set, so the agent\n    // weighs alternatives instead of relaying one verdict. A symptom-only node is\n    // a downstream victim, not the cause.\n    const candidates: RootCauseCandidate[] = result.candidates ?? []\n    for (const c of candidates.slice(0, 3)) {\n      facts.push({\n        text: `Candidate ${c.node} — ${c.classification}: ${c.reason}`,\n        ...(c.provenance ? { provenance: c.provenance } : {}),\n        confidence: c.confidence,\n      })\n    }\n    if (result.traversalPath.length > 1) {\n      facts.push({ text: `Traversal: ${result.traversalPath.join(' ← ')}` })\n    }\n    if (result.fixRecommendation) {\n      facts.push({ text: `Recommended fix: ${result.fixRecommendation}` })\n    }\n  }\n  return { heading: 'Root cause (navigation)', facts: facts.slice(0, MAX_FACTS_PER_SECTION) }\n}\n\nfunction buildDependenciesSection(graph: NeatGraph, node: string): AskSection | null {\n  const result = getTransitiveDependencies(graph, node, 2)\n  if (result.total === 0) return null\n  const facts: AskFact[] = result.dependencies\n    .slice(0, MAX_FACTS_PER_SECTION)\n    .map((d) => ({\n      text: `${d.nodeId} — ${d.edgeType} (distance ${d.distance})`,\n      // Per-fact provenance: the transitive walk mixes EXTRACTED and OBSERVED\n      // edges, so the tag is on the fact, not asserted for the whole section.\n      provenance: d.provenance,\n    }))\n  return { heading: 'Dependencies', facts }\n}\n\nfunction buildObservedSection(graph: NeatGraph, node: string): AskSection | null {\n  const result = getObservedDependencies(graph, node)\n  const facts: AskFact[] = []\n  for (const e of result.dependencies.slice(0, MAX_FACTS_PER_SECTION)) {\n    const via = e.source !== node ? ` via ${e.source}` : ''\n    facts.push({\n      text: `calls ${e.target}${via}${edgeSignalNote(e)}`,\n      provenance: e.provenance,\n      confidence: confidenceForEdge(e),\n    })\n  }\n  if (facts.length === 0) {\n    if (result.observed && result.inboundObservedCount > 0) {\n      // Pure receiver: seen by OTel, but calls nothing downstream.\n      facts.push({\n        text: `no outbound runtime calls, but OTel observed ${result.inboundObservedCount} inbound call path${result.inboundObservedCount === 1 ? '' : 's'} — a pure receiver`,\n        provenance: Provenance.OBSERVED,\n      })\n    } else {\n      return null\n    }\n  }\n  return { heading: 'Runtime dependencies (OBSERVED)', facts }\n}\n\nfunction buildBlastSection(graph: NeatGraph, node: string): AskSection | null {\n  const result = getBlastRadius(graph, node)\n  if (result.totalAffected === 0) return null\n  const facts: AskFact[] = result.affectedNodes\n    .slice(0, MAX_FACTS_PER_SECTION)\n    .map((n) => ({\n      text: `${n.nodeId} (distance ${n.distance})`,\n      provenance: n.edgeProvenance,\n      confidence: n.confidence,\n    }))\n  return {\n    heading: `Blast radius — ${result.totalAffected} dependent${result.totalAffected === 1 ? '' : 's'}`,\n    facts,\n  }\n}\n\n// A question asking which services call a database needs the incoming side of\n// that relationship. Reuse the blast walk, but keep only services connected\n// directly or through their own file/symbol call sites. A service reached via\n// another service is a dependent, not itself a caller of this database.\nfunction buildDatabaseCallersSection(graph: NeatGraph, node: string): AskSection {\n  const callers = getBlastRadius(graph, node).affectedNodes.filter((item) => {\n    if ((graph.getNodeAttributes(item.nodeId) as GraphNode).type !== NodeType.ServiceNode) return false\n    return item.path.slice(1, -1).every((id) => {\n      const type = (graph.getNodeAttributes(id) as GraphNode).type\n      return type === NodeType.FileNode || type === NodeType.SymbolNode\n    })\n  })\n  return {\n    heading: `Services calling ${node} — ${callers.length}`,\n    facts: callers.length > 0\n      ? callers.slice(0, MAX_FACTS_PER_SECTION).map((item) => ({\n          text: `${item.nodeId} (distance ${item.distance})`,\n          provenance: item.edgeProvenance,\n          confidence: item.confidence,\n        }))\n      : [{ text: `No inbound service callers found for ${node}.` }],\n  }\n}\n\nfunction buildIncidentsSection(node: string, incidents: ErrorEvent[] | undefined): AskSection | null {\n  const relevant = incidentsForNode(node, incidents)\n  if (relevant.length === 0) return null\n  const ordered = [...relevant].sort((a, b) => b.timestamp.localeCompare(a.timestamp)).slice(0, 4)\n  const facts: AskFact[] = ordered.map((ev) => ({\n    text: `${ev.timestamp} — ${ev.service}: ${ev.errorMessage}`,\n    // ErrorEvents are observation records — OBSERVED by definition.\n    provenance: Provenance.OBSERVED,\n  }))\n  return { heading: `Recent incidents (OBSERVED) — ${relevant.length} recorded`, facts }\n}\n\nfunction divergenceLine(d: Divergence): string {\n  if ((d.type === 'missing-observed' || d.type === 'missing-extracted') && d.column) {\n    return `[${d.type}] ${d.table ?? d.source} column ${d.column} — ${d.reason}`\n  }\n  // Symbol/field-grain (ADR-215) shares source == target (the code node); name\n  // the member and the declaring location instead of a `a → a` edge.\n  if (d.type === 'observed-symbol-mismatch') {\n    const at = d.location ? ` at ${d.location}` : ''\n    const member = d.symbol ? ` ${d.symbol}` : ''\n    return `[${d.type}] ${d.source}${member}${at} — ${d.reason}`\n  }\n  // Behavioral-failure (ADR-220) at the incident locus also shares source ==\n  // target; name the declaring file:line. The edge locus keeps the a → b form.\n  if (d.type === 'observed-failing' && !d.edgeType) {\n    const at = d.location ? ` at ${d.location}` : ''\n    return `[${d.type}] ${d.source}${at} — ${d.reason}`\n  }\n  return `[${d.type}] ${d.source} → ${d.target} — ${d.reason}`\n}\n\n// Missing-observed edges are waiting for a first runtime signal when the graph\n// has no OBSERVED edges at all. Do not present that state as disagreement.\nfunction runtimeEdgeState(graph: NeatGraph): { observed: boolean; stale: boolean } {\n  let observed = false\n  let stale = false\n  graph.forEachEdge((_id, attrs) => {\n    if ((attrs as GraphEdge).provenance === Provenance.OBSERVED) observed = true\n    if ((attrs as GraphEdge).provenance === Provenance.STALE) stale = true\n  })\n  return { observed, stale }\n}\n\nfunction pendingRuntimeMessage(graph: NeatGraph, divergences: Divergence[]): string | undefined {\n  const count = divergences.filter((d) => d.type === 'missing-observed').length\n  if (count === 0) return undefined\n  const { observed, stale } = runtimeEdgeState(graph)\n  if (observed) return undefined\n  const prefix = stale ? 'No current runtime observations — earlier runtime evidence is stale' : 'No runtime observed yet'\n  return `${prefix} — ${count} declared dependenc${count === 1 ? 'y is' : 'ies are'} waiting to be confirmed. Send traces (or connect a provider) and ask again.`\n}\n\nfunction noDivergenceMessage(graph: NeatGraph): string {\n  if (graph.order === 0) return 'Graph is empty — no declared or observed dependencies to compare.'\n  const { observed, stale } = runtimeEdgeState(graph)\n  if (!observed) return stale\n    ? 'No current runtime dependency observations to compare — earlier runtime evidence is stale.'\n    : 'No runtime dependency observations to compare with declared code.'\n  return 'None — declared code and observed runtime agree across the graph.'\n}\n\nfunction buildDivergenceSection(\n  graph: NeatGraph,\n  node: string,\n  incidents: ErrorEvent[] | undefined,\n): AskSection | null {\n  const result = computeDivergences(graph, { node, ...(incidents ? { incidents } : {}) })\n  if (result.totalAffected === 0) return null\n  const facts: AskFact[] = result.divergences.slice(0, MAX_FACTS_PER_SECTION).map((d) => ({\n    text: divergenceLine(d),\n    confidence: d.confidence,\n    // A divergence is composite by construction (EXTRACTED vs OBSERVED), so it\n    // carries no single provenance — the fact leaves it unset.\n  }))\n  return {\n    heading: `Divergences (EXTRACTED vs OBSERVED) — ${result.totalAffected}`,\n    facts,\n  }\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Global (entity-less) answers. Three intents are inherently graph-wide — an\n// agent's opening orient (\"give me an overview\", \"any divergences\", \"recent\n// incidents\"). When the question named no entity, these answer across the whole\n// graph instead of dead-ending, so a broad first question doesn't push the agent\n// back to grep (ADR-198). The other four intents genuinely need a subject and\n// keep their naming guidance.\n// ─────────────────────────────────────────────────────────────────────────────\n\nfunction buildGlobalDivergenceSection(\n  graph: NeatGraph,\n  incidents: ErrorEvent[] | undefined,\n): AskSection {\n  // computeDivergences already runs graph-wide with no `node` filter.\n  const result = computeDivergences(graph, incidents ? { incidents } : {})\n  const pending = pendingRuntimeMessage(graph, result.divergences)\n  const visible = pending\n    ? result.divergences.filter((d) => d.type !== 'missing-observed')\n    : result.divergences\n  if (visible.length === 0 && pending) {\n    return {\n      heading: 'Divergences (EXTRACTED vs OBSERVED)',\n      facts: [{ text: pending }],\n    }\n  }\n  if (result.totalAffected === 0) {\n    return {\n      heading: 'Divergences (EXTRACTED vs OBSERVED)',\n      facts: [{ text: noDivergenceMessage(graph) }],\n    }\n  }\n  const facts: AskFact[] = visible.slice(0, MAX_FACTS_PER_SECTION).map((d) => ({\n    text: divergenceLine(d),\n    confidence: d.confidence,\n    // Composite by construction (EXTRACTED vs OBSERVED), so no single provenance.\n  }))\n  if (pending && facts.length < MAX_FACTS_PER_SECTION) facts.push({ text: pending })\n  return {\n    heading: `Divergences (EXTRACTED vs OBSERVED) — ${visible.length}`,\n    facts,\n  }\n}\n\n// Aggregate the incident store by the node each failure is recorded against\n// (the finer affectedNode when present, else the owning service). Top-N by\n// count, then recency.\nfunction buildGlobalIncidentsSection(incidents: ErrorEvent[] | undefined): AskSection {\n  if (!incidents || incidents.length === 0) {\n    return {\n      heading: 'Incidents across the system',\n      facts: [{ text: 'None recorded — the OBSERVED incident store is empty.' }],\n    }\n  }\n  interface Agg {\n    key: string\n    count: number\n    latest: string\n    sampleMsg: string\n  }\n  const byKey = new Map<string, Agg>()\n  for (const ev of incidents) {\n    const key = ev.affectedNode || serviceId(ev.service)\n    const cur = byKey.get(key)\n    if (!cur) {\n      byKey.set(key, { key, count: 1, latest: ev.timestamp, sampleMsg: ev.errorMessage })\n    } else {\n      cur.count += 1\n      if (ev.timestamp > cur.latest) {\n        cur.latest = ev.timestamp\n        cur.sampleMsg = ev.errorMessage\n      }\n    }\n  }\n  const rows = [...byKey.values()]\n    .sort((a, b) => b.count - a.count || b.latest.localeCompare(a.latest) || a.key.localeCompare(b.key))\n    .slice(0, MAX_FACTS_PER_SECTION)\n  const facts: AskFact[] = rows.map((r) => ({\n    text: `${r.key} — ${r.count} incident${r.count === 1 ? '' : 's'}, latest ${r.latest}: ${r.sampleMsg}`,\n    provenance: Provenance.OBSERVED,\n  }))\n  return {\n    heading: `Incidents across the system — ${incidents.length} recorded`,\n    facts,\n  }\n}\n\n// A real system summary: what the graph is made of (nodes by kind, edges by\n// provenance), which services are busiest and which are failing, and how many\n// divergences stand. The orient an agent needs before it asks anything specific.\nfunction buildOverviewSections(\n  graph: NeatGraph,\n  incidents: ErrorEvent[] | undefined,\n): AskSection[] {\n  const nodeByType = new Map<string, number>()\n  const services: string[] = []\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as GraphNode\n    nodeByType.set(node.type, (nodeByType.get(node.type) ?? 0) + 1)\n    if (node.type === NodeType.ServiceNode) services.push(node.id)\n  })\n\n  const edgeByProv = new Map<Provenance, number>()\n  graph.forEachEdge((_id, attrs) => {\n    const p = (attrs as GraphEdge).provenance\n    edgeByProv.set(p, (edgeByProv.get(p) ?? 0) + 1)\n  })\n\n  const sections: AskSection[] = []\n  const count = (t: NodeType): number => nodeByType.get(t) ?? 0\n\n  // System shape: node + edge counts, each provenance tally tagged with its own\n  // provenance so the footer reflects how much of the graph is OBSERVED.\n  const shapeFacts: AskFact[] = [\n    { text: `${graph.order} nodes, ${graph.size} edges` },\n    {\n      text: `${count(NodeType.ServiceNode)} services, ${count(NodeType.FileNode)} files, ${count(NodeType.SymbolNode)} symbols, ${count(NodeType.DatabaseNode)} databases`,\n    },\n  ]\n  for (const p of [Provenance.EXTRACTED, Provenance.OBSERVED, Provenance.INFERRED, Provenance.STALE]) {\n    const n = edgeByProv.get(p) ?? 0\n    if (n > 0) shapeFacts.push({ text: `${n} ${p} edge${n === 1 ? '' : 's'}`, provenance: p })\n  }\n  sections.push({ heading: 'System shape', facts: shapeFacts })\n\n  // Busiest services by direct dependency count (getTransitiveDependencies at\n  // depth 1 — the same walk the per-node `dependencies` answer uses).\n  const depCounts = services\n    .map((s) => ({ s, n: getTransitiveDependencies(graph, s, 1).total }))\n    .filter((r) => r.n > 0)\n    .sort((a, b) => b.n - a.n || a.s.localeCompare(b.s))\n    .slice(0, MAX_FACTS_PER_SECTION)\n  if (depCounts.length > 0) {\n    sections.push({\n      heading: 'Busiest services (by direct dependencies)',\n      facts: depCounts.map((r) => ({\n        text: `${r.s} — ${r.n} direct dependenc${r.n === 1 ? 'y' : 'ies'}`,\n      })),\n    })\n  }\n\n  // Services/nodes with the most incidents.\n  if (incidents && incidents.length > 0) {\n    const incCount = new Map<string, number>()\n    for (const ev of incidents) {\n      const key = ev.affectedNode || serviceId(ev.service)\n      incCount.set(key, (incCount.get(key) ?? 0) + 1)\n    }\n    const top = [...incCount.entries()]\n      .sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))\n      .slice(0, MAX_FACTS_PER_SECTION)\n    sections.push({\n      heading: `Nodes with incidents — ${incidents.length} recorded`,\n      facts: top.map(([k, n]) => ({\n        text: `${k} — ${n} incident${n === 1 ? '' : 's'}`,\n        provenance: Provenance.OBSERVED,\n      })),\n    })\n  }\n\n  // Total divergences — the headline number for \"is anything wrong?\".\n  const div = computeDivergences(graph, incidents ? { incidents } : {})\n  const pending = pendingRuntimeMessage(graph, div.divergences)\n  const visibleCount = pending\n    ? div.divergences.filter((d) => d.type !== 'missing-observed').length\n    : div.totalAffected\n  const divergenceText = visibleCount > 0\n    ? `${visibleCount} divergence${visibleCount === 1 ? '' : 's'} between declared code and observed runtime — ask \"are there any divergences?\" for the list.${pending ? ` ${pending}` : ''}`\n    : pending ?? noDivergenceMessage(graph)\n  sections.push({\n    heading: 'Divergences',\n    facts: [{ text: divergenceText }],\n  })\n\n  return sections\n}\n\n// Route an entity-less question to a graph-wide answer, or null when the intent\n// needs a subject (dependencies / blast-radius / root-cause / observed).\nfunction buildGlobalSections(\n  intent: AskIntent,\n  graph: NeatGraph,\n  incidents: ErrorEvent[] | undefined,\n): AskSection[] | null {\n  switch (intent) {\n    case 'divergence':\n      return [buildGlobalDivergenceSection(graph, incidents)]\n    case 'incidents':\n      return [buildGlobalIncidentsSection(incidents)]\n    // A failure question with no subject — \"what is failing right now and why?\",\n    // the most natural on-call opener and the one the `## neat` directive sends\n    // through `ask` — is inherently graph-wide: it means \"what's failing across\n    // the system,\" not a dead-end for a node it never named. Answer it with the\n    // ranked incident store (culprit first), the same read `incidents` gives, so\n    // the agent lands on the failing node instead of naming guidance (ADR-198).\n    case 'root-cause':\n      return [buildGlobalIncidentsSection(incidents)]\n    case 'overview':\n      return buildOverviewSections(graph, incidents)\n    default:\n      return null\n  }\n}\n\ntype SectionKind = 'root-cause' | 'dependencies' | 'observed' | 'blast' | 'incidents' | 'divergence'\n\n// The section order for each intent: the intent's own traversal leads, the rest\n// follow as compact fused local context so one answer carries the whole picture.\nconst SECTION_ORDER: Record<AskIntent, SectionKind[]> = {\n  'root-cause': ['root-cause', 'incidents', 'blast', 'observed', 'divergence'],\n  'blast-radius': ['blast', 'dependencies', 'observed', 'incidents'],\n  dependencies: ['dependencies', 'observed', 'blast'],\n  observed: ['observed', 'dependencies', 'incidents'],\n  incidents: ['incidents', 'root-cause', 'observed'],\n  divergence: ['divergence', 'observed', 'dependencies', 'incidents'],\n  overview: ['dependencies', 'observed', 'blast', 'incidents', 'divergence'],\n}\n\nfunction buildSection(\n  kind: SectionKind,\n  graph: NeatGraph,\n  node: string,\n  incidents: ErrorEvent[] | undefined,\n  now: number,\n): AskSection | null {\n  switch (kind) {\n    case 'root-cause':\n      return buildRootCauseSection(graph, node, incidents, now)\n    case 'dependencies':\n      return buildDependenciesSection(graph, node)\n    case 'observed':\n      return buildObservedSection(graph, node)\n    case 'blast':\n      return buildBlastSection(graph, node)\n    case 'incidents':\n      return buildIncidentsSection(node, incidents)\n    case 'divergence':\n      return buildDivergenceSection(graph, node, incidents)\n  }\n}\n\n// The answer for a graph-wide (entity-less) question. Reads the leading global\n// section's headline so the summary names the finding without re-deriving it.\nfunction summarizeGlobal(intent: AskIntent, sections: AskSection[]): string {\n  const lead = sections[0]\n  switch (intent) {\n    case 'divergence': {\n      const pending = lead?.facts[0]?.text\n      if (pending?.startsWith('No runtime') || pending?.startsWith('No current runtime') || pending?.startsWith('Graph is empty')) return pending\n      const none = lead?.facts[0]?.text.startsWith('None') ?? true\n      return none\n        ? 'No divergences across the graph — declared code and observed runtime agree.'\n        : `${lead!.heading} across the graph, highest-confidence first below.`\n    }\n    case 'incidents': {\n      const none = lead?.facts[0]?.text.startsWith('None') ?? true\n      return none\n        ? 'No incidents recorded across the system — the OBSERVED incident store is empty.'\n        : `${lead!.heading}, aggregated by node below.`\n    }\n    case 'root-cause': {\n      // Subject-less \"what is failing?\" — lead with the top culprit and route the\n      // agent to its composed card, so the natural first question lands on the\n      // failing node + a next step, not a bare list (ADR-198, ADR-258).\n      const none = lead?.facts[0]?.text.startsWith('None') ?? true\n      if (none) return 'Nothing is failing right now — the OBSERVED incident store is empty.'\n      const top = lead!.facts[0]!.text.split(' — ')[0]\n      return `What's failing across the system, most-affected first below. Start with ${top} — call investigate(\"${top}\") for the composed card (cause, blast radius, fix locus).`\n    }\n    case 'overview':\n    default:\n      return `System overview across the whole graph: ${sections.length} view${sections.length === 1 ? '' : 's'} below — shape (nodes/edges by provenance), busiest services, incidents, and divergences.`\n  }\n}\n\n// The compact, answer-shaped summary the agent reads first. Derived from the\n// leading section so it names the finding, not a raw graph dump.\nfunction summarize(\n  question: string,\n  intent: AskIntent,\n  matched: AskMatch[],\n  primary: string | undefined,\n  sections: AskSection[],\n  scope: 'global' | 'node' | undefined,\n  ambiguousType?: EntityResolution['ambiguousType'],\n): string {\n  // Entity-less GLOBAL answer — the graph-wide orient (overview / divergences /\n  // incidents). The lead section already carries a headline; name the scope.\n  if (scope === 'global') {\n    return summarizeGlobal(intent, sections)\n  }\n  if (!primary) {\n    if (ambiguousType) {\n      const shown = ambiguousType.ids.slice(0, 10)\n      const more = ambiguousType.ids.length - shown.length\n      return `\"${ambiguousType.noun}\" matches ${ambiguousType.ids.length} nodes. Name one by ID: ${shown.join(', ')}${more > 0 ? `, and ${more} more` : ''}.`\n    }\n    // An entity-required intent (dependencies / blast-radius / root-cause /\n    // observed) with nothing named — keep the naming guidance, and point at the\n    // graph-wide questions that need no subject.\n    return `Nothing in \"${question}\" resolved to a node in the graph. Name a service, file, route, or table — e.g. \\`ask \"what does <service> depend on?\"\\`. For a graph-wide look, ask for an overview, divergences, or incidents.`\n  }\n  const lead = sections[0]\n  const others = matched.slice(1)\n  const alsoNote = others.length\n    ? ` Also matched: ${others.map((m) => m.nodeId).join(', ')}.`\n    : ''\n\n  let core: string\n  switch (intent) {\n    case 'root-cause': {\n      // Lead with the finding the root-cause section surfaced. When get_root_cause\n      // produced a verdict its \"Root cause:\" line is first; when it didn't but a\n      // node-local divergence (flag-mismatch / deploy-mismatch) stands as the\n      // cause, that divergence leads — name it as the cause rather than calling the\n      // node healthy. A genuine divergence is not the \"fallback context\" the honest\n      // path below refuses to dress up as a cause.\n      const rc = sections.find((s) => s.heading === 'Root cause (navigation)')\n      const first = rc?.facts[0]?.text\n      if (first?.startsWith('Root cause:')) {\n        core = first\n      } else if (first) {\n        core = `No incident is recorded for ${primary}, but a divergence on it is the likely cause: ${first}`\n      } else if (lead) {\n        core = `No root cause surfaced for ${primary} — it may be healthy, or the failure isn't recorded. Nearest context: ${lead.heading.toLowerCase()}.`\n      } else {\n        core = `No root cause surfaced for ${primary} — it may be healthy.`\n      }\n      break\n    }\n    case 'blast-radius':\n      core = lead ? `${lead.heading} of ${primary}.` : `${primary} has no dependents — nothing else would break if it failed.`\n      break\n    case 'dependencies':\n      core = lead?.heading.startsWith('Services calling')\n        ? `${lead.heading}.`\n        : lead ? `${primary}: ${lead.heading.toLowerCase()} listed below.` : `${primary} has no declared dependencies in the graph.`\n      break\n    case 'observed':\n      {\n        const observed = sections.find((s) => s.heading === 'Runtime dependencies (OBSERVED)')\n        core = observed\n          ? `${primary} at runtime: ${observed.facts.length} OBSERVED fact${observed.facts.length === 1 ? '' : 's'}.`\n          : `No runtime traffic OBSERVED for ${primary}.`\n      }\n      break\n    case 'incidents':\n      core = lead ? `${primary}: ${lead.heading.toLowerCase()}.` : `No incidents recorded against ${primary}.`\n      break\n    case 'divergence':\n      core = lead ? `${lead.heading} involving ${primary}.` : `No divergences involve ${primary} — declared and observed agree here.`\n      break\n    default:\n      core = `${primary}: ${sections.length} view${sections.length === 1 ? '' : 's'} of its fused local context below.`\n  }\n  return `${core}${alsoNote}`\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// The public entry — resolve, route, compose, validate.\n// ─────────────────────────────────────────────────────────────────────────────\n\nexport async function askGraph(\n  graph: NeatGraph,\n  question: string,\n  opts: AskOptions = {},\n): Promise<AskResult> {\n  const now = opts.now ?? Date.now()\n  const maxNodes = opts.maxNodes ?? DEFAULT_MAX_NODES\n  const intent = classifyIntent(question)\n  const resolution = await resolveEntities(graph, question, opts.searchIndex, maxNodes)\n  const matched = resolution.matched\n  const primary = matched[0]?.nodeId\n\n  const sections: AskSection[] = []\n  let scope: 'global' | 'node' | undefined\n  if (primary) {\n    scope = 'node'\n    const callersQuestion =\n      intent === 'dependencies' &&\n      (graph.getNodeAttributes(primary) as GraphNode).type === NodeType.DatabaseNode &&\n      /\\b(?:which|what)\\s+services?\\s+(?:talks?\\s+to|connects?\\s+to|uses?|hits?|calls?|reads?\\s+from|writes?\\s+to)\\b/i.test(question)\n    if (callersQuestion) sections.push(buildDatabaseCallersSection(graph, primary))\n    for (const kind of SECTION_ORDER[intent]) {\n      if (callersQuestion && kind === 'blast') continue\n      const s = buildSection(kind, graph, primary, opts.incidents, now)\n      if (s && s.facts.length > 0) sections.push(s)\n    }\n  } else {\n    // No entity named. The graph-wide intents (overview / divergences /\n    // incidents) answer across the whole graph instead of dead-ending; the\n    // entity-required intents fall through to naming guidance (scope stays unset).\n    const global = resolution.ambiguousType ? null : buildGlobalSections(intent, graph, opts.incidents)\n    if (global) {\n      scope = 'global'\n      for (const s of global) if (s.facts.length > 0) sections.push(s)\n    }\n  }\n\n  const answer = summarize(question, intent, matched, primary, sections, scope, resolution.ambiguousType)\n  const provSet = new Set<Provenance>()\n  for (const s of sections) for (const f of s.facts) if (f.provenance) provSet.add(f.provenance)\n  const confidence = sections[0]?.facts[0]?.confidence\n\n  return AskResultSchema.parse({\n    question,\n    intent,\n    matched,\n    ...(primary ? { primaryNode: primary } : {}),\n    ...(scope ? { scope } : {}),\n    sections,\n    answer,\n    ...(confidence !== undefined ? { confidence } : {}),\n    provenance: [...provSet],\n  })\n}\n","import { promises as fs } from 'node:fs'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Diff a snapshot on disk (or fetched over HTTP) against the live in-memory\n// graph. The \"base\" is the snapshot you supplied; the \"current\" is whatever\n// the server has loaded right now. Symmetric in shape, but consumers usually\n// want to read it as \"what changed since base.\"\n//\n// The shape mirrors the issue's spec (#77):\n//   { added: { nodes, edges }, removed: { nodes, edges },\n//     changed: { nodes: [{id, before, after}], edges: [{id, before, after}] } }\n//\n// Both timestamps are echoed back so the caller doesn't have to track them\n// separately.\n\ninterface PersistedNodeEntry {\n  key?: string\n  attributes?: Record<string, unknown>\n}\n\ninterface PersistedEdgeEntry {\n  key?: string\n  source?: string\n  target?: string\n  attributes?: Record<string, unknown>\n}\n\nexport interface PersistedSnapshot {\n  schemaVersion?: number\n  exportedAt?: string\n  graph?: {\n    nodes?: PersistedNodeEntry[]\n    edges?: PersistedEdgeEntry[]\n  }\n}\n\nexport interface GraphDiff {\n  base: { exportedAt?: string }\n  current: { exportedAt: string }\n  added: { nodes: GraphNode[]; edges: GraphEdge[] }\n  removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n  changed: {\n    nodes: { id: string; before: GraphNode; after: GraphNode }[]\n    edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n  }\n}\n\nexport async function loadSnapshotForDiff(target: string): Promise<PersistedSnapshot> {\n  if (/^https?:\\/\\//i.test(target)) {\n    const res = await fetch(target)\n    if (!res.ok) {\n      throw new Error(`fetch ${target} failed: ${res.status} ${res.statusText}`)\n    }\n    return (await res.json()) as PersistedSnapshot\n  }\n  const raw = await fs.readFile(target, 'utf8')\n  return JSON.parse(raw) as PersistedSnapshot\n}\n\nfunction indexEntries<T>(\n  entries: { key?: string; attributes?: Record<string, unknown> }[] | undefined,\n): Map<string, T> {\n  const m = new Map<string, T>()\n  if (!entries) return m\n  for (const entry of entries) {\n    const id = (entry.attributes?.id as string | undefined) ?? entry.key\n    if (!id) continue\n    m.set(id, entry.attributes as T)\n  }\n  return m\n}\n\nexport function computeGraphDiff(\n  liveGraph: NeatGraph,\n  baseSnapshot: PersistedSnapshot,\n  currentExportedAt: string = new Date().toISOString(),\n): GraphDiff {\n  const baseNodes = indexEntries<GraphNode>(baseSnapshot.graph?.nodes)\n  const baseEdges = indexEntries<GraphEdge>(baseSnapshot.graph?.edges)\n\n  const liveNodes = new Map<string, GraphNode>()\n  liveGraph.forEachNode((id, attrs) => liveNodes.set(id, attrs as GraphNode))\n  const liveEdges = new Map<string, GraphEdge>()\n  liveGraph.forEachEdge((id, attrs) => liveEdges.set(id, attrs as GraphEdge))\n\n  const result: GraphDiff = {\n    base: { exportedAt: baseSnapshot.exportedAt },\n    current: { exportedAt: currentExportedAt },\n    added: { nodes: [], edges: [] },\n    removed: { nodes: [], edges: [] },\n    changed: { nodes: [], edges: [] },\n  }\n\n  for (const [id, after] of liveNodes) {\n    const before = baseNodes.get(id)\n    if (!before) {\n      result.added.nodes.push(after)\n    } else if (!shallowEqual(before, after)) {\n      result.changed.nodes.push({ id, before, after })\n    }\n  }\n  for (const [id, before] of baseNodes) {\n    if (!liveNodes.has(id)) result.removed.nodes.push(before)\n  }\n  for (const [id, after] of liveEdges) {\n    const before = baseEdges.get(id)\n    if (!before) {\n      result.added.edges.push(after)\n    } else if (!shallowEqual(before, after)) {\n      result.changed.edges.push({ id, before, after })\n    }\n  }\n  for (const [id, before] of baseEdges) {\n    if (!liveEdges.has(id)) result.removed.edges.push(before)\n  }\n\n  return result\n}\n\n// Stable JSON comparison. Snapshot order isn't guaranteed, so canonicalising\n// keys before stringify keeps the comparison robust against re-ordered fields.\nfunction shallowEqual(a: unknown, b: unknown): boolean {\n  return canonicalJson(a) === canonicalJson(b)\n}\n\nfunction canonicalJson(value: unknown): string {\n  return JSON.stringify(value, (_key, v) => {\n    if (v && typeof v === 'object' && !Array.isArray(v)) {\n      return Object.keys(v as Record<string, unknown>)\n        .sort()\n        .reduce<Record<string, unknown>>((acc, k) => {\n          acc[k] = (v as Record<string, unknown>)[k]\n          return acc\n        }, {})\n    }\n    return v\n  })\n}\n","// Project registry — owns the per-project state that lives alongside the\n// graph map: snapshot/error/stale paths, scan path, optional search index.\n//\n// Routes use it via `resolve(project)`. Server / watch construct it once at\n// boot and pass it to buildApi. Tests can mock it with a small literal.\n\nimport path from 'node:path'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT, getGraph } from './graph.js'\nimport type { SearchIndex } from './search.js'\n\nexport interface ProjectPaths {\n  snapshotPath: string\n  errorsPath: string\n  staleEventsPath: string\n  embeddingsCachePath: string\n  // Policy-violations log per ADR-041 § Append-only ndjson sidecars. Lives\n  // in the same neat-out directory as the other ndjson sidecars; daemons\n  // wire PolicyViolationsLog to it.\n  policyViolationsPath: string\n}\n\n// Default project keeps the legacy filenames so existing M5 / β / γ users\n// see no behaviour change. Named projects fan out by name (ADR-026).\nexport function pathsForProject(project: string, baseDir: string): ProjectPaths {\n  if (project === DEFAULT_PROJECT) {\n    return {\n      snapshotPath: path.join(baseDir, 'graph.json'),\n      errorsPath: path.join(baseDir, 'errors.ndjson'),\n      staleEventsPath: path.join(baseDir, 'stale-events.ndjson'),\n      embeddingsCachePath: path.join(baseDir, 'embeddings.json'),\n      policyViolationsPath: path.join(baseDir, 'policy-violations.ndjson'),\n    }\n  }\n  return {\n    snapshotPath: path.join(baseDir, `${project}.json`),\n    errorsPath: path.join(baseDir, `errors.${project}.ndjson`),\n    staleEventsPath: path.join(baseDir, `stale-events.${project}.ndjson`),\n    embeddingsCachePath: path.join(baseDir, `embeddings.${project}.json`),\n    policyViolationsPath: path.join(baseDir, `policy-violations.${project}.ndjson`),\n  }\n}\n\nexport interface ProjectContext {\n  name: string\n  graph: NeatGraph\n  scanPath?: string\n  paths: ProjectPaths\n  searchIndex?: SearchIndex\n}\n\nexport class Projects {\n  private contexts = new Map<string, ProjectContext>()\n\n  upsert(ctx: ProjectContext): void {\n    this.contexts.set(ctx.name, ctx)\n  }\n\n  set(\n    name: string,\n    init: Omit<ProjectContext, 'name' | 'graph'> & { graph?: NeatGraph },\n  ): ProjectContext {\n    const ctx: ProjectContext = {\n      name,\n      graph: init.graph ?? getGraph(name),\n      scanPath: init.scanPath,\n      paths: init.paths,\n      searchIndex: init.searchIndex,\n    }\n    this.contexts.set(name, ctx)\n    return ctx\n  }\n\n  get(name: string): ProjectContext | undefined {\n    return this.contexts.get(name)\n  }\n\n  has(name: string): boolean {\n    return this.contexts.has(name)\n  }\n\n  list(): string[] {\n    return [...this.contexts.keys()].sort()\n  }\n\n  attachSearchIndex(name: string, index: SearchIndex | undefined): void {\n    const ctx = this.contexts.get(name)\n    if (ctx) ctx.searchIndex = index\n  }\n}\n\n// Parses NEAT_PROJECTS=a,b,c; trims whitespace, drops empty entries.\n// `default` is implicit (always loaded), so callers usually filter it out\n// before iterating extra projects.\nexport function parseExtraProjects(raw: string | undefined): string[] {\n  if (!raw) return []\n  return raw\n    .split(',')\n    .map((p) => p.trim())\n    .filter((p) => p.length > 0 && p !== DEFAULT_PROJECT)\n}\n","/**\n * Machine-level project registry + machine-wide daemon discovery.\n *\n * This module owns two surfaces under `~/.neat/`:\n *\n *  1. The legacy project registry at `~/.neat/projects.json` (ADR-048). One\n *     file, per-user, machine-local, not synced. Under the project-daemon\n *     contract (ADR-096) it is no longer the coordination point — it is read\n *     once for migration and otherwise left to the additive writes the daemon\n *     and orchestrator still perform. The read-modify-write helpers below keep\n *     their atomic-write + exclusive-lock machinery for that legacy surface.\n *\n *  2. The machine-wide daemon discovery directory at `~/.neat/daemons/`\n *     (ADR-096 §6). One file per running daemon — `<project>.json` — each owned\n *     solely by the daemon that wrote it (on start) and removes it (on graceful\n *     stop). Discovery is **append-only and lock-free**: a reader scans the\n *     directory and reconciles liveness; it never acquires a shared lock, so it\n *     can never deadlock against a daemon (#506). Losing or rebuilding the\n *     directory costs discovery convenience, not correctness — each project's\n *     own `neat-out/daemon.json` stays authoritative.\n *\n * `neat ps` / `neat list` and the per-daemon `pause` / `resume` / `uninstall`\n * verbs read discovery, falling back to the legacy registry where no daemon\n * file is present yet (the migration window before every daemon self-describes).\n *\n * The legacy lock is a file we exclusively-create (`O_EXCL`), hold while we\n * mutate, and unlink on the way out. Crude but cross-platform; matches what\n * `proper-lockfile` does internally without pulling the dep in. It never sits\n * on the discovery path.\n */\n\nimport { promises as fs, readFileSync, readdirSync, realpathSync } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport {\n  RegistryFileSchema,\n  type RegistryEntry,\n  type RegistryFile,\n  type RegistryStatus,\n} from '@neat.is/types'\n\nconst LOCK_TIMEOUT_MS = 5_000\nconst LOCK_RETRY_MS = 50\n\n// Resolve `~/.neat/` per call so tests can override `HOME` / `NEAT_HOME`\n// before each run without module-load order mattering.\nfunction neatHome(): string {\n  const override = process.env.NEAT_HOME\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(os.homedir(), '.neat')\n}\n\nexport function registryPath(): string {\n  return path.join(neatHome(), 'projects.json')\n}\n\nexport function registryLockPath(): string {\n  return path.join(neatHome(), 'projects.json.lock')\n}\n\n// The daemon writes its PID here on startup (daemon.ts). It's the authoritative\n// \"is a neat daemon running\" signal — more reliable than matching the lock's\n// own PID, since the daemon holds the registry lock only for brief read-modify-\n// write windows and an init that contends usually catches an orphaned lock\n// rather than the daemon mid-write.\nfunction daemonPidPath(): string {\n  return path.join(neatHome(), 'neatd.pid')\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #366 / ADR-096 §6 — machine-wide daemon discovery, lock-free.\n//\n// Each running daemon drops a `<project>.json` file into `~/.neat/daemons/`\n// on start and removes it on graceful stop. The file is a copy of that\n// project's authoritative `neat-out/daemon.json` record. A daemon owns only\n// its own file — there is no shared file and no shared lock. Discovery reads\n// the directory and reconciles liveness; it never acquires a lock, so it can\n// never deadlock against a daemon mid-write the way the registry lock did\n// (#506). The shape mirrors what the daemon writes (keystone #508); we read it\n// as plain JSON rather than importing the daemon's writer so the two stay\n// decoupled, and validate defensively so a malformed file is skipped, not\n// fatal.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport interface DaemonPorts {\n  rest: number\n  otlp: number\n  web: number\n}\n\nexport interface DaemonRecord {\n  project: string\n  // Project root whose `neat-out/` holds the authoritative record.\n  projectPath: string\n  pid: number\n  status: 'running' | 'stopped'\n  ports: DaemonPorts\n  // ISO8601.\n  startedAt: string\n  neatVersion: string\n}\n\n// A discovered daemon plus the liveness verdict the reader reconciled. `live`\n// is true only when the record claims `running` AND its pid is actually alive\n// — a daemon that crashed without clearing its file reads as `running` but\n// `live: false`, so `neat ps` never reports a ghost as up.\nexport interface DiscoveredDaemon {\n  record: DaemonRecord\n  live: boolean\n  // Where the discovery copy was read from. Useful for diagnostics and for the\n  // per-daemon verbs that clean a stale file.\n  source: string\n}\n\nexport function daemonsDir(): string {\n  return path.join(neatHome(), 'daemons')\n}\n\nfunction isFiniteInt(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v)\n}\n\n// Parse one discovery file's contents into a DaemonRecord, or undefined when\n// the shape doesn't hold. Defensive on purpose: discovery is convenience, so a\n// half-written or hand-edited file is skipped rather than crashing `neat ps`.\nfunction parseDaemonRecord(raw: string): DaemonRecord | undefined {\n  let obj: unknown\n  try {\n    obj = JSON.parse(raw)\n  } catch {\n    return undefined\n  }\n  if (typeof obj !== 'object' || obj === null) return undefined\n  const r = obj as Record<string, unknown>\n  const ports = r.ports as Record<string, unknown> | undefined\n  if (\n    typeof r.project !== 'string' ||\n    typeof r.projectPath !== 'string' ||\n    !isFiniteInt(r.pid) ||\n    (r.status !== 'running' && r.status !== 'stopped') ||\n    typeof r.startedAt !== 'string' ||\n    typeof r.neatVersion !== 'string' ||\n    !ports ||\n    !isFiniteInt(ports.rest) ||\n    !isFiniteInt(ports.otlp) ||\n    !isFiniteInt(ports.web)\n  ) {\n    return undefined\n  }\n  return {\n    project: r.project,\n    projectPath: r.projectPath,\n    pid: r.pid,\n    status: r.status,\n    ports: { rest: ports.rest, otlp: ports.otlp, web: ports.web },\n    startedAt: r.startedAt,\n    neatVersion: r.neatVersion,\n  }\n}\n\n// Liveness for a discovered daemon. Exported (via the default probe) so the\n// verbs and tests reconcile the same way: `running` claim AND pid alive.\nexport function isPidAlive(pid: number): boolean {\n  return isPidAliveDefault(pid)\n}\n\nexport interface DiscoveryProbe {\n  isPidAlive(pid: number): boolean\n}\n\nconst defaultDiscoveryProbe: DiscoveryProbe = { isPidAlive: isPidAliveDefault }\n\n/**\n * Scan `~/.neat/daemons/` and return every well-formed discovery record with\n * its reconciled liveness. Lock-free: a plain directory read, no rendezvous.\n *\n * A missing directory (no daemon has ever started under this model) yields an\n * empty list — first run, nothing to discover. Malformed or unreadable files\n * are skipped silently; discovery degrades to \"fewer entries,\" never an error.\n */\nexport async function discoverDaemons(\n  probe: DiscoveryProbe = defaultDiscoveryProbe,\n): Promise<DiscoveredDaemon[]> {\n  const dir = daemonsDir()\n  let names: string[]\n  try {\n    names = await fs.readdir(dir)\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n    throw err\n  }\n  const out: DiscoveredDaemon[] = []\n  for (const name of names) {\n    if (!name.endsWith('.json')) continue\n    const file = path.join(dir, name)\n    let raw: string\n    try {\n      raw = await fs.readFile(file, 'utf8')\n    } catch {\n      continue\n    }\n    const record = parseDaemonRecord(raw)\n    if (!record) continue\n    const live = record.status === 'running' && probe.isPidAlive(record.pid)\n    out.push({ record, live, source: file })\n  }\n  out.sort((a, b) => a.record.project.localeCompare(b.record.project))\n  return out\n}\n\n/**\n * `discoverDaemons`, synchronously, for a caller that resolves its target before\n * it can await anything: the MCP server picks its daemon at module load\n * (ADR-259). Same directory, parser, liveness rule and never-throws degrading.\n */\nexport function discoverDaemonsSync(probe: DiscoveryProbe = defaultDiscoveryProbe): DiscoveredDaemon[] {\n  const dir = daemonsDir()\n  let names: string[]\n  try {\n    names = readdirSync(dir)\n  } catch {\n    return []\n  }\n  const out: DiscoveredDaemon[] = []\n  for (const name of names) {\n    if (!name.endsWith('.json')) continue\n    const file = path.join(dir, name)\n    let raw: string\n    try {\n      raw = readFileSync(file, 'utf8')\n    } catch {\n      continue\n    }\n    const record = parseDaemonRecord(raw)\n    if (!record) continue\n    const live = record.status === 'running' && probe.isPidAlive(record.pid)\n    out.push({ record, live, source: file })\n  }\n  out.sort((a, b) => a.record.project.localeCompare(b.record.project))\n  return out\n}\n\n/**\n * Remove a daemon's discovery file. A daemon owns its own file, so this is for\n * the per-daemon verbs reconciling a record whose daemon is gone (a crashed\n * daemon that never cleared its own file) — never a rendezvous another process\n * coordinates through. Best-effort: an already-absent file is success.\n */\nexport async function removeDaemonRecord(source: string): Promise<void> {\n  await fs.unlink(source).catch(() => {})\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #366 / ADR-096 §8 — migration off the global registry.\n//\n// Installs carrying `~/.neat/projects.json` map their registered projects onto\n// per-project daemons on first run under this model. The discovery directory is\n// authoritative for \"what's running\"; the registry is read once to surface\n// projects that were registered before any daemon self-described, so the\n// machine-wide verbs still see them during the migration window. The registry\n// is no longer the coordination surface — nothing here writes it back.\n// ─────────────────────────────────────────────────────────────────────────\n\n// A unified view for the machine-wide verbs: a discovered daemon when one is\n// present, otherwise a legacy registry entry projected into the same shape so\n// `neat ps` / `neat list` render one table regardless of which surface the\n// project lives on yet.\nexport interface MachineProject {\n  project: string\n  projectPath: string\n  // 'running' / 'stopped' come from a live discovery record; 'registered'\n  // marks a legacy registry entry with no daemon file yet (migration window).\n  state: 'running' | 'stopped' | 'registered'\n  // Present only when a discovery record backs this row.\n  ports?: DaemonPorts\n  // Legacy registry status when the row came from the registry; undefined for\n  // a discovery-backed row.\n  registryStatus?: RegistryStatus\n  pid?: number\n}\n\n/**\n * The machine-wide project view the CLI verbs render. Discovery wins: every\n * `~/.neat/daemons/` record becomes a row (running or stopped per liveness).\n * Legacy registry entries whose path isn't already covered by a discovery\n * record are folded in as `registered` rows so a pre-#508 install still lists\n * its projects. Keyed on resolved path so a registry entry and its daemon\n * record collapse to one row.\n *\n * Read-only on both surfaces. The registry is read once for migration; nothing\n * here writes it back, in keeping with ADR-096 §8.\n */\nexport async function listMachineProjects(\n  probe: DiscoveryProbe = defaultDiscoveryProbe,\n): Promise<MachineProject[]> {\n  const discovered = await discoverDaemons(probe)\n  const byPath = new Map<string, MachineProject>()\n  for (const d of discovered) {\n    const key = await normalizeProjectPath(d.record.projectPath)\n    byPath.set(key, {\n      project: d.record.project,\n      projectPath: d.record.projectPath,\n      state: d.live ? 'running' : 'stopped',\n      ports: d.record.ports,\n      pid: d.record.pid,\n    })\n  }\n\n  // Migration read: legacy registry entries not already covered by a daemon\n  // record. Read once, never written back.\n  let legacy: RegistryEntry[] = []\n  try {\n    legacy = (await readRegistry()).projects\n  } catch {\n    // A corrupt legacy file shouldn't sink discovery — the daemons we found are\n    // still valid. Skip the legacy fold.\n    legacy = []\n  }\n  for (const entry of legacy) {\n    const key = await normalizeProjectPath(entry.path)\n    if (byPath.has(key)) continue\n    byPath.set(key, {\n      project: entry.name,\n      projectPath: entry.path,\n      state: 'registered',\n      registryStatus: entry.status,\n    })\n  }\n\n  return [...byPath.values()].sort((a, b) => a.project.localeCompare(b.project))\n}\n\n// Find a discovery record by project name, with its reconciled liveness. The\n// per-daemon verbs key on the project name the operator types; discovery is the\n// source of truth for whether a daemon is running and which pid to signal.\nexport async function findDaemonByProject(\n  name: string,\n  probe: DiscoveryProbe = defaultDiscoveryProbe,\n): Promise<DiscoveredDaemon | undefined> {\n  const discovered = await discoverDaemons(probe)\n  return discovered.find((d) => d.record.project === name)\n}\n\n// Signal a running daemon to shut down via its discovery-recorded pid. SIGTERM\n// is the graceful-stop signal every daemon already wires (neatd.ts) — the\n// daemon clears its own discovery file on the way out. Returns true when the\n// signal was delivered, false when the pid was already gone (nothing to stop).\nexport function signalDaemonStop(pid: number): boolean {\n  try {\n    process.kill(pid, 'SIGTERM')\n    return true\n  } catch (err) {\n    // ESRCH → already gone; treat as a no-op success of intent. EPERM and the\n    // rest surface as \"couldn't signal\" so the verb can report honestly.\n    if ((err as NodeJS.ErrnoException).code === 'ESRCH') return false\n    throw err\n  }\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #432 — distinguish a live daemon from a genuinely stale lock.\n//\n// `neat init` used to hang the full timeout on any contended lock and then\n// print one remediation: \"remove the file by hand.\" That advice is actively\n// dangerous when a neat daemon is alive — the daemon grabs the lock for its\n// own registry writes, so hand-removing it races the daemon and corrupts the\n// registry for the live process. The lock now carries the holder PID, and the\n// timeout (or first contention with a live daemon) resolves to a message that\n// names who holds it and what's safe to do.\n// ─────────────────────────────────────────────────────────────────────────\n\nexport type LockHolder =\n  | { kind: 'daemon'; pid: number }\n  | { kind: 'command'; pid: number }\n  | { kind: 'stale' }\n\n// Probes the holder-resolution logic depends on, broken out so tests can drive\n// each branch without a real daemon or live PIDs.\nexport interface LockHolderProbe {\n  // POSIX liveness via `process.kill(pid, 0)`: true if the process exists\n  // (including EPERM — alive but owned by another user), false if it's gone.\n  isPidAlive(pid: number): boolean\n  // PID recorded in `~/.neat/neatd.pid`, or undefined if there's no pidfile.\n  daemonPidFromFile(): Promise<number | undefined>\n  // Whether the daemon's always-open `/health` endpoint answers. Confirms a\n  // live neatd.pid is actually our daemon and not a reused PID.\n  daemonResponds(): Promise<boolean>\n}\n\nfunction isPidAliveDefault(pid: number): boolean {\n  try {\n    process.kill(pid, 0)\n    return true\n  } catch (err) {\n    // ESRCH → no such process (dead). EPERM → exists but owned by another user\n    // (alive). Treat anything else as not-alive: we'd rather under-claim a live\n    // holder than wrongly block on a lock we can't verify.\n    return (err as NodeJS.ErrnoException).code === 'EPERM'\n  }\n}\n\nasync function readPidFile(file: string): Promise<number | undefined> {\n  try {\n    const raw = await fs.readFile(file, 'utf8')\n    const pid = Number.parseInt(raw.trim(), 10)\n    return Number.isInteger(pid) && pid > 0 ? pid : undefined\n  } catch {\n    return undefined\n  }\n}\n\nconst defaultLockHolderProbe: LockHolderProbe = {\n  isPidAlive: isPidAliveDefault,\n  daemonPidFromFile: () => readPidFile(daemonPidPath()),\n  async daemonResponds(): Promise<boolean> {\n    const base = process.env.NEAT_API_URL ?? 'http://localhost:8080'\n    try {\n      // `/health` stays unauthenticated in every mode (auth.ts), so a reachable\n      // daemon answers it even with a bearer token set. Any HTTP response — not\n      // just 2xx — means a daemon owns the port. A short timeout keeps the\n      // fail-fast path well under a second.\n      await fetch(`${base}/health`, { signal: AbortSignal.timeout(750) })\n      return true\n    } catch {\n      return false\n    }\n  },\n}\n\n// Read the PID a lock holder recorded when it created the lock. Undefined for a\n// legacy empty lock, an unreadable file, or a lock unlinked out from under us.\nasync function readLockPid(lockPath: string): Promise<number | undefined> {\n  return readPidFile(lockPath)\n}\n\n// Decide who holds (or orphaned) the lock.\n//\n// The lock's own PID is the evidence, so it is read first: a live process named\n// in the lock is the holder, and it is \"the daemon\" only when the daemon pidfile\n// names that same process. Each project runs its own daemon, so a live pidfile\n// and an answering port say a daemon exists somewhere on the machine — not that\n// it is the one holding this lock (#1268).\n//\n// A lock with no live PID in it can't name anyone. There a live daemon still\n// dominates: while neatd is alive, hand-removing the lock is never safe, so we\n// surface the daemon message even when the lock itself is an empty orphan. We\n// never classify our own process as the blocker — a daemon serializing two of\n// its own registry writes contends with itself briefly and should just retry.\nexport async function classifyLockHolder(\n  lockPath: string,\n  probe: LockHolderProbe = defaultLockHolderProbe,\n): Promise<LockHolder> {\n  const lockPid = await readLockPid(lockPath)\n  const daemonPid = await probe.daemonPidFromFile()\n  if (lockPid !== undefined && lockPid !== process.pid && probe.isPidAlive(lockPid)) {\n    return { kind: lockPid === daemonPid ? 'daemon' : 'command', pid: lockPid }\n  }\n  if (\n    daemonPid !== undefined &&\n    daemonPid !== process.pid &&\n    probe.isPidAlive(daemonPid) &&\n    // Guards against a stale pidfile whose PID got reused.\n    (await probe.daemonResponds())\n  ) {\n    return { kind: 'daemon', pid: daemonPid }\n  }\n  return { kind: 'stale' }\n}\n\nexport function lockHolderMessage(holder: LockHolder, lockPath: string, timeoutMs: number): string {\n  switch (holder.kind) {\n    case 'daemon':\n      return (\n        `The neat daemon (pid ${holder.pid}) is holding the registry lock. ` +\n        'Register this project through the daemon, or stop neatd and re-run `neat init`.'\n      )\n    case 'command':\n      return (\n        `Another neat command (pid ${holder.pid}) is holding the registry lock. ` +\n        \"Wait for it to finish, or check `ps` if you're not sure what's running.\"\n      )\n    case 'stale':\n      return (\n        `timed out after ${timeoutMs}ms waiting for ${lockPath}. ` +\n        'Another neat process is holding the lock; if no such process exists, remove the file by hand.'\n      )\n  }\n}\n\n/**\n * Path normalisation per ADR-048 #7. Two `init` calls from different relative\n * paths to the same dir must collapse to one entry. `path.resolve` handles\n * relative-to-cwd; we pass it through `fs.realpath` when the dir exists so\n * symlinked paths land on the same canonical entry too.\n */\nexport async function normalizeProjectPath(input: string): Promise<string> {\n  const resolved = path.resolve(input)\n  try {\n    return await fs.realpath(resolved)\n  } catch {\n    return resolved\n  }\n}\n\n/**\n * tmp + fsync + rename. The fsync on the data fd guarantees the bytes are on\n * disk before rename swaps the inode; rename itself is atomic on POSIX.\n *\n * Exported so the init flow and test harnesses can use the same helper.\n */\nexport async function writeAtomically(target: string, contents: string): Promise<void> {\n  await fs.mkdir(path.dirname(target), { recursive: true })\n  const tmp = `${target}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`\n  const fd = await fs.open(tmp, 'w')\n  try {\n    await fd.writeFile(contents, 'utf8')\n    await fd.sync()\n  } finally {\n    await fd.close()\n  }\n  await fs.rename(tmp, target)\n}\n\nasync function acquireLock(\n  lockPath: string,\n  timeoutMs: number = LOCK_TIMEOUT_MS,\n  probe: LockHolderProbe = defaultLockHolderProbe,\n): Promise<void> {\n  const deadline = Date.now() + timeoutMs\n  await fs.mkdir(path.dirname(lockPath), { recursive: true })\n  let probedHolder = false\n  while (true) {\n    try {\n      const fd = await fs.open(lockPath, 'wx')\n      try {\n        // Stamp the lock with our PID so a contender can name who holds it and\n        // tell a live holder apart from a stale file. Best-effort: an empty\n        // lock still excludes correctly, it just can't be diagnosed.\n        await fd.writeFile(`${process.pid}\\n`, 'utf8')\n      } finally {\n        await fd.close()\n      }\n      return\n    } catch (err) {\n      const code = (err as NodeJS.ErrnoException).code\n      if (code !== 'EEXIST') throw err\n      // A live daemon holds the registry continuously enough that spinning the\n      // full timeout is pointless — surface the routed remediation on the first\n      // contention. A peer command clears on its own, so that one falls through\n      // to the retry.\n      if (!probedHolder) {\n        probedHolder = true\n        const holder = await classifyLockHolder(lockPath, probe)\n        if (holder.kind === 'daemon') {\n          throw new RegistryLockError(lockHolderMessage(holder, lockPath, timeoutMs))\n        }\n        // Nobody holds this one. A run killed mid-registration leaves the file\n        // behind, and it then blocked every project on the machine until someone\n        // deleted a file they had never heard of (#1241). Reclaim it instead.\n        //\n        // The race is benign: two contenders may both judge it stale and both\n        // unlink, but only one can win the exclusive create that follows and the\n        // loser sees EEXIST and retries. A lock carrying no readable PID waits\n        // out the write window first, so one being stamped right now is never\n        // taken from a live holder.\n        if (holder.kind === 'stale' && (await isReclaimableLock(lockPath))) {\n          await fs.unlink(lockPath).catch(() => {})\n          continue\n        }\n      }\n      if (Date.now() >= deadline) {\n        const holder = await classifyLockHolder(lockPath, probe)\n        throw new RegistryLockError(lockHolderMessage(holder, lockPath, timeoutMs))\n      }\n      await new Promise((r) => setTimeout(r, LOCK_RETRY_MS))\n    }\n  }\n}\n\n// How long a lock with no readable PID has to sit before it counts as\n// abandoned. The PID stamp is best-effort — a holder is briefly EEXIST-visible\n// before it has written — so a pid-less lock is only reclaimed once it has\n// outlived any plausible window between create and stamp.\nconst LOCK_UNSTAMPED_GRACE_MS = 5_000\n\n/**\n * Is this lock safe to take? Only called once the holder has been classified\n * stale — a dead PID, or none at all.\n *\n * A dead PID is unambiguous and reclaims immediately. No PID is not: it might be\n * a holder that has created the file and not yet stamped it, so that case waits\n * out the grace window and reclaims only if the file is genuinely old.\n */\nasync function isReclaimableLock(lockPath: string): Promise<boolean> {\n  const pid = await readLockPid(lockPath)\n  if (pid !== undefined) return true // classified stale with a PID = that PID is dead\n  try {\n    const stat = await fs.stat(lockPath)\n    return Date.now() - stat.mtimeMs > LOCK_UNSTAMPED_GRACE_MS\n  } catch {\n    // Gone between the EEXIST and here — the retry will simply take it.\n    return false\n  }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n  await fs.unlink(lockPath).catch(() => {})\n}\n\nasync function withLock<T>(fn: () => Promise<T>): Promise<T> {\n  const lock = registryLockPath()\n  await acquireLock(lock)\n  try {\n    return await fn()\n  } finally {\n    await releaseLock(lock)\n  }\n}\n\n/**\n * Read the registry from disk. Returns an empty registry if the file does\n * not exist yet — first run, never registered anything.\n *\n * Throws on parse / schema errors. The contract is single-source-of-truth;\n * a corrupt file is louder than a silent reset.\n */\nexport async function readRegistry(): Promise<RegistryFile> {\n  const file = registryPath()\n  let raw: string\n  try {\n    raw = await fs.readFile(file, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n      return { version: 1, projects: [] }\n    }\n    throw err\n  }\n  const parsed = JSON.parse(raw)\n  return RegistryFileSchema.parse(parsed)\n}\n\nasync function writeRegistry(reg: RegistryFile): Promise<void> {\n  // Re-parse before writing to surface schema drift introduced by callers\n  // mutating the in-memory object directly.\n  const validated = RegistryFileSchema.parse(reg)\n  await writeAtomically(registryPath(), JSON.stringify(validated, null, 2) + '\\n')\n}\n\nexport interface AddProjectOptions {\n  name: string\n  path: string\n  languages?: string[]\n  status?: RegistryStatus\n}\n\n/**\n * Anything the registry refuses to do.\n *\n * The identity lives on the class, not in the message text. Every caller that\n * prints one already prefixes its own name — the CLI writes `neat: ` — so a\n * message carrying `neat registry:` came out as `neat: neat registry: …`\n * (#1240). A non-CLI caller that wants to know where an error came from reads\n * `err.name`, which is more reliable than a string prefix anyway.\n */\nexport class RegistryError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = 'RegistryError'\n  }\n}\n\n/** The registry lock could not be taken, and says who holds it. */\nexport class RegistryLockError extends RegistryError {\n  constructor(message: string) {\n    super(message)\n    this.name = 'RegistryLockError'\n  }\n}\n\nexport class ProjectNameCollisionError extends RegistryError {\n  readonly projectName: string\n  constructor(name: string) {\n    super(`a project named \"${name}\" is already registered`)\n    this.name = 'ProjectNameCollisionError'\n    this.projectName = name\n  }\n}\n\n/**\n * Register a project, or update its `lastSeenAt` if the same path is already\n * registered under the same name (idempotent re-init).\n *\n * Hard error on name collision against a different path — ADR-046 #7. The\n * caller can recover by passing `--project <new-name>`.\n */\nexport async function addProject(opts: AddProjectOptions): Promise<RegistryEntry> {\n  const resolvedPath = await normalizeProjectPath(opts.path)\n  return withLock(async () => {\n    const reg = await readRegistry()\n    const byName = reg.projects.find((p) => p.name === opts.name)\n    const byPath = reg.projects.find((p) => p.path === resolvedPath)\n\n    if (byName && byName.path !== resolvedPath) {\n      throw new ProjectNameCollisionError(opts.name)\n    }\n\n    const now = new Date().toISOString()\n\n    if (byName && byName.path === resolvedPath) {\n      // Idempotent re-register: same name, same path. Refresh languages /\n      // status if the caller passed new ones.\n      byName.lastSeenAt = now\n      if (opts.languages) byName.languages = opts.languages\n      if (opts.status) byName.status = opts.status\n      await writeRegistry(reg)\n      return byName\n    }\n\n    if (byPath && byPath.name !== opts.name) {\n      // Same dir already registered under a different name. Treat as a\n      // collision so the user is forced to decide which name wins.\n      throw new ProjectNameCollisionError(byPath.name)\n    }\n\n    const entry: RegistryEntry = {\n      name: opts.name,\n      path: resolvedPath,\n      registeredAt: now,\n      languages: opts.languages ?? [],\n      status: opts.status ?? 'active',\n    }\n    reg.projects.push(entry)\n    await writeRegistry(reg)\n    return entry\n  })\n}\n\nexport async function getProject(name: string): Promise<RegistryEntry | undefined> {\n  const reg = await readRegistry()\n  return reg.projects.find((p) => p.name === name)\n}\n\n/**\n * The registered project a directory belongs to: the entry whose path is `dir` itself,\n * or failing that its nearest registered ancestor — so a verb run from `services/api`\n * inside a registered repo still finds the repo. Paths are compared after the same\n * normalisation registration applies (`normalizeProjectPath`), so a symlinked spelling\n * of the directory matches the realpath the registry stored.\n */\nexport async function findProjectByPath(dir: string): Promise<RegistryEntry | undefined> {\n  const here = await normalizeProjectPath(dir)\n  const { projects } = await readRegistry()\n  let best: RegistryEntry | undefined\n  for (const entry of projects) {\n    const inside = here === entry.path || here.startsWith(entry.path + path.sep)\n    if (inside && (!best || entry.path.length > best.path.length)) best = entry\n  }\n  return best\n}\n\n/**\n * Synchronous startup lookup for stdio clients such as MCP. This keeps the\n * registry file owned by this module while applying the same nearest-ancestor\n * rule as findProjectByPath and the same discovery parser as the CLI.\n */\nexport function registeredDaemonForPathSync(dir: string): {\n  registered: boolean\n  restPort?: number\n} {\n  const normalize = (input: string): string => {\n    const resolved = path.resolve(input)\n    try {\n      return realpathSync(resolved)\n    } catch {\n      return resolved\n    }\n  }\n  let raw: string\n  try {\n    raw = readFileSync(registryPath(), 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return { registered: false }\n    throw err\n  }\n  const projects = RegistryFileSchema.parse(JSON.parse(raw)).projects\n  const here = normalize(dir)\n  let best: RegistryEntry | undefined\n  for (const entry of projects) {\n    const entryPath = normalize(entry.path)\n    if (\n      (here === entryPath || here.startsWith(entryPath + path.sep)) &&\n      (!best || entryPath.length > normalize(best.path).length)\n    )\n      best = entry\n  }\n  if (!best) return { registered: false }\n  let files: string[]\n  try {\n    files = readdirSync(daemonsDir())\n  } catch {\n    return { registered: true }\n  }\n  for (const file of files) {\n    if (!file.endsWith('.json')) continue\n    try {\n      const record = parseDaemonRecord(readFileSync(path.join(daemonsDir(), file), 'utf8'))\n      if (record?.project === best.name && record.status !== 'stopped') {\n        return { registered: true, restPort: record.ports.rest }\n      }\n    } catch {\n      /* skip an unreadable discovery copy */\n    }\n  }\n  return { registered: true }\n}\n\nexport async function listProjects(): Promise<RegistryEntry[]> {\n  const reg = await readRegistry()\n  return reg.projects\n}\n\nexport async function setStatus(name: string, status: RegistryStatus): Promise<RegistryEntry> {\n  return withLock(async () => {\n    const reg = await readRegistry()\n    const entry = reg.projects.find((p) => p.name === name)\n    if (!entry) throw new RegistryError(`no project named \"${name}\"`)\n    entry.status = status\n    await writeRegistry(reg)\n    return entry\n  })\n}\n\nexport async function touchLastSeen(\n  name: string,\n  at: string = new Date().toISOString(),\n): Promise<void> {\n  await withLock(async () => {\n    const reg = await readRegistry()\n    const entry = reg.projects.find((p) => p.name === name)\n    if (!entry) return\n    entry.lastSeenAt = at\n    await writeRegistry(reg)\n  })\n}\n\n/**\n * Remove the registry entry for `name`. Per ADR-048 #6: this only removes the\n * registry row. It does **not** touch `neat-out/`, `policy.json`, or any user\n * file in the project directory. SDK-install rollback is a separate flow\n * (`neat-rollback.patch`) that the caller opts in to.\n */\nexport async function removeProject(name: string): Promise<RegistryEntry | undefined> {\n  return withLock(async () => {\n    const reg = await readRegistry()\n    const idx = reg.projects.findIndex((p) => p.name === name)\n    if (idx < 0) return undefined\n    const [removed] = reg.projects.splice(idx, 1)\n    await writeRegistry(reg)\n    return removed\n  })\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// #463 — prune dead-path entries so the registry doesn't accumulate zombies.\n//\n// Ephemeral tmp-dir projects (smoke runs, throwaway demos) leave entries whose\n// `path` is gone from disk. Without pruning the daemon logs an ENOENT warning\n// for each on every startup forever and `/api/health` lists them as permanent\n// `broken` rows. Pruning removes user-facing state, so it's deliberately\n// conservative: we only ever drop an entry on a *definite* ENOENT (the path is\n// genuinely gone). A transient stat failure — EACCES, EBUSY, an unmounted\n// drive — leaves the entry untouched; it isn't dead, just unreachable.\n//\n// Two modes:\n//  - Auto-prune (daemon bootstrap / reload) gates removal on a staleness TTL.\n//    An ENOENT entry is only dropped if its `lastSeenAt` is older than the TTL,\n//    so a recently-active project whose path is temporarily unavailable stays.\n//  - `neat prune` is explicit user intent, so it drops any ENOENT entry\n//    immediately regardless of age.\n// ─────────────────────────────────────────────────────────────────────────\n\nconst DAY_MS = 24 * 60 * 60 * 1000\n// Default 7 days, mirroring NEAT_STALE_THRESHOLDS' env-override shape.\nexport const DEFAULT_PRUNE_TTL_MS = 7 * DAY_MS\n\nexport function pruneTtlMs(): number {\n  const raw = process.env.NEAT_REGISTRY_PRUNE_TTL_MS\n  if (!raw) return DEFAULT_PRUNE_TTL_MS\n  const n = Number.parseInt(raw, 10)\n  if (Number.isFinite(n) && n >= 0) return n\n  console.warn(\n    `[neat] NEAT_REGISTRY_PRUNE_TTL_MS could not be parsed (${raw}); using default ${DEFAULT_PRUNE_TTL_MS}ms`,\n  )\n  return DEFAULT_PRUNE_TTL_MS\n}\n\n// Classify a single path: 'gone' (definite ENOENT), 'present' (stat succeeded,\n// directory exists), or 'unknown' (a transient/ambiguous error — never prune).\n// Exported so the daemon and tests can probe the same logic.\nexport type PathStatus = 'gone' | 'present' | 'unknown'\n\nasync function statPathStatus(p: string): Promise<PathStatus> {\n  try {\n    const stat = await fs.stat(p)\n    return stat.isDirectory() ? 'present' : 'unknown'\n  } catch (err) {\n    return (err as NodeJS.ErrnoException).code === 'ENOENT' ? 'gone' : 'unknown'\n  }\n}\n\nexport interface PruneOptions {\n  // Override the staleness gate. Auto-prune passes a TTL; `neat prune` passes\n  // `ttlMs: 0` to drop any ENOENT entry immediately. Default is the env-driven\n  // TTL.\n  ttlMs?: number\n  // Override the path probe (tests drive ENOENT / EACCES / present branches\n  // without a real filesystem). Defaults to a real stat.\n  statPath?: (p: string) => Promise<PathStatus>\n  // Clock injection for the staleness comparison; defaults to Date.now().\n  now?: () => number\n}\n\n/**\n * Remove registry entries whose `path` is definitely gone (ENOENT). Goes\n * through the same lock + atomic-write path as every other mutation — never a\n * raw rewrite — so the contract's atomicity invariant holds.\n *\n * Staleness gate: an ENOENT entry is dropped only when `ttlMs` is 0 (explicit\n * `neat prune`) or its `lastSeenAt` (falling back to `registeredAt`) is older\n * than `ttlMs`. A fresh ENOENT entry under a non-zero TTL is left in place — the\n * daemon still marks it `broken`, the TTL is the safety margin before removal.\n *\n * Returns the entries that were removed.\n */\nexport async function pruneRegistry(opts: PruneOptions = {}): Promise<RegistryEntry[]> {\n  const ttlMs = opts.ttlMs ?? pruneTtlMs()\n  const statPath = opts.statPath ?? statPathStatus\n  const now = opts.now ?? Date.now\n\n  return withLock(async () => {\n    const reg = await readRegistry()\n    const removed: RegistryEntry[] = []\n    const kept: RegistryEntry[] = []\n    for (const entry of reg.projects) {\n      const status = await statPath(entry.path)\n      if (status !== 'gone') {\n        // Present, or a transient/ambiguous error — keep it. We only prune on a\n        // definite ENOENT.\n        kept.push(entry)\n        continue\n      }\n      // Path is gone. Drop it immediately when there's no TTL gate, otherwise\n      // only once it's been quiet longer than the TTL.\n      if (ttlMs <= 0) {\n        removed.push(entry)\n        continue\n      }\n      const lastSeen = Date.parse(entry.lastSeenAt ?? entry.registeredAt)\n      const age = now() - (Number.isFinite(lastSeen) ? lastSeen : 0)\n      if (age > ttlMs) {\n        removed.push(entry)\n      } else {\n        kept.push(entry)\n      }\n    }\n    if (removed.length === 0) return []\n    reg.projects = kept\n    await writeRegistry(reg)\n    return removed\n  })\n}\n","// SSE handler for the frontend-facing event stream (ADR-051 #1).\n// Subscribes to the bus in events.ts, filters by project, writes\n// `event: <type>\\ndata: <json>\\n\\n` frames to the client. An initial\n// `:open\\n\\n` comment goes out at the handshake so EventSource opens\n// right away instead of waiting on the first event or heartbeat.\n//\n// Backpressure: per-connection queue cap of 1000 outstanding writes; once\n// hit, the connection is dropped with `event: error data: { reason:\n// 'backpressure' }` per ADR-051 #8. Heartbeat: comment line every 30s\n// keeps proxies from idle-timing out (ADR-051 #3).\n\nimport type { FastifyReply, FastifyRequest } from 'fastify'\nimport { readFileSync, statSync } from 'node:fs'\nimport { z } from 'zod'\nimport { ErrorEventSchema, IncidentEventPayloadSchema, incidentKindOf } from '@neat.is/types'\nimport {\n  EVENT_BUS_CHANNEL,\n  eventBus,\n  type NeatEventEnvelope,\n} from './events.js'\n\nexport const SSE_HEARTBEAT_MS = 30_000\nexport const SSE_BACKPRESSURE_CAP = 1000\n\nexport interface HandleSseOptions {\n  project: string\n  heartbeatMs?: number\n  backpressureCap?: number\n  incidentOnly?: boolean\n  incidentReplay?: z.infer<typeof IncidentTriggerSchema>[]\n}\n\nexport const INCIDENT_TRIGGER_STREAM_SCOPE = 'incident-only-v1'\nconst IncidentTriggerSchema = IncidentEventPayloadSchema.extend({\n  incidentId: z.string().regex(/^[A-Za-z0-9:_-]{1,100}$/),\n  affectedNode: z.string().min(1).max(512),\n  service: z.string().min(1).max(256),\n  at: z.string().datetime(),\n})\n\nconst MAX_REPLAY_BYTES = 16 * 1024 * 1024\nconst MAX_REPLAY_EVENTS = 10_000\n\nfunction isExtractionFailure(row: Record<string, unknown>): boolean {\n  const keys = Object.keys(row)\n  return keys.every(key => ['source', 'producer', 'file', 'error', 'stack', 'ts'].includes(key))\n    && typeof row.producer === 'string' && typeof row.file === 'string'\n    && typeof row.error === 'string' && typeof row.ts === 'string'\n    && (row.stack === undefined || typeof row.stack === 'string')\n    && !Number.isNaN(Date.parse(row.ts))\n}\n\n/** Read the append-ordered incident ledger before opening a hosted stream.\n * Any corruption, missing cursor, or oversized ledger fails closed. The\n * source-bearing ErrorEvents are decoded only inside the daemon.\n */\nexport function loadIncidentReplay(errorsPath: string, cursor?: string): z.infer<typeof IncidentTriggerSchema>[] {\n  if (cursor !== undefined && !/^[A-Za-z0-9:_-]{1,100}$/.test(cursor)) throw new Error('incident replay unavailable')\n  try {\n    if (statSync(errorsPath).size > MAX_REPLAY_BYTES) throw new Error('incident replay unavailable')\n    const raw = readFileSync(errorsPath, 'utf8')\n    if (raw && !raw.endsWith('\\n')) throw new Error('incident replay unavailable')\n    const seen = new Map<string, string>()\n    const events: z.infer<typeof IncidentTriggerSchema>[] = []\n    for (const line of raw.split('\\n')) {\n      if (!line) continue\n      if (events.length >= MAX_REPLAY_EVENTS) throw new Error('incident replay unavailable')\n      const row: unknown = JSON.parse(line)\n      if (row !== null && typeof row === 'object' && !Array.isArray(row)\n        && 'source' in row && row.source === 'extract') {\n        if (!isExtractionFailure(row as Record<string, unknown>)) throw new Error('incident replay unavailable')\n        continue\n      }\n      const event = ErrorEventSchema.parse(row)\n      const trigger = IncidentTriggerSchema.parse({incidentId:event.id,affectedNode:event.affectedNode,\n        service:event.service,incidentKind:incidentKindOf(event),at:event.timestamp})\n      const prior = seen.get(trigger.incidentId), encoded = JSON.stringify(trigger)\n      if (prior !== undefined) {\n        if (prior !== encoded) throw new Error('incident replay unavailable')\n        continue\n      }\n      seen.set(trigger.incidentId, encoded)\n      events.push(trigger)\n    }\n    if (cursor === undefined) return events\n    const at = events.findIndex(event => event.incidentId === cursor)\n    if (at < 0) throw new Error('incident replay unavailable')\n    return events.slice(at + 1)\n  } catch { throw new Error('incident replay unavailable') }\n}\n\nexport function handleSse(\n  req: FastifyRequest,\n  reply: FastifyReply,\n  opts: HandleSseOptions,\n): void {\n  const heartbeatMs = opts.heartbeatMs ?? SSE_HEARTBEAT_MS\n  const backpressureCap = opts.backpressureCap ?? SSE_BACKPRESSURE_CAP\n\n  reply.raw.setHeader('Content-Type', 'text/event-stream')\n  reply.raw.setHeader('Cache-Control', 'no-cache, no-transform')\n  reply.raw.setHeader('Connection', 'keep-alive')\n  reply.raw.setHeader('X-Accel-Buffering', 'no')\n  if (opts.incidentOnly) {\n    reply.raw.setHeader('X-NEAT-Event-Scope', INCIDENT_TRIGGER_STREAM_SCOPE)\n    reply.raw.setHeader('X-NEAT-Project', opts.project)\n    if (opts.incidentReplay) reply.raw.setHeader('X-NEAT-Replay-Complete', '1')\n  }\n  reply.raw.flushHeaders?.()\n\n  // Flushing headers leaves the response body empty, so the browser's\n  // EventSource stays in CONNECTING (readyState 0) until the first body byte\n  // lands — which, on a quiet graph, is the first real event or the 30s\n  // heartbeat, whichever comes first. Write a comment line right away so the\n  // stream opens at the handshake and EventSource fires onopen immediately.\n  // A colon-prefixed comment is a no-op per the SSE spec (clients ignore it,\n  // same as the heartbeat), so it sits outside the locked ADR-051 taxonomy.\n  // Written raw, bypassing the backpressure accounting below, exactly like\n  // the heartbeat does.\n  reply.raw.write(':open\\n\\n')\n  for (const trigger of opts.incidentReplay ?? []) {\n    reply.raw.write(`id: ${trigger.incidentId}\\nevent: incident\\ndata: ${JSON.stringify(trigger)}\\n\\n`)\n  }\n\n  let pending = 0\n  let dropped = false\n\n  const closeConnection = (): void => {\n    if (dropped) return\n    dropped = true\n    eventBus.off(EVENT_BUS_CHANNEL, listener)\n    clearInterval(heartbeat)\n    if (!reply.raw.writableEnded) reply.raw.end()\n  }\n\n  const writeFrame = (frame: string): void => {\n    if (dropped) return\n    if (pending >= backpressureCap) {\n      // Past the cap — emit one final error frame and drop. Don't try to\n      // gracefully drain; a slow consumer that's already 1000 frames behind\n      // is not going to catch up.\n      const errFrame = `event: error\\ndata: ${JSON.stringify({ reason: 'backpressure' })}\\n\\n`\n      reply.raw.write(errFrame)\n      closeConnection()\n      return\n    }\n    pending++\n    reply.raw.write(frame, () => {\n      pending = Math.max(0, pending - 1)\n    })\n  }\n\n  const listener = (envelope: NeatEventEnvelope): void => {\n    if (envelope.project !== opts.project) return\n    if (opts.incidentOnly) {\n      if (envelope.type !== 'incident') return\n      const trigger = IncidentTriggerSchema.safeParse(envelope.payload)\n      if (!trigger.success) return\n      writeFrame(`id: ${trigger.data.incidentId}\\nevent: incident\\ndata: ${JSON.stringify(trigger.data)}\\n\\n`)\n      return\n    }\n    writeFrame(`event: ${envelope.type}\\ndata: ${JSON.stringify(envelope.payload)}\\n\\n`)\n  }\n\n  eventBus.on(EVENT_BUS_CHANNEL, listener)\n\n  const heartbeat = setInterval(() => {\n    if (dropped) return\n    reply.raw.write(':heartbeat\\n\\n')\n  }, heartbeatMs)\n  if (typeof heartbeat.unref === 'function') heartbeat.unref()\n\n  req.raw.on('close', closeConnection)\n  reply.raw.on('close', closeConnection)\n  reply.raw.on('error', closeConnection)\n}\n","// The PR verdict, computed where the source, the extractor and the OBSERVED\n// graph already are (ADR-235).\n//\n// neat-action posts a verdict-first comment on a pull request: what the PR adds\n// and removes in the graph, and — against a connected host — what production\n// actually runs through the things it touches. Producing it takes the engine:\n// the PR's base and head are each extracted, and the two graphs diffed, before\n// a host is asked anything. The hosted control plane has no engine and may not\n// grow one, so on hosted NEAT the tenant daemon does this work and hands back\n// the finished comment.\n//\n// What this module does for one request:\n//   1. clone the base commit and the head commit, depth 1, into temp dirs;\n//   2. extract each into its own scratch graph — never the project's graph;\n//   3. diff them with the Action's own logic;\n//   4. read the OBSERVED half from the project's live graph, which is only read;\n//   5. render with the Action's own renderer, and return the markdown.\n//\n// The diffing, formatting and rendering are imported from the Action's module,\n// not reimplemented: the hosted comment and the Action's comment are one\n// implementation and cannot disagree.\n//\n// Bounds: one verdict at a time per daemon, one scratch graph per commit, a\n// wall-clock limit, and temp dirs removed whatever happens.\n\nimport { createHash } from 'node:crypto'\nimport { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport {\n  changedFileNodeIds,\n  changedNodeIds,\n  changedNodesForObservedScan,\n  diffGraphs,\n  formatDivergences,\n  graphFromExport,\n  observedBreakFrom,\n  renderVerdict,\n} from '@neat.is/action/src/graph.mjs'\nimport { PrVerdictBodySchema, type ErrorEvent } from '@neat.is/types'\nimport { defaultCloneCommit, scrubCloneToken, type CloneCommit } from './connectors/hosted-repos.js'\nimport { computeDivergences } from './divergences.js'\nimport { extractFromDirectory } from './extract.js'\nimport { makeGraph, type NeatGraph } from './graph.js'\nimport { getObservedDependencies } from './traverse.js'\n\n/** Two shallow clones and two extractions of a large repo fit comfortably; a wedged clone does not. */\nexport const DEFAULT_PR_VERDICT_TIMEOUT_MS = 240_000\n\n/** A changed-files list longer than this is a PR nobody reads a comment on; cap what is matched. */\nconst MAX_CHANGED_FILES = 3000\n\nexport type PrVerdictStage = 'clone-base' | 'clone-head' | 'extract-base' | 'extract-head'\n\nexport interface PrVerdictRequest {\n  owner: string\n  name: string\n  baseSha: string\n  headSha: string\n  /** `https://x-access-token:<token>@github.com/<owner>/<name>.git`. Used for the two clones, then gone. */\n  cloneUrl: string\n  /** Repo-relative paths the PR changes, from the caller. Absent → the two trees are compared. */\n  changedFiles?: string[]\n  tone?: 'loud' | 'professional'\n}\n\nexport interface PrVerdictResult {\n  marker: string\n  body: string\n  base: { sha: string; nodes: number; edges: number }\n  head: { sha: string; nodes: number; edges: number }\n  changedFiles: number\n  observedBreaks: number\n  divergences: number\n  durationMs: number\n}\n\n/** A verdict that could not be produced, carrying the HTTP status the route answers with. */\nexport class PrVerdictError extends Error {\n  constructor(\n    message: string,\n    readonly status: 400 | 422 | 429 | 504,\n    readonly stage?: PrVerdictStage,\n    /** For a 400: the schema's issues, returned as `details`. */\n    readonly details?: unknown,\n  ) {\n    super(message)\n    this.name = 'PrVerdictError'\n  }\n}\n\n/**\n * Validate a request body against `PrVerdictBodySchema` (rest-api.md §Schema validation: every POST body\n * parses through a Zod schema from `@neat.is/types`, failures are 400 with the issues in `details`). Beyond\n * the schema, the changed-files list is capped.\n */\nexport function parsePrVerdictRequest(body: unknown): PrVerdictRequest {\n  const parsed = PrVerdictBodySchema.safeParse(body)\n  if (!parsed.success) {\n    throw new PrVerdictError('invalid pr-verdict body', 400, undefined, parsed.error.issues)\n  }\n  const { changedFiles, tone, ...rest } = parsed.data\n  return {\n    ...rest,\n    ...(changedFiles ? { changedFiles: changedFiles.slice(0, MAX_CHANGED_FILES) } : {}),\n    ...(tone ? { tone } : {}),\n  }\n}\n\nexport interface PrVerdictDeps {\n  /** Test seam: the single-commit clone (defaults to isomorphic-git). */\n  cloneCommit?: CloneCommit\n  /** Test seam: the extractor (defaults to extractFromDirectory). */\n  extract?: typeof extractFromDirectory\n  /** Root the temp clone dirs are made under (default os.tmpdir()). */\n  tmpRoot?: string\n  timeoutMs?: number\n  now?: () => number\n}\n\nexport interface PrVerdictContext {\n  /** The project's live graph. Read for OBSERVED; never written. */\n  liveGraph: NeatGraph\n  /** The project's recorded incidents, for symbol-grain divergences — the same read `/graph/divergences` does. */\n  incidents?: ErrorEvent[]\n}\n\nexport type PrVerdictRunner = (req: PrVerdictRequest, ctx: PrVerdictContext) => Promise<PrVerdictResult>\n\n/**\n * A runner that computes one verdict at a time. A request that arrives while one is running is refused with\n * 429 rather than queued: each verdict holds two checkouts and two graphs, and a tenant is sized for one.\n */\nexport function createPrVerdictRunner(deps: PrVerdictDeps = {}): PrVerdictRunner {\n  let busy = false\n  return async (req, ctx) => {\n    if (busy) throw new PrVerdictError('a verdict is already being computed on this daemon', 429)\n    busy = true\n    const timeoutMs = deps.timeoutMs ?? DEFAULT_PR_VERDICT_TIMEOUT_MS\n    // The work carries the same deadline: every stage gives up when it passes, and the checkouts are removed\n    // on the way out. So the work settles at the deadline even when a clone has stalled, `busy` clears, and\n    // the next request is served instead of refused until a restart. The timer below is the backstop for\n    // the in-memory steps between stages.\n    const deadline = (deps.now ?? Date.now)() + timeoutMs\n    const work = computePrVerdict(req, ctx, deps, deadline).finally(() => {\n      busy = false\n    })\n    let timer: ReturnType<typeof setTimeout> | undefined\n    const timeout = new Promise<never>((_, reject) => {\n      timer = setTimeout(\n        () => reject(new PrVerdictError(`verdict did not finish within ${timeoutMs}ms`, 504)),\n        timeoutMs,\n      )\n    })\n    try {\n      return await Promise.race([work, timeout])\n    } finally {\n      if (timer) clearTimeout(timer)\n      work.catch(() => {})\n    }\n  }\n}\n\nasync function computePrVerdict(\n  req: PrVerdictRequest,\n  ctx: PrVerdictContext,\n  deps: PrVerdictDeps,\n  deadline: number,\n): Promise<PrVerdictResult> {\n  const now = deps.now ?? Date.now\n  const startedAt = now()\n  const cloneCommit = deps.cloneCommit ?? defaultCloneCommit\n  const extract = deps.extract ?? extractFromDirectory\n  const root = await fs.mkdtemp(path.join(deps.tmpRoot ?? os.tmpdir(), 'neat-pr-'))\n  const baseDir = path.join(root, 'base')\n  const headDir = path.join(root, 'head')\n\n  // Run one stage against what is left of the deadline. A stage that can't be cancelled — a fetch, an\n  // extraction — is abandoned, not stopped: it finishes or fails on its own, against checkouts that the\n  // `finally` below has already removed.\n  const stage = async <T>(name: PrVerdictStage, run: () => Promise<T>): Promise<T> => {\n    const left = deadline - now()\n    if (left <= 0) throw new PrVerdictError(`verdict ran out of time before ${name}`, 504, name)\n    const work = run()\n    work.catch(() => {})\n    let timer: ReturnType<typeof setTimeout> | undefined\n    const expired = new Promise<never>((_, reject) => {\n      timer = setTimeout(() => reject(new PrVerdictError(`verdict ran out of time during ${name}`, 504, name)), left)\n    })\n    try {\n      return await Promise.race([work, expired])\n    } catch (err) {\n      if (err instanceof PrVerdictError) throw err\n      const why = scrubCloneToken((err as Error).message ?? String(err)).slice(0, 300)\n      throw new PrVerdictError(`${name} failed — ${why}`, 422, name)\n    } finally {\n      if (timer) clearTimeout(timer)\n    }\n  }\n  // The pass names its source like a repo-sync pass does (ADR-233) and stays quiet: these graphs belong to\n  // no project, so there is no extraction for anyone to be told about.\n  const extractOpts = { source: `${req.owner}/${req.name}`, announce: false }\n\n  try {\n    await fs.mkdir(baseDir)\n    await fs.mkdir(headDir)\n    await stage('clone-base', () => cloneCommit(req.cloneUrl, req.baseSha, baseDir))\n    await stage('clone-head', () => cloneCommit(req.cloneUrl, req.headSha, headDir))\n\n    // One scratch graph per commit. Neither is registered under a project name, so nothing that serves the\n    // project — REST, MCP, the persist loop, the event bus — can reach them.\n    const baseGraph = makeGraph()\n    const headGraph = makeGraph()\n    await stage('extract-base', () => extract(baseGraph, baseDir, extractOpts))\n    await stage('extract-head', () => extract(headGraph, headDir, extractOpts))\n\n    const base = graphFromExport(baseGraph.export())\n    const head = graphFromExport(headGraph.export())\n    const delta = diffGraphs(base, head)\n    const changedPaths = req.changedFiles ?? (await changedPathsBetween(baseDir, headDir))\n    const changedFiles = changedFileNodeIds(head, changedPaths)\n\n    // The OBSERVED half, from the live graph — the same two questions the Action asks a host over HTTP\n    // (action-hosted-seam.md), asked in process and handed to the same formatters.\n    const divergences = formatDivergences(\n      computeDivergences(ctx.liveGraph, { incidents: ctx.incidents ?? [] }),\n      changedNodeIds(base, head),\n    )\n    const observedBreaks = []\n    for (const node of changedNodesForObservedScan(base, head)) {\n      if (!ctx.liveGraph.hasNode(node.id)) continue\n      const found = observedBreakFrom(node, getObservedDependencies(ctx.liveGraph, node.id))\n      if (found) observedBreaks.push(found)\n    }\n\n    const { marker, body: rendered } = renderVerdict({\n      graph: head,\n      delta,\n      changedFiles,\n      divergences,\n      observedBreaks,\n      tone: req.tone ?? 'loud',\n    })\n    // The Action finds its own sticky comment by this marker. A hosted comment that carried it would be taken\n    // for the Action's on a repo running both, and the two would overwrite each other. The caller stamps its\n    // own marker; `marker` stays in the response so a caller can recognise an Action comment.\n    const body = rendered.startsWith(marker) ? rendered.slice(marker.length).replace(/^(?:\\r?\\n)+/, '') : rendered\n    return {\n      marker,\n      body,\n      base: { sha: req.baseSha, nodes: baseGraph.order, edges: baseGraph.size },\n      head: { sha: req.headSha, nodes: headGraph.order, edges: headGraph.size },\n      changedFiles: changedFiles.length,\n      observedBreaks: observedBreaks.length,\n      divergences: divergences.length,\n      durationMs: now() - startedAt,\n    }\n  } finally {\n    await fs.rm(root, { recursive: true, force: true }).catch(() => {})\n  }\n}\n\nconst SKIP_DIRS: ReadonlySet<string> = new Set(['.git', 'node_modules', 'neat-out'])\n\n/** Every file under `dir`, repo-relative with forward slashes, mapped to a content hash. */\nasync function hashTree(dir: string): Promise<Map<string, string>> {\n  const out = new Map<string, string>()\n  const walk = async (rel: string): Promise<void> => {\n    const entries = await fs.readdir(path.join(dir, rel), { withFileTypes: true }).catch(() => [])\n    for (const entry of entries) {\n      const child = rel ? `${rel}/${entry.name}` : entry.name\n      if (entry.isDirectory()) {\n        if (!SKIP_DIRS.has(entry.name)) await walk(child)\n      } else if (entry.isFile()) {\n        const bytes = await fs.readFile(path.join(dir, child)).catch(() => null)\n        if (bytes) out.set(child, createHash('sha1').update(bytes).digest('hex'))\n      }\n    }\n  }\n  await walk('')\n  return out\n}\n\n/**\n * The paths that differ between two checkouts — added, removed or changed. The fallback when the caller\n * sent no changed-files list. It is a direct comparison of the two commits: with depth-1 clones there is no\n * merge base, so files that moved on the base branch after the PR branched show up here too. The caller's\n * list, taken from the PR itself, is the better source.\n */\nexport async function changedPathsBetween(baseDir: string, headDir: string): Promise<string[]> {\n  const [base, head] = await Promise.all([hashTree(baseDir), hashTree(headDir)])\n  const changed: string[] = []\n  for (const [file, hash] of head) if (base.get(file) !== hash) changed.push(file)\n  for (const file of base.keys()) if (!head.has(file)) changed.push(file)\n  return changed.sort().slice(0, MAX_CHANGED_FILES)\n}\n","// Pure graph logic for the NEAT PR action — no dependencies, so it runs and\n// tests with plain Node. Given two NEAT `graph.json` snapshots (a PR's base and\n// head), it computes what the graph gained/lost and the blast radius of the\n// changed files, and renders the sticky PR comment.\n\nimport { readFileSync } from 'node:fs'\n\nexport const MARKER = '<!-- neat-action:graph-impact -->'\n\nconst shortId = (id) => String(id).split(':').slice(-1)[0]\nconst fence = (s) => '`' + s + '`'\n\n// Load a NEAT snapshot (graph.json). Nodes/edges live under `.graph` (graphology\n// export); tolerate a flat shape too.\nexport function loadGraph(path) {\n  return graphFromExport(JSON.parse(readFileSync(path, 'utf8')))\n}\n\n// The same shape from an already-parsed snapshot or a graphology `export()` —\n// what a host holding the graph in memory passes instead of a file path.\nexport function graphFromExport(raw) {\n  const g = raw.graph ?? raw\n  const nodes = new Map((g.nodes ?? []).map((n) => [n.key, n.attributes ?? {}]))\n  const edges = (g.edges ?? []).map((e) => ({\n    key: e.key,\n    source: e.source,\n    target: e.target,\n    ...(e.attributes ?? {}),\n  }))\n  return { nodes, edges }\n}\n\nconst namesByType = (entries, type) =>\n  entries.filter(([, a]) => a.type === type).map(([k, a]) => a.name ?? shortId(k))\n\n// The route/table delta between base and head, keyed on node id.\nexport function diffGraphs(base, head) {\n  const added = [...head.nodes].filter(([k]) => !base.nodes.has(k))\n  const removed = [...base.nodes].filter(([k]) => !head.nodes.has(k))\n  return {\n    routesAdded: namesByType(added, 'RouteNode'),\n    routesRemoved: namesByType(removed, 'RouteNode'),\n    tablesAdded: namesByType(added, 'InfraNode'),\n    tablesRemoved: namesByType(removed, 'InfraNode'),\n  }\n}\n\n// Map changed paths (repo-relative) to FileNode ids, matching a FileNode's\n// service-relative `path` as a suffix so it works in both flat and monorepo repos.\nexport function changedFileNodeIds(graph, changedPaths) {\n  const ids = []\n  for (const [key, attrs] of graph.nodes) {\n    if (attrs.type !== 'FileNode' || !attrs.path) continue\n    if (changedPaths.some((c) => c === attrs.path || c.endsWith('/' + attrs.path))) ids.push(key)\n  }\n  return ids\n}\n\n// Every node id the PR adds or removes — what the divergence findings are\n// filtered against. With no base graph, everything in head counts.\nexport function changedNodeIds(base, head) {\n  if (!base) return [...head.nodes.keys()]\n  return [\n    ...[...head.nodes.keys()].filter((k) => !base.nodes.has(k)),\n    ...[...base.nodes.keys()].filter((k) => !head.nodes.has(k)),\n  ]\n}\n\n// Keep the divergences that involve a node this PR changed, and format them.\n// `data` is a host's /graph/divergences response (or the same result in\n// memory); tolerant of its shape.\nexport function formatDivergences(data, changedIds) {\n  const findings = Array.isArray(data)\n    ? data\n    : (data?.divergences ?? data?.findings ?? data?.items ?? [])\n  const changed = new Set(changedIds)\n  return findings\n    .filter((f) => changed.has(f.source) || changed.has(f.target) || changed.has(f.nodeId))\n    .slice(0, 10)\n    .map((f) => {\n      const kind = f.kind || f.type || 'divergence'\n      const s = shortId(f.source ?? f.nodeId ?? '')\n      const t = f.target ? ' → `' + shortId(f.target) + '`' : ''\n      const why = f.reason || f.message || ''\n      return `${kind}: \\`${s}\\`${t}${why ? ' — ' + why : ''}`\n    })\n}\n\n// Turn one node's /graph/observed-dependencies answer into an observed break,\n// or null when production doesn't run the node. A node the OTel layer has seen\n// (as caller or callee) is one production is live on, so removing or changing\n// it is a break. Counts are reported as they come; nothing is invented.\nexport function observedBreakFrom(node, data) {\n  const observed = Boolean(data?.observed)\n  const dependentCount = Number(data?.inboundObservedCount ?? 0)\n  const callCount = Array.isArray(data?.dependencies) ? data.dependencies.length : 0\n  if (!observed && dependentCount === 0 && callCount === 0) return null\n  // Node-level inbound block (ADR-190): how hard and how recently production\n  // hits this node. New keys — never overwrite callCount (outbound deps) or\n  // dependentCount (inbound edge count). Present only when the host serves\n  // them; absent → the renderer degrades to counts and fabricates nothing.\n  const inboundVolume = typeof data.inboundVolume === 'number' ? data.inboundVolume : undefined\n  const window = typeof data.window === 'string' ? data.window : undefined\n  const inboundLastObserved =\n    typeof data.inboundLastObserved === 'string' ? data.inboundLastObserved : undefined\n  return {\n    id: node.id,\n    type: node.type,\n    label: node.label,\n    change: node.change,\n    dependentCount,\n    callCount,\n    ...(inboundVolume !== undefined ? { inboundVolume } : {}),\n    ...(window !== undefined ? { window } : {}),\n    ...(inboundLastObserved !== undefined ? { inboundLastObserved } : {}),\n  }\n}\n\n// Transitive inbound dependents of a node — everything that would be affected if\n// it changed. Follows edges *into* the node (an importer, or the owning service),\n// bounded by depth. Mirrors the direction NEAT's getBlastRadius walks; the\n// production action calls the engine's getBlastRadius, this is the CI-local form.\nexport function blastRadius(graph, nodeId, maxDepth = 10) {\n  const inbound = new Map()\n  for (const e of graph.edges) {\n    if (!inbound.has(e.target)) inbound.set(e.target, [])\n    inbound.get(e.target).push({ source: e.source, type: e.type })\n  }\n  const seen = new Set([nodeId])\n  const dependents = []\n  let frontier = [nodeId]\n  for (let d = 0; d < maxDepth && frontier.length; d++) {\n    const next = []\n    for (const n of frontier) {\n      for (const { source } of inbound.get(n) ?? []) {\n        if (seen.has(source)) continue\n        seen.add(source)\n        dependents.push(source)\n        next.push(source)\n      }\n    }\n    frontier = next\n  }\n  return dependents\n}\n\n// Render the sticky comment. `changedFiles` are FileNode ids (from git ∩ graph);\n// `connected` flips the footer to the fused-tier message.\nexport function renderComment({\n  graph,\n  delta,\n  changedFiles = [],\n  divergences = [],\n  connected = false,\n}) {\n  const L = [MARKER, '### 🔷 NEAT — graph impact of this PR', '']\n\n  const anyDelta =\n    delta.routesAdded.length +\n    delta.routesRemoved.length +\n    delta.tablesAdded.length +\n    delta.tablesRemoved.length\n  L.push('**What changed in the graph**')\n  if (delta.routesAdded.length) L.push('- ➕ routes: ' + delta.routesAdded.map(fence).join(', '))\n  if (delta.routesRemoved.length) L.push('- ➖ routes: ' + delta.routesRemoved.map(fence).join(', '))\n  if (delta.tablesAdded.length) L.push('- ➕ tables: ' + delta.tablesAdded.map(fence).join(', '))\n  if (delta.tablesRemoved.length)\n    L.push(\n      '- ➖ tables: ' +\n        delta.tablesRemoved.map(fence).join(', ') +\n        '  ⚠️ removed reference — confirm nothing else still reads it',\n    )\n  if (!anyDelta) L.push('- no route/table/dependency changes detected')\n\n  const filesInGraph = changedFiles.filter((f) => graph.nodes.has(f))\n  if (filesInGraph.length) {\n    L.push('', '**Blast radius**')\n    for (const f of filesInGraph) {\n      const deps = blastRadius(graph, f)\n        .filter((d) => d.startsWith('file:'))\n        .map(shortId)\n      L.push(\n        '- ' +\n          fence(shortId(f)) +\n          ' → depended on by ' +\n          (deps.length ? deps.map(fence).join(', ') : '_nothing else in-repo_'),\n      )\n    }\n  }\n\n  if (divergences.length) {\n    L.push('', '**Divergence (declared vs observed)** — from the connected NEAT host')\n    for (const d of divergences) L.push('- ' + d)\n  }\n\n  L.push(\n    '',\n    connected\n      ? '> _Weighted against production traffic (OBSERVED) via the connected NEAT host._'\n      : '> _Static graph (EXTRACTED) only — this run cannot see production. Without the OBSERVED layer the Action has no way to know whether anything here is called in prod, so it does not flag observed breaks. Point `neat-api-url` at a connected NEAT host to weight this by production traffic (OBSERVED), flag declared-vs-observed divergence, and get observed-break detection._',\n  )\n  return { marker: MARKER, body: L.join('\\n') }\n}\n\n// The set of nodes this PR removes or changes — the surface the observed-break\n// scan runs against. \"Removed\" is the classic break (present in base, gone in\n// head); \"changed\" is a same-id node whose attributes moved under it (a route\n// whose handler changed, a table whose columns shifted). Each carries the id the\n// host's /graph/observed-dependencies endpoint is keyed on, plus a label/type for\n// rendering. Bounded so a huge PR can't fan out into hundreds of host calls.\nconst stable = (obj) =>\n  JSON.stringify(obj, Object.keys(obj ?? {}).sort())\n\nexport function changedNodesForObservedScan(base, head, { limit = 25 } = {}) {\n  const out = []\n  for (const [key, attrs] of base.nodes) {\n    if (!head.nodes.has(key)) {\n      out.push({ id: key, type: attrs.type, label: attrs.name ?? shortId(key), change: 'removed' })\n    }\n  }\n  for (const [key, attrs] of head.nodes) {\n    const b = base.nodes.get(key)\n    if (b && stable(b) !== stable(attrs)) {\n      out.push({ id: key, type: attrs.type, label: attrs.name ?? shortId(key), change: 'changed' })\n    }\n  }\n  return out.slice(0, limit)\n}\n\nconst plural = (n) => (n === 1 ? '' : 's')\n\n// Recency comes RAW from the host and is formatted HERE, never consumed\n// pre-formatted (ADR-190 honesty rule). A raw ISO timestamp → \"14m ago\".\nfunction formatAge(iso) {\n  const t = Date.parse(iso)\n  if (!Number.isFinite(t)) return null\n  const ms = Date.now() - t\n  if (ms < 0) return 'just now'\n  const s = Math.round(ms / 1000)\n  if (s < 60) return `${s}s ago`\n  const m = Math.round(s / 60)\n  if (m < 60) return `${m}m ago`\n  const h = Math.round(m / 60)\n  if (h < 48) return `${h}h ago`\n  return `${Math.round(h / 24)}d ago`\n}\n\n// The window phrase prints ONLY when the host names a window (ADR-190). A\n// lifetime count must never be rendered as \"in 7d\" — a fabricated window is\n// banned — so an unknown/absent window yields no phrase, never a guessed one.\nfunction windowPhrase(window) {\n  if (window === '7d') return 'in 7d'\n  if (window === 'lifetime') return '(lifetime)'\n  return ''\n}\n\n// \"served 3,214× in 7d, last seen 14m ago\" when the host serves the inbound\n// block; null when it doesn't, so the caller degrades to counts. Never\n// fabricates a volume or a window.\nfunction observedTraffic(b) {\n  if (typeof b.inboundVolume !== 'number') return null\n  const win = windowPhrase(b.window)\n  const served = `served ${b.inboundVolume.toLocaleString('en-US')}×${win ? ' ' + win : ''}`\n  const age = b.inboundLastObserved ? formatAge(b.inboundLastObserved) : null\n  return age ? `${served}, last seen ${age}` : served\n}\n\n// The fusion/freshness footnote. We state the provenance we actually have —\n// EXTRACTED static graph fused with OBSERVED traffic from the connected host —\n// and never invent a \"last seen 14m ago\" timestamp the host doesn't hand us.\nconst FUSION_NOTE =\n  '<sub>Fused view — the static graph (EXTRACTED) weighted against production traffic (OBSERVED) from the connected NEAT host. Observed-break checks ran live against that host.</sub>'\n\nconst TONE_COPY = {\n  loud: {\n    green: '## ✅ NEAT — all clear',\n    yellow: '## ⚠️ NEAT — a few minor problems',\n    red: '## 🛑 NEAT — FUCK NO. Here are the problems:',\n  },\n  professional: {\n    green: '## ✅ NEAT — all clear',\n    yellow: '## ⚠️ NEAT — Minor issues to review',\n    red: '## 🛑 NEAT — Critical: production will break',\n  },\n}\n\n// One observed break → its ranked one-liner and its detail line. `dependentCount`\n// is the host's inboundObservedCount (OBSERVED callers of the node); `callCount`\n// is the number of OBSERVED outbound edges it makes. When the host serves the\n// node-level inbound block (ADR-190) we lead with the visceral \"served N×\n// {window}, last seen {age}\"; the volume and recency come raw and are formatted\n// here. When those fields are absent we degrade to honest counts of observed\n// dependents and fabricate neither a volume nor a window.\nfunction breakHeadline(b) {\n  const verb = b.change === 'removed' ? 'deletes' : 'changes'\n  const what = fence(b.label) + (b.type === 'InfraNode' ? ' (data store)' : '')\n  const consequence =\n    b.type === 'RouteNode'\n      ? 'Live callers 404.'\n      : b.type === 'InfraNode'\n        ? 'Live readers and writers fail.'\n        : 'Live callers break.'\n  const traffic = observedTraffic(b)\n  if (traffic) {\n    return `**🔴 Production will break** — this PR ${verb} ${what}, ${traffic} (OBSERVED). ${consequence}`\n  }\n  if (b.dependentCount > 0) {\n    return `**🔴 Production will break** — this PR ${verb} ${what}, ${b.dependentCount} observed dependent${plural(b.dependentCount)} (OBSERVED). ${consequence}`\n  }\n  return `**🔴 Production will break** — this PR ${verb} ${what}, seen live in production making ${b.callCount} observed call${plural(b.callCount)} (OBSERVED). Runtime behavior changes.`\n}\n\nfunction breakDetail(b) {\n  return (\n    '- ' +\n    fence(b.label) +\n    ` — ${b.change} ${b.type ?? 'node'}; ` +\n    `${b.dependentCount} observed inbound dependent${plural(b.dependentCount)}, ` +\n    `${b.callCount} observed outbound call${plural(b.callCount)}. ` +\n    'Provenance: OBSERVED (live traffic on the connected host).'\n  )\n}\n\n// Verdict-first report for the connected (fused) tier. The severity model:\n//   🛑 RED    — one or more observed breaks (prod calls something this PR removes/changes)\n//   ⚠️ YELLOW — divergences, or removed routes/tables (static blast-radius risk), no break\n//   ✅ GREEN   — nothing observed is touched and no new divergence\n// `observedBreaks` come from the host's /graph/observed-dependencies scan (see\n// main.mjs). `divergences` are the pre-formatted strings from /graph/divergences.\n// The Sniper dispatch and full-graph-diff links render only when their URLs are\n// supplied — the Action points at those seams, it does not drive them.\nexport function renderVerdict({\n  graph,\n  delta,\n  changedFiles = [],\n  divergences = [],\n  observedBreaks = [],\n  tone = 'loud',\n  sniperDispatchUrl = '',\n  graphDiffUrl = '',\n}) {\n  const copy = TONE_COPY[tone] ?? TONE_COPY.loud\n\n  // Dedupe: a removed route/table that is an observed break is a 🔴 finding, so\n  // don't also list it as a 🟠 static \"removed reference.\"\n  const brokenRoutes = new Set(\n    observedBreaks.filter((b) => b.type === 'RouteNode').map((b) => b.label),\n  )\n  const brokenTables = new Set(\n    observedBreaks.filter((b) => b.type === 'InfraNode').map((b) => b.label),\n  )\n  const staticConcerns = []\n  for (const r of delta.routesRemoved ?? []) {\n    if (brokenRoutes.has(r)) continue\n    staticConcerns.push({\n      headline: `**🟠 Removed route** — ${fence(r)} no longer exists; confirm nothing in-repo still calls it.`,\n      detail: `- Route ${fence(r)} removed. The connected host observed no production traffic on it — static-only concern.`,\n    })\n  }\n  for (const t of delta.tablesRemoved ?? []) {\n    if (brokenTables.has(t)) continue\n    staticConcerns.push({\n      headline: `**🟠 Removed reference** — ${fence(t)} no longer exists; confirm nothing in-repo still reads it.`,\n      detail: `- Table/infra ${fence(t)} removed. The connected host observed no production traffic on it — static-only concern.`,\n    })\n  }\n\n  // Ranked findings: observed breaks first (🔴), then divergences (🟠), then\n  // static concerns (🟠).\n  const findings = [\n    ...observedBreaks.map((b) => ({ headline: breakHeadline(b), detail: breakDetail(b) })),\n    ...divergences.map((d) => ({\n      headline: `**🟠 Divergence** — ${d}`,\n      detail: `- ${d}`,\n    })),\n    ...staticConcerns,\n  ]\n\n  const tier =\n    observedBreaks.length > 0 ? 'red' : findings.length > 0 ? 'yellow' : 'green'\n\n  const actionLinks = []\n  if (sniperDispatchUrl)\n    actionLinks.push(`**[⚡ Dispatch Sniper to fix these →](${sniperDispatchUrl})**`)\n  if (graphDiffUrl) actionLinks.push(`[Full graph diff →](${graphDiffUrl})`)\n\n  const L = [MARKER, '']\n\n  if (tier === 'green') {\n    L.push(\n      copy.green,\n      '',\n      'Nothing this PR touches is observed in production, and it introduces no new divergences.',\n      '',\n      FUSION_NOTE,\n    )\n    return { marker: MARKER, body: L.join('\\n'), tier }\n  }\n\n  if (tier === 'yellow') {\n    L.push(\n      copy.yellow,\n      '',\n      `${findings.length} minor problem${plural(findings.length)} — read ${findings.length === 1 ? 'it' : 'them'} below.`,\n      '',\n      '<details><summary>Read them →</summary>',\n      '',\n    )\n    findings.forEach((f, i) => L.push(`${i + 1}. ${f.headline}`))\n    L.push('', ...findings.map((f) => f.detail))\n    L.push('', '</details>')\n    if (actionLinks.length) L.push('', ...actionLinks)\n    L.push('', FUSION_NOTE)\n    return { marker: MARKER, body: L.join('\\n'), tier }\n  }\n\n  // red\n  L.push(copy.red, '')\n  findings.forEach((f, i) => L.push(`${i + 1}. ${f.headline}`))\n  L.push('', '<details><summary>Full detail →</summary>', '')\n  L.push(...findings.map((f) => f.detail))\n\n  // Fold the raw graph delta and in-repo blast radius into the detail block so\n  // the structural context isn't lost under the verdict.\n  const anyDelta =\n    (delta.routesAdded?.length ?? 0) +\n    (delta.routesRemoved?.length ?? 0) +\n    (delta.tablesAdded?.length ?? 0) +\n    (delta.tablesRemoved?.length ?? 0)\n  if (anyDelta) {\n    L.push('', '**Graph delta**')\n    if (delta.routesAdded?.length) L.push('- ➕ routes: ' + delta.routesAdded.map(fence).join(', '))\n    if (delta.routesRemoved?.length)\n      L.push('- ➖ routes: ' + delta.routesRemoved.map(fence).join(', '))\n    if (delta.tablesAdded?.length) L.push('- ➕ tables: ' + delta.tablesAdded.map(fence).join(', '))\n    if (delta.tablesRemoved?.length)\n      L.push('- ➖ tables: ' + delta.tablesRemoved.map(fence).join(', '))\n  }\n  const filesInGraph = (changedFiles ?? []).filter((f) => graph?.nodes?.has(f))\n  if (filesInGraph.length) {\n    L.push('', '**Blast radius (in-repo)**')\n    for (const f of filesInGraph) {\n      const deps = blastRadius(graph, f)\n        .filter((d) => d.startsWith('file:'))\n        .map(shortId)\n      L.push(\n        '- ' +\n          fence(shortId(f)) +\n          ' → depended on by ' +\n          (deps.length ? deps.map(fence).join(', ') : '_nothing else in-repo_'),\n      )\n    }\n  }\n  L.push('', '</details>')\n  if (actionLinks.length) L.push('', ...actionLinks)\n  L.push('', FUSION_NOTE)\n  return { marker: MARKER, body: L.join('\\n'), tier }\n}\n","// Hosted-profile repo source for the \"add your repos\" track (connectors.md §3a, INFRA-ADR-011, #19).\n//\n// The local daemon extracts its mounted /workspace. The hosted daemon has no mount — the code it should\n// graph is the set of GitHub repos the customer bound to this project through the hosted GitHub App. This\n// module is the daemon's side of that: it asks the control plane which repos are bound\n// (GET /internal/projects/:id/repos), shallow-clones each with the short-lived GitHub App installation\n// token the CP hands back in the clone URL, extracts the working tree into the project graph (the SAME\n// extractFromDirectory the local /workspace path runs — never a hosted fork, per hosted-platform.md), and\n// reports the outcome back so the dashboard's RepoStatus reflects reality.\n//\n// Same hosted-profile discipline as connectors/hosted.ts (its sibling): the credential is CP-brokered,\n// short-lived, used within the call, never written to disk or the snapshot, and never logged. Delivery\n// auth is the project auth token the daemon was provisioned with (NEAT_AUTH_TOKEN) — the CP verifies it\n// against the project's sealed auth envelope, exactly as it does the connector /internal routes.\n\nimport os from 'node:os'\nimport path from 'node:path'\nimport { mkdtemp, rm } from 'node:fs/promises'\nimport type { NeatGraph } from '../graph.js'\nimport { extractFromDirectory } from '../extract.js'\nimport { invalidateSourceBaseline, retainSourceBaselines } from '../extract/source-baseline.js'\n\n// Mirror of the CP's repo-delivery shape (INFRA-ADR-011 repo half). Kept structural here so neat-core takes\n// no dependency on the CP package — the same stance connectors/hosted.ts takes on DeliveredCredential.\ninterface RepoToSync {\n  owner: string\n  name: string\n  /** The branch to clone; the CP resolves it from the installation. Optional — absent means clone the\n   *  repository's own default branch. */\n  defaultBranch?: string\n  /** `https://x-access-token:<installationToken>@github.com/owner/name.git` — token minted per pull,\n   *  short-lived. Never logged. */\n  cloneUrl: string\n  expiresAt?: string | null\n  /** The CP's current status for the repo. The daemon syncs the ones still awaiting a pass ('syncing'); a\n   *  terminal 'synced'/'failed' is left alone until the CP re-queues it (bind / push / resync flips it back\n   *  to 'syncing'). Absent (an older CP that doesn't send it) is treated as \"sync it\". */\n  syncStatus?: string\n}\n\nexport interface HostedRepoSyncDeps {\n  /** Control-plane base URL (NEAT_CP_URL). The daemon calls its `/internal` repo routes here. */\n  cpUrl: string\n  /** The control-plane project id (`prj_…`, NEAT_CP_PROJECT_ID) these repos belong to. */\n  projectId: string\n  /** The project auth token the daemon was provisioned with (NEAT_AUTH_TOKEN). Never logged. */\n  daemonToken: string\n  fetchImpl?: typeof fetch\n}\n\n/** Cap a CP call so a slow control plane can't stall the sync loop. */\nconst CP_REQUEST_TIMEOUT_MS = 10_000\n/** Re-pull the bound-repo list on this cadence; the CP's `syncStatus` gates which actually re-clone. */\nconst DEFAULT_SYNC_INTERVAL_MS = 5 * 60_000\n/** A single clone can't run forever — a wedged clone must not hold the pass open. */\nconst CLONE_TIMEOUT_MS = 5 * 60_000\n\n/** Replace an inline `x-access-token:<token>@` so a clone URL never reaches a log or the CP verbatim. */\nfunction scrubToken(s: string): string {\n  return s.replace(/x-access-token:[^@\\s]+@/g, 'x-access-token:***@')\n}\n\nasync function cpGet<T>(pathname: string, deps: HostedRepoSyncDeps): Promise<T> {\n  const f = deps.fetchImpl ?? fetch\n  const res = await f(`${deps.cpUrl.replace(/\\/+$/, '')}${pathname}`, {\n    headers: { authorization: `Bearer ${deps.daemonToken}`, accept: 'application/json' },\n    signal: AbortSignal.timeout(CP_REQUEST_TIMEOUT_MS),\n  })\n  if (!res.ok) throw new Error(`control plane ${pathname} → HTTP ${res.status}`)\n  return (await res.json()) as T\n}\n\ninterface StatusUpdate {\n  syncStatus: 'syncing' | 'synced' | 'failed'\n  detail?: string\n  lastSyncAt?: string\n}\n\nasync function cpPostStatus(\n  deps: HostedRepoSyncDeps,\n  owner: string,\n  name: string,\n  body: StatusUpdate,\n): Promise<void> {\n  const f = deps.fetchImpl ?? fetch\n  const url =\n    `${deps.cpUrl.replace(/\\/+$/, '')}/internal/projects/${deps.projectId}` +\n    `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(name)}/status`\n  const res = await f(url, {\n    method: 'POST',\n    headers: { authorization: `Bearer ${deps.daemonToken}`, 'content-type': 'application/json' },\n    body: JSON.stringify(body),\n    signal: AbortSignal.timeout(CP_REQUEST_TIMEOUT_MS),\n  })\n  // A 404 means the binding is gone (the repo was unbound mid-sync) — a stale report is a no-op, not a\n  // failure worth reporting back or retrying.\n  if (!res.ok && res.status !== 404) throw new Error(`control plane status POST → HTTP ${res.status}`)\n}\n\n/**\n * Clone seam. The default uses isomorphic-git — a pure-JS shallow clone, so the daemon image needs no `git`\n * binary and the token never reaches a process argv. It's `import()`ed lazily inside the default so it stays\n * out of the CLI's startup path (only the hosted daemon ever calls it). Injected in tests, so no pass ever\n * touches the network or isomorphic-git. Never logs the URL (it carries the installation token).\n */\nexport type CloneRepo = (cloneUrl: string, ref: string | undefined, destDir: string) => Promise<void | string>\n\nconst defaultCloneRepo: CloneRepo = async (cloneUrl, ref, destDir) => {\n  const [{ default: git }, httpMod, fs] = await Promise.all([\n    import('isomorphic-git'),\n    import('isomorphic-git/http/node'),\n    import('node:fs'),\n  ])\n  const http = (httpMod as { default?: unknown }).default ?? httpMod\n  // The CP delivers the token in the URL userinfo (x-access-token:<token>@github.com). Lift it out and pass\n  // it via onAuth so isomorphic-git authenticates without the token surviving in the recorded remote URL.\n  const parsed = new URL(cloneUrl)\n  const password = parsed.password || parsed.username\n  const username = parsed.password ? parsed.username : 'x-access-token'\n  const cleanUrl = `${parsed.protocol}//${parsed.host}${parsed.pathname}`\n  const clone = git.clone({\n    fs,\n    http: http as never,\n    dir: destDir,\n    url: cleanUrl,\n    // Absent ref → isomorphic-git clones the remote's default branch.\n    ...(ref ? { ref } : {}),\n    singleBranch: true,\n    depth: 1,\n    onAuth: () => ({ username, password }),\n  })\n  let timer: ReturnType<typeof setTimeout> | undefined\n  const timeout = new Promise<never>((_, reject) => {\n    timer = setTimeout(() => reject(new Error(`clone timed out after ${CLONE_TIMEOUT_MS}ms`)), CLONE_TIMEOUT_MS)\n  })\n  try {\n    await Promise.race([clone, timeout])\n    return await git.resolveRef({ fs, dir: destDir, ref: 'HEAD' })\n  } finally {\n    if (timer) clearTimeout(timer)\n  }\n}\n\n/**\n * Clone one commit. The pr-verdict route needs a PR's base and head as they were, not a branch tip, so this\n * fetches the commit by SHA at depth 1 and checks it out. Same credential handling as `defaultCloneRepo`: the\n * token is lifted out of the URL and handed to isomorphic-git through `onAuth`, so it is never recorded in\n * the clone's config or put on a process argv, and the URL is never logged.\n */\nexport type CloneCommit = (cloneUrl: string, sha: string, destDir: string) => Promise<void>\n\nexport const defaultCloneCommit: CloneCommit = async (cloneUrl, sha, destDir) => {\n  const [{ default: git }, httpMod, fs] = await Promise.all([\n    import('isomorphic-git'),\n    import('isomorphic-git/http/node'),\n    import('node:fs'),\n  ])\n  const http = (httpMod as { default?: unknown }).default ?? httpMod\n  const parsed = new URL(cloneUrl)\n  const password = parsed.password || parsed.username\n  const username = parsed.password ? parsed.username : 'x-access-token'\n  const cleanUrl = `${parsed.protocol}//${parsed.host}${parsed.pathname}`\n  const clone = (async () => {\n    await git.init({ fs, dir: destDir })\n    // isomorphic-git's fetch maps what it receives through the remote's refspec, so the remote has to exist\n    // in config — with the token-free URL; the credential only ever travels through onAuth.\n    await git.addRemote({ fs, dir: destDir, remote: 'origin', url: cleanUrl })\n    await git.fetch({\n      fs,\n      http: http as never,\n      dir: destDir,\n      remote: 'origin',\n      // A full SHA is fetched as itself; the remote doesn't have to advertise a ref that points at it.\n      ref: sha,\n      remoteRef: sha,\n      singleBranch: true,\n      depth: 1,\n      tags: false,\n      ...(password ? { onAuth: () => ({ username, password }) } : {}),\n    })\n    await git.checkout({ fs, dir: destDir, ref: sha, force: true })\n  })()\n  // Same ceiling as a branch clone: a stalled fetch must not hold the caller open. isomorphic-git can't be\n  // cancelled, so the abandoned fetch runs on until it fails or finishes, writing into a directory the\n  // caller removes.\n  clone.catch(() => {})\n  let timer: ReturnType<typeof setTimeout> | undefined\n  const timeout = new Promise<never>((_, reject) => {\n    timer = setTimeout(() => reject(new Error(`clone timed out after ${CLONE_TIMEOUT_MS}ms`)), CLONE_TIMEOUT_MS)\n  })\n  try {\n    await Promise.race([clone, timeout])\n  } finally {\n    if (timer) clearTimeout(timer)\n  }\n}\n\n/** Exposed for callers that report a clone failure: a clone URL must never reach a log or a response. */\nexport function scrubCloneToken(s: string): string {\n  return scrubToken(s)\n}\n\nexport interface RepoSyncInput {\n  deps: HostedRepoSyncDeps\n  graph: NeatGraph\n  /** The daemon's project name — for log lines only; the graph is the slot's own. */\n  project: string\n  /** Test seam: the clone impl (defaults to system git). */\n  cloneRepo?: CloneRepo\n  /** Test seam: the extractor (defaults to extractFromDirectory). */\n  extract?: typeof extractFromDirectory\n  /** How often to re-pull the bound-repo list (default 5 min). */\n  intervalMs?: number\n  /** Root under which each pass mkdtemp's a fresh clone dir (default os.tmpdir()). */\n  tmpRoot?: string\n  onSkip?: (repo: string, reason: string) => void\n  onError?: (repo: string, err: Error) => void\n  /** Test seam for the reported lastSyncAt. */\n  now?: () => number\n  /**\n   * Sync every listed repo this pass regardless of its control-plane status — the boot pass sets it (#1215).\n   * A fresh instance's graph holds nothing, and the CP's `synced` describes a *past* instance on a past disk,\n   * so the first pass after boot must re-extract everything; later passes fall back to `needsSync`.\n   * A predicate narrows that to the repos still owed their boot extraction.\n   */\n  forceResync?: boolean | ((repo: string) => boolean)\n  /** Called with `owner/name` once a repo's clone has been extracted this pass, complete or not. */\n  onExtracted?: (repo: string) => void\n}\n\n/**\n * Whether a repo needs a sync pass under the steady-state rule: the CP has (re-)queued it (`syncing`), or it\n * carries no status (an older CP). `synced`/`failed` are terminal here — but only for *later* passes. The\n * boot pass (`forceResync`, #1215) ignores this and re-extracts everything, because a fresh instance's graph\n * holds nothing regardless of what the CP remembers from a past instance.\n */\nfunction needsSync(r: RepoToSync): boolean {\n  return r.syncStatus === undefined || r.syncStatus === 'syncing'\n}\n\nfunction validRepoRow(row: unknown): row is RepoToSync {\n  if (!row || typeof row !== 'object') return false\n  const r = row as Partial<RepoToSync>\n  if (typeof r.owner !== 'string' || typeof r.name !== 'string' || typeof r.cloneUrl !== 'string') return false\n  if (!/^[A-Za-z0-9_.-]+$/.test(r.owner) || !/^[A-Za-z0-9_.-]+$/.test(r.name)) return false\n  if (r.syncStatus !== undefined && !['syncing', 'synced', 'failed'].includes(r.syncStatus)) return false\n  try {\n    const url = new URL(r.cloneUrl)\n    return url.protocol === 'https:' && url.hostname === 'github.com' && !url.port &&\n      !url.search && !url.hash && url.pathname === `/${r.owner}/${r.name}.git`\n  } catch { return false }\n}\n\n/** Clone and extract one repo, reporting the outcome to the CP. Resolves true when it extracted. */\nasync function syncOneRepo(r: RepoToSync, input: RepoSyncInput): Promise<boolean> {\n  const { deps, graph } = input\n  const cloneRepo = input.cloneRepo ?? defaultCloneRepo\n  const extract = input.extract ?? extractFromDirectory\n  const label = `${r.owner}/${r.name}`\n  const tmpRoot = input.tmpRoot ?? os.tmpdir()\n  let dir: string | undefined\n  try {\n    invalidateSourceBaseline(graph, label, 'syncing')\n    dir = await mkdtemp(path.join(tmpRoot, 'neat-repo-'))\n    // Reflect the resync while it runs so the console pill is honest (#1215): a fresh instance re-extracting a\n    // repo the CP still calls `synced` shouldn't leave it looking done mid-clone. Best-effort — a status ping\n    // that fails must never abort the extraction that follows.\n    await cpPostStatus(deps, r.owner, r.name, { syncStatus: 'syncing', detail: 'cloning' }).catch(() => {})\n    const sha = await cloneRepo(r.cloneUrl, r.defaultBranch, dir)\n    // Extraction merges into the slot's live graph by scanPath-relative path, so a fresh clone dir each\n    // pass upserts the same FileNodes and the ghost-retire sweep drops files removed from the repo.\n    //\n    // `source` is what keeps that sweep inside this repo (ADR-233). Without it the pass swept the whole\n    // graph against one clone dir, so every other bound repo's files read as deleted and were retired —\n    // the node loss in #1294, and the empty EXTRACTED layer after a restore in #1291. The token has to\n    // outlive the directory, which the clone dir does not: it is mkdtemp'd here and removed in `finally`.\n    const extracted = await extract(graph, dir, {\n      source: label,\n      ...(typeof sha === 'string' ? { sourceCommit: { repository: label, sha } } : {}),\n    })\n    input.onExtracted?.(label)\n    // A returned pass can still be incomplete: parser failures and deliberately skipped files leave part of\n    // the source unrepresented. That decides the source baseline and nothing else. The graph did land, and\n    // re-cloning the same commit would fail the same way, so the repo reports synced and waits for its next\n    // push like any other.\n    const errors = extracted?.extractionErrors ?? 0\n    const skipped = extracted?.skippedFiles ?? 0\n    const incomplete = errors > 0 || skipped > 0\n    if (incomplete) invalidateSourceBaseline(graph, label)\n    // Report the extraction outcome so the dashboard shows a live result rather than the bind-time\n    // \"queued for sync\" — the CP merges `detail` only when we send it.\n    const nodes = extracted?.nodesAdded ?? 0\n    const edges = extracted?.edgesAdded ?? 0\n    await cpPostStatus(deps, r.owner, r.name, {\n      syncStatus: 'synced',\n      detail:\n        `extracted ${nodes} node${nodes === 1 ? '' : 's'}, ${edges} edge${edges === 1 ? '' : 's'}` +\n        (incomplete ? ` (incomplete: ${errors} errors, ${skipped} skipped files)` : ''),\n      lastSyncAt: new Date(input.now?.() ?? Date.now()).toISOString(),\n    })\n    return true\n  } catch (err) {\n    invalidateSourceBaseline(graph, label)\n    input.onError?.(label, err as Error)\n    // Best-effort failure report — a pass never throws, so one bad repo can't stop the others or the loop.\n    await cpPostStatus(deps, r.owner, r.name, {\n      syncStatus: 'failed',\n      detail: scrubToken((err as Error).message).slice(0, 300),\n    }).catch(() => {})\n    return false\n  } finally {\n    if (dir) await rm(dir, { recursive: true, force: true }).catch(() => {})\n  }\n}\n\n/**\n * One sync pass: pull the bound-repo list from the CP and sync each repo that needs it. `forceResync` (the\n * boot pass, #1215) syncs every listed repo regardless of status; otherwise `needsSync` decides. Returns\n * whether the repo list was actually read — the loop uses that to hold the boot resync open until a pass\n * lands, so a control-plane blip at boot doesn't burn the one-time full resync. Never throws — a list-read\n * failure logs via `onSkip` and the pass ends, exactly as a connector discovery failure leaves the slot\n * intact. Exported so tests can await a deterministic pass.\n */\nexport async function runRepoSyncPass(input: RepoSyncInput): Promise<boolean> {\n  return (await runRepoSyncPassCounted(input)).listed\n}\n\n/** What one pass did: whether the bound-repo list was read, and how the repos it took on came out. */\nexport interface RepoSyncPassCounts {\n  listed: boolean\n  synced: number\n  failed: number\n}\n\n/** `runRepoSyncPass`, returning the per-repo tally as well — what the on-demand trigger reports (#1293). */\nexport async function runRepoSyncPassCounted(input: RepoSyncInput): Promise<RepoSyncPassCounts> {\n  const counts: RepoSyncPassCounts = { listed: false, synced: 0, failed: 0 }\n  let repos: RepoToSync[]\n  try {\n    repos = await cpGet<RepoToSync[]>(`/internal/projects/${input.deps.projectId}/repos`, input.deps)\n  } catch (err) {\n    invalidateSourceBaseline(input.graph)\n    input.onSkip?.('(all)', `control plane repo list unreadable — ${(err as Error).message}`)\n    return counts\n  }\n  if (!Array.isArray(repos)) {\n    invalidateSourceBaseline(input.graph)\n    return counts\n  }\n  counts.listed = true\n  const validRepos = repos.filter(validRepoRow)\n  const invalidCount = repos.length - validRepos.length\n  if (invalidCount) {\n    counts.failed += invalidCount\n    for (let index = 0; index < invalidCount; index++) {\n      input.onSkip?.('(invalid)', 'control plane repo row invalid')\n    }\n  }\n  // Evidence is per repo: an unbound repo's entry goes, and one the CP now calls failed stops counting.\n  retainSourceBaselines(input.graph, validRepos.map((r) => `${r.owner}/${r.name}`))\n  for (const r of validRepos) {\n    if (r.syncStatus === 'failed') invalidateSourceBaseline(input.graph, `${r.owner}/${r.name}`)\n  }\n  for (const r of validRepos) {\n    // The boot pass re-extracts everything (#1215); later passes fall back to the CP-status rule.\n    const forced =\n      typeof input.forceResync === 'function'\n        ? input.forceResync(`${r.owner}/${r.name}`)\n        : input.forceResync === true\n    if (!forced && !needsSync(r)) continue\n    if (await syncOneRepo(r, input)) counts.synced++\n    else counts.failed++\n  }\n  return counts\n}\n\n/** A finished pass, as the on-demand trigger reports it. */\nexport interface RepoSyncPassSummary extends RepoSyncPassCounts {\n  startedAt: string\n  finishedAt: string\n}\n\n/**\n * The answer to \"sync now\" (#1293). `started` — nothing was running, a pass has begun. `queued` — a pass was\n * already running, and one more will follow it. Joining the running pass outright would be wrong: it read\n * the bound-repo list before this request, so a repo bound since would be missed; the follow-up re-reads the\n * list. Any number of requests during one pass coalesce into that single follow-up. `lastPass` is the most\n * recent pass to finish, absent until one has.\n */\nexport interface RepoSyncRequestResult {\n  status: 'started' | 'queued'\n  lastPass?: RepoSyncPassSummary\n}\n\n/** What `startRepoSync` hands back: the stop it always returned, carrying the on-demand trigger. */\nexport type RepoSyncHandle = (() => void) & {\n  /** Start a pass now, or queue one behind the pass in flight. Returns at once; never throws. */\n  syncNow: () => RepoSyncRequestResult\n  /** Resolves when no pass is running and none is queued. A test seam. */\n  settled: () => Promise<void>\n}\n\n/**\n * Start the repo-sync loop: a boot pass (fire-and-forget, so a clone+extract never stalls slot bootstrap)\n * plus a repeating pass on `intervalMs`. Returns one stop that halts the schedule; an in-flight pass is\n * allowed to finish. Passes never overlap (a slow pass skips the next tick rather than piling up). The stop\n * also carries `syncNow`, so a bind, a Resync or a push doesn't have to wait for the timer (#1293).\n */\nexport async function startRepoSync(input: RepoSyncInput): Promise<RepoSyncHandle> {\n  const intervalMs = input.intervalMs ?? DEFAULT_SYNC_INTERVAL_MS\n  const now = (): number => input.now?.() ?? Date.now()\n  let stopped = false\n  // The run in flight, if any — one pass plus whatever follow-up was queued behind it.\n  let inFlight: Promise<void> | null = null\n  // Set by a \"sync now\" that arrived mid-pass: run once more when this pass ends.\n  let again = false\n  let lastPass: RepoSyncPassSummary | undefined\n  // The first pass to actually reach the CP re-extracts every bound repo (#1215): a fresh instance's graph\n  // holds nothing, so the CP's `synced` from a past instance must not skip it. The obligation is per repo: one\n  // is discharged once its clone has been extracted, so a failed clone retries that repo alone and a repo that\n  // keeps failing, or a row this daemon doesn't recognise, never holds the others open.\n  const bootExtracted = new Set<string>()\n  const run = async (): Promise<void> => {\n    try {\n      do {\n        again = false\n        const startedAt = new Date(now()).toISOString()\n        const counts = await runRepoSyncPassCounted({\n          ...input,\n          forceResync: (repo) => !bootExtracted.has(repo),\n          onExtracted: (repo) => {\n            bootExtracted.add(repo)\n            input.onExtracted?.(repo)\n          },\n        })\n        lastPass = { ...counts, startedAt, finishedAt: new Date(now()).toISOString() }\n      } while (again && !stopped)\n    } finally {\n      inFlight = null\n    }\n  }\n  // The timer's tick: skipped while a pass runs, so passes never overlap or pile up.\n  const tick = (): void => {\n    if (stopped || inFlight) return\n    inFlight = run()\n  }\n  tick()\n  const timer = setInterval(tick, intervalMs)\n  if (typeof timer.unref === 'function') timer.unref()\n  const stop = (): void => {\n    stopped = true\n    clearInterval(timer)\n  }\n  return Object.assign(stop, {\n    syncNow: (): RepoSyncRequestResult => {\n      const summary = lastPass ? { lastPass } : {}\n      if (inFlight) {\n        again = true\n        return { status: 'queued', ...summary }\n      }\n      inFlight = run()\n      return { status: 'started', ...summary }\n    },\n    settled: async (): Promise<void> => {\n      while (inFlight) await inFlight\n    },\n  })\n}\n\nexport interface MaybeStartRepoSyncInput {\n  graph: NeatGraph\n  project: string\n  env?: NodeJS.ProcessEnv\n  fetchImpl?: typeof fetch\n  cloneRepo?: CloneRepo\n  extract?: typeof extractFromDirectory\n  intervalMs?: number\n  tmpRoot?: string\n  onSkip?: (repo: string, reason: string) => void\n  onError?: (repo: string, err: Error) => void\n}\n\n/**\n * The daemon slot calls this unconditionally; it starts repo-sync only when the hosted-profile env is\n * present (NEAT_CP_URL + NEAT_CP_PROJECT_ID + NEAT_AUTH_TOKEN, all injected by the provisioner). Absent —\n * the local daemon — it's a no-op stop, so the slot's line is additive and the local path is unchanged\n * (hosted-platform.md: hosted wraps, never forks). Mirrors maybeStartHostedConnectors.\n */\nexport async function maybeStartRepoSync(\n  input: MaybeStartRepoSyncInput,\n): Promise<(() => void) & Partial<Pick<RepoSyncHandle, 'syncNow' | 'settled'>>> {\n  const env = input.env ?? process.env\n  const cpUrl = env.NEAT_CP_URL\n  const projectId = env.NEAT_CP_PROJECT_ID\n  const daemonToken = env.NEAT_AUTH_TOKEN\n  if (!cpUrl || !projectId || !daemonToken) return () => {}\n  return startRepoSync({\n    deps: { cpUrl, projectId, daemonToken, ...(input.fetchImpl ? { fetchImpl: input.fetchImpl } : {}) },\n    graph: input.graph,\n    project: input.project,\n    ...(input.cloneRepo ? { cloneRepo: input.cloneRepo } : {}),\n    ...(input.extract ? { extract: input.extract } : {}),\n    ...(input.intervalMs !== undefined ? { intervalMs: input.intervalMs } : {}),\n    ...(input.tmpRoot ? { tmpRoot: input.tmpRoot } : {}),\n    ...(input.onSkip ? { onSkip: input.onSkip } : {}),\n    ...(input.onError ? { onError: input.onError } : {}),\n  })\n}\n","// Connector configuration — `~/.neat/connectors.json` read + env-ref\n// resolution (docs/contracts/connector-config.md, ADR-130).\n//\n// This is the file family sibling to the machine-level project registry\n// (registry.ts): per-user, machine-local, never version-controlled. Where the\n// project registry says which projects exist, `connectors.json` says which\n// built connectors are turned on for them and where each one's credential\n// comes from. It is\n// the one file in the family that references real secrets, so it is mode\n// `0600` and — by default — holds a *pointer* to a secret (an env-var\n// reference resolved only at daemon-read time), never the secret itself\n// (contract §1, §2).\n//\n// This module owns two of the contract's three seams: reading/validating the\n// file (`readConnectorsConfig`) and resolving a `credential` env-ref to a\n// value in memory (`resolveCredential`). The provider dispatch table\n// (connectors/registry.ts) turns a resolved entry into a `ConnectorRegistration`;\n// the daemon (daemon.ts) triggers the read at slot bootstrap and hands the\n// registrations to `startConnectorPollLoop`. This file never writes the\n// snapshot and never lets a resolved secret reach disk (contract §6,\n// connectors.md §6, contracts.md Rule 13).\n\nimport os from 'node:os'\nimport path from 'node:path'\nimport { promises as fs } from 'node:fs'\n\n// Only bump 1 → 2 when the on-disk shape changes in a way an old reader\n// couldn't ignore. A file with no `version` reads as 1 (the shape below).\nexport const CONNECTORS_CONFIG_VERSION = 1\n\n/**\n * A credential, before resolution. Either a single env-ref/plaintext string\n * (single-field providers — `\"$RAILWAY_TOKEN\"`), or a per-field map of them\n * (multi-field providers — `{ managementToken: \"$SUPABASE_MGMT_TOKEN\",\n * postgresConnectionString: \"$SUPABASE_DB_URL\" }`). A leading `$` marks the\n * string as the name of an environment variable; anything else is a literal\n * (contract §2).\n */\nexport type CredentialRef = string | Record<string, string>\n\n/**\n * One entry in `~/.neat/connectors.json`. Mirrors the contract §1 schema\n * exactly — `credentials`/`config`/`enabled`/`addedAt` are deliberately\n * absent; the shape converged on a single `credential` ref plus opaque\n * `options`, and every listed entry is active (there is no `enabled` gate).\n */\nexport interface ConnectorEntry {\n  // Addressable handle, auto-slugged from provider (disambiguated by project\n  // when a provider repeats). The CLI's `remove <id>` / `test <id>` use it.\n  id: string\n  // 'supabase' | 'railway' | 'firebase' | 'cloudflare' | ... — validated\n  // against the dispatch table (registry.ts), not hardcoded here.\n  provider: string\n  // Matches a registered project's `name`; omitted binds to whichever project\n  // the daemon is bootstrapping (one daemon per project, ADR-096).\n  project?: string\n  // Env-ref by default (see resolveCredential).\n  credential: CredentialRef\n  // Provider-shaped, non-secret config (project ref, service-id mappings,\n  // poll cadence). Opaque here; the dispatch table maps it onto each\n  // provider's own config type.\n  options?: Record<string, unknown>\n}\n\nexport interface ConnectorsConfig {\n  version: number\n  connectors: ConnectorEntry[]\n}\n\n/**\n * A credential after env-ref resolution — values in memory only. `single`\n * for a one-string credential (the dispatch table knows which record key it\n * lands under); `fields` for a multi-field credential (the keys are already\n * the provider's own).\n */\nexport type ResolvedCredential =\n  | { kind: 'single'; value: string }\n  | { kind: 'fields'; fields: Record<string, string> }\n\n/**\n * Thrown when a `$VAR` credential reference names an environment variable\n * that isn't set. Kept distinct from every other failure so a caller can\n * tell \"you forgot to `export`\" apart from \"your token is wrong\" (contract\n * §4). The message names the variable *with* its `$` — `\"$SUPABASE_KEY is\n * unset\"` — so a log line points straight at what to set.\n */\nexport class EnvRefUnsetError extends Error {\n  readonly ref: string\n  readonly varName: string\n  constructor(ref: string, varName: string) {\n    super(`${ref} is unset`)\n    this.name = 'EnvRefUnsetError'\n    this.ref = ref\n    this.varName = varName\n  }\n}\n\n// Resolve `~/.neat/` the same way registry.ts does, per call, so a test\n// overriding NEAT_HOME (or HOME) before a run lands here too — module-load\n// order never matters.\nfunction neatHome(): string {\n  const override = process.env.NEAT_HOME\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(os.homedir(), '.neat')\n}\n\nexport function connectorsConfigPath(home: string = neatHome()): string {\n  return path.join(home, 'connectors.json')\n}\n\n// Owner-read/write only. Anything with group or other bits set is looser than\n// the contract's `0600` guarantee and gets a warning (not a refusal — a\n// mis-permissioned file is a hygiene problem, not a reason to leave a\n// connector dark).\nconst MODE_MASK_LOOSER_THAN_0600 = 0o077\n\nasync function warnIfModeLooserThan0600(file: string): Promise<void> {\n  // The POSIX bits are meaningless on Windows; skip the check there rather\n  // than warn on every read.\n  if (process.platform === 'win32') return\n  try {\n    const stat = await fs.stat(file)\n    if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {\n      const mode = (stat.mode & 0o777).toString(8).padStart(3, '0')\n      console.warn(\n        `[neat] ${file} is mode 0${mode}, looser than the 0600 this file's secrets call for — run \\`chmod 600 ${file}\\``,\n      )\n    }\n  } catch {\n    // Racing a delete between read and stat is harmless — the read already\n    // succeeded; skip the permission warning rather than crash on it.\n  }\n}\n\n/**\n * Read and validate `~/.neat/connectors.json`.\n *\n * - A missing file is the common, un-configured case → an empty connector\n *   list, never an error (the daemon just starts no poll loops).\n * - A malformed file throws a clear error naming what's wrong. The daemon's\n *   read path catches it and leaves the slot's connectors empty rather than\n *   crashing the whole daemon (contract §6, `project-registry.md`'s\n *   graceful-skip discipline).\n * - A file looser than `0600` is read but warns.\n */\nexport async function readConnectorsConfig(\n  home: string = neatHome(),\n): Promise<ConnectorsConfig> {\n  const file = connectorsConfigPath(home)\n  let raw: string\n  try {\n    raw = await fs.readFile(file, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n      return { version: CONNECTORS_CONFIG_VERSION, connectors: [] }\n    }\n    throw err\n  }\n  await warnIfModeLooserThan0600(file)\n\n  let parsed: unknown\n  try {\n    parsed = JSON.parse(raw)\n  } catch (err) {\n    throw new Error(`${file} is not valid JSON: ${(err as Error).message}`)\n  }\n  return validateConfig(parsed, file)\n}\n\nfunction validateConfig(parsed: unknown, file: string): ConnectorsConfig {\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n    throw new Error(`${file} must be a JSON object with a \"connectors\" array`)\n  }\n  const obj = parsed as Record<string, unknown>\n  const version = obj.version === undefined ? CONNECTORS_CONFIG_VERSION : obj.version\n  if (typeof version !== 'number' || !Number.isInteger(version)) {\n    throw new Error(`${file}: \"version\" must be an integer`)\n  }\n  const rawConnectors = obj.connectors\n  if (!Array.isArray(rawConnectors)) {\n    throw new Error(`${file}: \"connectors\" must be an array`)\n  }\n  const connectors = rawConnectors.map((entry, i) => validateEntry(entry, i, file))\n  return { version, connectors }\n}\n\nfunction validateEntry(entry: unknown, index: number, file: string): ConnectorEntry {\n  const where = `${file}: connectors[${index}]`\n  if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n    throw new Error(`${where} must be an object`)\n  }\n  const e = entry as Record<string, unknown>\n  const id = e.id\n  if (typeof id !== 'string' || id.length === 0) {\n    throw new Error(`${where}.id must be a non-empty string`)\n  }\n  const provider = e.provider\n  if (typeof provider !== 'string' || provider.length === 0) {\n    throw new Error(`${where}.provider must be a non-empty string`)\n  }\n  if (e.project !== undefined && typeof e.project !== 'string') {\n    throw new Error(`${where}.project must be a string when present`)\n  }\n  const credential = validateCredentialRef(e.credential, `${where}.credential`)\n  let options: Record<string, unknown> | undefined\n  if (e.options !== undefined) {\n    if (typeof e.options !== 'object' || e.options === null || Array.isArray(e.options)) {\n      throw new Error(`${where}.options must be an object when present`)\n    }\n    options = e.options as Record<string, unknown>\n  }\n  return {\n    id,\n    provider,\n    ...(typeof e.project === 'string' ? { project: e.project } : {}),\n    credential,\n    ...(options ? { options } : {}),\n  }\n}\n\nfunction validateCredentialRef(raw: unknown, where: string): CredentialRef {\n  if (typeof raw === 'string') {\n    if (raw.length === 0) throw new Error(`${where} must be a non-empty string`)\n    return raw\n  }\n  if (typeof raw === 'object' && raw !== null && !Array.isArray(raw)) {\n    const fields = raw as Record<string, unknown>\n    const keys = Object.keys(fields)\n    if (keys.length === 0) throw new Error(`${where} object must have at least one field`)\n    for (const key of keys) {\n      const v = fields[key]\n      if (typeof v !== 'string' || v.length === 0) {\n        throw new Error(`${where}.${key} must be a non-empty string`)\n      }\n    }\n    return fields as Record<string, string>\n  }\n  throw new Error(`${where} must be a string or an object of strings`)\n}\n\n/**\n * Resolve one credential ref to values held only in memory.\n *\n * A `$`-prefixed string is an environment-variable reference — resolved\n * against `env` (default `process.env`) at the moment the daemon builds a\n * registration; an unset variable throws `EnvRefUnsetError`. Any other string\n * is an explicit plaintext literal (the opt-in at-rest fallback, contract\n * §2), passed through unchanged. A field map resolves each value the same\n * way.\n */\nexport function resolveCredential(\n  ref: CredentialRef,\n  env: NodeJS.ProcessEnv = process.env,\n): ResolvedCredential {\n  if (typeof ref === 'string') {\n    return { kind: 'single', value: resolveRef(ref, env) }\n  }\n  const fields: Record<string, string> = {}\n  for (const [key, value] of Object.entries(ref)) {\n    fields[key] = resolveRef(value, env)\n  }\n  return { kind: 'fields', fields }\n}\n\n// A leading `$` (with at least one char after it) marks an env-ref; the value\n// must be set and non-empty. Everything else — including a bare `\"$\"` — is a\n// plaintext literal.\nfunction resolveRef(value: string, env: NodeJS.ProcessEnv): string {\n  if (value.length > 1 && value.startsWith('$')) {\n    const varName = value.slice(1)\n    const resolved = env[varName]\n    if (resolved === undefined || resolved.length === 0) {\n      throw new EnvRefUnsetError(value, varName)\n    }\n    return resolved\n  }\n  return value\n}\n\n/**\n * Whether a connector entry belongs to the project a daemon slot is\n * bootstrapping. An entry with no `project` binds to whatever project is\n * being bootstrapped (the single-daemon-per-project common case); an entry\n * naming a project matches only that one. A non-match is skipped, never\n * errored (contract §6).\n */\nexport function connectorMatchesProject(entry: ConnectorEntry, project: string): boolean {\n  return entry.project === undefined || entry.project === project\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Write side — `neat connector add/remove` mutate this file (contract §1, §3).\n//\n// The read side above never touches disk beyond a read; this is the half the\n// CLI drives. Two invariants the contract calls non-negotiable ride here: the\n// file lands mode `0600` on every write (owner-only — it points at real\n// secrets), and every write is atomic (tmp + fsync + rename) under an\n// exclusive lock, so a concurrent write can't leave a half-file behind. The\n// same discipline the sibling machine-level registry file already holds\n// (registry.ts), plus the explicit `0600` this file's secrets add.\n// ─────────────────────────────────────────────────────────────────────────\n\nconst CONNECTORS_LOCK_TIMEOUT_MS = 5_000\nconst CONNECTORS_LOCK_RETRY_MS = 50\n\nexport function connectorsConfigLockPath(home: string = neatHome()): string {\n  return path.join(home, 'connectors.json.lock')\n}\n\n// A leading `$` (with at least one char after it) marks a value as an env-ref,\n// the exact rule `resolveRef` above resolves by. Kept as one predicate so the\n// writer, the reader, and the `list` display can never disagree on what counts\n// as a pointer vs a literal.\nexport function isEnvRef(value: string): boolean {\n  return value.length > 1 && value.startsWith('$')\n}\n\n/**\n * Redact a credential ref to its env-ref pointer for a read surface — the\n * connector-status endpoint (`GET /:project/connectors`, ADR-136) and any other\n * caller that must show a connector's credential without ever resolving it. A\n * single-field credential redacts to one string; a multi-field one to a\n * field→pointer map. An env-ref (`$VAR`) is safe to show verbatim — it names the\n * variable, not the secret; a plaintext literal shows `****`. Reuses `isEnvRef`,\n * the same predicate the daemon resolver and `describeCredential` rely on, so no\n * read surface can drift from what actually counts as a pointer. This never\n * touches the environment — the secret value is never read here (connectors.md\n * §6, connector-config.md §2).\n */\nexport function redactCredentialRef(ref: CredentialRef): string | Record<string, string> {\n  const one = (value: string): string => (isEnvRef(value) ? value : '****')\n  if (typeof ref === 'string') return one(ref)\n  const out: Record<string, string> = {}\n  for (const [key, value] of Object.entries(ref)) out[key] = one(value)\n  return out\n}\n\n/**\n * tmp + fsync + rename, with the tmp file created mode `0600` so the bytes are\n * never briefly readable by group/other before the rename swaps them in. An\n * explicit `chmod(0o600)` on the handle backs the open-mode up in case a umask\n * ever widened it (it can't for `0600`, but the belt-and-suspenders keeps the\n * guarantee legible to the contract's future permission audit). rename is\n * atomic on POSIX and carries the tmp inode's mode with it.\n */\nasync function writeConfigAtomically0600(file: string, contents: string): Promise<void> {\n  await fs.mkdir(path.dirname(file), { recursive: true })\n  const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`\n  const fd = await fs.open(tmp, 'w', 0o600)\n  try {\n    await fd.writeFile(contents, 'utf8')\n    await fd.chmod(0o600)\n    await fd.sync()\n  } finally {\n    await fd.close()\n  }\n  await fs.rename(tmp, file)\n}\n\n// Exclusive-create lock, the same cross-platform flock stand-in the sibling\n// registry uses: `wx` fails if the file exists, so whoever creates it holds the\n// lock; a contender retries until the 5s timeout. Best-effort PID stamp so a\n// stuck lock names who to look for.\nasync function acquireConnectorsLock(\n  lockPath: string,\n  timeoutMs: number = CONNECTORS_LOCK_TIMEOUT_MS,\n): Promise<void> {\n  const deadline = Date.now() + timeoutMs\n  await fs.mkdir(path.dirname(lockPath), { recursive: true })\n  for (;;) {\n    try {\n      const fd = await fs.open(lockPath, 'wx')\n      try {\n        await fd.writeFile(`${process.pid}\\n`, 'utf8')\n      } finally {\n        await fd.close()\n      }\n      return\n    } catch (err) {\n      if ((err as NodeJS.ErrnoException).code !== 'EEXIST') throw err\n      if (Date.now() >= deadline) {\n        throw new Error(\n          `neat connector: timed out after ${timeoutMs}ms waiting for ${lockPath}. ` +\n            'Another neat process may be writing the connector config; if none is, remove that file by hand.',\n        )\n      }\n      await new Promise((r) => setTimeout(r, CONNECTORS_LOCK_RETRY_MS))\n    }\n  }\n}\n\nasync function releaseConnectorsLock(lockPath: string): Promise<void> {\n  await fs.unlink(lockPath).catch(() => {})\n}\n\nasync function withConnectorsLock<T>(home: string, fn: () => Promise<T>): Promise<T> {\n  const lock = connectorsConfigLockPath(home)\n  await acquireConnectorsLock(lock)\n  try {\n    return await fn()\n  } finally {\n    await releaseConnectorsLock(lock)\n  }\n}\n\nfunction serializeConfig(config: ConnectorsConfig): string {\n  return (\n    JSON.stringify(\n      { version: config.version ?? CONNECTORS_CONFIG_VERSION, connectors: config.connectors },\n      null,\n      2,\n    ) + '\\n'\n  )\n}\n\n/**\n * Insert `entry`, or replace the existing entry with the same `id`. The whole\n * read-modify-write runs under one lock so two concurrent adds can't clobber\n * each other, and the entry is validated before it lands so a malformed write\n * fails loudly rather than corrupting the file. Returns whether an existing\n * entry was replaced (vs a fresh insert) so the CLI can report which happened.\n */\nexport async function upsertConnectorEntry(\n  entry: ConnectorEntry,\n  home: string = neatHome(),\n): Promise<{ replaced: boolean }> {\n  const file = connectorsConfigPath(home)\n  return withConnectorsLock(home, async () => {\n    const config = await readConnectorsConfig(home)\n    // Re-validate through the same reader-side check so a hand-built entry\n    // can't slip a bad shape past the writer.\n    validateEntry(entry, config.connectors.length, file)\n    const idx = config.connectors.findIndex((c) => c.id === entry.id)\n    const replaced = idx >= 0\n    if (replaced) config.connectors[idx] = entry\n    else config.connectors.push(entry)\n    await writeConfigAtomically0600(file, serializeConfig(config))\n    return { replaced }\n  })\n}\n\n/**\n * Remove the entry with `id`. Returns the removed entry, or `undefined` when no\n * entry carried that id (the CLI turns that into a clear \"no such id\"). Atomic\n * `0600` rewrite under the same lock as `upsertConnectorEntry`.\n */\nexport async function removeConnectorEntry(\n  id: string,\n  home: string = neatHome(),\n): Promise<ConnectorEntry | undefined> {\n  const file = connectorsConfigPath(home)\n  return withConnectorsLock(home, async () => {\n    const config = await readConnectorsConfig(home)\n    const idx = config.connectors.findIndex((c) => c.id === id)\n    if (idx < 0) return undefined\n    const [removed] = config.connectors.splice(idx, 1)\n    await writeConfigAtomically0600(file, serializeConfig(config))\n    return removed\n  })\n}\n\n// Lower-case, collapse any run of non-alphanumerics to a single hyphen, trim\n// stray hyphens. Turns a project name or provider into a stable id fragment.\nfunction slugFragment(value: string): string {\n  return value\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Auto-slug an `id` from the provider, disambiguated by project when a provider\n * repeats (contract §1). Bare provider first (`supabase`); on collision, the\n * provider plus its project (`supabase-brief`); then a numeric suffix\n * (`supabase-2`) as a last resort so `add` never fails just to name an entry.\n */\nexport function autoSlugConnectorId(\n  provider: string,\n  project: string | undefined,\n  existingIds: ReadonlySet<string>,\n): string {\n  const base = slugFragment(provider) || 'connector'\n  if (!existingIds.has(base)) return base\n  const projectFrag = project ? slugFragment(project) : ''\n  if (projectFrag) {\n    const withProject = `${base}-${projectFrag}`\n    if (!existingIds.has(withProject)) return withProject\n  }\n  const stem = projectFrag ? `${base}-${projectFrag}` : base\n  for (let n = 2; ; n++) {\n    const candidate = `${stem}-${n}`\n    if (!existingIds.has(candidate)) return candidate\n  }\n}\n\n/** One credential field rendered for `list`, never carrying a resolved secret. */\nexport interface CredentialFieldDisplay {\n  // Present only for a multi-field credential; the single-string form has none.\n  field?: string\n  kind: 'env-ref' | 'plaintext'\n  // The env-var name (with its `$`) for a ref — safe to print, it's a pointer,\n  // not the secret — or a fixed `****` mask for a plaintext literal.\n  display: string\n  // env-ref only: whether the referenced variable is set in `env`.\n  status?: 'set' | 'unset'\n}\n\n/**\n * Render a credential for `neat connector list` — the redacted view, never the\n * resolved secret (contract §2, and the never-log-a-secret rule connectors.md\n * §6 / contracts.md Rule 13 already hold). An env-ref shows its `$VAR` pointer\n * plus whether that variable is currently set; a plaintext literal shows only\n * `****`. Reuses `isEnvRef` so the display can't drift from what the daemon\n * actually resolves.\n */\nexport function describeCredential(\n  ref: CredentialRef,\n  env: NodeJS.ProcessEnv = process.env,\n): CredentialFieldDisplay[] {\n  const one = (value: string, field?: string): CredentialFieldDisplay => {\n    if (isEnvRef(value)) {\n      const varName = value.slice(1)\n      const resolved = env[varName]\n      const set = typeof resolved === 'string' && resolved.length > 0\n      return {\n        ...(field ? { field } : {}),\n        kind: 'env-ref',\n        display: value,\n        status: set ? 'set' : 'unset',\n      }\n    }\n    return { ...(field ? { field } : {}), kind: 'plaintext', display: '****' }\n  }\n  if (typeof ref === 'string') return [one(ref)]\n  return Object.entries(ref).map(([k, v]) => one(v, k))\n}\n","// Connector poll-status tracker — the in-process record of each connector's\n// most recent poll tick (docs/contracts/connectors.md §8, ADR-136).\n//\n// The connector poll loop (`startConnectorPollLoop`, index.ts) writes here on\n// EVERY tick, success and failure; the connector-status endpoint\n// (`GET /:project/connectors`, api.ts) reads here. A process-local module\n// singleton is the right shape for the same reason `logs-store.ts` is: this is\n// live runtime state, not graph or snapshot state — a daemon restart loses it\n// and re-derives it on the next poll, exactly the \"OBSERVED is a live signal,\n// not an archive\" trade the rest of the connectors plane already makes.\n//\n// Nothing here ever holds a credential. The tracker records an id, an outcome,\n// a short error string, a signal count, and timestamps — the resolved secret\n// stays inside the `ConnectorContext` that flows to `poll()` and never reaches\n// this module (connectors.md §6, connector-config.md §6).\n\nimport type { ConnectorPollState, ConnectorStatus } from '@neat.is/types'\n\n// A connector polls on a 60s default cadence (`DEFAULT_POLL_INTERVAL_MS`,\n// index.ts). Five intervals of silence is the point past which \"hasn't polled\n// recently\" is worth surfacing as `stale` rather than a healthy connector that\n// simply hasn't ticked yet. This is a connector-poll concept, deliberately\n// distinct from the per-edge-type OBSERVED→STALE thresholds (ingest.ts) — those\n// decay graph edges; this flags a poll loop that has gone quiet or wedged.\nexport const CONNECTOR_STALE_THRESHOLD_MS = 5 * 60_000\n\n// One connector's last recorded tick. `lastOkAt` is kept separately from\n// `lastPollAt` so a run of failing ticks can still tell how long it has been\n// since the connector last actually succeeded — that gap is what `stale` reads.\ninterface PollRecord {\n  lastPollAt: string\n  lastOutcome: 'ok' | 'error'\n  lastError: string | null\n  signalsLastPoll: number\n  lastOkAt: string | null\n}\n\nconst records = new Map<string, PollRecord>()\n\nconst MAX_ERROR_LEN = 200\n\n/**\n * Reduce a poll error to a short, single-line string safe to expose on the\n * status endpoint. Collapses whitespace and truncates — a poll error carries a\n * provider name and HTTP status, never a credential (the junction's own error\n * strings are secret-free by construction, connectors/registry.ts §authProbe),\n * and the truncation caps any accidental verbosity.\n */\nexport function sanitizePollError(err: unknown): string {\n  const msg = err instanceof Error ? err.message : String(err)\n  const collapsed = msg.replace(/\\s+/g, ' ').trim()\n  return collapsed.length > MAX_ERROR_LEN ? `${collapsed.slice(0, MAX_ERROR_LEN - 1)}…` : collapsed\n}\n\nexport interface PollTick {\n  outcome: 'ok' | 'error'\n  // The tick's own start time, ISO8601.\n  at: string\n  // Signals the tick returned — recorded on a successful tick, 0 otherwise.\n  signalsLastPoll?: number\n  // Short, secret-free message on a failing tick; ignored on a successful one.\n  error?: string | null\n}\n\n/**\n * Record one poll tick for connector `id`. Called by the poll loop on every\n * tick. A successful tick advances `lastOkAt`; a failing tick leaves the prior\n * `lastOkAt` in place so `stale` still measures time-since-last-success.\n */\nexport function recordConnectorPoll(id: string, tick: PollTick): void {\n  const prev = records.get(id)\n  records.set(id, {\n    lastPollAt: tick.at,\n    lastOutcome: tick.outcome,\n    lastError: tick.outcome === 'error' ? (tick.error ?? null) : null,\n    signalsLastPoll: tick.signalsLastPoll ?? 0,\n    lastOkAt: tick.outcome === 'ok' ? tick.at : (prev?.lastOkAt ?? null),\n  })\n}\n\n// Derive the reported state from the raw record + wall clock. `error` wins over\n// `stale` because \"the last tick threw\" is the fresher, more actionable signal;\n// `stale` is for a connector whose last *success* has aged out of the window\n// (a loop that stopped ticking, so no fresh error either).\nfunction deriveState(rec: PollRecord, now: number, thresholdMs: number): ConnectorPollState {\n  if (rec.lastOutcome === 'error') return 'error'\n  const okAt = rec.lastOkAt ? Date.parse(rec.lastOkAt) : NaN\n  if (!Number.isNaN(okAt) && now - okAt > thresholdMs) return 'stale'\n  return 'healthy'\n}\n\n/**\n * The live status for connector `id`. An id with no recorded tick is `idle`\n * with null timestamps — the honest \"configured but not yet polled\" state, the\n * same shape the endpoint returns for a freshly added connector. `now` and\n * `thresholdMs` are injectable for deterministic tests.\n */\nexport function getConnectorStatus(\n  id: string,\n  now: number = Date.now(),\n  thresholdMs: number = CONNECTOR_STALE_THRESHOLD_MS,\n): ConnectorStatus {\n  const rec = records.get(id)\n  if (!rec) {\n    return {\n      state: 'idle',\n      lastPollAt: null,\n      lastOutcome: null,\n      lastError: null,\n      signalsLastPoll: 0,\n    }\n  }\n  return {\n    state: deriveState(rec, now, thresholdMs),\n    lastPollAt: rec.lastPollAt,\n    lastOutcome: rec.lastOutcome,\n    lastError: rec.lastError,\n    signalsLastPoll: rec.signalsLastPoll,\n  }\n}\n\n/** Drop every recorded status. Test-only — the daemon never clears mid-run. */\nexport function resetConnectorStatus(): void {\n  records.clear()\n}\n","// Connectors plane — the provider-agnostic pull/map/fuse pipeline\n// (docs/contracts/connectors.md, docs/connectors/README.md, ADR-124).\n//\n// A provider module (packages/core/src/connectors/<provider>/, none shipped\n// yet) owns exactly two things: fetching `ObservedSignal[]` off its own API\n// (`ObservedConnector.poll`) and mapping a signal's targetKind/targetName to\n// a NEAT node id (the `resolveTarget` callback below). Everything after that\n// — resolving a static call site, minting the OBSERVED edge — is written\n// once, here, and is identical for every provider: a connector-sourced edge\n// and a span-sourced edge carry the same provenance and land through the\n// same mutation primitives OTel ingest uses (README.md's opening paragraph).\n//\n// Mutation authority (ADR-030 — see contracts.test.ts's \"Lifecycle contract\"\n// audit): only ingest.ts and extract/* may call a graph mutator directly.\n// This module never does — every node/edge write below goes through an\n// ingest.ts primitive (`ensureServiceNode`, `ensureObservedFileNode`,\n// `upsertObservedEdge`), exported for exactly this reuse. A future\n// provider's own target-node creation (a Supabase table InfraNode, say)\n// belongs in ingest.ts too, for the same reason — this module only ever\n// calls into it, never mutates the graph itself.\n\nimport { NodeType, parseFileId, Provenance, type EdgeTypeValue, type GraphEdge } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n  appendConnectorIncident,\n  ensureInfraNode,\n  ensureObservedFileNode,\n  ensureServiceNode,\n  mergeObservedColumns,\n  mergeObservedDeployState,\n  mergeObservedDeployContext,\n  reconcileObservedRelPath,\n  upsertObservedEdge,\n  type CallSite,\n} from '../ingest.js'\nimport type { ConnectorContext, CredentialSource, ObservedConnector, ObservedSignal } from './types.js'\nimport { recordConnectorPoll, sanitizePollError } from './status.js'\n\nexport type {\n  ConnectorCallSite,\n  ConnectorContext,\n  CredentialSource,\n  ObservedConnector,\n  ObservedSignal,\n} from './types.js'\n\n// env-unscoped, matching the sentinel identity.ts uses for \"no deployment\n// signal\" (ADR-074 §2) — a connector signal carries no\n// deployment.environment(.name) the way an OTel span might.\nconst NO_ENV = 'unknown'\n\n/**\n * What a provider's target-resolution step hands back for one signal. The\n * generic pipeline needs both endpoints of the edge it's about to mint:\n *\n * - `serviceName` is the NEAT manifest service whose code produced the\n *   signal — the edge's source. The shared pipeline turns it into a plain\n *   ServiceNode id, or a FileNode id once the fuse step below resolves the\n *   signal's callSite against it.\n * - `targetNodeId` is the id the provider's own mapping already resolved —\n *   an `infraId(...)` sub-resource, a RouteNode, a ServiceNode, whatever\n *   (see each provider's docs/connectors/<provider>.md §Fusion).\n *\n * Returning `null` skips the signal honestly: an unresolvable target never\n * fabricates a node or edge (the same discipline file-awareness.md §6\n * states for OTel ingest).\n */\nexport interface ResolvedConnectorTarget {\n  targetNodeId: string\n  serviceName: string\n  edgeType: EdgeTypeValue\n  /**\n   * Set when `targetNodeId` names an InfraNode no static extractor has (yet)\n   * declared — the honest \"observed but undeclared\" fallback\n   * (docs/contracts/connectors.md §4a, ADR-133). A provider's `resolveTarget`\n   * has no mutation authority of its own (ADR-030), so it declares the need\n   * here instead of creating the node itself; the generic pipeline below\n   * calls `ensureInfraNode` before minting the edge. `targetNodeId` MUST equal\n   * `infraId(kind, name)` when this is set.\n   */\n  ensureInfraNode?: { kind: string; name: string; provider: string }\n}\n\nexport type ResolveConnectorTarget = (\n  signal: ObservedSignal,\n  ctx: ConnectorContext,\n) => ResolvedConnectorTarget | null\n\nexport interface ConnectorPollResult {\n  // Signals connector.poll() returned this tick.\n  signalCount: number\n  // Fresh OBSERVED edges minted.\n  edgesCreated: number\n  // Existing OBSERVED edges whose signal block advanced.\n  edgesUpdated: number\n  // Signals that resolved to no target (resolveTarget returned null, or the\n  // resolved target/service node doesn't exist in the graph yet) — dropped\n  // honestly rather than minting a fabricated edge. An incident-emitting\n  // signal (ADR-185) that resolves and writes counts as neither an edge nor\n  // unresolved; a signal count that exceeds edges+unresolved is the tick's\n  // incident tally.\n  unresolved: number\n}\n\n// #803 — file-grain a connector observation by attribution. A pull-connector's\n// signal carries the target (table / route) it observed but no source location —\n// the provider telemetry never recorded which line called it. The static\n// extractor does: `<client>.from('table')` mints a `file → target` EXTRACTED\n// edge. So when a connector observes `service → target` with no call site of its\n// own, land the OBSERVED edge on the file that statically makes that call —\n// but only when exactly one file in the service does, so the attribution is a\n// fact, not a guess. Ambiguous (several call sites) or none → service-coarse,\n// honestly (connectors.md — never fabricate a source).\nfunction staticCallSiteFor(\n  graph: NeatGraph,\n  serviceName: string,\n  targetNodeId: string,\n): CallSite | undefined {\n  if (!graph.hasNode(targetNodeId)) return undefined\n  const sites: CallSite[] = []\n  for (const edgeId of graph.inboundEdges(targetNodeId)) {\n    const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (edge.provenance !== Provenance.EXTRACTED) continue\n    const parsed = parseFileId(edge.source)\n    if (!parsed || parsed.service !== serviceName || !edge.evidence) continue\n    const site: CallSite = { relPath: edge.evidence.file }\n    if (edge.evidence.line !== undefined) site.line = edge.evidence.line\n    sites.push(site)\n  }\n  return sites.length === 1 ? sites[0] : undefined\n}\n\n// #803 — file-grain an *ingress* observation whose target is a RouteNode.\n// `staticCallSiteFor` can't reach a route: routes.ts owns a route via\n// `service ──CONTAINS──▶ route`, not a `file → route` call-site edge, so there\n// is nothing inbound to attribute through. But the RouteNode already records\n// its own definition site — `path` (the service-relative source file routes.ts\n// parsed the route from) and `line`. So a connector that observes a route being\n// hit (Cloudflare Workers, Firebase Hosting) file-grains onto that recorded\n// site directly: the route's own source location, a fact the static pass\n// already established, never a guess. This generalizes what railway/index.ts\n// does per-connector — it reads `route.path`/`route.line` into the signal's own\n// `callSite` in its map layer — into the shared pipeline, so every\n// route-targeting connector file-grains the same way without duplicating the\n// lookup. (Railway keeps setting its own `callSite`, which still wins below;\n// this only covers connectors that resolve a route target but carry no\n// callSite of their own.)\nfunction routeCallSiteFor(graph: NeatGraph, targetNodeId: string): CallSite | undefined {\n  if (!graph.hasNode(targetNodeId)) return undefined\n  const attrs = graph.getNodeAttributes(targetNodeId) as { type?: string; path?: string; line?: number }\n  if (attrs.type !== NodeType.RouteNode || !attrs.path) return undefined\n  const site: CallSite = { relPath: attrs.path }\n  if (attrs.line !== undefined) site.line = attrs.line\n  return site\n}\n\n/**\n * One poll cycle: fetch, map, fuse, mint. Pure with respect to `ctx` — the\n * caller (`startConnectorPollLoop` below, or a one-shot `neat sync`) owns\n * advancing `ctx.since` between calls.\n */\nexport async function runConnectorPoll(\n  connector: ObservedConnector,\n  ctx: ConnectorContext,\n  graph: NeatGraph,\n  resolveTarget: ResolveConnectorTarget,\n): Promise<ConnectorPollResult> {\n  const signals = await connector.poll(ctx)\n  let edgesCreated = 0\n  let edgesUpdated = 0\n  let unresolved = 0\n\n  for (const signal of signals) {\n    const resolved = resolveTarget(signal, ctx)\n    if (!resolved) {\n      unresolved++\n      continue\n    }\n\n    // Incident-emitting connector (ADR-185, connectors.md §10). A signal that\n    // carries a failure the provider recorded writes an OBSERVED incident on\n    // the resolved node instead of minting an edge — the terminal write is the\n    // only thing that differs. resolveTarget already resolved `targetNodeId`\n    // through the fused-node lookup, so the incident attributes to the extracted\n    // node get_incident_history / get_root_cause read, never a twin. Ensure the\n    // originating service exists as an endpoint first (the same auto-create the\n    // edge path does below), so a service-anchored incident lands on a real node\n    // even for a service OTel never reached. Dropped honestly when the pipeline\n    // has no ledger to write to (`ctx.errorsPath` absent — a programmatic caller\n    // that opted out) or the resolved node still isn't in the graph — the same\n    // missing-target discipline the edge path holds.\n    // Deploy-state stamp (ADR-225) — a k8s deploy-state signal carries the\n    // running image / ready replicas to record on the service node as OBSERVED\n    // attributes, no edge and no incident. Ensure the service node (the same\n    // auto-create the incident/edge paths do), stamp the observed deploy state\n    // via the ingest primitive (the additive-node-attribute path, mirroring\n    // `mergeObservedColumns`), and stop — a deploy-state-only signal (callCount 0,\n    // no incident) mints nothing else. This records the running image for *every*\n    // workload, healthy included, so the declared-vs-observed compare catches a\n    // stuck rollout that fires no incident.\n    if (signal.deployState) {\n      ensureServiceNode(graph, resolved.serviceName, NO_ENV)\n      mergeObservedDeployState(graph, resolved.targetNodeId, signal.deployState)\n      continue\n    }\n\n    if (signal.incident) {\n      ensureServiceNode(graph, resolved.serviceName, NO_ENV)\n      if (!ctx.errorsPath || !graph.hasNode(resolved.targetNodeId)) {\n        unresolved++\n        continue\n      }\n      // The workload's deploy context goes onto its node (ADR-243); the incident keeps\n      // its identity only.\n      if (signal.incident.deployContext) {\n        mergeObservedDeployContext(\n          graph,\n          resolved.targetNodeId,\n          signal.incident.id,\n          signal.incident.timestamp,\n          signal.incident.deployContext,\n        )\n      }\n      await appendConnectorIncident(ctx.errorsPath, {\n        id: signal.incident.id,\n        timestamp: signal.incident.timestamp,\n        service: signal.incident.service,\n        errorType: signal.incident.errorType,\n        errorMessage: signal.incident.errorMessage,\n        ...(signal.incident.attributes ? { attributes: signal.incident.attributes } : {}),\n        affectedNode: resolved.targetNodeId,\n      }, ctx.project)\n      continue\n    }\n\n    // Honest-fallback declaration (§ResolvedConnectorTarget doc) — ensure the\n    // InfraNode exists before the upsert below needs it to. Idempotent no-op\n    // once the node is created on a later poll.\n    if (resolved.ensureInfraNode) {\n      const { kind, name, provider } = resolved.ensureInfraNode\n      ensureInfraNode(graph, kind, name, provider)\n    }\n\n    // ADR-157 — when the provider's signal parsed columns off its query text\n    // (Neon / Supabase `pg_stat_statements`), merge them onto the resolved table\n    // node as OBSERVED column attributes, through the same ingest primitive OTel\n    // ingest uses. A no-op for a non-table target or a signal with no columns, so\n    // a route / REST-path signal grows nothing.\n    mergeObservedColumns(graph, resolved.targetNodeId, signal.columns)\n\n    // Same shape ingest.ts's handleSpan uses for every span: auto-create a\n    // minimal ServiceNode the first time this service is seen so the edge\n    // upsert below always has a source endpoint, even for a service the\n    // static extractor hasn't reached (or never will, in an OTel-less setup).\n    const serviceNodeId = ensureServiceNode(graph, resolved.serviceName, NO_ENV)\n\n    // File-grain fusion when the signal carries a call site, through the\n    // same reconcileObservedRelPath path OTel ingest uses (file-awareness.md\n    // §4) — service-level, honestly, when it doesn't (§6, never fabricated).\n    const callSite: CallSite | undefined = signal.callSite\n      ? { relPath: signal.callSite.file, line: signal.callSite.line }\n      : routeCallSiteFor(graph, resolved.targetNodeId) ??\n        staticCallSiteFor(graph, resolved.serviceName, resolved.targetNodeId)\n    const sourceId = callSite\n      ? ensureObservedFileNode(graph, resolved.serviceName, serviceNodeId, callSite)\n      : serviceNodeId\n    const evidence = callSite\n      ? {\n          file: reconcileObservedRelPath(graph, resolved.serviceName, callSite.relPath),\n          line: callSite.line,\n        }\n      : undefined\n\n    // upsertObservedEdge increments its signal block by exactly one call per\n    // invocation — the right unit for a single span, but a connector signal\n    // is already an aggregate over the whole poll window (`callCount` calls,\n    // `errorCount` of them failing). Replay it that many times so the\n    // edge's spanCount/errorCount — and the confidence grade derived from\n    // them, ADR-066 — land the same as if `callCount` individual spans had\n    // arrived, rather than undercounting a batched signal down to +1.\n    const calls = Math.trunc(signal.callCount)\n    // A non-finite count (NaN/Infinity from a provider's shape drift) is\n    // neither an observation nor an honest miss — drop it rather than letting\n    // a zero-iteration loop below tally a phantom edge update (gate #8).\n    if (!Number.isFinite(calls) || calls < 1) continue\n    const errors = Number.isFinite(signal.errorCount)\n      ? Math.min(Math.max(Math.trunc(signal.errorCount), 0), calls)\n      : 0\n\n    let created = false\n    let ok = true\n    for (let i = 0; i < calls; i++) {\n      const result = upsertObservedEdge(\n        graph,\n        resolved.edgeType,\n        sourceId,\n        resolved.targetNodeId,\n        signal.lastObservedIso,\n        i < errors,\n        evidence,\n      )\n      if (!result) {\n        // Target node doesn't exist yet — an extractor gap (supabase.md\n        // §Static extractor gap documents exactly this case) or a provider\n        // that hasn't minted it. Honest miss, not a crash.\n        ok = false\n        break\n      }\n      if (i === 0) created = result.created\n    }\n    if (!ok) {\n      unresolved++\n      continue\n    }\n    if (created) edgesCreated++\n    else edgesUpdated++\n  }\n\n  return { signalCount: signals.length, edgesCreated, edgesUpdated, unresolved }\n}\n\nexport interface ConnectorPollLoopOptions {\n  intervalMs?: number\n  onError?: (err: unknown) => void\n  // The connector's config-entry id (ADR-130). When set, every tick — success\n  // and failure — is recorded to the in-process status tracker (status.ts) the\n  // connector-status endpoint reads (ADR-136). A programmatic connector with no\n  // id records nothing and never appears on that endpoint.\n  connectorId?: string\n  // Hosted profile (connectors.md §3: \"profile changes credential source\"). When set, the loop resolves a\n  // fresh credential from this broker before every poll and uses it for that tick, instead of the static\n  // `ctx.credentials` captured at loop start — so a short-lived access token brokered by the control plane\n  // (INFRA-ADR-011) is renewed before it expires. The source is expected to cache and only refetch near\n  // expiry, so this is cheap per tick. A broker failure surfaces as an error tick (the poll is skipped, not\n  // run credential-less). Absent = local profile: `ctx.credentials` is used unchanged every tick.\n  refreshCredentials?: () => Promise<Record<string, unknown>>\n}\n\nconst DEFAULT_POLL_INTERVAL_MS = 60_000\n\n/**\n * Recurring wrapper around `runConnectorPoll` — the same setInterval +\n * unref + try/catch + stop-closure shape `startStalenessLoop` (ingest.ts)\n * already uses for the daemon's per-project background tasks, reused here\n * rather than reinvented. `daemon.ts` wires this in exactly where it wires\n * `startStalenessLoop`, tearing both down together per project slot.\n *\n * Advances `since` to the tick's own start time after every successful\n * poll — the next tick asks the provider for \"since last tick\" rather than\n * replaying. A tick that throws logs and leaves `since` where it was, so a\n * transient provider outage doesn't silently skip the gap once it recovers.\n */\nexport function startConnectorPollLoop(\n  connector: ObservedConnector,\n  ctx: ConnectorContext,\n  graph: NeatGraph,\n  resolveTarget: ResolveConnectorTarget,\n  options: ConnectorPollLoopOptions = {},\n): () => void {\n  let stopped = false\n  let since = ctx.since\n  const intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS\n  const connectorId = options.connectorId\n  const onError =\n    options.onError ??\n    ((err: unknown) => console.error(`[neatd] connector poll failed (${connector.provider})`, err))\n\n  const tick = (): void => {\n    if (stopped) return\n    void (async () => {\n      const tickStartedAt = new Date().toISOString()\n      try {\n        // Hosted profile: renew the brokered credential before polling (a no-op refetch when the cached\n        // token is still fresh). Local profile leaves ctx.credentials untouched. A broker failure throws\n        // here and is recorded as an error tick below — the poll never runs on a stale or absent credential.\n        const credentials = options.refreshCredentials ? await options.refreshCredentials() : ctx.credentials\n        const result = await runConnectorPoll(connector, { ...ctx, credentials, since }, graph, resolveTarget)\n        since = tickStartedAt\n        // Record the successful tick for the status endpoint (ADR-136). This is\n        // additive to the poll — it never changes what the tick mints or how\n        // `since` advances.\n        if (connectorId) {\n          recordConnectorPoll(connectorId, {\n            outcome: 'ok',\n            at: tickStartedAt,\n            signalsLastPoll: result.signalCount,\n          })\n        }\n      } catch (err) {\n        onError(err)\n        // The failed tick becomes a queryable fact instead of only a log line.\n        // `sanitizePollError` keeps the recorded message short and secret-free.\n        if (connectorId) {\n          recordConnectorPoll(connectorId, {\n            outcome: 'error',\n            at: tickStartedAt,\n            error: sanitizePollError(err),\n          })\n        }\n      }\n    })()\n  }\n\n  // Poll once immediately, then on the interval — a freshly-added connector\n  // produces OBSERVED data and a queryable status right away instead of sitting\n  // idle until the first interval elapses (#871: an operator watched an idle\n  // connector for minutes with no signal it was even scheduled).\n  tick()\n  const interval = setInterval(tick, intervalMs)\n  if (typeof interval.unref === 'function') interval.unref()\n  return () => {\n    stopped = true\n    clearInterval(interval)\n  }\n}\n\n/**\n * One project's registered connector, ready for `daemon.ts` to poll on an\n * interval. Deliberately thin — no config-loading or credential-broker logic\n * lives here (that's provider- and profile-specific, later work per\n * docs/contracts/connectors.md §3); this is just the seam a daemon slot\n * wires a connector through.\n */\nexport interface ConnectorRegistration {\n  // The config-entry id this registration was built from, when it came from\n  // ~/.neat/connectors.json (ADR-130). The daemon threads it into the poll loop\n  // so every tick is recorded per-id for the connector-status endpoint\n  // (ADR-136). Absent for a programmatic registration a caller passes directly.\n  id?: string\n  connector: ObservedConnector\n  credentials: Record<string, unknown>\n  resolveTarget: ResolveConnectorTarget\n  intervalMs?: number\n  // A refreshable credential (connector-config.md §9, ADR-230) resolves to a per-tick source instead of a\n  // fixed record — a GCP service-account key that mints and re-mints a ~1h token. When set, the daemon wires\n  // it to the poll loop's `refreshCredentials` option so a long-running local GCP connector never polls with\n  // a dead token. Absent for a static credential (the common case), which the loop reuses unchanged per tick.\n  refreshCredentials?: CredentialSource\n}\n","// Provider dispatch table — the one place a connector provider registers\n// (docs/contracts/connector-config.md §5, ADR-130).\n//\n// The shipped provider factories deliberately differ in shape: Supabase and\n// Firebase hand back `{ connector, resolveTarget }` from one call, Railway\n// pairs `createRailwayConnector(graph, config)` with a separate\n// `createRailwayResolveTarget(config)`, and Cloudflare constructs its\n// connector class directly alongside `createCloudflareResolveTarget(config)`.\n// This table is the normalization seam that adapts all of them into the one\n// uniform `ConnectorRegistration` the daemon's poll loop consumes — the same\n// data-driven discipline `compat.json` holds for driver logic (CLAUDE.md\n// § Don't do). A new provider adds one entry here; daemon.ts and cli.ts never\n// grow a per-provider branch.\n//\n// `buildRegistration` turns one resolved config entry into a registration;\n// `loadConnectorRegistrations` reads the whole file (via connectors-config.ts)\n// and builds every entry that matches a project. The daemon calls the latter\n// at slot bootstrap.\n\nimport type { NeatGraph } from '../graph.js'\nimport type { ConnectorRegistration, ObservedConnector, ResolveConnectorTarget } from './index.js'\nimport { startConnectorPollLoop } from './index.js'\nimport type { CredentialSource } from './types.js'\nimport { GCP_LOGGING_READ_SCOPE, createGcpTokenSource, parseServiceAccountKey } from './gcp-auth.js'\nimport { bearerAuthHeader, junctionFetch } from './junction.js'\nimport { createSupabaseConnector, DEFAULT_SUPABASE_MANAGEMENT_API_URL, type SupabaseConnectorConfig } from './supabase/index.js'\nimport {\n  createRailwayConnector,\n  createRailwayResolveTarget,\n  resolveLatestRailwayDeploymentId,\n  type RailwayConnectorConfig,\n} from './railway/index.js'\nimport { createFirebaseConnector, type FirebaseServiceMap } from './firebase/index.js'\nimport {\n  CloudflareConnector,\n  createCloudflareResolveTarget,\n  type CloudflareConnectorConfig,\n} from './cloudflare/index.js'\nimport {\n  createVercelDrain,\n  deleteVercelDrain,\n  testVercelDrainDelivery,\n  type VercelConnectorConfig,\n  type VercelCredentials,\n} from './vercel/index.js'\nimport { createNeonConnector, fetchNeonStatements, type NeonConnectorConfig } from './neon/index.js'\nimport { createCloudRunConnector, type CloudRunConnectorConfig } from './cloud-run/index.js'\nimport { createGcpLbConnector, type GcpLbConnectorConfig } from './gcp-lb/index.js'\nimport {\n  createRenderConnector,\n  createRenderResolveTarget,\n  DEFAULT_RENDER_API_URL,\n  type RenderConnectorConfig,\n} from './render/index.js'\nimport {\n  createPlanetscaleConnector,\n  DEFAULT_PLANETSCALE_API_URL,\n  planetscaleAuthHeader,\n  type PlanetscaleConnectorConfig,\n} from './planetscale/index.js'\nimport { createEasConnector, fetchErroredBuilds, type EasConnectorConfig } from './eas/index.js'\nimport {\n  connectorMatchesProject,\n  EnvRefUnsetError,\n  readConnectorsConfig,\n  resolveCredential,\n  type ConnectorEntry,\n} from '../connectors-config.js'\n\n/** What a provider's factory pairing produces once normalized. */\ninterface BuiltConnector {\n  connector: ObservedConnector\n  resolveTarget: ResolveConnectorTarget\n}\n\n/**\n * The verdict of a provider's cheap auth round-trip (contract §4). `ok` means\n * the resolved credential authenticated against the provider; a failure names\n * why in plain terms the CLI can print verbatim — never echoing the credential\n * itself.\n */\nexport type ConnectorValidation = { ok: true } | { ok: false; reason: string }\n\n/** What a dispatch-table validator receives — already-resolved credentials. */\nexport interface ValidateInput {\n  // env-refs already resolved to their in-memory values (contract §2). Keyed\n  // the way this provider's `poll()` reads them.\n  credentials: Record<string, unknown>\n  // Non-secret provider config from the entry's `options`.\n  options: Record<string, unknown>\n  // Dependency-injection seam for tests — a fake `fetch` stands in for the live\n  // provider so validate-on-add never needs a real account (contract §4's\n  // round-trip is exercised against a stub, mirroring each connector's own\n  // `fetchImpl` test seam).\n  fetchImpl?: typeof fetch\n  // Database-backed providers use this test seam for their auth round-trip.\n  // Production leaves it absent and executes the real bounded junction read.\n  dbProbe?: (connectionString: string, accountKey: string) => Promise<void>\n}\n\n// The Cloudflare API host, defaulted here rather than importing a private const\n// out of the connector's client — the same value cloudflare/client.ts uses.\nconst CLOUDFLARE_API_BASE_URL = 'https://api.cloudflare.com/client/v4'\n\n/**\n * One authenticated GET/POST through the shared junction (ADR-131), interpreted\n * as a validation verdict. A 2xx means the credential authenticated; a 401/403\n * means the provider rejected it (the \"creds present but wrong\" case the\n * contract keeps distinct from an unset env-ref); any other status or a\n * transport failure is reported as an inability to confirm, never a false\n * \"valid\". The bearer token flows into the Authorization header and nowhere\n * else — the reason strings below carry only the provider name and HTTP status,\n * never the secret (contract §2, connectors.md §6).\n */\nasync function authProbe(input: {\n  provider: string\n  accountKey: string\n  url: string | URL\n  token: string\n  // Most providers carry `Authorization: Bearer <token>` (the default built\n  // from `token`). A provider whose auth header is a different shape — e.g.\n  // PlanetScale's non-Bearer `id:token` service-token form — passes it here,\n  // and the round-trip's 2xx/401/403 verdict logic is otherwise identical.\n  authHeader?: Record<string, string>\n  init?: RequestInit\n  fetchImpl?: typeof fetch\n}): Promise<ConnectorValidation> {\n  const { provider, accountKey, url, token, authHeader, init, fetchImpl } = input\n  try {\n    const res = await junctionFetch(\n      url,\n      {\n        ...(init ?? {}),\n        headers: {\n          ...(authHeader ?? bearerAuthHeader(token)),\n          ...((init?.headers as Record<string, string>) ?? {}),\n        },\n      },\n      { provider, accountKey, ...(fetchImpl ? { fetchImpl } : {}) },\n    )\n    if (res.ok) return { ok: true }\n    if (res.status === 401 || res.status === 403) {\n      return { ok: false, reason: `${provider} rejected the credential (HTTP ${res.status})` }\n    }\n    return {\n      ok: false,\n      reason: `${provider} auth check returned HTTP ${res.status} ${res.statusText} — could not confirm the credential`,\n    }\n  } catch (err) {\n    return {\n      ok: false,\n      reason: `${provider} auth check could not reach the provider: ${(err as Error).message}`,\n    }\n  }\n}\n\n/**\n * The field-schema surface `neat connector add` reads to know what to prompt\n * for and validate structurally (contract §5). Shared by pull providers\n * ({@link ProviderDispatch}) and push providers ({@link PushProviderDispatch})\n * so the CLI's credential/option handling never branches on provider shape —\n * it reads this and dispatches the rest.\n */\nexport interface ProviderFieldSchema {\n  provider: string\n  // The credential-record key a single-string credential resolves into (this\n  // provider's primary secret field). A multi-field credential carries its\n  // own keys and ignores this.\n  primaryCredentialKey: string\n  // Credential-record keys this provider requires. Checked before any network\n  // call so a missing field fails honestly rather than silently downstream.\n  requiredCredentialFields: readonly string[]\n  // `options` keys this provider requires.\n  requiredOptionFields: readonly string[]\n}\n\n/**\n * One *pull* provider's dispatch-table entry. Beyond the field schema it\n * carries the factory the daemon's poll loop consumes (contract §5) — declared\n * here so provider specifics live in data the table reads, never scattered\n * across the CLI and daemon.\n */\nexport interface ProviderDispatch extends ProviderFieldSchema {\n  // Adapt (graph, non-secret options) into the uniform connector pairing.\n  build(graph: NeatGraph, options: Record<string, unknown>): BuiltConnector\n  // The cheap auth round-trip `neat connector add`/`test` run before writing\n  // (contract §4, §5). Data-driven like everything else on this entry: the CLI\n  // never hand-rolls a per-provider auth check, it dispatches here.\n  validate(input: ValidateInput): Promise<ConnectorValidation>\n}\n\n/**\n * One *push* provider's dispatch-table entry (connectors.md §9, ADR-146). A\n * push provider has no `poll()` — its telemetry arrives at the daemon's OTLP\n * receiver because `provision` configured the provider to forward it. Beyond\n * the shared field schema and `validate`, it carries a provision/deprovision\n * lifecycle the pull shape has no need for. Registered in\n * {@link PUSH_PROVIDER_DISPATCH}, parallel to {@link PROVIDER_DISPATCH}.\n */\nexport interface PushProviderDispatch extends ProviderFieldSchema {\n  // The same cheap round-trip §4 names — for a drain, it authenticates the\n  // provider credential *and* confirms the daemon's OTLP endpoint is reachable\n  // and accepts the drain's bearer. Run by `add` (pre-provision) and `test`.\n  validate(input: ValidateInput): Promise<ConnectorValidation>\n  // Create the provider-side resource (the drain). On success returns an opaque\n  // handle merged into the entry's `options` (e.g. `{ drainId }`) so a later\n  // `remove` can tear it down, plus an optional operator-facing note.\n  provision(input: ValidateInput): Promise<ProvisionResult>\n  // Delete the provider-side resource. Idempotent — an already-gone resource is\n  // a success, not an error (connectors.md §9).\n  deprovision(input: ValidateInput): Promise<DeprovisionResult>\n}\n\nexport type ProvisionResult =\n  | { ok: true; options?: Record<string, unknown>; note?: string }\n  | { ok: false; reason: string }\n\nexport type DeprovisionResult = { ok: true; note?: string } | { ok: false; reason: string }\n\n// ── The table. Five providers are designed; four are built and register\n// here. Vercel's Drains connector (#724) is a push connector still awaiting a\n// `receive()` amendment to connectors.md — it adds its entry when it lands.\nexport const PROVIDER_DISPATCH: Record<string, ProviderDispatch> = {\n  supabase: {\n    provider: 'supabase',\n    primaryCredentialKey: 'managementToken',\n    requiredCredentialFields: ['managementToken'],\n    requiredOptionFields: ['apiProjectRef', 'nodeRef', 'serviceName'],\n    build(graph, options) {\n      // createSupabaseConnector already returns the pairing.\n      return createSupabaseConnector(graph, options as unknown as SupabaseConnectorConfig)\n    },\n    // GET /v1/projects — the Management API's own auth-gated list endpoint, the\n    // cheapest confirmation the management token is live (the same surface\n    // client.ts polls, minus the heavy log query).\n    validate({ credentials, options, fetchImpl }) {\n      const cfg = options as Partial<SupabaseConnectorConfig>\n      const baseUrl = cfg.managementApiUrl ?? DEFAULT_SUPABASE_MANAGEMENT_API_URL\n      return authProbe({\n        provider: 'supabase',\n        accountKey: cfg.apiProjectRef ?? 'validate',\n        url: `${baseUrl}/v1/projects`,\n        token: String(credentials.managementToken ?? ''),\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  railway: {\n    provider: 'railway',\n    primaryCredentialKey: 'token',\n    requiredCredentialFields: ['token'],\n    requiredOptionFields: ['environmentId', 'serviceId', 'serviceNameById'],\n    build(graph, options) {\n      const config = options as unknown as RailwayConnectorConfig\n      // Split factories — connector and resolveTarget are built separately.\n      return {\n        connector: createRailwayConnector(graph, config),\n        resolveTarget: createRailwayResolveTarget(config),\n      }\n    },\n    // Runs the same `deployments` lookup the poller itself needs\n    // (railway/client.ts's resolveLatestRailwayDeploymentId) rather than a\n    // trivial `{ __typename }` probe. That trivial form is a false positive\n    // for this provider: `Authorization: Bearer <token>` authenticates at\n    // Railway's HTTP gateway (any well-formed token gets a 2xx on a query\n    // that touches no real data) but is not authorized for the connector's\n    // actual queries, which come back as an HTTP-200 response carrying a\n    // GraphQL-level \"Not Authorized\" error — invisible to authProbe's\n    // status-code-only check. Probing with the real lookup, through the same\n    // Project-Access-Token header client.ts sends, catches both failure\n    // modes: an HTTP-level rejection (thrown as a fetch/status error) and a\n    // GraphQL-level one (thrown by railwayGraphQL's own body.errors check).\n    async validate({ credentials, options, fetchImpl }) {\n      const cfg = options as Partial<RailwayConnectorConfig>\n      if (!cfg.environmentId || !cfg.serviceId) {\n        return { ok: false, reason: 'railway: environmentId and serviceId are required to validate' }\n      }\n      const config: RailwayConnectorConfig = {\n        environmentId: cfg.environmentId,\n        serviceId: cfg.serviceId,\n        serviceNameById: cfg.serviceNameById ?? {},\n        ...(cfg.apiUrl ? { apiUrl: cfg.apiUrl } : {}),\n      }\n      try {\n        await resolveLatestRailwayDeploymentId(config, String(credentials.token ?? ''), fetchImpl)\n        return { ok: true }\n      } catch (err) {\n        return { ok: false, reason: `railway auth check failed: ${(err as Error).message}` }\n      }\n    },\n  },\n  firebase: {\n    provider: 'firebase',\n    // Firebase reads both projectId and accessToken from the credential; the\n    // single-string form maps to the secret, and the required-fields check\n    // below catches a projectId that was never supplied.\n    primaryCredentialKey: 'accessToken',\n    requiredCredentialFields: ['projectId', 'accessToken'],\n    requiredOptionFields: [],\n    build(graph, options) {\n      // options is the FirebaseServiceMap; createFirebaseConnector returns the\n      // pairing.\n      return createFirebaseConnector(graph, options as unknown as FirebaseServiceMap)\n    },\n    // GET the project's Cloud Logging log-name list (pageSize 1) — within the\n    // same `roles/logging.viewer` grant the connector polls under, and the\n    // lightest call that still fails 401/403 on a bad or wrong-scoped token.\n    validate({ credentials, fetchImpl }) {\n      const projectId = String(credentials.projectId ?? '')\n      return authProbe({\n        provider: 'firebase',\n        accountKey: projectId || 'validate',\n        url: `https://logging.googleapis.com/v2/projects/${projectId}/logs?pageSize=1`,\n        token: String(credentials.accessToken ?? ''),\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  cloudflare: {\n    provider: 'cloudflare',\n    primaryCredentialKey: 'apiToken',\n    requiredCredentialFields: ['apiToken'],\n    // `workers` dropped as a required field (ADR-133) — the mapping is now\n    // derived from the extracted graph's platform tag; an `options.workers`\n    // entry still works as an explicit override\n    // (CloudflareConnectorConfig.workers).\n    requiredOptionFields: ['accountId'],\n    build(graph, options) {\n      const config = options as unknown as CloudflareConnectorConfig\n      // Class + separate resolveTarget factory; resolveTarget now closes over\n      // the graph to resolve against the platform tag (ADR-133).\n      return {\n        connector: new CloudflareConnector(config),\n        resolveTarget: createCloudflareResolveTarget(config, graph),\n      }\n    },\n    // GET /accounts/{accountId}/tokens/verify — the *account-scoped* token-verify\n    // endpoint. A Workers connector token is scoped to the account, and the\n    // user-level `GET /user/tokens/verify` returns 401 \"Invalid API Token\" for\n    // such a token even though it authenticates fine against the account's own\n    // resources (confirmed live). Probing the account-scoped verify endpoint —\n    // `accountId` is already required for this provider — returns 200\n    // `{status:\"active\"}` for a working token and 401 for a bad one, so a valid\n    // Workers token is no longer falsely rejected at `neat connector add`.\n    validate({ credentials, options, fetchImpl }) {\n      const cfg = options as Partial<CloudflareConnectorConfig>\n      const baseUrl = cfg.baseUrl ?? CLOUDFLARE_API_BASE_URL\n      return authProbe({\n        provider: 'cloudflare',\n        accountKey: cfg.accountId ?? 'validate',\n        url: `${baseUrl}/accounts/${cfg.accountId ?? ''}/tokens/verify`,\n        token: String(credentials.apiToken ?? ''),\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  neon: {\n    provider: 'neon',\n    primaryCredentialKey: 'connectionString',\n    requiredCredentialFields: ['connectionString'],\n    requiredOptionFields: ['projectId', 'serviceName'],\n    build(_graph, options) {\n      return createNeonConnector(options as unknown as NeonConnectorConfig)\n    },\n    async validate({ credentials, options, dbProbe }) {\n      const projectId = String(options.projectId ?? '')\n      const connectionString = String(credentials.connectionString ?? '')\n      try {\n        if (dbProbe) await dbProbe(connectionString, projectId)\n        else await fetchNeonStatements(connectionString, projectId, 1)\n        return { ok: true }\n      } catch (err) {\n        return { ok: false, reason: `neon telemetry read failed: ${(err as Error).message}` }\n      }\n    },\n  },\n  'cloud-run': {\n    provider: 'cloud-run',\n    // Cloud Run reads both projectId and accessToken from the credential; the\n    // single-string form maps to the secret (the token), and the required-fields\n    // check below catches a projectId that was never supplied.\n    primaryCredentialKey: 'accessToken',\n    requiredCredentialFields: ['projectId', 'accessToken'],\n    requiredOptionFields: [],\n    build(graph, options) {\n      return createCloudRunConnector(graph, options as unknown as CloudRunConnectorConfig)\n    },\n    // POST entries:list with pageSize 1 — the exact surface poll() reads, so the\n    // probe checks the actual `logging.logEntries.list` permission the connector\n    // needs. A GET on the lighter logs.list endpoint (as Firebase probes) would\n    // instead check `logging.logs.list`, falsely rejecting a correctly-scoped\n    // custom role that carries only `logging.logEntries.list` (the narrowest\n    // grant docs/connectors/cloud-run.md documents) — the same false-negative\n    // trap Railway's validate avoids by probing its real query. A 2xx means the\n    // token can list log entries; 401/403 means the provider rejected it.\n    validate({ credentials, fetchImpl }) {\n      const projectId = String(credentials.projectId ?? '')\n      return authProbe({\n        provider: 'cloud-run',\n        accountKey: projectId || 'validate',\n        url: 'https://logging.googleapis.com/v2/entries:list',\n        token: String(credentials.accessToken ?? ''),\n        init: {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({ resourceNames: [`projects/${projectId}`], pageSize: 1 }),\n        },\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  'gcp-lb': {\n    provider: 'gcp-lb',\n    // Like cloud-run, gcp-lb reads both projectId and accessToken from the\n    // credential; the single-string form maps to the secret (the token), and the\n    // required-fields check below catches a projectId that was never supplied.\n    primaryCredentialKey: 'accessToken',\n    requiredCredentialFields: ['projectId', 'accessToken'],\n    requiredOptionFields: [],\n    build(graph, options) {\n      return createGcpLbConnector(graph, options as unknown as GcpLbConnectorConfig)\n    },\n    // POST entries:list with pageSize 1 — the exact surface poll() reads, so the\n    // probe checks the actual `logging.logEntries.list` permission the connector\n    // needs. This is the same Cloud Logging read-verdict cloud-run's validate\n    // uses (a lighter GET on logs.list would instead check `logging.logs.list`,\n    // falsely rejecting a correctly-scoped custom role carrying only\n    // `logging.logEntries.list`). A 2xx means the token can list log entries;\n    // 401/403 means the provider rejected it.\n    validate({ credentials, fetchImpl }) {\n      const projectId = String(credentials.projectId ?? '')\n      return authProbe({\n        provider: 'gcp-lb',\n        accountKey: projectId || 'validate',\n        url: 'https://logging.googleapis.com/v2/entries:list',\n        token: String(credentials.accessToken ?? ''),\n        init: {\n          method: 'POST',\n          headers: { 'Content-Type': 'application/json' },\n          body: JSON.stringify({ resourceNames: [`projects/${projectId}`], pageSize: 1 }),\n        },\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  render: {\n    provider: 'render',\n    primaryCredentialKey: 'token',\n    requiredCredentialFields: ['token'],\n    requiredOptionFields: ['ownerId', 'resourceId', 'serviceName'],\n    build(graph, options) {\n      const config = options as unknown as RenderConnectorConfig\n      // Split factories — connector and resolveTarget are built separately.\n      return {\n        connector: createRenderConnector(graph, config),\n        resolveTarget: createRenderResolveTarget(config),\n      }\n    },\n    // GET /v1/services?limit=1 — the cheapest read the Render API key\n    // authenticates against (render.com/docs/api). Unlike Railway's GraphQL\n    // gateway, Render is a plain REST API: a live key returns 2xx, a bad one a\n    // 401/403, so authProbe's status-code check is a true verdict here. The\n    // logs query itself also needs an ownerId + resource; `services` needs\n    // neither and still fails 401 on a bad token, so it's the honest probe.\n    validate({ credentials, options, fetchImpl }) {\n      const cfg = options as Partial<RenderConnectorConfig>\n      const baseUrl = cfg.apiUrl ?? DEFAULT_RENDER_API_URL\n      return authProbe({\n        provider: 'render',\n        accountKey: cfg.ownerId ?? 'validate',\n        url: `${baseUrl}/services?limit=1`,\n        token: String(credentials.token ?? ''),\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  planetscale: {\n    provider: 'planetscale',\n    // The secret is the service token; a single-string credential maps to it,\n    // and the required-fields check below catches a serviceTokenId that was\n    // never supplied (the same two-part shape cloud-run uses for\n    // projectId/accessToken).\n    primaryCredentialKey: 'serviceToken',\n    requiredCredentialFields: ['serviceTokenId', 'serviceToken'],\n    requiredOptionFields: ['organization', 'database', 'branch', 'serviceName'],\n    build(graph, options) {\n      // createPlanetscaleConnector already returns the pairing.\n      return createPlanetscaleConnector(graph, options as unknown as PlanetscaleConnectorConfig)\n    },\n    // GET .../insights?per_page=1 over a short window — the exact read poll()\n    // performs, minus the pagination. A live `read_database` token returns\n    // 2xx; a bad one a 401/403, so authProbe's status-code check is a true\n    // verdict. PlanetScale's auth header is the non-Bearer `id:token` form\n    // (planetscale.com/docs/api/reference/service-tokens), passed as an\n    // explicit `authHeader` rather than the default bearer.\n    validate({ credentials, options, fetchImpl }) {\n      const cfg = options as Partial<PlanetscaleConnectorConfig>\n      const baseUrl = cfg.apiUrl ?? DEFAULT_PLANETSCALE_API_URL\n      const to = new Date()\n      const from = new Date(to.getTime() - 60 * 60 * 1000)\n      const url = new URL(\n        `${baseUrl}/organizations/${encodeURIComponent(cfg.organization ?? '')}/databases/${encodeURIComponent(\n          cfg.database ?? '',\n        )}/branches/${encodeURIComponent(cfg.branch ?? '')}/insights`,\n      )\n      url.searchParams.set('from', from.toISOString())\n      url.searchParams.set('to', to.toISOString())\n      url.searchParams.set('per_page', '1')\n      return authProbe({\n        provider: 'planetscale',\n        accountKey: cfg.database ?? 'validate',\n        url,\n        token: '',\n        authHeader: planetscaleAuthHeader(\n          String(credentials.serviceTokenId ?? ''),\n          String(credentials.serviceToken ?? ''),\n        ),\n        ...(fetchImpl ? { fetchImpl } : {}),\n      })\n    },\n  },\n  eas: {\n    provider: 'eas',\n    // The secret is a single robot-user EXPO_TOKEN; a single-string credential\n    // maps to `token`. `appId` is non-secret config (connector-config.md §7.1).\n    primaryCredentialKey: 'token',\n    requiredCredentialFields: ['token'],\n    requiredOptionFields: ['appId'],\n    build(graph, options) {\n      // createEasConnector already returns the { connector, resolveTarget } pairing.\n      return createEasConnector(graph, options as unknown as EasConnectorConfig)\n    },\n    // Runs the connector's real `builds` query at limit 1 — the exact read poll()\n    // performs, minus the pages — so the probe checks both that the EXPO_TOKEN\n    // authenticates and that this app id is reachable, the same probe-the-real-\n    // query discipline Railway and Cloud Run use over a trivial `{ __typename }`.\n    // A bad or wrong-scoped token comes back as an Expo GraphQL error, which\n    // `fetchErroredBuilds` throws on, so it fails honestly here rather than\n    // silently at the first poll.\n    async validate({ credentials, options, fetchImpl }) {\n      const cfg = options as Partial<EasConnectorConfig>\n      const appId = String(cfg.appId ?? '')\n      if (!appId) return { ok: false, reason: 'eas: appId is required to validate' }\n      const probeConfig: EasConnectorConfig = {\n        appId,\n        pageSize: 1,\n        maxPages: 1,\n        ...(cfg.apiUrl ? { apiUrl: cfg.apiUrl } : {}),\n      }\n      try {\n        await fetchErroredBuilds(String(credentials.token ?? ''), probeConfig, fetchImpl)\n        return { ok: true }\n      } catch (err) {\n        return { ok: false, reason: `eas auth check failed: ${(err as Error).message}` }\n      }\n    },\n  },\n}\n\nexport function getProviderDispatch(provider: string): ProviderDispatch | undefined {\n  return PROVIDER_DISPATCH[provider]\n}\n\n// Read the two secrets a Vercel drain needs out of an already-resolved\n// credential record (registry keeps them env-refs until this point, §2/§6).\nfunction vercelCredsFrom(credentials: Record<string, unknown>): VercelCredentials {\n  return { token: String(credentials.token ?? ''), otelToken: String(credentials.otelToken ?? '') }\n}\n\n// Rebuild the typed Vercel config from an entry's opaque `options`. `projectIds`\n// tolerates both an array and a comma-separated string (the shape a `--project-\n// ids` CLI flag lands as); everything absent stays absent.\nfunction vercelConfigFromOptions(options: Record<string, unknown>): VercelConnectorConfig {\n  const raw = options.projectIds\n  let projectIds: string[] | undefined\n  if (Array.isArray(raw)) projectIds = raw.filter((p): p is string => typeof p === 'string')\n  else if (typeof raw === 'string' && raw.trim().length > 0) {\n    projectIds = raw.split(',').map((s) => s.trim()).filter((s) => s.length > 0)\n  }\n  return {\n    teamId: String(options.teamId ?? ''),\n    endpoint: String(options.endpoint ?? ''),\n    ...(projectIds && projectIds.length > 0 ? { projectIds } : {}),\n    ...(typeof options.drainId === 'string' ? { drainId: options.drainId } : {}),\n    ...(typeof options.drainName === 'string' ? { drainName: options.drainName } : {}),\n    ...(typeof options.apiBaseUrl === 'string' ? { apiBaseUrl: options.apiBaseUrl } : {}),\n    ...(typeof options.secret === 'string' ? { secret: options.secret } : {}),\n  }\n}\n\n// ── The push table. One provider so far — Vercel (ADR-146). A push provider\n// registers here instead of PROVIDER_DISPATCH: it provisions a drain rather\n// than exposing a poll(), so it carries a provision/deprovision lifecycle and\n// no `build`. `neat connector add/remove/test` dispatch through it exactly as\n// they dispatch pull providers through PROVIDER_DISPATCH.\nexport const PUSH_PROVIDER_DISPATCH: Record<string, PushProviderDispatch> = {\n  vercel: {\n    provider: 'vercel',\n    // The Vercel access token is the \"primary\" secret a single `--token`\n    // populates; `otelToken` (the daemon's OTLP bearer) is the second field.\n    primaryCredentialKey: 'token',\n    requiredCredentialFields: ['token', 'otelToken'],\n    // teamId scopes every Drains call; endpoint is where the drain delivers.\n    // projectIds is optional (absent → the drain covers the whole team).\n    requiredOptionFields: ['teamId', 'endpoint'],\n    // POST /v1/drains/test — authenticates the token and pings the endpoint\n    // with a sample event, so `success` means the credential is live *and* the\n    // daemon's OTLP endpoint is reachable and accepted the drain's bearer.\n    async validate({ credentials, options, fetchImpl }) {\n      const result = await testVercelDrainDelivery(\n        vercelConfigFromOptions(options),\n        vercelCredsFrom(credentials),\n        fetchImpl,\n      )\n      if (result.status === 'success') return { ok: true }\n      return {\n        ok: false,\n        reason: result.error ?? `vercel drain delivery test returned \"${result.status ?? 'no status'}\"`,\n      }\n    },\n    // POST /v1/drains — creates the trace drain, returns its id to store in\n    // `options.drainId`. A created-but-not-enabled drain is surfaced as a note,\n    // not a failure (the entry still points at a real drain).\n    async provision({ credentials, options, fetchImpl }) {\n      try {\n        const created = await createVercelDrain(\n          vercelConfigFromOptions(options),\n          vercelCredsFrom(credentials),\n          fetchImpl,\n        )\n        const note =\n          created.status && created.status !== 'enabled'\n            ? `the drain was created but its status is \"${created.status}\"${created.disabledReason ? ` (${created.disabledReason})` : ''} — check the Vercel dashboard`\n            : undefined\n        return { ok: true, options: { drainId: created.id }, ...(note ? { note } : {}) }\n      } catch (err) {\n        return { ok: false, reason: (err as Error).message }\n      }\n    },\n    // DELETE /v1/drains/{id} — idempotent (deleteVercelDrain treats 404 as\n    // success). No recorded drainId → nothing to delete, still a success.\n    async deprovision({ credentials, options, fetchImpl }) {\n      const drainId = typeof options.drainId === 'string' ? options.drainId : ''\n      if (!drainId) {\n        return { ok: true, note: 'no drain id was recorded — nothing to delete on the Vercel side' }\n      }\n      try {\n        await deleteVercelDrain(\n          vercelConfigFromOptions(options),\n          drainId,\n          vercelCredsFrom(credentials),\n          fetchImpl,\n        )\n        return { ok: true }\n      } catch (err) {\n        return { ok: false, reason: (err as Error).message }\n      }\n    },\n  },\n}\n\nexport function getPushProviderDispatch(provider: string): PushProviderDispatch | undefined {\n  return PUSH_PROVIDER_DISPATCH[provider]\n}\n\n/** Whether a provider provisions a drain (push) rather than being polled (pull). */\nexport function isPushProvider(provider: string): boolean {\n  return provider in PUSH_PROVIDER_DISPATCH\n}\n\n/**\n * The field schema for a provider from *either* table — what the CLI reads to\n * prompt for and structurally check credentials/options without caring whether\n * the provider is pull or push.\n */\nexport function getProviderFieldSchema(provider: string): ProviderFieldSchema | undefined {\n  return PROVIDER_DISPATCH[provider] ?? PUSH_PROVIDER_DISPATCH[provider]\n}\n\n/** Every registered provider name, pull and push — for CLI \"known providers\" hints. */\nexport function knownProviderNames(): string[] {\n  return [...Object.keys(PROVIDER_DISPATCH), ...Object.keys(PUSH_PROVIDER_DISPATCH)].sort()\n}\n\nexport type BuildResult =\n  | { ok: true; registration: ConnectorRegistration }\n  // `push: true` marks a benign skip — the entry is a push provider with no\n  // poll registration to build (connectors.md §9), not a broken entry.\n  | { ok: false; reason: string; push?: boolean }\n\n/**\n * Resolve an entry's env-ref credential to in-memory values keyed the way this\n * provider reads them (contract §2, §6), and confirm every required credential\n * field is present. The `unset-env` failure is kept distinct from every other\n * kind so a caller can tell \"you forgot to `export`\" apart from \"your token is\n * malformed\" (contract §4). Shared by `buildRegistration` (daemon read) and\n * `validateConnectorEntry` (the CLI) so both resolve credentials identically.\n */\ntype CredentialResolution =\n  | { ok: true; credentials: Record<string, unknown>; refreshCredentials?: CredentialSource }\n  | { ok: false; kind: 'unset-env' | 'error' | 'missing-field'; reason: string }\n\n// The GCP connectors consume a short-lived Google access token (~1h). When one carries a service-account key\n// instead of a pre-minted token, its credential resolves to a refreshable token source, not a fixed value\n// (ADR-230) — so a long-running local daemon re-mints rather than polling with a dead token past the hour.\nconst GCP_SERVICE_ACCOUNT_PROVIDERS: ReadonlySet<string> = new Set(['cloud-run', 'gcp-lb', 'firebase'])\n\nfunction resolveEntryCredentials(\n  dispatch: ProviderFieldSchema,\n  entry: ConnectorEntry,\n  env: NodeJS.ProcessEnv,\n  fetchImpl?: typeof fetch,\n): CredentialResolution {\n  let credentials: Record<string, unknown>\n  try {\n    const resolved = resolveCredential(entry.credential, env)\n    credentials =\n      resolved.kind === 'single'\n        ? { [dispatch.primaryCredentialKey]: resolved.value }\n        : { ...resolved.fields }\n  } catch (err) {\n    if (err instanceof EnvRefUnsetError) return { ok: false, kind: 'unset-env', reason: err.message }\n    return { ok: false, kind: 'error', reason: (err as Error).message }\n  }\n  // Refreshable GCP service-account credential (ADR-230): a `{ serviceAccountKey: \"$…\" }` credential on a GCP\n  // connector resolves to a per-tick token source over that key, not a static value. The source mints and\n  // caches a `{ projectId, accessToken }` — the exact record the GCP connectors already read — so no connector\n  // code changes and the required-field check below is satisfied by the mint, not a stored token.\n  if (\n    GCP_SERVICE_ACCOUNT_PROVIDERS.has(entry.provider) &&\n    typeof credentials.serviceAccountKey === 'string' &&\n    credentials.serviceAccountKey.length > 0\n  ) {\n    try {\n      const key = parseServiceAccountKey(credentials.serviceAccountKey)\n      const source = createGcpTokenSource(key, GCP_LOGGING_READ_SCOPE, fetchImpl ? { fetchImpl } : {})\n      return { ok: true, credentials: { projectId: key.project_id }, refreshCredentials: source }\n    } catch (err) {\n      return { ok: false, kind: 'error', reason: (err as Error).message }\n    }\n  }\n  const missingCreds = dispatch.requiredCredentialFields.filter((k) => !credentials[k])\n  if (missingCreds.length > 0) {\n    return {\n      ok: false,\n      kind: 'missing-field',\n      reason: `credential missing required field(s): ${missingCreds.join(', ')}`,\n    }\n  }\n  return { ok: true, credentials }\n}\n\n/**\n * Turn one resolved config entry into a `ConnectorRegistration`, or a skip\n * reason. Never throws — a bad entry (unknown provider, unset env-ref,\n * missing required field, provider factory rejecting its config) resolves to\n * `{ ok: false, reason }` so one broken connector never takes the daemon slot\n * down with it (contract §6).\n */\nexport function buildRegistration(\n  entry: ConnectorEntry,\n  graph: NeatGraph,\n  env: NodeJS.ProcessEnv = process.env,\n): BuildResult {\n  const dispatch = PROVIDER_DISPATCH[entry.provider]\n  if (!dispatch) {\n    // A push provider (ADR-146) has no poll registration — it provisioned a\n    // drain and its data arrives via the OTLP receiver. Flag that as a benign,\n    // expected skip, distinct from a genuinely unknown provider, so the daemon\n    // never treats a configured Vercel connector as a broken entry\n    // (connectors.md §9).\n    if (isPushProvider(entry.provider)) {\n      return {\n        ok: false,\n        push: true,\n        reason: `push provider \"${entry.provider}\" ingests via the OTLP receiver — nothing to poll`,\n      }\n    }\n    return { ok: false, reason: `unknown provider \"${entry.provider}\"` }\n  }\n\n  const creds = resolveEntryCredentials(dispatch, entry, env)\n  if (!creds.ok) return { ok: false, reason: creds.reason }\n  const credentials = creds.credentials\n\n  const options = entry.options ?? {}\n  const missingOpts = dispatch.requiredOptionFields.filter((k) => !(k in options))\n  if (missingOpts.length > 0) {\n    return {\n      ok: false,\n      reason: `options missing required field(s): ${missingOpts.join(', ')}`,\n    }\n  }\n\n  let built: BuiltConnector\n  try {\n    built = dispatch.build(graph, options)\n  } catch (err) {\n    return { ok: false, reason: (err as Error).message }\n  }\n\n  const intervalMs = typeof options.intervalMs === 'number' ? options.intervalMs : undefined\n  return {\n    ok: true,\n    registration: {\n      // Carry the entry id so the daemon can key this connector's poll-status\n      // records to it (ADR-136).\n      id: entry.id,\n      connector: built.connector,\n      credentials,\n      resolveTarget: built.resolveTarget,\n      ...(intervalMs !== undefined ? { intervalMs } : {}),\n      // A refreshable credential (ADR-230) resolves to a per-tick token source; carry it so the daemon wires\n      // it to the poll loop's `refreshCredentials`. Absent for a static credential.\n      ...(creds.refreshCredentials ? { refreshCredentials: creds.refreshCredentials } : {}),\n    },\n  }\n}\n\n/**\n * The verdict `neat connector add` (validate-on-add) and `neat connector test`\n * both report (contract §4). Five distinct outcomes so the CLI can speak\n * plainly: `ok` (authenticated), `unset-env` (a `$VAR` credential's variable\n * isn't set — resolution failure, *not* the provider rejecting a token),\n * `rejected` (creds resolved but the provider's auth path turned them down),\n * `unknown-provider`, and `missing-field` (a required credential/option is\n * absent — caught before any network call).\n */\nexport type ValidateOutcome =\n  | { status: 'ok' }\n  | { status: 'unset-env'; reason: string }\n  | { status: 'rejected'; reason: string }\n  | { status: 'unknown-provider'; reason: string }\n  | { status: 'missing-field'; reason: string }\n\n/**\n * Run the provider's cheap auth round-trip against an entry — resolving its\n * env-ref credential first, so an unset variable short-circuits as `unset-env`\n * before any request goes out (contract §4). Dispatches the actual round-trip\n * through the table's `validate` (§5), so no per-provider auth logic lives in\n * the CLI. `fetchImpl` is the test seam that stands a fake provider in for the\n * live one.\n */\nexport async function validateConnectorEntry(\n  entry: ConnectorEntry,\n  env: NodeJS.ProcessEnv = process.env,\n  fetchImpl?: typeof fetch,\n): Promise<ValidateOutcome> {\n  // Either table — a pull provider's auth probe and a push provider's\n  // drain-delivery test are the same `validate` shape (contract §4, §9), so\n  // `neat connector test` reads one and dispatches without branching.\n  const dispatch = PROVIDER_DISPATCH[entry.provider] ?? PUSH_PROVIDER_DISPATCH[entry.provider]\n  if (!dispatch) {\n    return { status: 'unknown-provider', reason: `unknown provider \"${entry.provider}\"` }\n  }\n  const creds = resolveEntryCredentials(dispatch, entry, env, fetchImpl)\n  if (!creds.ok) {\n    if (creds.kind === 'unset-env') return { status: 'unset-env', reason: creds.reason }\n    return { status: 'missing-field', reason: creds.reason }\n  }\n  const options = entry.options ?? {}\n  const missingOpts = dispatch.requiredOptionFields.filter((k) => !(k in options))\n  if (missingOpts.length > 0) {\n    return {\n      status: 'missing-field',\n      reason: `options missing required field(s): ${missingOpts.join(', ')}`,\n    }\n  }\n  // A refreshable credential (ADR-230) has no stored token to probe — minting one *is* the auth probe. Mint\n  // once and hand the provider's `validate` the same `{ projectId, accessToken }` a poll would get; a mint\n  // failure (a rejected service-account key) is a rejected credential, reported as such.\n  let credentials = creds.credentials\n  if (creds.refreshCredentials) {\n    try {\n      credentials = { ...credentials, ...(await creds.refreshCredentials()) }\n    } catch (err) {\n      return { status: 'rejected', reason: (err as Error).message }\n    }\n  }\n  const result = await dispatch.validate({\n    credentials,\n    options,\n    ...(fetchImpl ? { fetchImpl } : {}),\n  })\n  return result.ok ? { status: 'ok' } : { status: 'rejected', reason: result.reason }\n}\n\nexport interface LoadConnectorsInput {\n  // The project this daemon slot is bootstrapping — only entries that match\n  // it (or omit `project`) load.\n  project: string\n  // The slot's live graph; resolveTarget closes over it.\n  graph: NeatGraph\n  // Resolved NEAT_HOME; defaults to the env-based resolution in\n  // connectors-config.ts.\n  home?: string\n  env?: NodeJS.ProcessEnv\n  // Called once per skipped entry (unknown provider, unset env-ref, missing\n  // field, ...) so the daemon can log it. A skip is never fatal.\n  onSkip?: (entry: ConnectorEntry, reason: string) => void\n}\n\n/**\n * Read `~/.neat/connectors.json` and build a registration for every entry\n * that matches `project`. The daemon calls this at slot bootstrap and hands\n * the result to `startConnectorPollLoop`. A missing file yields an empty\n * list; a malformed file yields an empty list plus one skip callback, never a\n * throw — the daemon must survive a hand-edited config.\n */\nexport async function loadConnectorRegistrations(\n  input: LoadConnectorsInput,\n): Promise<ConnectorRegistration[]> {\n  const { project, graph, home, env = process.env, onSkip } = input\n  let connectors: ConnectorEntry[]\n  try {\n    connectors = (await readConnectorsConfig(home)).connectors\n  } catch (err) {\n    onSkip?.(\n      { id: '(file)', provider: '(all)', credential: '' },\n      `connectors.json unreadable — ${(err as Error).message}`,\n    )\n    return []\n  }\n\n  const registrations: ConnectorRegistration[] = []\n  for (const entry of connectors) {\n    if (!connectorMatchesProject(entry, project)) continue\n    const result = buildRegistration(entry, graph, env)\n    if (result.ok) registrations.push(result.registration)\n    // A push provider (ADR-146) is not a poll connector — its absence from the\n    // registration list is expected, not a fault, so it never fires the\n    // error-oriented onSkip (connectors.md §9). Its drain delivers via the OTLP\n    // receiver regardless of this loop.\n    else if (!result.push) onSkip?.(entry, result.reason)\n  }\n  return registrations\n}\n\nexport interface StartConnectorPollingInput {\n  project: string\n  graph: NeatGraph\n  // The project's working directory, handed to each poll as ctx.projectDir.\n  projectDir: string\n  // The project's incident ledger (`errors.ndjson`), handed to each poll as\n  // ctx.errorsPath so an incident-emitting connector (ADR-185) can write a\n  // build-failure incident. Absent → incident signals drop honestly; a\n  // traffic-only setup never needs it.\n  errorsPath?: string\n  // Resolved NEAT_HOME. Absent → the connectors file isn't read (only `extra`\n  // is polled), which is how a caller with no home opts out of file connectors.\n  home?: string\n  // Registrations a programmatic caller supplies directly (the daemon's\n  // opts.connectors seam), polled ahead of the file-configured ones to match\n  // the daemon's original merge order.\n  extra?: ConnectorRegistration[]\n  onSkip?: (entry: ConnectorEntry, reason: string) => void\n}\n\n/**\n * Load every project-matched connector from `~/.neat/connectors.json` and start\n * a poll loop for each, returning one stop that tears them all down. This is the\n * single place a daemon entrypoint turns stored connectors into running polls:\n * both the multi-project daemon (`daemon.ts`) and `neat watch` (`watch.ts`) go\n * through it, so a CLI-added connector polls the same way whichever way the\n * project is served. Before #871, `neat watch` wired no connectors at all — the\n * loading lived only in `daemon.ts`, so a connector added against a `neat watch`\n * project loaded, validated, and then sat idle forever.\n */\nexport async function startConnectorPolling(input: StartConnectorPollingInput): Promise<() => void> {\n  const fileConnectors = input.home\n    ? await loadConnectorRegistrations({\n        project: input.project,\n        graph: input.graph,\n        home: input.home,\n        ...(input.onSkip ? { onSkip: input.onSkip } : {}),\n      })\n    : []\n  const all = [...(input.extra ?? []), ...fileConnectors]\n  const stopFns = all.map((registration) =>\n    startConnectorPollLoop(\n      registration.connector,\n      {\n        projectDir: input.projectDir,\n        project: input.project,\n        credentials: registration.credentials,\n        ...(input.errorsPath ? { errorsPath: input.errorsPath } : {}),\n      },\n      input.graph,\n      registration.resolveTarget,\n      {\n        intervalMs: registration.intervalMs,\n        connectorId: registration.id,\n        // A refreshable credential (ADR-230) mints a fresh token each tick; the static path leaves this unset\n        // and the loop reuses ctx.credentials, exactly as before.\n        ...(registration.refreshCredentials ? { refreshCredentials: registration.refreshCredentials } : {}),\n      },\n    ),\n  )\n  return () => {\n    for (const stop of stopFns) stop()\n  }\n}\n\n/**\n * The outcome of a push provider's provision/deprovision (connectors.md §9),\n * shaped like {@link ValidateOutcome} so `neat connector add`/`remove` report\n * both with one vocabulary. `ok` optionally carries `options` — an opaque\n * handle to merge into the entry (e.g. `{ drainId }`) — and an operator `note`.\n * `not-push` names the caller error of asking a pull provider to provision.\n */\nexport type PushActionOutcome =\n  | { status: 'ok'; options?: Record<string, unknown>; note?: string }\n  | { status: 'unset-env'; reason: string }\n  | { status: 'missing-field'; reason: string }\n  | { status: 'failed'; reason: string }\n  | { status: 'unknown-provider'; reason: string }\n  | { status: 'not-push'; reason: string }\n\ntype PushResolved =\n  | { ok: true; dispatch: PushProviderDispatch; credentials: Record<string, unknown>; options: Record<string, unknown> }\n  | { ok: false; outcome: PushActionOutcome }\n\n// Shared front half of provision/deprovision: find the push dispatch, resolve\n// the entry's env-ref credential, and confirm required options are present —\n// the same pre-flight `validateConnectorEntry` runs, kept identical so a push\n// `add`/`remove` fails on a missing field exactly where `test` would.\nfunction resolvePushEntry(entry: ConnectorEntry, env: NodeJS.ProcessEnv): PushResolved {\n  const dispatch = PUSH_PROVIDER_DISPATCH[entry.provider]\n  if (!dispatch) {\n    return PROVIDER_DISPATCH[entry.provider]\n      ? {\n          ok: false,\n          outcome: {\n            status: 'not-push',\n            reason: `provider \"${entry.provider}\" is polled, not provisioned — there is no drain to manage`,\n          },\n        }\n      : { ok: false, outcome: { status: 'unknown-provider', reason: `unknown provider \"${entry.provider}\"` } }\n  }\n  const creds = resolveEntryCredentials(dispatch, entry, env)\n  if (!creds.ok) {\n    const status = creds.kind === 'unset-env' ? 'unset-env' : creds.kind === 'missing-field' ? 'missing-field' : 'failed'\n    return { ok: false, outcome: { status, reason: creds.reason } }\n  }\n  const options = entry.options ?? {}\n  const missingOpts = dispatch.requiredOptionFields.filter((k) => !(k in options))\n  if (missingOpts.length > 0) {\n    return {\n      ok: false,\n      outcome: { status: 'missing-field', reason: `options missing required field(s): ${missingOpts.join(', ')}` },\n    }\n  }\n  return { ok: true, dispatch, credentials: creds.credentials, options }\n}\n\n/**\n * Provision a push provider's drain (connectors.md §9) — run by `neat connector\n * add` after validation, before the entry is written. On success the returned\n * `options` (the drain handle) is merged into the entry so `remove` can undo it.\n */\nexport async function provisionConnector(\n  entry: ConnectorEntry,\n  env: NodeJS.ProcessEnv = process.env,\n  fetchImpl?: typeof fetch,\n): Promise<PushActionOutcome> {\n  const resolved = resolvePushEntry(entry, env)\n  if (!resolved.ok) return resolved.outcome\n  const result = await resolved.dispatch.provision({\n    credentials: resolved.credentials,\n    options: resolved.options,\n    ...(fetchImpl ? { fetchImpl } : {}),\n  })\n  if (!result.ok) return { status: 'failed', reason: result.reason }\n  return { status: 'ok', ...(result.options ? { options: result.options } : {}), ...(result.note ? { note: result.note } : {}) }\n}\n\n/**\n * Deprovision a push provider's drain — run by `neat connector remove` before\n * the entry is dropped, so a stored entry never outlives its live drain. The\n * provider's `deprovision` is idempotent (an already-gone drain is a success).\n */\nexport async function deprovisionConnector(\n  entry: ConnectorEntry,\n  env: NodeJS.ProcessEnv = process.env,\n  fetchImpl?: typeof fetch,\n): Promise<PushActionOutcome> {\n  const resolved = resolvePushEntry(entry, env)\n  if (!resolved.ok) return resolved.outcome\n  const result = await resolved.dispatch.deprovision({\n    credentials: resolved.credentials,\n    options: resolved.options,\n    ...(fetchImpl ? { fetchImpl } : {}),\n  })\n  if (!result.ok) return { status: 'failed', reason: result.reason }\n  return { status: 'ok', ...(result.note ? { note: result.note } : {}) }\n}\n","// GCP service-account token source — the refreshable credential for the GCP connectors\n// (docs/contracts/connector-config.md §9, ADR-230).\n//\n// The GCP connectors (cloud-run, firebase, gcp-lb) consume a short-lived OAuth\n// access token (~1h) and perform no auth handshake of their own. A static\n// env-ref credential resolves once at slot bootstrap and then goes stale — a\n// long-running daemon polls with a dead token after an hour. This module is the\n// fix: it mints a fresh access token from a service-account key via the OAuth2\n// JWT-bearer flow, caches it, and re-mints before it expires. The poll loop\n// calls the returned source each tick (the shipped `refreshCredentials` seam,\n// index.ts); the connector still receives an already-minted `{ projectId,\n// accessToken }` and never sees the refresh.\n//\n// The JWT-bearer flow follows Google's own docs\n// (https://developers.google.com/identity/protocols/oauth2/service-account):\n//   - token endpoint: POST https://oauth2.googleapis.com/token\n//   - grant_type: urn:ietf:params:oauth:grant-type:jwt-bearer\n//   - JWT header: { alg: \"RS256\", typ: \"JWT\" }\n//   - claims: iss (client_email), scope (space-delimited), aud (the token\n//     endpoint exactly), iat, exp (<= iat + 3600); sub only for domain-wide\n//     delegation, unused here\n//   - POST body: application/x-www-form-urlencoded, grant_type + assertion\n//   - response: { access_token, token_type: \"Bearer\", expires_in }\n//\n// No new dependency: the JWT is signed with Node's built-in `crypto` (RS256),\n// and the token exchange goes through the shared junction like every other\n// outbound connector call (connectors.md §Authority, ADR-131).\n\nimport { createSign } from 'node:crypto'\nimport { junctionFetch } from './junction.js'\nimport type { CredentialSource } from './types.js'\n\n// The default OAuth2 token endpoint (`aud` claim + POST target). A service-\n// account key carries its own `token_uri`, which is this value in practice; the\n// key's value wins when present, and `opts.tokenUri` overrides both for tests.\nconst DEFAULT_TOKEN_URI = 'https://oauth2.googleapis.com/token'\nconst JWT_BEARER_GRANT = 'urn:ietf:params:oauth:grant-type:jwt-bearer'\n\n// The maximum lifetime Google allows for the assertion JWT (`exp <= iat + 3600`).\nconst ASSERTION_LIFETIME_S = 3600\n// Re-mint this long before the access token's stated expiry, so a token is never\n// handed to a poll on the edge of expiring (clock skew + request latency margin).\nconst DEFAULT_REFRESH_SKEW_MS = 60_000\n\n/** The narrow Cloud Logging read scope the GCP connectors need (cloud-run, gcp-lb, firebase). */\nexport const GCP_LOGGING_READ_SCOPE = 'https://www.googleapis.com/auth/logging.read'\n\n/**\n * The fields this module reads from a service-account key JSON. A real key\n * carries more (type, private_key_id, client_id, auth_uri, ...), all ignored —\n * these three are what the JWT-bearer exchange and the GCP connectors need.\n */\nexport interface GcpServiceAccountKey {\n  client_email: string\n  private_key: string\n  // The GCP project the connectors key their signal + rate-limit bucket on\n  // (not a secret). Standard on every SA key JSON.\n  project_id: string\n  // Optional per-key override of the token endpoint; defaults to DEFAULT_TOKEN_URI.\n  token_uri?: string\n}\n\n/**\n * Parse and validate a service-account key JSON string. Throws a clear,\n * secret-free error naming the missing field rather than failing opaquely at\n * sign time. The private key is never logged or echoed — only its absence is\n * reported.\n */\nexport function parseServiceAccountKey(json: string): GcpServiceAccountKey {\n  let raw: unknown\n  try {\n    raw = JSON.parse(json)\n  } catch {\n    throw new Error('gcp service-account key: not valid JSON')\n  }\n  if (!raw || typeof raw !== 'object') {\n    throw new Error('gcp service-account key: expected a JSON object')\n  }\n  const obj = raw as Record<string, unknown>\n  const clientEmail = obj['client_email']\n  const privateKey = obj['private_key']\n  const projectId = obj['project_id']\n  if (typeof clientEmail !== 'string' || clientEmail.length === 0) {\n    throw new Error('gcp service-account key: missing client_email')\n  }\n  if (typeof privateKey !== 'string' || privateKey.length === 0) {\n    throw new Error('gcp service-account key: missing private_key')\n  }\n  if (typeof projectId !== 'string' || projectId.length === 0) {\n    throw new Error('gcp service-account key: missing project_id')\n  }\n  const key: GcpServiceAccountKey = { client_email: clientEmail, private_key: privateKey, project_id: projectId }\n  if (typeof obj['token_uri'] === 'string' && (obj['token_uri'] as string).length > 0) {\n    key.token_uri = obj['token_uri'] as string\n  }\n  return key\n}\n\nfunction base64url(input: Buffer | string): string {\n  return Buffer.from(input).toString('base64url')\n}\n\n// Build and RS256-sign the assertion JWT for the JWT-bearer grant. Pure given\n// `nowMs` — the caller owns the clock so tests are deterministic.\nexport function buildServiceAccountAssertion(\n  key: GcpServiceAccountKey,\n  scope: string,\n  tokenUri: string,\n  nowMs: number,\n): string {\n  const iat = Math.floor(nowMs / 1000)\n  const header = { alg: 'RS256', typ: 'JWT' }\n  const claims = {\n    iss: key.client_email,\n    scope,\n    aud: tokenUri,\n    iat,\n    exp: iat + ASSERTION_LIFETIME_S,\n  }\n  const signingInput = `${base64url(JSON.stringify(header))}.${base64url(JSON.stringify(claims))}`\n  const signature = createSign('RSA-SHA256').update(signingInput).end().sign(key.private_key)\n  return `${signingInput}.${base64url(signature)}`\n}\n\nexport interface MintedToken {\n  accessToken: string\n  // Absolute epoch-ms the token expires — derived from the response's\n  // `expires_in` at mint time, so the cache can decide when to re-mint.\n  expiresAtMs: number\n}\n\nexport interface GcpTokenSourceOptions {\n  // Dependency-injection seam for tests — defaults to the platform `fetch`,\n  // threaded into the junction the same way every connector's fetchImpl is.\n  fetchImpl?: typeof fetch\n  // Injectable clock (epoch-ms); defaults to Date.now. Lets a test advance time\n  // past a token's expiry to prove the re-mint.\n  now?: () => number\n  // Override the token endpoint (the key's `token_uri`, else DEFAULT_TOKEN_URI).\n  tokenUri?: string\n  // Re-mint this long before stated expiry (default 60s).\n  refreshSkewMs?: number\n}\n\n/**\n * One token exchange: sign the assertion, POST it through the junction, parse\n * the access token + its lifetime. Never retried at this layer beyond the\n * junction's own transient-failure retry; a rejected key (a 400 `invalid_grant`)\n * throws, secret-free.\n */\nexport async function mintGcpAccessToken(\n  key: GcpServiceAccountKey,\n  scope: string,\n  opts: GcpTokenSourceOptions = {},\n): Promise<MintedToken> {\n  const now = opts.now ?? Date.now\n  const tokenUri = opts.tokenUri ?? key.token_uri ?? DEFAULT_TOKEN_URI\n  const mintedAtMs = now()\n  const assertion = buildServiceAccountAssertion(key, scope, tokenUri, mintedAtMs)\n  const body = new URLSearchParams({ grant_type: JWT_BEARER_GRANT, assertion }).toString()\n\n  const res = await junctionFetch(\n    tokenUri,\n    {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n      body,\n    },\n    // accountKey: the GCP project id — an identifier, safe to log, the same\n    // per-(provider, accountKey) rate-limit bucket key the GCP connectors use.\n    { provider: 'gcp-auth', accountKey: key.project_id, ...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}) },\n  )\n  if (!res.ok) {\n    // No body echo — a token-endpoint error body can restate the assertion.\n    throw new Error(`gcp token mint failed: ${res.status} ${res.statusText}`)\n  }\n  const json = (await res.json()) as { access_token?: unknown; expires_in?: unknown }\n  const accessToken = json.access_token\n  if (typeof accessToken !== 'string' || accessToken.length === 0) {\n    throw new Error('gcp token mint returned no access_token')\n  }\n  const expiresInS = typeof json.expires_in === 'number' && json.expires_in > 0 ? json.expires_in : ASSERTION_LIFETIME_S\n  return { accessToken, expiresAtMs: mintedAtMs + expiresInS * 1000 }\n}\n\n/**\n * A cached, self-refreshing token source over a service-account key. The\n * returned source mints on first call and re-mints only when the cached token\n * is within `refreshSkewMs` of expiry — so the poll loop can call it every tick\n * cheaply. It hands back `{ projectId, accessToken }`, the exact record shape\n * the GCP connectors already read, so no connector changes.\n *\n * Concurrent calls share one in-flight mint (a burst of ticks never fans out\n * into parallel token requests).\n */\nexport function createGcpTokenSource(\n  key: GcpServiceAccountKey,\n  scope: string,\n  opts: GcpTokenSourceOptions = {},\n): CredentialSource {\n  const now = opts.now ?? Date.now\n  const skewMs = opts.refreshSkewMs ?? DEFAULT_REFRESH_SKEW_MS\n  let cached: MintedToken | null = null\n  let inFlight: Promise<MintedToken> | null = null\n\n  const fresh = (): boolean => cached !== null && now() < cached.expiresAtMs - skewMs\n\n  return async (): Promise<Record<string, unknown>> => {\n    if (!fresh()) {\n      if (!inFlight) {\n        inFlight = mintGcpAccessToken(key, scope, opts)\n          .then((minted) => {\n            cached = minted\n            return minted\n          })\n          .finally(() => {\n            inFlight = null\n          })\n      }\n      await inFlight\n    }\n    return { projectId: key.project_id, accessToken: cached!.accessToken }\n  }\n}\n","// The connector junction (ADR-131, docs/contracts/connectors.md). Every\n// connector's outbound call — `railway/client.ts`, `firebase/logging-api.ts`,\n// `cloudflare/client.ts`, `supabase/client.ts`, `supabase/postgres-client.ts`\n// — routes through `junctionFetch` (HTTP) or `dbJunction` (the Supabase\n// `pg` path) instead of its own bare `fetch()`/`pg` query. Before this\n// module, each connector reinvented the same thin, unprotected wrapper: no\n// timeout, no retry, no rate-limiting, no shared credential-header\n// convention, no shared outbound-health logging. None of that is a\n// per-provider concern — it's the same discipline every outbound call needs,\n// which is exactly why ADR-131 makes the outbound connection itself a\n// junction, the same way `connectors/index.ts` is already the one junction\n// every provider's inbound signal converges through on its way into the\n// graph.\n//\n// Passive/ambient discipline (connectors.md §2) still holds: this module\n// never issues a call a connector didn't already decide to make. What it\n// adds is what happens *around* a call a connector was always going to\n// make — bounding it in time, backing off instead of hammering a transient\n// failure, and self-throttling per customer account so a retry storm can\n// never look like the load-generation that principle forbids, even under\n// retry.\n\n// ── shared primitives: token-bucket rate limiting ──────────────────────────\n\n/**\n * A token bucket's shape: `capacity` tokens available as burst, refilling\n * one token every `refillMs`. Keyed on `(provider, accountKey)` — never\n * global — so one customer's aggressive polling can never throttle\n * another's (ADR-131 decision #1's rate-limiting clause).\n */\nexport interface TokenBucketConfig {\n  /** Maximum tokens the bucket can hold — the burst allowance. */\n  capacity: number\n  /** Milliseconds to refill exactly one token. */\n  refillMs: number\n}\n\ninterface TokenBucketState extends TokenBucketConfig {\n  tokens: number\n  updatedAt: number\n}\n\n// module-level — the one process-wide set of buckets every connector's call\n// shares, keyed per (provider, accountKey) exactly as ADR-131 specifies.\nconst buckets = new Map<string, TokenBucketState>()\n\nfunction bucketMapKey(provider: string, accountKey: string): string {\n  return `${provider}\\x00${accountKey}`\n}\n\nfunction getBucket(provider: string, accountKey: string, config: TokenBucketConfig): TokenBucketState {\n  const key = bucketMapKey(provider, accountKey)\n  const existing = buckets.get(key)\n  if (existing && existing.capacity === config.capacity && existing.refillMs === config.refillMs) {\n    return existing\n  }\n  // First sighting of this (provider, accountKey) pair, or a call-site\n  // override changed the bucket's shape — start a fresh, full bucket rather\n  // than reinterpreting old token state under a new capacity/refill rate.\n  const fresh: TokenBucketState = { ...config, tokens: config.capacity, updatedAt: Date.now() }\n  buckets.set(key, fresh)\n  return fresh\n}\n\nfunction refillBucket(bucket: TokenBucketState, now: number): void {\n  if (now <= bucket.updatedAt) return\n  const elapsed = now - bucket.updatedAt\n  const grant = elapsed / bucket.refillMs\n  if (grant <= 0) return\n  bucket.tokens = Math.min(bucket.capacity, bucket.tokens + grant)\n  bucket.updatedAt = now\n}\n\n/**\n * Thrown when a bucket is exhausted and waiting for the next token would\n * exceed the call's remaining wall-clock budget — the bounded-wait counterpart\n * to blocking indefinitely. A connector's own poll tick (60s by default,\n * connectors/index.ts's DEFAULT_POLL_INTERVAL_MS) always has slack for a\n * short, self-imposed throttle wait; this only fires when the bucket is so\n * depleted that waiting would itself become the unbounded hang ADR-131's\n * wall-clock budget exists to prevent.\n */\nexport class RateLimitExceededError extends Error {\n  constructor(provider: string, accountKey: string) {\n    super(\n      `junction: rate limit exceeded for ${provider}:${accountKey} — waiting for the next token would exceed this call's wall-clock budget`,\n    )\n    this.name = 'RateLimitExceededError'\n  }\n}\n\nfunction delay(ms: number): Promise<void> {\n  if (ms <= 0) return Promise.resolve()\n  return new Promise((resolve) => {\n    const timer = setTimeout(resolve, ms)\n    if (typeof timer.unref === 'function') timer.unref()\n  })\n}\n\n/**\n * Blocks until the (provider, accountKey) bucket holds a token, or throws\n * `RateLimitExceededError` when the wait would blow the remaining budget.\n * Every retry re-acquires a token here too (not just the first attempt) —\n * the per-account bucket has to hold under retry for the ambient/passive\n * principle to survive a transient-failure storm (ADR-131 consequences).\n */\nasync function acquireToken(\n  provider: string,\n  accountKey: string,\n  config: TokenBucketConfig,\n  remainingBudgetMs: number,\n): Promise<number> {\n  const bucket = getBucket(provider, accountKey, config)\n  refillBucket(bucket, Date.now())\n  if (bucket.tokens >= 1) {\n    bucket.tokens -= 1\n    return 0\n  }\n  const waitMs = Math.ceil((1 - bucket.tokens) * bucket.refillMs)\n  if (waitMs > remainingBudgetMs) {\n    throw new RateLimitExceededError(provider, accountKey)\n  }\n  await delay(waitMs)\n  refillBucket(bucket, Date.now())\n  bucket.tokens = Math.max(0, bucket.tokens - 1)\n  return waitMs\n}\n\n/**\n * Test-only seam — production code never calls this. Mirrors ingest.ts's\n * `resetUnidentifiedSpanWarnings`/`resetNoSourceMapWarnings` pattern: clears\n * every provider/account bucket so each test starts from a fresh, full\n * bucket instead of bleeding state across cases sharing this module.\n */\nexport function resetJunctionRateLimiters(): void {\n  buckets.clear()\n}\n\n// ── per-provider default bucket sizes ───────────────────────────────────────\n//\n// ADR-131's Phase 1 surveys found exactly one hard number:  Cloudflare's\n// Telemetry Query API at ~300 requests / 5 minutes. Railway's GraphQL API,\n// Firebase's Cloud Logging `entries.list`, and Supabase's Management API\n// each have a real limit the docs surveyed couldn't pin down — every one of\n// docs/connectors/{railway,firebase,supabase}.md flags its own rate limit as\n// \"needs-endpoint-testing\" / \"unconfirmed\" rather than citing a number. Those\n// three therefore get the same conservative placeholder bucket, not three\n// independently-guessed numbers dressed up as if they were documented —\n// tightened once a live project confirms the real ceiling for each,\n// exactly the discipline those docs already ask of every other unconfirmed\n// surface. `supabase-postgres` is different again: pg_stat_statements is a\n// raw Postgres connection, not a rate-limited REST API, so its bucket is a\n// self-imposed ceiling against a retry storm hammering the customer's own\n// database, not a provider-documented cap.\nexport const JUNCTION_DEFAULT_RATE_LIMITS: Record<string, TokenBucketConfig> = {\n  // ~300 requests / 5 minutes (ADR-131). Burst capacity holds a third of\n  // that ceiling; steady-state refill (1 token / 3s = 20/min = 100/5min)\n  // stays well clear of the documented limit even under sustained polling.\n  cloudflare: { capacity: 100, refillMs: 3_000 },\n  // Placeholder pending a live project confirming the real cap\n  // (docs/connectors/railway.md: \"does not appear to publish one as of this\n  // writing\").\n  railway: { capacity: 30, refillMs: 10_000 },\n  // Placeholder pending a live rate-limit check (docs/connectors/\n  // firebase.md: \"needs-endpoint-testing against entries.list's live rate\n  // limits\").\n  firebase: { capacity: 30, refillMs: 10_000 },\n  // Placeholder pending a live rate-limit check (docs/connectors/supabase.md:\n  // \"the documented rate limit for this specific endpoint is unconfirmed\").\n  supabase: { capacity: 30, refillMs: 10_000 },\n  // Not a documented API limit at all — a self-imposed ceiling on the raw\n  // pg_stat_statements connection (see module header above).\n  'supabase-postgres': { capacity: 20, refillMs: 3_000 },\n  // A direct pg_stat_statements read. This is a self-imposed ceiling on the\n  // customer's Neon compute, not a published management-API limit.\n  neon: { capacity: 20, refillMs: 3_000 },\n  // Push provider (ADR-146): the Drains REST API is touched only by `neat\n  // connector add/remove/test` (provision/deprovision/validate), never a poll\n  // loop, so this bucket is exercised a handful of times per command. Kept\n  // conservative pending a documented Drains-API rate limit.\n  vercel: { capacity: 20, refillMs: 5_000 },\n  // Render's REST API (api-docs.render.com/reference/rate-limiting) isn't\n  // pinned here to a single confirmed number — this is a conservative\n  // placeholder pending a live project, matching the other pull providers.\n  render: { capacity: 30, refillMs: 10_000 },\n}\n\n// Fallback for any provider not named above (a future connector that hasn't\n// had its own bucket sized yet) — conservative, not tuned to any specific\n// provider's documented limit.\nconst JUNCTION_GENERIC_RATE_LIMIT: TokenBucketConfig = { capacity: 20, refillMs: 5_000 }\n\nfunction defaultRateLimitFor(provider: string): TokenBucketConfig {\n  return JUNCTION_DEFAULT_RATE_LIMITS[provider] ?? JUNCTION_GENERIC_RATE_LIMIT\n}\n\n// ── shared primitives: backoff + outbound-health logging ──────────────────\n\nexport const JUNCTION_DEFAULT_TIMEOUT_MS = 10_000\nexport const JUNCTION_DEFAULT_MAX_ATTEMPTS = 3\nexport const JUNCTION_DEFAULT_INITIAL_BACKOFF_MS = 200\nexport const JUNCTION_DEFAULT_BACKOFF_MULTIPLIER = 4\n// 30s — comfortably under connectors/index.ts's 60s DEFAULT_POLL_INTERVAL_MS,\n// so even a fully-retried call (3 attempts, each up to the 10s timeout, plus\n// backoff) can never make one poll tick pile up on the next.\nexport const JUNCTION_DEFAULT_MAX_ELAPSED_MS = 30_000\nexport const JUNCTION_DEFAULT_DB_TIMEOUT_MS = 10_000\n\nasync function backoff(\n  attempt: number,\n  initialBackoffMs: number,\n  backoffMultiplier: number,\n  remainingBudgetMs: number,\n): Promise<void> {\n  // attempt 1 -> initialBackoffMs (200ms default), attempt 2 ->\n  // initialBackoffMs * multiplier (800ms default), ... — exponential,\n  // capped so a retry's own wait never overruns what's left of the call's\n  // wall-clock budget.\n  const raw = initialBackoffMs * backoffMultiplier ** (attempt - 1)\n  const capped = Math.max(0, Math.min(raw, remainingBudgetMs))\n  await delay(capped)\n}\n\n// The four outcomes ADR-131 names, plus `failed` for the single-attempt,\n// never-retried case (a 4xx, or a first attempt that used up the whole\n// budget) — a superset of the ADR's list, not a departure from it.\nexport type JunctionOutcome = 'success' | 'retried-then-succeeded' | 'retried-then-failed' | 'rate-limited' | 'failed'\n\n// Cloud Logging's / the Management API's own query strings carry real\n// content in the URL (Supabase's `sql=` query param, in particular) —\n// logging is stripped to origin + pathname so an outbound-health line never\n// echoes a credential or a query body back into stderr.\nfunction safeUrlLabel(url: string | URL): string {\n  try {\n    const u = typeof url === 'string' ? new URL(url) : url\n    return `${u.origin}${u.pathname}`\n  } catch {\n    return String(url)\n  }\n}\n\n// Structured outbound-health logging through the same mechanism the rest of\n// NEAT already uses for a connector's own diagnostics — console.log/warn/error\n// with a bracketed prefix (connectors/index.ts's `[neatd] connector poll\n// failed (...)`, ingest.ts's `[neat] ...` / `[neatd] ...` lines). Not a new\n// logging library — this is what a future `neat connector list --verbose`\n// reads stderr/stdout for.\nfunction logOutcome(\n  provider: string,\n  accountKey: string,\n  outcome: JunctionOutcome,\n  method: string,\n  label: string,\n  attempt: number,\n  startedAt: number,\n): void {\n  const elapsedMs = Date.now() - startedAt\n  const line = `[neat connector] ${provider}:${accountKey} ${method} ${label} — ${outcome} (attempt ${attempt}, ${elapsedMs}ms)`\n  if (outcome === 'success' || outcome === 'retried-then-succeeded') {\n    console.log(line)\n  } else if (outcome === 'rate-limited') {\n    console.warn(line)\n  } else {\n    console.error(line)\n  }\n}\n\n// ── credential injection ────────────────────────────────────────────────────\n\n/**\n * The one credential shape every connector so far shares (Railway, Firebase,\n * Cloudflare, and Supabase's Management API all carry `Authorization: Bearer\n * <token>` — see each provider's client.ts). Cuts the four near-identical\n * \"build the auth header\" blocks down to one (ADR-131 decision #1).\n */\nexport function bearerAuthHeader(token: string): { Authorization: string } {\n  return { Authorization: `Bearer ${token}` }\n}\n\n// ── junctionFetch ───────────────────────────────────────────────────────────\n\nexport interface JunctionPolicy {\n  /** 'railway' | 'firebase' | 'cloudflare' | 'supabase' | ... — half of the rate-limit bucket key and every outbound-health log line. */\n  provider: string\n  /**\n   * Whatever identifies one customer's account to this provider — a Supabase\n   * project ref, a Railway environment id, a Cloudflare account id, a GCP\n   * project id for Firebase (ADR-131). An identifier, never a secret itself\n   * — safe to log (contracts.md §6 governs the credential, not this).\n   */\n  accountKey: string\n  /** AbortController timeout per attempt, ms. Default 10s. */\n  timeoutMs?: number\n  /** Total attempts including the first, before giving up. Default 3. */\n  maxAttempts?: number\n  /** Wall-clock budget for the whole call (all attempts + backoff + rate-limit waits), ms. Default 30s. */\n  maxElapsedMs?: number\n  /** First retry's backoff delay, ms. Default 200. */\n  initialBackoffMs?: number\n  /** Backoff growth factor per retry. Default 4 (200ms, 800ms, ...). */\n  backoffMultiplier?: number\n  /** Per-(provider, accountKey) token bucket. Defaults to this provider's entry in JUNCTION_DEFAULT_RATE_LIMITS. */\n  rateLimit?: TokenBucketConfig\n  /** Dependency-injection seam for tests — defaults to the platform global `fetch`, read at call time so tests can stub `globalThis.fetch` per call. */\n  fetchImpl?: typeof fetch\n}\n\n/**\n * The one function every connector's outbound HTTP call goes through\n * (ADR-131). Times out and retries a transient failure with backoff, never\n * retries a 4xx, self-throttles per `(provider, accountKey)` even across\n * retries, and logs the call's outcome. Mirrors a bare `fetch()`'s contract\n * closely on purpose: on success *or* a non-retryable failure, this returns\n * the `Response` as-is — the caller's own `if (!res.ok) throw ...` still\n * constructs the same error it always did. This is a transport-layer\n * wrapper, not a second place that decides what a failed call means.\n */\nexport async function junctionFetch(url: string | URL, init: RequestInit = {}, policy: JunctionPolicy): Promise<Response> {\n  const {\n    provider,\n    accountKey,\n    timeoutMs = JUNCTION_DEFAULT_TIMEOUT_MS,\n    maxAttempts = JUNCTION_DEFAULT_MAX_ATTEMPTS,\n    maxElapsedMs = JUNCTION_DEFAULT_MAX_ELAPSED_MS,\n    initialBackoffMs = JUNCTION_DEFAULT_INITIAL_BACKOFF_MS,\n    backoffMultiplier = JUNCTION_DEFAULT_BACKOFF_MULTIPLIER,\n    rateLimit = defaultRateLimitFor(provider),\n    fetchImpl = fetch,\n  } = policy\n\n  const method = (init.method ?? 'GET').toUpperCase()\n  const label = safeUrlLabel(url)\n  const startedAt = Date.now()\n  let attempt = 0\n  let sawRetry = false\n\n  for (;;) {\n    attempt++\n    const remainingBudget = maxElapsedMs - (Date.now() - startedAt)\n    if (remainingBudget <= 0) {\n      logOutcome(provider, accountKey, 'retried-then-failed', method, label, attempt - 1, startedAt)\n      throw new Error(\n        `junction: ${provider}:${accountKey} ${method} ${label} exceeded its wall-clock budget (${maxElapsedMs}ms) after ${attempt - 1} attempt(s)`,\n      )\n    }\n\n    try {\n      await acquireToken(provider, accountKey, rateLimit, remainingBudget)\n    } catch (err) {\n      if (err instanceof RateLimitExceededError) {\n        logOutcome(provider, accountKey, 'rate-limited', method, label, attempt, startedAt)\n      }\n      throw err\n    }\n\n    const controller = new AbortController()\n    const timer = setTimeout(() => controller.abort(), timeoutMs)\n    if (typeof timer.unref === 'function') timer.unref()\n\n    try {\n      const res = await fetchImpl(url, { ...init, signal: controller.signal })\n      clearTimeout(timer)\n\n      if (res.ok || res.status < 500) {\n        // Success, or a non-retryable failure (4xx, or anything outside the\n        // 5xx retry class) — never retried (ADR-131: \"a 4xx never retries\").\n        logOutcome(provider, accountKey, sawRetry ? 'retried-then-succeeded' : 'success', method, label, attempt, startedAt)\n        return res\n      }\n\n      // 5xx — transient by assumption, retry with backoff if attempts/budget remain.\n      if (attempt >= maxAttempts) {\n        logOutcome(provider, accountKey, sawRetry ? 'retried-then-failed' : 'failed', method, label, attempt, startedAt)\n        return res\n      }\n      sawRetry = true\n      await backoff(attempt, initialBackoffMs, backoffMultiplier, maxElapsedMs - (Date.now() - startedAt))\n    } catch (err) {\n      clearTimeout(timer)\n      // Anything caught here is the fetch call itself failing — a network\n      // error or this junction's own timeout abort — the same \"network\n      // errors, and timeout\" retry class ADR-131 names alongside 5xx.\n      if (attempt >= maxAttempts) {\n        logOutcome(provider, accountKey, sawRetry ? 'retried-then-failed' : 'failed', method, label, attempt, startedAt)\n        throw err\n      }\n      sawRetry = true\n      await backoff(attempt, initialBackoffMs, backoffMultiplier, maxElapsedMs - (Date.now() - startedAt))\n    }\n  }\n}\n\n// ── dbJunction ───────────────────────────────────────────────────────────────\n\nexport interface DbJunctionPolicy {\n  /** Provider name for the rate-limit bucket and log lines — e.g. 'supabase-postgres'. */\n  provider: string\n  /** Whatever identifies one customer's account/project — the pg-path analog of JunctionPolicy.accountKey. */\n  accountKey: string\n  /** Soft timeout, ms. Default 10s. See DbJunctionTimeoutError's doc comment for what \"soft\" means here. */\n  timeoutMs?: number\n  maxAttempts?: number\n  maxElapsedMs?: number\n  initialBackoffMs?: number\n  backoffMultiplier?: number\n  rateLimit?: TokenBucketConfig\n}\n\n/**\n * A `pg` query has no portable, version-safe cancel-on-timeout the way\n * `AbortController` gives `fetch` (node-postgres's own cancel path is a\n * separate wire message, not a drop-in `signal` option on `Client#query` for\n * the version range this workspace pins — see postgres-client.ts's header\n * comment on why `pg`'s default import is used at all). `dbJunction`'s\n * timeout is therefore \"stop waiting and let the caller retry with a fresh\n * connection,\" not \"cancel the in-flight query on the wire\" — stated\n * honestly here rather than implying a cancellation guarantee this\n * dependency doesn't give.\n */\nexport class DbJunctionTimeoutError extends Error {\n  constructor(ms: number) {\n    super(`junction: db query exceeded its ${ms}ms timeout`)\n    this.name = 'DbJunctionTimeoutError'\n  }\n}\n\nfunction withTimeout<T>(run: () => Promise<T>, timeoutMs: number): Promise<T> {\n  return new Promise<T>((resolve, reject) => {\n    const timer = setTimeout(() => reject(new DbJunctionTimeoutError(timeoutMs)), timeoutMs)\n    if (typeof timer.unref === 'function') timer.unref()\n    run().then(\n      (value) => {\n        clearTimeout(timer)\n        resolve(value)\n      },\n      (err) => {\n        clearTimeout(timer)\n        reject(err)\n      },\n    )\n  })\n}\n\n// SQLSTATE classes/codes that mean \"transient — try again\": connection\n// exception (08xxx) and cannot_connect_now (57P03), plus Node's own\n// socket-level error codes for a connection that never got established at\n// all. Everything else — auth failure (28xxx), insufficient privilege\n// (42501), syntax error (42601) — is this surface's equivalent of a 4xx: a\n// bad credential or a malformed query is not a transient condition\n// (ADR-131), so it's never retried.\nconst RETRYABLE_NODE_ERROR_CODES = new Set(['ECONNREFUSED', 'ECONNRESET', 'ETIMEDOUT', 'EHOSTUNREACH', 'EAI_AGAIN', 'EPIPE'])\n\nfunction isRetryableDbError(err: unknown): boolean {\n  if (err instanceof DbJunctionTimeoutError) return true\n  const code = (err as { code?: unknown } | undefined)?.code\n  if (typeof code !== 'string') return false\n  if (code.startsWith('08') || code === '57P03') return true\n  return RETRYABLE_NODE_ERROR_CODES.has(code)\n}\n\n/**\n * The `pg`-path counterpart to `junctionFetch` (ADR-131 decision #2) —\n * same retry/backoff and per-`(provider, accountKey)` rate-limit primitives,\n * adapted to a `run()` thunk (postgres-client.ts's connect/query/end\n * sequence) instead of a `fetch` call. Each retry re-opens its own\n * connection via `run()` — it never assumes the failed attempt's socket is\n * safely reusable.\n */\nexport async function dbJunction<T>(run: () => Promise<T>, policy: DbJunctionPolicy): Promise<T> {\n  const {\n    provider,\n    accountKey,\n    timeoutMs = JUNCTION_DEFAULT_DB_TIMEOUT_MS,\n    maxAttempts = JUNCTION_DEFAULT_MAX_ATTEMPTS,\n    maxElapsedMs = JUNCTION_DEFAULT_MAX_ELAPSED_MS,\n    initialBackoffMs = JUNCTION_DEFAULT_INITIAL_BACKOFF_MS,\n    backoffMultiplier = JUNCTION_DEFAULT_BACKOFF_MULTIPLIER,\n    rateLimit = defaultRateLimitFor(provider),\n  } = policy\n\n  const startedAt = Date.now()\n  let attempt = 0\n  let sawRetry = false\n\n  for (;;) {\n    attempt++\n    const remainingBudget = maxElapsedMs - (Date.now() - startedAt)\n    if (remainingBudget <= 0) {\n      logOutcome(provider, accountKey, 'retried-then-failed', 'QUERY', 'db', attempt - 1, startedAt)\n      throw new Error(\n        `junction: ${provider}:${accountKey} db query exceeded its wall-clock budget (${maxElapsedMs}ms) after ${attempt - 1} attempt(s)`,\n      )\n    }\n\n    try {\n      await acquireToken(provider, accountKey, rateLimit, remainingBudget)\n    } catch (err) {\n      if (err instanceof RateLimitExceededError) {\n        logOutcome(provider, accountKey, 'rate-limited', 'QUERY', 'db', attempt, startedAt)\n      }\n      throw err\n    }\n\n    try {\n      const result = await withTimeout(run, timeoutMs)\n      logOutcome(provider, accountKey, sawRetry ? 'retried-then-succeeded' : 'success', 'QUERY', 'db', attempt, startedAt)\n      return result\n    } catch (err) {\n      if (!isRetryableDbError(err) || attempt >= maxAttempts) {\n        logOutcome(provider, accountKey, sawRetry ? 'retried-then-failed' : 'failed', 'QUERY', 'db', attempt, startedAt)\n        throw err\n      }\n      sawRetry = true\n      await backoff(attempt, initialBackoffMs, backoffMultiplier, maxElapsedMs - (Date.now() - startedAt))\n    }\n  }\n}\n","// The Supabase connector (docs/connectors/supabase.md, ADR-124) — the\n// connectors plane's first provider. poll() pulls both surfaces\n// supabase.md §Surfaces used specifies: the Management API's edge_logs query\n// (client.ts, mapped by map.ts's mapEdgeLogRowsToSignals) always, and a\n// direct pg_stat_statements read (postgres-client.ts, mapped by map.ts's\n// diffPgStatStatementsToSignals) only when `ctx.credentials.postgresConnectionString`\n// is present — its absence is how the hosted profile's documented\n// \"log-surface-only\" first cut (supabase.md §Scope) falls out of this same\n// poll() with no profile-conditional branch (connectors.md §3). Target\n// resolution — preferring the table/RPC InfraNode a future extractor cut\n// will mint, falling back to the project-level InfraNode the current\n// extractor already does — lives in resolve.ts. Everything downstream of\n// resolution (minting the OBSERVED edge) is the shared connectors/index.ts\n// pipeline; this module never touches the graph directly (ADR-030).\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport { boundedSupabaseLogWindow, fetchSupabaseEdgeLogs } from './client.js'\nimport { diffPgStatStatementsToSignals, mapEdgeLogRowsToSignals, type StatementBaseline } from './map.js'\nimport { fetchPgStatStatements, DEFAULT_STATEMENT_LIMIT } from './postgres-client.js'\nimport { createSupabaseResolveTarget } from './resolve.js'\nimport { readSupabaseCredentials, type SupabaseConnectorConfig } from './types.js'\n\nexport type {\n  PgStatStatementsRow,\n  SupabaseConnectorConfig,\n  SupabaseCredentials,\n  SupabaseEdgeLogRow,\n  SupabaseLogsAllResponse,\n} from './types.js'\nexport { readSupabaseCredentials, SUPABASE_RPC_TARGET_KIND, SUPABASE_TABLE_TARGET_KIND } from './types.js'\nexport {\n  boundedSupabaseLogWindow,\n  DEFAULT_LOG_LIMIT,\n  DEFAULT_SUPABASE_MANAGEMENT_API_URL,\n  fetchSupabaseEdgeLogs,\n  SUPABASE_LOG_QUERY_MAX_WINDOW_MS,\n} from './client.js'\nexport { DEFAULT_STATEMENT_LIMIT, fetchPgStatStatements } from './postgres-client.js'\nexport {\n  diffPgStatStatementsToSignals,\n  mapEdgeLogRowsToSignals,\n  tableNameFromQueryText,\n  targetFromRestPath,\n  type StatementBaseline,\n} from './map.js'\nexport { createSupabaseResolveTarget } from './resolve.js'\n\n// supabase.md's own \"24h window\" governs `boundedSupabaseLogWindow` — this is\n// only the connector-level default passed in when a caller doesn't override\n// `config.maxLookbackMs`; the window is hard-capped at\n// SUPABASE_LOG_QUERY_MAX_WINDOW_MS regardless (client.ts).\nconst DEFAULT_MAX_LOOKBACK_MS = 24 * 60 * 60 * 1000\n\nexport interface SupabaseConnectorDeps {\n  fetchPgStatStatements?: typeof fetchPgStatStatements\n  onPostgresSurfaceError?: (err: unknown, summary: string) => void\n}\n\nfunction errorCode(err: unknown): string | undefined {\n  const code = (err as { code?: unknown } | undefined)?.code\n  return typeof code === 'string' && code.length > 0 ? code : undefined\n}\n\nexport function describeSupabasePostgresSurfaceFailure(projectRef: string, err: unknown): string {\n  const code = errorCode(err)\n  let reason: string\n  switch (code) {\n    case '42501':\n      reason = 'permission denied; grant pg_read_all_stats to the configured Postgres role'\n      break\n    case '42P01':\n    case '42704':\n      reason = 'pg_stat_statements is not enabled or visible to the configured Postgres role'\n      break\n    case '28P01':\n    case '28000':\n      reason = 'Postgres credential rejected'\n      break\n    case '3D000':\n      reason = 'database not found'\n      break\n    default: {\n      const name = err instanceof Error && err.name ? err.name : 'Error'\n      reason = code ? `${name} ${code}` : name\n    }\n  }\n  return (\n    `supabase connector: pg_stat_statements surface unavailable for project ${projectRef} ` +\n    `(${reason}); continuing with Management API log surface.`\n  )\n}\n\nexport class SupabaseConnector implements ObservedConnector {\n  readonly provider = 'supabase'\n\n  // pg_stat_statements.calls is cumulative, not per-window (map.ts's\n  // diffPgStatStatementsToSignals doc comment) — this Map carries the\n  // previous poll's counts across ticks, the same way\n  // `startConnectorPollLoop` (connectors/index.ts) carries `since` across\n  // ticks for every connector. Lives on the instance, not `ConnectorContext`,\n  // because `ConnectorContext` is rebuilt fresh per tick (connectors/index.ts's\n  // `{ ...ctx, since }`) while this connector object is the one thing every\n  // tick shares.\n  private readonly statementBaselines = new Map<string, StatementBaseline>()\n\n  // `deps.fetchPgStatStatements` defaults to the real Postgres-backed\n  // implementation; tests override it to exercise the \"both surfaces\n  // combine\" and \"surface 2 only runs when a connection string is present\"\n  // behavior without a live database — the same dependency-injection seam\n  // `fetchImpl` gives cloudflare/client.ts's tests for `fetch`.\n  constructor(\n    private readonly config: SupabaseConnectorConfig,\n    private readonly deps: SupabaseConnectorDeps = {},\n  ) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const creds = readSupabaseCredentials(ctx.credentials)\n    const now = new Date()\n    const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS\n    const { startIso, endIso } = boundedSupabaseLogWindow(ctx.since, now, maxLookbackMs)\n\n    const logRows = await fetchSupabaseEdgeLogs(this.config, creds.managementToken, startIso, endIso)\n    const signals: ObservedSignal[] = mapEdgeLogRowsToSignals(logRows)\n\n    // Surface 2 only runs when a Postgres connection string is present —\n    // supabase.md §Scope's local-profile-only-for-now split, expressed\n    // entirely through what `ctx.credentials` carries rather than a\n    // profile-conditional branch in this method (connectors.md §3).\n    if (creds.postgresConnectionString) {\n      const fetchStatements = this.deps.fetchPgStatStatements ?? fetchPgStatStatements\n      try {\n        const statementRows = await fetchStatements(\n          creds.postgresConnectionString,\n          this.config.statementLimit ?? DEFAULT_STATEMENT_LIMIT,\n          this.config.apiProjectRef,\n        )\n        signals.push(...diffPgStatStatementsToSignals(statementRows, this.statementBaselines, now.toISOString()))\n      } catch (err) {\n        const summary = describeSupabasePostgresSurfaceFailure(this.config.apiProjectRef, err)\n        if (this.deps.onPostgresSurfaceError) this.deps.onPostgresSurfaceError(err, summary)\n        else console.warn(summary)\n      }\n    }\n\n    return signals\n  }\n}\n\n/**\n * Wires up a ready-to-register Supabase connector: the `ObservedConnector`\n * plus the `resolveTarget` callback `runConnectorPoll` /\n * `startConnectorPollLoop` (connectors/index.ts) need alongside it. Built\n * together because `resolveTarget` closes over `graph` — the shared\n * scaffold's `ResolveConnectorTarget` signature (index.ts) never receives it\n * directly — the same pairing `createFirebaseConnector` uses.\n */\nexport function createSupabaseConnector(\n  graph: NeatGraph,\n  config: SupabaseConnectorConfig,\n  deps: SupabaseConnectorDeps = {},\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new SupabaseConnector(config, deps),\n    resolveTarget: createSupabaseResolveTarget(graph, config),\n  }\n}\n","// Management API log-query client (docs/connectors/supabase.md §Surfaces\n// used #1). Read-only, ambient — this issues one query per poll tick against\n// telemetry Supabase already collects for every Cloud project (edge_logs),\n// never a synthetic request against the project itself (connectors.md §2).\n//\n// GET https://api.supabase.com/v1/projects/{ref}/analytics/endpoints/logs.all\n// — confirmed live against api.supabase.com/api/v1-json (operationId\n// `v1-get-project-logs-all`) during this connector's build: a GET request\n// with `sql` / `iso_timestamp_start` / `iso_timestamp_end` as query-string\n// parameters, not a POST with a JSON body. The endpoint is marked\n// `deprecated: true` in that spec but remains the documented, currently\n// reachable surface — see types.ts's header comment for the full citation\n// list and the open dialect question this connector's SQL still needs\n// live-project confirmation against.\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type {\n  SupabaseConnectorConfig,\n  SupabaseEdgeLogRow,\n  SupabaseLogsAllResponse,\n} from './types.js'\n\nexport const DEFAULT_SUPABASE_MANAGEMENT_API_URL = 'https://api.supabase.com'\n\n// supabase.com/docs/guides/telemetry/logs's \"LIMIT and result row limitations\"\n// section: \"The Logs Explorer has a maximum of 1000 rows per run.\"\nexport const DEFAULT_LOG_LIMIT = 1000\n\n// The OpenAPI description for this endpoint: \"The timestamp range must be no\n// more than 24 hours and is rounded to the nearest minute. If the range is\n// more than 24 hours, a validation error will be thrown.\" A hard provider\n// ceiling, not merely a connector default — bounds `boundedSupabaseLogWindow`\n// below regardless of `config.maxLookbackMs`.\nexport const SUPABASE_LOG_QUERY_MAX_WINDOW_MS = 24 * 60 * 60 * 1000\n\n/**\n * `since` bounded by the provider's max lookback window (docs/contracts/\n * connectors.md §\"Poll cadence and backfill\") — a gap wider than the window\n * (a laptop off for a week) backfills from `now - window`, never an\n * unbounded full-history replay. `truncated` is true whenever the effective\n * start got clipped to the window floor rather than reflecting `since`\n * verbatim, so callers can log the gap being lossily capped rather than\n * silently swallowing it.\n */\nexport function boundedSupabaseLogWindow(\n  since: string | undefined,\n  now: Date,\n  maxLookbackMs: number,\n): { startIso: string; endIso: string; truncated: boolean } {\n  const window = Math.min(maxLookbackMs, SUPABASE_LOG_QUERY_MAX_WINDOW_MS)\n  const floor = new Date(now.getTime() - window)\n  const endIso = now.toISOString()\n  if (!since) return { startIso: floor.toISOString(), endIso, truncated: false }\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return { startIso: floor.toISOString(), endIso, truncated: false }\n  if (sinceMs < floor.getTime()) return { startIso: floor.toISOString(), endIso, truncated: true }\n  return { startIso: new Date(sinceMs).toISOString(), endIso, truncated: false }\n}\n\n// The flat projection this connector needs out of edge_logs's nested\n// metadata.request/metadata.response arrays — field names confirmed against\n// worked examples on supabase.com/docs/guides/telemetry/logs,\n// .../advanced-log-filtering, and\n// .../troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9\n// (all fetched during this build). `regexp_contains(request.path, ...)`\n// narrows to the PostgREST surface (`/rest/v1/...`) this connector's fusion\n// targets — Auth/Storage/Realtime/Functions traffic on the same project is\n// out of scope (supabase.md §Out of scope) and excluded here rather than\n// fetched and dropped client-side. `FORMAT_TIMESTAMP` renders a strict\n// ISO8601 UTC string so map.ts never has to guess a timezone.\nfunction buildEdgeLogsQuery(limit: number): string {\n  const safeLimit = Math.max(1, Math.trunc(limit) || DEFAULT_LOG_LIMIT)\n  return [\n    'select',\n    \"  format_timestamp('%Y-%m-%dT%H:%M:%E6SZ', timestamp) as timestamp,\",\n    '  request.method as method,',\n    '  request.path as path,',\n    '  response.status_code as status_code',\n    'from edge_logs',\n    'cross join unnest(metadata) as metadata',\n    'cross join unnest(metadata.request) as request',\n    'cross join unnest(metadata.response) as response',\n    \"where regexp_contains(request.path, '^/rest/v1/')\",\n    'order by timestamp asc',\n    `limit ${safeLimit}`,\n  ].join('\\n')\n}\n\nfunction logsAllHttpFailureMessage(status: number): string {\n  if (status === 401 || status === 403) {\n    return (\n      `supabase connector: logs.all request rejected (HTTP ${status}). ` +\n      'Check the Management API token, its analytics read scope, and --api-project-ref.'\n    )\n  }\n  if (status === 404) {\n    return 'supabase connector: logs.all project not found (HTTP 404). Check --api-project-ref.'\n  }\n  if (status === 429) {\n    return (\n      'supabase connector: logs.all rate-limited (HTTP 429). ' +\n      'The connector will retry on the next poll; reduce poll cadence if this persists.'\n    )\n  }\n  if (status === 400) {\n    return (\n      'supabase connector: logs.all query rejected (HTTP 400). ' +\n      'Provider details redacted; confirm the live log-query dialect before shipping this connector.'\n    )\n  }\n  return `supabase connector: logs.all request failed (HTTP ${status}); provider details redacted.`\n}\n\nfunction providerErrorDetails(error: SupabaseLogsAllResponse['error']): string {\n  if (!error || typeof error === 'string') return ''\n  const parts: string[] = []\n  if (typeof error.code === 'number') parts.push(`code ${error.code}`)\n  if (typeof error.status === 'string' && /^[A-Z0-9_.-]+$/.test(error.status)) {\n    parts.push(`status ${error.status}`)\n  }\n  return parts.length > 0 ? ` (${parts.join(', ')})` : ''\n}\n\nexport async function fetchSupabaseEdgeLogs(\n  config: SupabaseConnectorConfig,\n  token: string,\n  startIso: string,\n  endIso: string,\n  fetchImpl: typeof fetch = fetch,\n): Promise<SupabaseEdgeLogRow[]> {\n  const baseUrl = config.managementApiUrl ?? DEFAULT_SUPABASE_MANAGEMENT_API_URL\n  const url = new URL(`${baseUrl}/v1/projects/${config.apiProjectRef}/analytics/endpoints/logs.all`)\n  url.searchParams.set('sql', buildEdgeLogsQuery(config.logLimit ?? DEFAULT_LOG_LIMIT))\n  url.searchParams.set('iso_timestamp_start', startIso)\n  url.searchParams.set('iso_timestamp_end', endIso)\n\n  const res = await junctionFetch(\n    url,\n    { method: 'GET', headers: bearerAuthHeader(token) },\n    // accountKey: the Supabase project ref (ADR-131's own worked example) —\n    // the Management API's rate limit is enforced per project.\n    { provider: 'supabase', accountKey: config.apiProjectRef, fetchImpl },\n  )\n  if (!res.ok) {\n    throw new Error(logsAllHttpFailureMessage(res.status))\n  }\n  let body: SupabaseLogsAllResponse\n  try {\n    body = (await res.json()) as SupabaseLogsAllResponse\n  } catch {\n    throw new Error('supabase connector: logs.all returned invalid JSON; provider details redacted.')\n  }\n  if (body.error) {\n    throw new Error(\n      `supabase connector: logs.all returned a provider error${providerErrorDetails(body.error)}; provider message redacted.`,\n    )\n  }\n  return body.result ?? []\n}\n","// Maps both Supabase surfaces to ObservedSignal[] (docs/connectors/\n// supabase.md §Fusion, ADR-124). Two independent producers feed the same\n// signal vocabulary (SUPABASE_TABLE_TARGET_KIND / SUPABASE_RPC_TARGET_KIND):\n//\n//   1. edge_logs rows (client.ts) — the request path names the table/RPC\n//      directly (`/rest/v1/<table>` / `/rest/v1/rpc/<fn>`), so this mapping\n//      is a straight parse, aggregated per (kind, name) the same bucketing\n//      shape railway/connector.ts uses for httpLogs.\n//   2. pg_stat_statements rows (postgres-client.ts) — carries no table\n//      column at all (postgresql.org/docs/current/pgstatstatements.html: \"the\n//      view provides no table-level identification columns\"), only raw query\n//      text, and its counters are lifetime cumulative, not per-poll-window —\n//      so this mapping both extracts a table name from a recognized\n//      PostgREST-shaped query and diffs against the previous poll's counts to\n//      turn a cumulative total into this window's delta.\n\nimport { columnsFromSqlStatement } from '../../otel.js'\nimport type { ObservedSignal } from '../types.js'\nimport { SUPABASE_RPC_TARGET_KIND, SUPABASE_TABLE_TARGET_KIND, type PgStatStatementsRow, type SupabaseEdgeLogRow } from './types.js'\n\n// ── Surface 1: edge_logs → ObservedSignal[] ─────────────────────────────────\n\n// `/rest/v1/rpc/<fn>` must be checked before the bare table pattern — every\n// RPC path is also a `/rest/v1/...` path, so checking table-shape first would\n// misclassify every RPC call as a table named `rpc`.\nconst REST_RPC_PATH_RE = /^\\/rest\\/v1\\/rpc\\/([^/?]+)/\nconst REST_TABLE_PATH_RE = /^\\/rest\\/v1\\/([^/?]+)/\n\ninterface RestTarget {\n  targetKind: typeof SUPABASE_TABLE_TARGET_KIND | typeof SUPABASE_RPC_TARGET_KIND\n  name: string\n}\n\n// Exported for direct testing of the path-parsing rule supabase.md §Fusion\n// specifies verbatim (\"`/rest/v1/orders` → table `orders`, `/rest/v1/rpc/\n// get_totals` → RPC `get_totals`\"). Returns null for anything else this\n// connector's edge_logs query shouldn't even have returned (its own `where\n// regexp_contains(path, '^/rest/v1/')` filter already narrows to this\n// prefix) but is checked again here rather than trusting the query alone —\n// the same \"never trust the filter alone\" discipline firebase/map.ts states\n// for its own resource-type check.\nexport function targetFromRestPath(path: string): RestTarget | null {\n  const rpcMatch = REST_RPC_PATH_RE.exec(path)\n  if (rpcMatch) return { targetKind: SUPABASE_RPC_TARGET_KIND, name: rpcMatch[1]! }\n  const tableMatch = REST_TABLE_PATH_RE.exec(path)\n  if (tableMatch) return { targetKind: SUPABASE_TABLE_TARGET_KIND, name: tableMatch[1]! }\n  return null\n}\n\n// 5xx is the unambiguous failure threshold, the same convention firebase/\n// map.ts and cloudflare/map.ts already use for their own status-code signals\n// (a bare 4xx is often correct PostgREST behavior — a RLS-denied read, a\n// not-found row — not necessarily a service defect).\nconst ERROR_STATUS_THRESHOLD = 500\n\ninterface Bucket {\n  targetKind: RestTarget['targetKind']\n  targetName: string\n  callCount: number\n  errorCount: number\n  lastObservedIso: string\n}\n\nexport function mapEdgeLogRowsToSignals(rows: SupabaseEdgeLogRow[]): ObservedSignal[] {\n  const buckets = new Map<string, Bucket>()\n  if (!Array.isArray(rows)) return []\n\n  for (const row of rows) {\n    // A shape-drifted response can carry a null/garbage slot or a row missing\n    // the path/timestamp a signal needs — drop it honestly rather than\n    // throwing (connectors.md §4). Timestamp is required: a signal claiming an\n    // observation with no time to stand on isn't a truthful one (the same\n    // `if (!timestamp) return null` firebase/map.ts already applies).\n    if (!row || typeof row !== 'object') continue\n    if (typeof row.path !== 'string' || typeof row.timestamp !== 'string') continue\n    const target = targetFromRestPath(row.path)\n    // Not a `/rest/v1/...` PostgREST path — Auth/Storage/Realtime/Functions\n    // traffic on the same project, out of scope for this cut (supabase.md\n    // §Out of scope). Dropped honestly, never forced through as a guessed\n    // table/RPC name.\n    if (!target) continue\n\n    const key = `${target.targetKind}:${target.name}`\n    const isError = row.status_code >= ERROR_STATUS_THRESHOLD\n    const existing = buckets.get(key)\n    if (existing) {\n      existing.callCount += 1\n      if (isError) existing.errorCount += 1\n      if (row.timestamp > existing.lastObservedIso) existing.lastObservedIso = row.timestamp\n    } else {\n      buckets.set(key, {\n        targetKind: target.targetKind,\n        targetName: target.name,\n        callCount: 1,\n        errorCount: isError ? 1 : 0,\n        lastObservedIso: row.timestamp,\n      })\n    }\n  }\n\n  return [...buckets.values()].map((b) => ({\n    targetKind: b.targetKind,\n    targetName: b.targetName,\n    callCount: b.callCount,\n    errorCount: b.errorCount,\n    lastObservedIso: b.lastObservedIso,\n  }))\n}\n\n// ── Surface 2: pg_stat_statements → ObservedSignal[] ────────────────────────\n\n// PostgREST always issues a fully schema-qualified, double-quoted-identifier\n// query per request (`... FROM \"public\".\"orders\" ...`, or bare `\"orders\"`\n// without a schema qualifier depending on search_path) — a recognizable,\n// mechanical shape, the same \"framework-aware, not a bare guess\" discipline\n// extract/calls/supabase.ts itself applies to a JS call site, just applied to\n// generated SQL text here instead. A query whose FROM target doesn't match\n// this shape (a user-defined Postgres function's own internal query, a\n// migration, an ORM issuing something else entirely) is dropped honestly —\n// pg_stat_statements carries no table column to fall back on\n// (postgresql.org/docs/current/pgstatstatements.html), so guessing past a\n// parse miss here would fabricate a target, not infer one.\nconst FROM_TABLE_RE = /\\bfrom\\s+\"?(?:[a-z_][a-z0-9_]*\"?\\.)?\"?([a-z_][a-z0-9_]*)\"?/i\nconst SYSTEM_SCHEMA_PREFIXES = ['pg_', 'information_schema']\n\nexport function tableNameFromQueryText(query: string): string | null {\n  const match = FROM_TABLE_RE.exec(query)\n  if (!match) return null\n  const name = match[1]!\n  const lower = name.toLowerCase()\n  if (SYSTEM_SCHEMA_PREFIXES.some((prefix) => lower.startsWith(prefix))) return null\n  return name\n}\n\nexport interface StatementBaseline {\n  calls: number\n}\n\n/**\n * `pg_stat_statements.calls` is a lifetime cumulative counter, not a per-poll\n * count — replaying it verbatim every tick would re-mint the statement's\n * entire history as \"this window's calls\" on every single poll, ballooning\n * without bound. This diffs each row's `calls` against the previous poll's\n * value for the same `queryid`, carried in `previous` (owned by the\n * connector instance across ticks — see index.ts) and mutated in place:\n *\n * - A `queryid` seen for the first time only establishes a baseline this\n *   tick — no signal, since there is no \"since last poll\" value yet to\n *   subtract from (never replay a statement's full lifetime history as if it\n *   were one window's activity, the same bounded-lookback discipline every\n *   other connector applies to its own `since` watermark).\n * - A `queryid` whose `calls` decreased since the last poll (a Postgres\n *   restart, an explicit `pg_stat_statements_reset()`) is treated as a fresh\n *   baseline the same way — a negative delta is never fabricated into a\n *   signal.\n * - A `queryid` that drops out of this poll's rows entirely (evicted past\n *   `pg_stat_statements.max`, or simply out-ranked by busier statements past\n *   `statementLimit`) has its baseline removed, so a later reappearance\n *   starts fresh rather than diffing against stale state.\n *\n * `errorCount` is always 0 — pg_stat_statements carries no failure signal for\n * a statement (no distinction between a successful and a failed execution in\n * its own columns), so this is never fabricated.\n *\n * `lastObservedIso` uses the poll tick's own wall-clock time, not a\n * provider-supplied event time — unlike every other signal in this codebase.\n * pg_stat_statements has no per-row timestamp at all (it's a cumulative\n * counter snapshot, not an event log), so there is no provider event time to\n * read; the poll tick is the closest honest proxy for \"this activity was\n * observed as of this counter snapshot,\" the same tick-start-time convention\n * `startConnectorPollLoop` (connectors/index.ts) already uses for its own\n * `since` bookkeeping.\n */\nexport function diffPgStatStatementsToSignals(\n  rows: PgStatStatementsRow[],\n  previous: Map<string, StatementBaseline>,\n  nowIso: string,\n): ObservedSignal[] {\n  const signals: ObservedSignal[] = []\n  const seen = new Set<string>()\n  if (!Array.isArray(rows)) return signals\n\n  for (const row of rows) {\n    // Drop a null/garbage slot or a row with no usable queryid honestly rather\n    // than throwing on `.queryid` (connectors.md §4).\n    if (!row || typeof row !== 'object' || typeof row.queryid !== 'string') continue\n    const calls = Number(row.calls)\n    // A non-numeric `calls` (shape drift) can't produce an honest delta — skip\n    // it entirely rather than diffing NaN into a NaN-valued callCount signal\n    // the downstream pipeline would mis-tally (gate #8 truthful counts).\n    if (!Number.isFinite(calls)) continue\n\n    seen.add(row.queryid)\n    const prior = previous.get(row.queryid)\n    previous.set(row.queryid, { calls })\n\n    if (!prior || calls < prior.calls) continue // fresh baseline this tick, no signal\n    const delta = calls - prior.calls\n    if (delta <= 0) continue\n\n    const table = tableNameFromQueryText(row.query)\n    if (!table) continue // can't honestly attribute a table — dropped, never guessed\n\n    // ADR-157 — the same PostgREST-shaped query text names the columns it\n    // touched; carry them (shared parser, not a second copy) so the pipeline\n    // merges them onto the table node as OBSERVED column attributes. Empty for a\n    // shape `columnsFromSqlStatement` degrades on.\n    const columns = columnsFromSqlStatement(row.query)\n    signals.push({\n      targetKind: SUPABASE_TABLE_TARGET_KIND,\n      targetName: table,\n      callCount: delta,\n      errorCount: 0,\n      lastObservedIso: nowIso,\n      ...(columns.length > 0 ? { columns } : {}),\n    })\n  }\n\n  for (const queryid of [...previous.keys()]) {\n    if (!seen.has(queryid)) previous.delete(queryid)\n  }\n\n  return signals\n}\n","// Supabase connector — provider-specific types (docs/connectors/supabase.md,\n// ADR-124). First connectors-plane provider; the shared pull/map/fuse\n// scaffold (connectors/index.ts) and the three sibling providers (Railway,\n// Firebase, Cloudflare) already landed on main — this module follows their\n// fetch/map/resolve split.\n//\n// Scope per supabase.md: Supabase Cloud only, two surfaces —\n//   1. the Management API's log-query endpoint over edge_logs (table/RPC\n//      grain from the REST request path, both credential profiles)\n//   2. a direct, read-only Postgres connection reading pg_stat_statements\n//      (local profile from day one; hosted is a fast-follow pending a\n//      customer-provisioned least-privilege role — supabase.md §Scope)\n//\n// Every field name below was confirmed against Supabase's own live docs\n// during this connector's build, not recalled from training data:\n//   - endpoint + request/response envelope (GET, not POST — confirmed\n//     against the live OpenAPI spec at https://api.supabase.com/api/v1-json,\n//     operationId `v1-get-project-logs-all`, `deprecated: true` but still the\n//     documented and currently-working surface): query params `sql` /\n//     `iso_timestamp_start` / `iso_timestamp_end`, response `{ result, error }`\n//   - edge_logs row shape (`metadata[].request.{method,path}`,\n//     `metadata[].response.status_code`): supabase.com/docs/guides/telemetry/logs,\n//     .../advanced-log-filtering, and\n//     .../troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9\n//     (all fetched during this build — each shows a worked `cross join\n//     unnest(...)` query selecting exactly these fields)\n//   - 24h window cap + 1000-row cap: the logs guide's own \"LIMIT and result\n//     row limitations\" section (\"a maximum of 1000 rows per run\") and the\n//     OpenAPI description's \"timestamp range must be no more than 24 hours\"\n//   - pg_stat_statements column names: postgresql.org/docs/current/pgstatstatements.html\n// Anything not directly confirmed by those pages is flagged inline as\n// needs-endpoint-testing, the same discipline railway/types.ts uses.\n\n/**\n * `ConnectorContext.credentials` shape for this provider. Both fields are\n * genuine secrets (contracts.md §6 — never logged, never written to a node\n * or edge, never reaches the snapshot):\n *\n * - `managementToken` — a bearer token for the Management API's log-query\n *   surface. The connector doesn't need to know which kind: a developer's own\n *   personal access token (`sbp_...`) locally, or an OAuth-app token for the\n *   hosted profile. The exact OAuth scope that gates the `logs.all` endpoint is\n *   NOT confirmed (#792): Supabase's public OAuth taxonomy is resource-level\n *   (`projects`, `database`, `rest`, … each `:read`/`:write`) with no\n *   analytics- or logs-specific scope, so the log query most likely rides\n *   `projects:read` rather than any `analytics:read`. Treat the precise gating\n *   scope as needs-endpoint-testing against a live OAuth token — a personal\n *   access token sidesteps the question locally either way.\n * - `postgresConnectionString` — optional. Present only when this connector\n *   instance should also poll pg_stat_statements (the local profile, which\n *   already holds a full database credential for its own project). Its\n *   absence is exactly how the hosted profile's \"log-surface-only\" first cut\n *   (supabase.md §Scope) falls out of this same code path, with no\n *   profile-conditional branch in the connector logic itself (connectors.md\n *   §3 — profile changes credential source, never pull/map/fuse logic).\n */\nexport interface SupabaseCredentials {\n  managementToken: string\n  postgresConnectionString?: string\n}\n\nexport function readSupabaseCredentials(raw: Record<string, unknown>): SupabaseCredentials {\n  const managementToken = raw['managementToken']\n  if (typeof managementToken !== 'string' || managementToken.length === 0) {\n    throw new Error('supabase connector: credentials.managementToken must be a non-empty string')\n  }\n  const postgresConnectionString = raw['postgresConnectionString']\n  if (\n    postgresConnectionString !== undefined &&\n    (typeof postgresConnectionString !== 'string' || postgresConnectionString.length === 0)\n  ) {\n    throw new Error(\n      'supabase connector: credentials.postgresConnectionString must be a non-empty string when present',\n    )\n  }\n  return {\n    managementToken,\n    ...(postgresConnectionString ? { postgresConnectionString } : {}),\n  }\n}\n\n/**\n * Config resolved once at connector setup (never re-derived from a response\n * at poll time, the same \"resolved once, never guessed\" discipline ADR-127\n * states for Railway's serviceNameById).\n */\nexport interface SupabaseConnectorConfig {\n  // The real Supabase project ref — a 20-character lowercase string\n  // (confirmed against the live OpenAPI path-parameter schema:\n  // `minLength: 20, maxLength: 20, pattern: \"^[a-z]+$\"`) — used as the `{ref}`\n  // path segment calling the Management API. This is NOT necessarily the same\n  // string as `nodeRef` below; see that field's own doc comment for why the\n  // two are kept separate.\n  apiProjectRef: string\n  // The exact node-identity token this project resolves to under\n  // `extract/calls/supabase.ts`'s own scheme (supabase.md §Fusion): either\n  // the literal `*.supabase.co` host from a `createClient(...)` call\n  // (`\"<apiProjectRef>.supabase.co\"` in the common case, since a Supabase\n  // project's URL is always that shape) or the literal string `'env'` when\n  // the app's code passes a non-literal URL (`process.env.SUPABASE_URL`).\n  // Kept as an explicit, separate field — never derived by string-\n  // concatenating `apiProjectRef` + `.supabase.co` here — because that\n  // derivation would silently be wrong for the (very common) env-driven case,\n  // and this identity has to match the extractor's own resolution exactly or\n  // fusion never lands (identity.md — ids constructed via the shared\n  // `infraId` helper, never guessed at by a second producer).\n  nodeRef: string\n  // The NEAT manifest service name this connector's signals attribute the\n  // OBSERVED CALLS edge's source to. Supabase's own telemetry carries no\n  // caller-service dimension at all on either surface (both are project- or\n  // database-scoped, not per-caller), unlike Railway's per-service httpLogs\n  // or Firebase's per-resource Cloud Logging entries — so there is no signal\n  // to map from; this is supplied once, honestly, rather than guessed.\n  serviceName: string\n  // Management API base URL override, for tests. Defaults to the real host.\n  managementApiUrl?: string\n  // Cap on how far an absent `since` (or a gap wider than this window, e.g. a\n  // laptop off for a week) backfills, ms. Hard-capped at 24h regardless of\n  // this value — the Management API's own documented maximum query window\n  // (supabase.md §Surfaces, confirmed against the live OpenAPI description\n  // above) — a caller passing a larger value here still only ever gets a\n  // last-24h query.\n  maxLookbackMs?: number\n  // Rows requested per log query. Defaults to 1000, the Logs Explorer's own\n  // documented per-run maximum (see this file's header) — raising this above\n  // 1000 has no effect since the provider caps it there regardless.\n  logLimit?: number\n  // Max pg_stat_statements rows read per poll (surface 2), ordered by `calls`\n  // descending so the busiest statements are never starved by an unbounded\n  // table falling off a smaller cap. A defensive bound, not a documented\n  // Postgres limit — pg_stat_statements can grow to `pg_stat_statements.max`\n  // (default 5000) distinct statements on a busy project.\n  statementLimit?: number\n}\n\n// ── Surface 1: Management API log query ────────────────────────────────────\n\n// AnalyticsResponse per the live OpenAPI spec's `components.schemas` — `result`\n// is typed `array of {}` there (an intentionally untyped passthrough of\n// whatever the underlying query returns); the concrete row shape below is\n// this connector's own SQL's flat projection (see client.ts's query string),\n// not the full nested `edge_logs` row.\nexport interface SupabaseLogsAllResponse {\n  result?: SupabaseEdgeLogRow[]\n  error?:\n    | string\n    | {\n        code: number\n        message: string\n        status: string\n        errors: { domain: string; location: string; locationType: string; message: string; reason: string }[]\n      }\n}\n\n/**\n * One row of this connector's own flat SQL projection over `edge_logs`\n * (client.ts) — not the raw nested log row Supabase stores (which nests\n * `request`/`response` inside a repeated `metadata` field, requiring\n * `cross join unnest(...)` to reach). `timestamp` is formatted to a strict\n * ISO8601 UTC string inside the SQL itself (`FORMAT_TIMESTAMP(...)`) so this\n * connector never has to guess a timezone client-side.\n *\n * needs-endpoint-testing: Supabase's own docs (surfaced during this build)\n * disagree with themselves on the query dialect this endpoint accepts —\n * every worked example on supabase.com/docs uses BigQuery syntax\n * (`cross join unnest`, `regexp_contains`, `cast(... as datetime)`), which is\n * what the query in client.ts is written in, but at least one indexed source\n * describes this endpoint as running \"ClickHouse SQL\" instead. Both dialects\n * support `cross join unnest`-style array flattening, but the exact function\n * names (`FORMAT_TIMESTAMP` vs a ClickHouse equivalent) could differ. Build\n * this against a live Supabase project before treating the query string as\n * locked, exactly as railway/types.ts's own needs-endpoint-testing notes ask\n * for every other unconfirmed surface in this codebase.\n */\nexport interface SupabaseEdgeLogRow {\n  timestamp: string\n  method: string\n  path: string\n  status_code: number\n}\n\n// ── Surface 2: pg_stat_statements ───────────────────────────────────────────\n\n/**\n * One row of `pg_stat_statements`, the subset this connector reads\n * (postgresql.org/docs/current/pgstatstatements.html, Table F.22). Reading\n * `query`/`queryid` for statements another role executed requires the\n * connecting role to hold `pg_read_all_stats` or superuser — exactly the\n * built-in role supabase.md §Surfaces names as available on every Supabase\n * Cloud project without needing `service_role` or the project's admin\n * `postgres` role.\n *\n * `queryid`, `calls`, and `rows` are Postgres `bigint` columns; node-postgres\n * returns `bigint` as a JS `string` by default (no custom type parser\n * configured here) to avoid silent precision loss on values past\n * `Number.MAX_SAFE_INTEGER` — map.ts's diffing logic accounts for this.\n * `total_exec_time` is `double precision`, which node-postgres does return as\n * a native JS `number`.\n */\nexport interface PgStatStatementsRow {\n  queryid: string\n  query: string\n  calls: string\n  total_exec_time: number\n  rows: string\n}\n\n// Provider vocabulary for ObservedSignal.targetKind/targetName (connectors.md\n// §1 — \"the provider's own vocabulary\"; only this connector's own map.ts /\n// resolve.ts ever interpret these strings). Matches the `infraId` kind\n// literals ADR-124 §5 specifies for Supabase sub-resources.\nexport const SUPABASE_TABLE_TARGET_KIND = 'supabase-table'\nexport const SUPABASE_RPC_TARGET_KIND = 'supabase-rpc'\n","// pg_stat_statements direct-Postgres client (docs/connectors/supabase.md\n// §Surfaces used #2). Read-only, ambient — a single SELECT against a system\n// view Postgres already maintains; this connector never writes to the\n// database it polls (connectors.md §2).\n//\n// Uses `pg` (node-postgres) — already a real dependency elsewhere in this\n// workspace (demo/service-b, e2e/capture/app) rather than a new client\n// library choice. `import pg from 'pg'` (default import, then destructure)\n// rather than `import { Client } from 'pg'`: `pg`'s CJS build doesn't\n// consistently expose static named exports across the major versions this\n// workspace already carries (demo/service-b pins 7.4.0; e2e/capture/app pins\n// ^8.12.0), so the default-import-then-destructure form node-postgres's own\n// docs recommend for ESM/TypeScript consumers is the version-safe one.\n\nimport pg from 'pg'\nimport { dbJunction } from '../junction.js'\nimport type { PgStatStatementsRow } from './types.js'\n\nconst { Client } = pg\n\n// Defensive cap, not a documented Postgres limit — see types.ts's\n// `statementLimit` doc comment for why (pg_stat_statements.max, default 5000\n// distinct statements on a busy project).\nexport const DEFAULT_STATEMENT_LIMIT = 500\n\n// Only ever SELECTs from pg_stat_statements, ordered by call volume so the\n// busiest statements are never starved by the LIMIT. The `query ~* '^\\s*select'`\n// filter narrows to read statements — the shape supabase-js's `.from()`/`.rpc()`\n// calls over PostgREST actually issue — rather than every INSERT/UPDATE/DDL\n// statement pg_stat_statements also tracks, which this connector's read-call-\n// count signal (supabase.md §Surfaces — \"call count / total time\") has no use\n// for.\nconst STATEMENTS_QUERY = `\n  select queryid, query, calls, total_exec_time, rows\n  from pg_stat_statements\n  where query ~* '^\\\\s*select\\\\b'\n  order by calls desc\n  limit $1\n`\n\n// The minimal surface this module needs off a `pg.Client` — narrowed so tests\n// can inject a fake implementation (no real database) the same way\n// cloudflare/client.ts's `fetchImpl` parameter injects a fake `fetch`\n// (dependency injection, not a production mock — connectors.md §5 bars mocks\n// on the runtime poll path itself, not on this seam).\nexport interface PgClientLike {\n  connect(): Promise<void>\n  query<T>(text: string, values?: unknown[]): Promise<{ rows: T[] }>\n  end(): Promise<void>\n}\n\n/**\n * Opens one short-lived connection per poll, runs the read, closes it. Poll\n * cadence is at most once a minute (DEFAULT_POLL_INTERVAL_MS,\n * connectors/index.ts) against a single query — a pool would add lifecycle\n * complexity (idle-connection reaping, exhaustion under a misconfigured\n * interval) for no real benefit at this call rate.\n *\n * `SET default_transaction_read_only = on` is a session-level, defense-in-\n * depth guard on top of whatever grant the connection string's role already\n * holds — belt-and-suspenders for the \"never writes on the read path\" rule\n * (connectors.md §2), not a substitute for the role itself being scoped\n * read-only (supabase.md §Scope's `pg_read_all_stats`-holding role).\n *\n * `clientFactory` defaults to a real `pg.Client`; tests override it with a\n * fake `PgClientLike` to exercise the query/session-guard behavior without a\n * live Postgres connection.\n *\n * Routed through `dbJunction` (ADR-131) — the same timeout/retry/rate-limit\n * discipline `junctionFetch` gives every HTTP-based connector, adapted to\n * this connect/query/end sequence. `accountKey` defaults to `'unknown'` only\n * for a caller that genuinely has no project identity to hand in (there is\n * none in this codebase — supabase/index.ts always passes its own\n * `config.apiProjectRef`); the fallback exists so this function still works\n * standalone rather than requiring every caller to thread one through.\n */\nexport async function fetchPgStatStatements(\n  connectionString: string,\n  limit: number = DEFAULT_STATEMENT_LIMIT,\n  accountKey: string = 'unknown',\n  clientFactory: (connectionString: string) => PgClientLike = (cs) => new Client({ connectionString: cs }),\n): Promise<PgStatStatementsRow[]> {\n  return dbJunction(\n    async () => {\n      const client = clientFactory(connectionString)\n      await client.connect()\n      try {\n        await client.query('SET default_transaction_read_only = on')\n        const result = await client.query<PgStatStatementsRow>(STATEMENTS_QUERY, [limit])\n        return result.rows\n      } finally {\n        await client.end()\n      }\n    },\n    { provider: 'supabase-postgres', accountKey },\n  )\n}\n","// Target resolution — the Supabase-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning a signal's (targetKind, targetName)\n// into a NEAT node id.\n//\n// This is the one place this connector's design departs from Railway/\n// Firebase's fusion pattern in a way worth calling out explicitly. Those two\n// providers fuse onto a RouteNode a static extractor (routes.ts) already\n// builds today. Supabase's own static extractor (extract/calls/supabase.ts)\n// recognizes only `createClient(...)` — not `.from()`/`.rpc()` — so the\n// table/RPC-grain InfraNode this connector's signals are meant to land on\n// (`infraId('supabase-table', ...)` / `infraId('supabase-rpc', ...)`,\n// supabase.md §Fusion) never exists in today's graph. `resolveTarget` cannot\n// create it either: a provider module has no mutation authority (ADR-030 —\n// only ingest.ts and extract/* call a graph mutator directly), and\n// `ResolveConnectorTarget`'s own signature only names an id, it never creates\n// one (the same constraint railway/connector.ts's own doc comment names for\n// its `unmatched-route` case).\n//\n// So: prefer the table/RPC InfraNode when it exists (the day a follow-up\n// extractor cut adds `.from()`/`.rpc()` parsing, this connector's edges\n// sharpen to that grain automatically, no connector-side change required —\n// exactly ADR-124's \"the fusion payoff compounds once a follow-up issue\n// extends the extractor to match\"); fall back to the project-level InfraNode\n// the *current* extractor already mints from a `createClient(...)` call\n// (`infraId('supabase', nodeRef)`) when it doesn't — project-level, honestly,\n// never fabricated. Neither existing is an honest miss (extraction hasn't run\n// against this project's code, or found no `createClient(...)` call to\n// resolve `nodeRef` from) — connectors.md §4's \"lands service-level (or\n// provider-node-level), honestly\" applies on the target side here exactly as\n// it does on the source side for every other connector's callSite-less case.\n\nimport { EdgeType, infraId } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport type { ConnectorContext, ObservedSignal } from '../types.js'\nimport { SUPABASE_RPC_TARGET_KIND, SUPABASE_TABLE_TARGET_KIND, type SupabaseConnectorConfig } from './types.js'\n\nexport function createSupabaseResolveTarget(\n  graph: NeatGraph,\n  config: SupabaseConnectorConfig,\n): ResolveConnectorTarget {\n  return (signal: ObservedSignal, _ctx: ConnectorContext): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== SUPABASE_TABLE_TARGET_KIND && signal.targetKind !== SUPABASE_RPC_TARGET_KIND) {\n      return null\n    }\n\n    const subResourceId = infraId(signal.targetKind, `${config.nodeRef}/${signal.targetName}`)\n    if (graph.hasNode(subResourceId)) {\n      return { targetNodeId: subResourceId, serviceName: config.serviceName, edgeType: EdgeType.CALLS }\n    }\n\n    // #803 — the static extractor mints table/RPC call sites at bare\n    // `infra:<kind>:<table>` grain (it parses `<client>.from('table')` but can't\n    // know the connector's nodeRef). Prefer that table node when it exists so the\n    // observation lands table-grained — and can then fuse onto the file→table\n    // static call site for file-grain — rather than collapsing to the project node.\n    const bareResourceId = infraId(signal.targetKind, signal.targetName)\n    if (graph.hasNode(bareResourceId)) {\n      return { targetNodeId: bareResourceId, serviceName: config.serviceName, edgeType: EdgeType.CALLS }\n    }\n\n    const projectLevelId = infraId('supabase', config.nodeRef)\n    if (graph.hasNode(projectLevelId)) {\n      return { targetNodeId: projectLevelId, serviceName: config.serviceName, edgeType: EdgeType.CALLS }\n    }\n\n    // Neither node exists yet — extraction hasn't run against this project's\n    // code, or found no `createClient(...)` call resolving to this `nodeRef`.\n    // Honest miss (connectors.md's \"never fabricates a node or edge\"),\n    // dropped rather than guessed.\n    return null\n  }\n}\n","// Railway connector (ADR-127, docs/connectors/railway.md) — the second\n// connectors-plane provider after the shared pull/map/fuse scaffold\n// (ADR-124, connectors/index.ts). Railway names nothing in application code:\n// the signal comes entirely from Railway's own edge/ingress layer (httpLogs)\n// and L4 flow records (networkFlowLogs), so fusion binds onto the RouteNode\n// `extract/routes.ts` already builds — the same node an OBSERVED server span\n// would fuse onto if the app were OTel-instrumented — rather than a\n// client-SDK call site the way the Supabase connector design does.\n\nimport type { RouteNode } from '@neat.is/types'\nimport { EdgeType, NodeType, serviceId } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { normalizePathTemplate } from '../../extract/routes.js'\nimport type {\n  ConnectorCallSite,\n  ConnectorContext,\n  ObservedConnector,\n  ObservedSignal,\n  ResolveConnectorTarget,\n} from '../index.js'\nimport type { RailwayConnectorConfig, RailwayHttpLogEntry, RailwayNetworkFlowLogEntry } from './types.js'\nimport {\n  DEFAULT_MAX_LOOKBACK_MS,\n  boundedRailwayStartDate,\n  fetchRailwayHttpLogs,\n  fetchRailwayNetworkFlowLogs,\n  readRailwayToken,\n  resolveLatestRailwayDeploymentId,\n} from './client.js'\n\nexport type { RailwayConnectorConfig, RailwayHttpLogEntry, RailwayNetworkFlowLogEntry } from './types.js'\nexport { DEFAULT_RAILWAY_API_URL, resolveLatestRailwayDeploymentId } from './client.js'\n\n// A signal's `targetKind` for this provider (README.md's \"provider's own\n// vocabulary\" — connectors/index.ts never inspects these strings itself):\n//\n// - 'route'           — the record's (method, path) normalised onto an\n//                        existing RouteNode (extract/routes.ts). targetName\n//                        already carries that RouteNode's own graph id.\n// - 'unmatched-route' — no RouteNode resolved. See createRailwayResolveTarget\n//                        below for why this drops honestly rather than\n//                        fabricating a target.\n// - 'peer-service'    — a networkFlowLogs record naming another Railway\n//                        service. targetName carries the raw Railway\n//                        peerServiceId, resolved through config.serviceNameById.\nconst ROUTE_TARGET_KIND = 'route'\nconst UNMATCHED_ROUTE_TARGET_KIND = 'unmatched-route'\nconst PEER_SERVICE_TARGET_KIND = 'peer-service'\n\n// ── route index (read-only graph query) ────────────────────────────────────\n//\n// Mirrors extract/calls/route-match.ts's own buildRouteIndex/findRoute — not\n// imported, since neither is exported from that module (only\n// normalizePathTemplate is, which this file reuses directly rather than\n// re-deriving the path-template normalisation rules). This is the\n// connectors-plane side of the same (method, normalised-path) matching\n// route-match.ts already does for a client call site, applied here to\n// Railway's own edge-observed (method, path) pairs instead of a parsed HTTP\n// client call (docs/connectors/railway.md §Fusion).\n\ninterface RailwayRouteIndexEntry {\n  method: string\n  normalizedPath: string\n  routeNodeId: string\n  path: string\n  line?: number\n}\n\nexport function buildRailwayRouteIndex(graph: NeatGraph, serviceName: string): RailwayRouteIndexEntry[] {\n  const out: RailwayRouteIndexEntry[] = []\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as unknown as { type?: string }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    if (route.service !== serviceName) return\n    out.push({\n      method: route.method.toUpperCase(),\n      normalizedPath: normalizePathTemplate(route.pathTemplate),\n      routeNodeId: route.id,\n      path: route.path,\n      line: route.line,\n    })\n  })\n  return out\n}\n\n// httpLogs always carries a concrete method (unlike a statically parsed\n// client call site, which sometimes can't determine one) — so unlike\n// route-match.ts's findRoute, there's no \"caller method unknown\" passthrough\n// case, only the route's own `ALL` wildcard.\nfunction findRailwayRoute(\n  entries: RailwayRouteIndexEntry[],\n  method: string,\n  normalizedPath: string,\n): RailwayRouteIndexEntry | undefined {\n  return entries.find(\n    (e) => e.normalizedPath === normalizedPath && (e.method === 'ALL' || e.method === method),\n  )\n}\n\nfunction bucketKey(method: string, normalizedPath: string): string {\n  return `${method} ${normalizedPath}`\n}\n\nfunction isHttpErrorStatus(status: number): boolean {\n  return status >= 400\n}\n\ninterface SignalBucket {\n  callCount: number\n  errorCount: number\n  lastObservedIso: string\n  targetKind: string\n  targetName: string\n  callSite?: ConnectorCallSite\n}\n\nfunction upsertBucket(\n  buckets: Map<string, SignalBucket>,\n  key: string,\n  isError: boolean,\n  timestamp: string,\n  build: () => Omit<SignalBucket, 'callCount' | 'errorCount' | 'lastObservedIso'>,\n): void {\n  const existing = buckets.get(key)\n  if (existing) {\n    existing.callCount += 1\n    if (isError) existing.errorCount += 1\n    if (timestamp > existing.lastObservedIso) existing.lastObservedIso = timestamp\n    return\n  }\n  buckets.set(key, { callCount: 1, errorCount: isError ? 1 : 0, lastObservedIso: timestamp, ...build() })\n}\n\n// ── httpLogs → ObservedSignal[] ─────────────────────────────────────────────\n//\n// Route-grain fusion (docs/connectors/railway.md §Fusion): normalise each\n// record's `path` the same way route-match.ts normalises a client call\n// site's URL path, then match against the polled service's own RouteNodes.\n// A match carries the matched RouteNode's own `path`/`line` as this signal's\n// callSite — reconciled onto the EXTRACTED service-relative path\n// (connectors/index.ts's shared fuse step) the same way every other OBSERVED\n// surface in NEAT lands file-grained, because that path IS the extracted\n// path a static pass already walked (routes.ts's own file:line).\nexport function mapRailwayHttpLogsToSignals(\n  entries: RailwayHttpLogEntry[],\n  routeIndex: RailwayRouteIndexEntry[],\n): ObservedSignal[] {\n  const buckets = new Map<string, SignalBucket>()\n  if (!Array.isArray(entries)) return []\n\n  for (const entry of entries) {\n    // Drop a null/garbage slot or a row missing the method/path/timestamp a\n    // signal needs, honestly, rather than throwing on `.toUpperCase()` /\n    // normalizePathTemplate's `.split()` (connectors.md §4).\n    if (!entry || typeof entry !== 'object') continue\n    if (typeof entry.method !== 'string' || typeof entry.path !== 'string' || typeof entry.timestamp !== 'string') {\n      continue\n    }\n    const method = entry.method.toUpperCase()\n    const normalizedPath = normalizePathTemplate(entry.path)\n    const match = findRailwayRoute(routeIndex, method, normalizedPath)\n    const isError = isHttpErrorStatus(entry.httpStatus)\n\n    if (match) {\n      upsertBucket(buckets, `route:${match.routeNodeId}`, isError, entry.timestamp, () => ({\n        targetKind: ROUTE_TARGET_KIND,\n        targetName: match.routeNodeId,\n        // RouteNode.line is optional in the schema (packages/types/src/\n        // nodes.ts) even though routes.ts always sets it today — skip the\n        // callSite rather than fabricate a line when it's ever absent\n        // (file-awareness.md §6).\n        ...(match.line !== undefined ? { callSite: { file: match.path, line: match.line } } : {}),\n      }))\n    } else {\n      // No RouteNode resolves — the app's framework/router isn't one\n      // routes.ts recognises yet, or the path doesn't match any declared\n      // template. See createRailwayResolveTarget below for why this\n      // targetKind always resolves to null (an honest \"unresolved\" miss)\n      // rather than a fabricated target.\n      upsertBucket(\n        buckets,\n        `unmatched:${bucketKey(method, normalizedPath)}`,\n        isError,\n        entry.timestamp,\n        () => ({\n          targetKind: UNMATCHED_ROUTE_TARGET_KIND,\n          targetName: bucketKey(method, normalizedPath),\n        }),\n      )\n    }\n  }\n\n  return [...buckets.values()].map((b) => ({\n    targetKind: b.targetKind,\n    targetName: b.targetName,\n    callCount: b.callCount,\n    errorCount: b.errorCount,\n    lastObservedIso: b.lastObservedIso,\n    ...(b.callSite ? { callSite: b.callSite } : {}),\n  }))\n}\n\n// ── networkFlowLogs → ObservedSignal[] ──────────────────────────────────────\n//\n// Service-dependency signal, independent of any route (docs/connectors/\n// railway.md §Fusion — \"independent of whether any route resolves for the\n// traffic that produced the flow\"). A record with no `peerServiceId` names\n// no Railway-internal peer (public internet egress, say) and is dropped\n// honestly — never guessed at.\nexport function mapRailwayNetworkFlowLogsToSignals(\n  entries: RailwayNetworkFlowLogEntry[],\n): ObservedSignal[] {\n  const buckets = new Map<string, SignalBucket>()\n  if (!Array.isArray(entries)) return []\n\n  for (const entry of entries) {\n    // A null/garbage slot, or a record with no Railway-internal peer (public\n    // egress carries a null peerServiceId), drops honestly rather than\n    // throwing or being guessed at (connectors.md §4, railway.md §Fusion).\n    if (!entry || typeof entry !== 'object') continue\n    if (typeof entry.peerServiceId !== 'string' || entry.peerServiceId.length === 0) continue\n    if (typeof entry.timestamp !== 'string') continue\n    const isError = entry.dropCause !== null && entry.dropCause !== ''\n    upsertBucket(buckets, entry.peerServiceId, isError, entry.timestamp, () => ({\n      targetKind: PEER_SERVICE_TARGET_KIND,\n      targetName: entry.peerServiceId as string,\n    }))\n  }\n\n  return [...buckets.values()].map((b) => ({\n    targetKind: b.targetKind,\n    targetName: b.targetName,\n    callCount: b.callCount,\n    errorCount: b.errorCount,\n    lastObservedIso: b.lastObservedIso,\n  }))\n}\n\n// ── target resolution (README.md pipeline step 2 — provider-specific) ──────\n//\n// A pure function of (signal, ctx, config) — no graph access, unlike\n// poll()/the route index above, which need a read-only graph query to match\n// against existing RouteNodes. That matching already happened in poll();\n// resolveTarget's job here is only the id-shape mapping README.md describes\n// (\"targetKind/targetName → NEAT node id\").\nexport function createRailwayResolveTarget(config: RailwayConnectorConfig): ResolveConnectorTarget {\n  return (signal: ObservedSignal) => {\n    const serviceName = config.serviceNameById[config.serviceId]\n    // This connector's own polled service has no configured mapping — a\n    // config error, not something to guess past (docs/connectors/railway.md\n    // §Fusion, \"resolved once, never guessed\").\n    if (!serviceName) return null\n\n    if (signal.targetKind === ROUTE_TARGET_KIND) {\n      // targetName is already the exact RouteNode graph id poll()'s route\n      // index resolved — this is the two-sided divergence's OBSERVED half,\n      // landing on the same node the EXTRACTED client↔route CALLS edge\n      // (route-match.ts, ADR-119) and a future OBSERVED server span (#576)\n      // would.\n      return { targetNodeId: signal.targetName, serviceName, edgeType: EdgeType.CALLS }\n    }\n\n    if (signal.targetKind === PEER_SERVICE_TARGET_KIND) {\n      const peerName = config.serviceNameById[signal.targetName]\n      // Unmapped peer serviceId — dropped honestly rather than guessed\n      // (docs/connectors/railway.md §Fusion). A future config update adding\n      // the mapping picks this traffic up on the next poll; it never\n      // fabricates a peer identity in the meantime.\n      if (!peerName) return null\n      return { targetNodeId: serviceId(peerName), serviceName, edgeType: EdgeType.CONNECTS_TO }\n    }\n\n    // UNMATCHED_ROUTE_TARGET_KIND (and anything else unrecognised): no\n    // RouteNode resolved for this traffic, and the scaffold's shared pipeline\n    // (connectors/index.ts) has no primitive to auto-vivify one the way\n    // ensureGraphqlOperationNode/ensureGrpcMethodNode do for an OTel span\n    // (ingest.ts) — those exist on the OTLP-ingest path, not on\n    // ResolveConnectorTarget's (signal, ctx) => ResolvedConnectorTarget\n    // shape, which only names an id, never creates one. Even if it could:\n    // RouteNode.path is a required field (packages/types/src/nodes.ts)\n    // naming the real source location a static extractor found — a\n    // Railway-observed route with no static match has no honest value to\n    // put there, so minting one here would fabricate provenance\n    // (file-awareness.md §6). Returning null routes this through the\n    // scaffold's own honest-miss path (ConnectorPollResult.unresolved)\n    // instead of forcing an edge. See this PR's description for the gap\n    // this leaves open: a route Railway observes but no static extractor\n    // recognises today produces no missing-extracted divergence via this\n    // connector, pending either a scaffold extension (observed-first target\n    // creation, mirroring the OTel-ingest pattern) or a product decision on\n    // how to represent it without fabricating a path.\n    return null\n  }\n}\n\n// ── connector ────────────────────────────────────────────────────────────────\n//\n// Constructed with a `graph` reference so poll() can read (never mutate,\n// per ADR-030 mutation authority — every write this connector's signals\n// eventually cause flows back through connectors/index.ts's ingest.ts\n// primitives, not through this module) the polled service's existing\n// RouteNodes to match httpLogs against, the same read-only access\n// extract/calls/route-match.ts already has to the graph for the identical\n// purpose on the static-extraction side.\nexport function createRailwayConnector(graph: NeatGraph, config: RailwayConnectorConfig): ObservedConnector {\n  return {\n    provider: 'railway',\n    async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n      const token = readRailwayToken(ctx.credentials)\n      const now = new Date()\n      const maxLookbackMs = config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS\n      const startDate = boundedRailwayStartDate(ctx.since, now, maxLookbackMs)\n      const endDate = now.toISOString()\n\n      // httpLogs is scoped by deploymentId, which is minted fresh on every\n      // redeploy — resolved here, every poll, from the stable\n      // (environmentId, serviceId) pair (client.ts). A service with no\n      // deployment yet (or none this token can see) gets an honest empty\n      // httpLogs result rather than a thrown error — the same \"empty window,\n      // not a failure\" treatment an empty startDate..endDate range gets.\n      const deploymentId = await resolveLatestRailwayDeploymentId(config, token)\n      // allSettled, not all: httpLogs and networkFlowLogs are independent\n      // surfaces (docs/connectors/railway.md §Surfaces) — a transient failure\n      // on one (a flaky upstream 400, a timeout) shouldn't discard a\n      // perfectly good result from the other. Each failure is reported\n      // through ctx's own onError path (connectors/index.ts's\n      // startConnectorPollLoop), not swallowed — it just doesn't cost the\n      // other surface's signals too.\n      const [httpLogsResult, flowLogsResult] = await Promise.allSettled([\n        deploymentId ? fetchRailwayHttpLogs(config, token, deploymentId, startDate, endDate) : Promise.resolve([]),\n        fetchRailwayNetworkFlowLogs(config, token),\n      ])\n      if (httpLogsResult.status === 'rejected') {\n        console.error('[neat connector] railway httpLogs poll failed', httpLogsResult.reason)\n      }\n      if (flowLogsResult.status === 'rejected') {\n        console.error('[neat connector] railway networkFlowLogs poll failed', flowLogsResult.reason)\n      }\n      const httpLogs = httpLogsResult.status === 'fulfilled' ? httpLogsResult.value : []\n      const flowLogs = flowLogsResult.status === 'fulfilled' ? flowLogsResult.value : []\n\n      const serviceName = config.serviceNameById[config.serviceId]\n      const routeIndex = serviceName ? buildRailwayRouteIndex(graph, serviceName) : []\n\n      return [\n        ...mapRailwayHttpLogsToSignals(httpLogs, routeIndex),\n        ...mapRailwayNetworkFlowLogsToSignals(flowLogs),\n      ]\n    },\n  }\n}\n","// Railway GraphQL client — the fetch half of this connector's poll() (ADR-127,\n// docs/connectors/railway.md). Passive and ambient only (docs/contracts/\n// connectors.md §2): two read-only queries, never a mutation, never a\n// synthetic request to keep the connection warm.\n\nimport { junctionFetch } from '../junction.js'\nimport type { RailwayConnectorConfig, RailwayHttpLogEntry, RailwayNetworkFlowLogEntry } from './types.js'\n\nexport const DEFAULT_RAILWAY_API_URL = 'https://backboard.railway.com/graphql/v2'\n\n// docs/connectors/railway.md §\"Out of scope for this cut\" flags the\n// neighbouring plan-tier question the same way: Railway's docs don't publish\n// a retention/lookback window for httpLogs/networkFlowLogs as of this\n// writing. 24h is a conservative default pending a live project confirming\n// the real cap — never an unbounded full-history query regardless\n// (docs/contracts/connectors.md §\"Poll cadence and backfill\").\nexport const DEFAULT_MAX_LOOKBACK_MS = 24 * 60 * 60 * 1000\nexport const DEFAULT_LOG_LIMIT = 1000\n\ninterface RailwayGraphQLError {\n  message: string\n}\n\ninterface RailwayGraphQLResponse<T> {\n  data?: T\n  errors?: RailwayGraphQLError[]\n}\n\n// A Project-Access-Token is the credential ADR-127 scopes this connector to\n// (docs/connectors/railway.md §Scope) — both local and hosted profiles carry\n// it the same way (docs/contracts/connectors.md §3). Read from\n// `ConnectorContext.credentials` at poll time, never logged, never written\n// into a node/edge (contract §6).\nexport function readRailwayToken(credentials: Record<string, unknown>): string {\n  const token = credentials.token\n  if (typeof token !== 'string' || token.length === 0) {\n    throw new Error(\n      'Railway connector requires ctx.credentials.token (a Project-Access-Token or account Bearer token)',\n    )\n  }\n  return token\n}\n\n// Railway authenticates its two token families through different headers, and a\n// token presented on the wrong one is rejected exactly the way a bad token is:\n// an HTTP-200 body carrying a GraphQL \"Not Authorized\" error, never a 401/403\n// (#868; the 2026-07-08 live check in #738 saw this for a Project-Access-Token\n// on `Authorization: Bearer`). A **project** token uses Railway's dedicated\n// `Project-Access-Token` header; an **account** or **team** token uses\n// `Authorization: Bearer`. `readRailwayToken` accepts either and can't know\n// which it holds up front, so the connector resolves the working header on a\n// token's first query and reuses it for the rest of the process — the same\n// \"resolved once, never guessed\" discipline this connector applies to the\n// service mapping (docs/connectors/railway.md §Fusion), here applied to auth.\ntype RailwayAuthStyle = 'bearer' | 'project-access-token'\n\n// Ordered account-first: `Authorization: Bearer` is the header a personal\n// account token wants — the credential a user reaches for first, and the\n// connector's pre-#749 default — so the common case resolves on the first\n// attempt and only a project token pays a single extra probe per process.\nconst RAILWAY_AUTH_STYLES: readonly RailwayAuthStyle[] = ['bearer', 'project-access-token']\n\nfunction railwayAuthHeader(style: RailwayAuthStyle, token: string): Record<string, string> {\n  return style === 'bearer' ? { Authorization: `Bearer ${token}` } : { 'Project-Access-Token': token }\n}\n\n// The header a given token resolved to, memoised for this process so steady-\n// state polling never re-probes. Keyed by the raw token — which already lives\n// in memory for the life of a poll, and is never logged nor written to a node\n// or edge (docs/contracts/connectors.md §6). Bounded by the number of distinct\n// Railway tokens a daemon carries (one per connector), i.e. tiny.\nconst resolvedRailwayAuthStyle = new Map<string, RailwayAuthStyle>()\n\n// Test-only: the memo is process-global, so a suite exercising both token\n// families needs to start each case from an unresolved state.\nexport function __resetRailwayAuthStyleCache(): void {\n  resolvedRailwayAuthStyle.clear()\n}\n\nfunction isRailwayNotAuthorized(err: unknown): boolean {\n  return err instanceof Error && /not authorized/i.test(err.message)\n}\n\nasync function railwayGraphQLOnce<T>(\n  apiUrl: string,\n  style: RailwayAuthStyle,\n  token: string,\n  query: string,\n  variables: Record<string, unknown>,\n  accountKey: string,\n  fetchImpl?: typeof fetch,\n): Promise<T> {\n  const res = await junctionFetch(\n    apiUrl,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        ...railwayAuthHeader(style, token),\n      },\n      body: JSON.stringify({ query, variables }),\n    },\n    { provider: 'railway', accountKey, ...(fetchImpl ? { fetchImpl } : {}) },\n  )\n  if (!res.ok) {\n    throw new Error(`Railway GraphQL request failed: ${res.status} ${res.statusText}`)\n  }\n  const body = (await res.json()) as RailwayGraphQLResponse<T>\n  if (body.errors && body.errors.length > 0) {\n    throw new Error(`Railway GraphQL errors: ${body.errors.map((e) => e.message).join('; ')}`)\n  }\n  if (!body.data) throw new Error('Railway GraphQL response carried no data')\n  return body.data\n}\n\n// `accountKey` is Railway's environmentId (ADR-131's per-`(provider,\n// accountKey)` rate-limit bucket) — a Project-Access-Token is minted per\n// environment, not per account (docs/connectors/railway.md §Scope), so the\n// environment is the closest thing this connector's config carries to \"one\n// customer's account\" for this provider.\nasync function railwayGraphQL<T>(\n  apiUrl: string,\n  token: string,\n  query: string,\n  variables: Record<string, unknown>,\n  accountKey: string,\n  fetchImpl?: typeof fetch,\n): Promise<T> {\n  const known = resolvedRailwayAuthStyle.get(token)\n  const styles = known ? [known] : RAILWAY_AUTH_STYLES\n  let lastNotAuthorized: Error | undefined\n  for (let i = 0; i < styles.length; i++) {\n    const style = styles[i]\n    try {\n      const data = await railwayGraphQLOnce<T>(apiUrl, style, token, query, variables, accountKey, fetchImpl)\n      resolvedRailwayAuthStyle.set(token, style)\n      return data\n    } catch (err) {\n      // Only an auth rejection is worth retrying on the other header. A real\n      // query error (bad variables, a provider outage) fails the same way on\n      // both headers, so surface it immediately rather than mask it behind a\n      // second call. When the style is already memoised, `styles` has one entry\n      // and this never retries.\n      if (isRailwayNotAuthorized(err) && i < styles.length - 1) {\n        lastNotAuthorized = err as Error\n        continue\n      }\n      throw err\n    }\n  }\n  // Both headers rejected the token: it is genuinely unauthorized. Surface the\n  // provider's own message, unchanged from the single-header days (#738 tests).\n  throw lastNotAuthorized ?? new Error('Railway GraphQL: no auth style resolved')\n}\n\n// Live-confirmed against backboard.railway.com/graphql/v2 (2026-07-08) via\n// schema introspection — httpLogs is scoped by `deploymentId`, not\n// `environmentId`/`serviceId` as originally assumed; startDate/endDate/limit\n// are valid but optional. `HttpLog`'s own field names matched the original\n// guess exactly (docs.railway.com/cli/logs's attribute list was accurate),\n// so only the query's arguments changed, not the row shape below.\nconst HTTP_LOGS_QUERY = `\n  query HttpLogs($deploymentId: String!, $startDate: String, $endDate: String, $limit: Int) {\n    httpLogs(deploymentId: $deploymentId, startDate: $startDate, endDate: $endDate, limit: $limit) {\n      timestamp\n      method\n      path\n      httpStatus\n      totalDuration\n      requestId\n      deploymentId\n      edgeRegion\n    }\n  }\n`\n\n// Live-confirmed: networkFlowLogs takes no startDate/endDate/limit at all —\n// only environmentId (required) + serviceId (optional); its only windowing\n// is cursor pagination (afterDate/afterLimit/anchorDate/beforeDate/\n// beforeLimit) this connector doesn't exercise yet. `NetworkFlowLog` has no\n// `timestamp` field either — aliased here from its real field `captureStart`\n// so the rest of the connector keeps reading `entry.timestamp` unchanged.\nconst NETWORK_FLOW_LOGS_QUERY = `\n  query NetworkFlowLogs($environmentId: String!, $serviceId: String) {\n    networkFlowLogs(environmentId: $environmentId, serviceId: $serviceId) {\n      timestamp: captureStart\n      peerServiceId\n      peerKind\n      direction\n      byteCount\n      packetCount\n      dropCause\n    }\n  }\n`\n\n// httpLogs needs a deploymentId, which is minted fresh on every redeploy —\n// unlike the serviceId→name mapping (docs/connectors/railway.md §Fusion,\n// \"resolved once, never guessed\"), a deploymentId can't be resolved once at\n// connector-setup time without going stale the next time the service\n// redeploys. Resolved fresh each poll from the stable (environmentId,\n// serviceId) pair instead. Picks the newest SUCCESS deployment; falls back to\n// the newest of any status if none has succeeded yet, so a service between\n// its first (failed) deploy and its first success still has an id to poll\n// against (httpLogs simply comes back empty for it until a real deploy lands).\nconst DEPLOYMENTS_QUERY = `\n  query LatestDeployment($environmentId: String!, $serviceId: String!) {\n    deployments(input: { environmentId: $environmentId, serviceId: $serviceId }, first: 5) {\n      edges { node { id status createdAt } }\n    }\n  }\n`\n\ninterface RailwayDeploymentNode {\n  id: string\n  status: string\n  createdAt: string\n}\n\nexport async function resolveLatestRailwayDeploymentId(\n  config: RailwayConnectorConfig,\n  token: string,\n  fetchImpl?: typeof fetch,\n): Promise<string | null> {\n  const data = await railwayGraphQL<{ deployments: { edges: { node: RailwayDeploymentNode }[] } }>(\n    config.apiUrl ?? DEFAULT_RAILWAY_API_URL,\n    token,\n    DEPLOYMENTS_QUERY,\n    { environmentId: config.environmentId, serviceId: config.serviceId },\n    config.environmentId,\n    fetchImpl,\n  )\n  const nodes = data.deployments.edges.map((e) => e.node)\n  const newestFirst = [...nodes].sort((a, b) => b.createdAt.localeCompare(a.createdAt))\n  const success = newestFirst.find((n) => n.status === 'SUCCESS')\n  return (success ?? newestFirst[0])?.id ?? null\n}\n\nexport async function fetchRailwayHttpLogs(\n  config: RailwayConnectorConfig,\n  token: string,\n  deploymentId: string,\n  startDate: string,\n  endDate: string,\n): Promise<RailwayHttpLogEntry[]> {\n  const data = await railwayGraphQL<{ httpLogs: RailwayHttpLogEntry[] }>(\n    config.apiUrl ?? DEFAULT_RAILWAY_API_URL,\n    token,\n    HTTP_LOGS_QUERY,\n    { deploymentId, startDate, endDate, limit: config.limit ?? DEFAULT_LOG_LIMIT },\n    config.environmentId,\n  )\n  return data.httpLogs\n}\n\nexport async function fetchRailwayNetworkFlowLogs(\n  config: RailwayConnectorConfig,\n  token: string,\n): Promise<RailwayNetworkFlowLogEntry[]> {\n  const data = await railwayGraphQL<{ networkFlowLogs: RailwayNetworkFlowLogEntry[] }>(\n    config.apiUrl ?? DEFAULT_RAILWAY_API_URL,\n    token,\n    NETWORK_FLOW_LOGS_QUERY,\n    { environmentId: config.environmentId, serviceId: config.serviceId },\n    config.environmentId,\n  )\n  return data.networkFlowLogs\n}\n\n// `since` bounded by the provider's max lookback window (docs/contracts/\n// connectors.md §\"Poll cadence and backfill\") — a gap wider than the window\n// (a laptop off for a week) backfills from `now - maxLookbackMs`, never an\n// unbounded full-history replay. An absent or unparseable `since` (no prior\n// poll) gets the same treatment as too-old a `since`.\nexport function boundedRailwayStartDate(since: string | undefined, now: Date, maxLookbackMs: number): string {\n  const floor = new Date(now.getTime() - maxLookbackMs)\n  if (!since) return floor.toISOString()\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return floor.toISOString()\n  return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString()\n}\n","// The Firebase connector (docs/connectors/firebase.md, ADR-128) — third\n// connectors-plane provider, after Supabase (ADR-124) and Railway (ADR-127).\n//\n// Scoped to Cloud Functions / Cloud Run / Firebase Hosting request logs only.\n// Firestore and Firebase Auth are named non-goals (firebase.md §Scope — no\n// least-privilege telemetry path exists for either, not merely unbuilt); this\n// module never reads or references either surface.\n//\n// poll() pulls Cloud Logging's `entries.list` (logging-api.ts), filtered to\n// entries carrying an `httpRequest`, and maps each one to an ObservedSignal\n// (map.ts). Target resolution — matching a signal onto a statically-\n// extracted RouteNode via the shared route-match.ts normalisation, or an\n// honest miss when none resolves — lives in resolve.ts. Everything\n// downstream of resolution (minting the OBSERVED edge) is the shared\n// connectors/index.ts pipeline; this module never touches the graph\n// directly (ADR-030).\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport {\n  fetchHttpRequestLogEntries,\n  readFirebaseCredentials,\n  DEFAULT_LOOKBACK_MS,\n  type FirebaseResourceType,\n} from './logging-api.js'\nimport { mapLogEntriesToSignals } from './map.js'\nimport { createFirebaseResolveTarget, type FirebaseServiceMap } from './resolve.js'\n\nexport type { FirebaseCredentials, FirebaseResourceType } from './logging-api.js'\nexport type { FirebaseServiceMap } from './resolve.js'\nexport { createFirebaseResolveTarget } from './resolve.js'\nexport type { FirebaseTargetIdentity } from './map.js'\nexport { mapLogEntryToSignal, mapLogEntriesToSignals, packFirebaseTargetName, parseFirebaseTargetName } from './map.js'\n\nexport class FirebaseConnector implements ObservedConnector {\n  readonly provider = 'firebase'\n\n  constructor(private readonly opts: { resourceTypes?: readonly FirebaseResourceType[] } = {}) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const creds = readFirebaseCredentials(ctx.credentials)\n    const sinceIso = ctx.since ?? new Date(Date.now() - DEFAULT_LOOKBACK_MS).toISOString()\n    const entries = await fetchHttpRequestLogEntries(creds, sinceIso, this.opts.resourceTypes)\n    return mapLogEntriesToSignals(entries)\n  }\n}\n\n/**\n * Wires up a ready-to-register Firebase connector: the `ObservedConnector`\n * plus the `resolveTarget` callback `runConnectorPoll` /\n * `startConnectorPollLoop` (connectors/index.ts) need alongside it. Both are\n * built together because `resolveTarget` closes over `graph` — the shared\n * scaffold's `ResolveConnectorTarget` signature (index.ts) never receives it\n * directly.\n */\nexport function createFirebaseConnector(\n  graph: NeatGraph,\n  serviceMap: FirebaseServiceMap,\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new FirebaseConnector(\n      serviceMap.excludeCloudRun ? { resourceTypes: ['cloud_function', 'firebase_domain'] } : {},\n    ),\n    resolveTarget: createFirebaseResolveTarget(graph, serviceMap),\n  }\n}\n","// Cloud Logging `entries.list` — the raw fetch half of the Firebase connector\n// (docs/connectors/firebase.md, ADR-128). This file owns exactly the wire\n// shape and the HTTP call; mapping a `LogEntry` to an `ObservedSignal` lives\n// in map.ts, and target resolution lives in resolve.ts — the same\n// fetch/map/resolve split every other provider module keeps (connectors.md\n// §Authority).\n//\n// Every field name below was confirmed live against Google's own docs rather\n// than recalled from training data (per this connector's build instructions):\n//   - request/response envelope + endpoint:\n//     https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list\n//   - LogEntry + HttpRequest field names:\n//     https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry\n//   - monitored-resource labels for cloud_function / cloud_run_revision /\n//     firebase_domain:\n//     https://cloud.google.com/logging/docs/api/v2/resource-list\n// Anything not directly confirmed by those pages is called out inline as\n// unconfirmed rather than asserted as fact.\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\n\n// ── credentials ──────────────────────────────────────────────────────────\n\n// `ConnectorContext.credentials` is opaque at the shared-scaffold layer\n// (types.ts) — this is the Firebase-specific shape it must carry. Per\n// docs/connectors/firebase.md §Surfaces used, both the local and hosted\n// profile use the same narrow grant (`roles/monitoring.viewer`,\n// `roles/logging.viewer`, `roles/cloudfunctions.viewer`,\n// `roles/firebasehosting.viewer`) — there's no Fork-A-style split here the\n// way Supabase's `pg_stat_statements` gap forced. Minting `accessToken` (a\n// service-account or ADC-derived OAuth token scoped to those roles) is a\n// profile-specific broker/config concern (connectors.md §3) outside this\n// connector's job — `poll()` only ever consumes an already-minted token, the\n// same way Railway's connector consumes an already-minted\n// `Project-Access-Token` rather than performing its own auth handshake.\nexport interface FirebaseCredentials {\n  projectId: string\n  accessToken: string\n}\n\nexport function readFirebaseCredentials(raw: Record<string, unknown>): FirebaseCredentials {\n  const projectId = raw['projectId']\n  const accessToken = raw['accessToken']\n  if (typeof projectId !== 'string' || projectId.length === 0) {\n    throw new Error('firebase connector: credentials.projectId must be a non-empty string')\n  }\n  if (typeof accessToken !== 'string' || accessToken.length === 0) {\n    throw new Error('firebase connector: credentials.accessToken must be a non-empty string')\n  }\n  return { projectId, accessToken }\n}\n\n// ── Cloud Logging wire types ─────────────────────────────────────────────\n\n// The three monitored-resource types this connector polls (firebase.md\n// §Surfaces used). 2nd-gen Cloud Functions can surface under either\n// `cloud_function` or `cloud_run_revision` depending on how Google's own\n// logging pipeline attributes the request — both are polled so neither shape\n// is missed.\nexport type FirebaseResourceType = 'cloud_function' | 'cloud_run_revision' | 'firebase_domain'\n\nconst RESOURCE_TYPES: readonly FirebaseResourceType[] = [\n  'cloud_function',\n  'cloud_run_revision',\n  'firebase_domain',\n]\n\nexport function isFirebaseResourceType(value: string): value is FirebaseResourceType {\n  return (RESOURCE_TYPES as readonly string[]).includes(value)\n}\n\n// MonitoredResource (LogEntry.resource). `labels` carries the resource-type-\n// specific identity fields confirmed at\n// https://cloud.google.com/logging/docs/api/v2/resource-list:\n//   cloud_function:      project_id, function_name, region\n//   cloud_run_revision:  project_id, service_name, revision_name, location,\n//                        configuration_name\n//   firebase_domain:     project_id, site_name, domain_name\nexport interface MonitoredResource {\n  type: string\n  labels?: Record<string, string>\n}\n\n// HttpRequest (LogEntry.httpRequest), field names confirmed against the\n// LogEntry reference page above. Every field is optional in the wire type —\n// a structured request log is expected to carry requestMethod/requestUrl/\n// status, but nothing here is guaranteed present, so the mapper (map.ts)\n// treats an absent field as an honest miss rather than guessing a default.\nexport interface HttpRequest {\n  requestMethod?: string\n  requestUrl?: string\n  requestSize?: string\n  status?: number\n  responseSize?: string\n  userAgent?: string\n  remoteIp?: string\n  serverIp?: string\n  referer?: string\n  latency?: string\n  cacheLookup?: boolean\n  cacheHit?: boolean\n  cacheValidatedWithOriginServer?: boolean\n  cacheFillBytes?: string\n  protocol?: string\n}\n\n// LogEntry, the subset of fields this connector reads. `timestamp` is the\n// provider's own event time (confirmed string/Timestamp-format field) — used\n// as `ObservedSignal.lastObservedIso`, never `receiveTimestamp` (ingest-time),\n// matching the \"provider's own event time, never poll-arrival time\" rule\n// (connectors/README.md §Poll cadence and backfill).\nexport interface LogEntry {\n  logName?: string\n  resource?: MonitoredResource\n  timestamp?: string\n  receiveTimestamp?: string\n  severity?: string\n  insertId?: string\n  httpRequest?: HttpRequest\n}\n\nexport interface EntriesListRequest {\n  resourceNames: string[]\n  filter?: string\n  orderBy?: string\n  pageSize?: number\n  pageToken?: string\n}\n\nexport interface EntriesListResponse {\n  entries?: LogEntry[]\n  nextPageToken?: string\n}\n\n// ── filter construction ──────────────────────────────────────────────────\n\n// Cloud Logging query-language operators confirmed against\n// https://cloud.google.com/logging/docs/view/logging-query-language:\n//   - `resource.type = (\"a\" OR \"b\")` for a multi-value match\n//   - `httpRequest:*` as the field-exists test\n//   - `timestamp >= \"<RFC3339>\"` for a lower bound\n// Joined with explicit `AND` rather than relying on the query language's\n// documented (but not directly re-confirmed here) implicit-AND-per-line\n// behaviour.\nexport function buildEntriesFilter(\n  sinceIso: string,\n  resourceTypes: readonly FirebaseResourceType[] = RESOURCE_TYPES,\n): string {\n  return [\n    `resource.type = (${resourceTypes.map((t) => `\"${t}\"`).join(' OR ')})`,\n    'httpRequest:*',\n    `timestamp >= \"${sinceIso}\"`,\n  ].join(' AND ')\n}\n\n// No documented lookback cap surfaced for `entries.list` itself (bounded only\n// by the log bucket's own retention, typically 30 days on the `_Default`\n// bucket) — mirrors docs/connectors/supabase.md's \"capped at 24h lookback\"\n// convention for a local-profile poll with no prior high-water mark, the\n// closest documented analog in this codebase, rather than inventing an\n// unbounded first query.\nexport const DEFAULT_LOOKBACK_MS = 24 * 60 * 60 * 1000\n\nconst ENTRIES_LIST_URL = 'https://logging.googleapis.com/v2/entries:list'\nconst PAGE_SIZE = 1000\n// Defensive cap on pagination — entries.list documents no page-count limit,\n// so this bounds the loop the same way STITCH_MAX_DEPTH bounds trace-stitch\n// BFS elsewhere in ingest.ts, rather than trusting an unbounded while(true).\nconst MAX_PAGES = 20\n\nexport async function fetchHttpRequestLogEntries(\n  creds: FirebaseCredentials,\n  sinceIso: string,\n  resourceTypes?: readonly FirebaseResourceType[],\n): Promise<LogEntry[]> {\n  const filter = buildEntriesFilter(sinceIso, resourceTypes)\n  const out: LogEntry[] = []\n  let pageToken: string | undefined\n  for (let page = 0; page < MAX_PAGES; page++) {\n    const body: EntriesListRequest = {\n      resourceNames: [`projects/${creds.projectId}`],\n      filter,\n      orderBy: 'timestamp asc',\n      pageSize: PAGE_SIZE,\n      ...(pageToken ? { pageToken } : {}),\n    }\n    const res = await junctionFetch(\n      ENTRIES_LIST_URL,\n      {\n        method: 'POST',\n        headers: {\n          ...bearerAuthHeader(creds.accessToken),\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify(body),\n      },\n      // accountKey: the GCP project id (ADR-131's own worked example for\n      // Firebase) — one customer's Cloud Logging quota is scoped per GCP\n      // project, not per Firebase site/function.\n      { provider: 'firebase', accountKey: creds.projectId },\n    )\n    if (!res.ok) {\n      throw new Error(`Cloud Logging entries.list failed: ${res.status} ${res.statusText}`)\n    }\n    const json = (await res.json()) as EntriesListResponse\n    // A well-formed page carries an array (absent when the window is empty);\n    // a shape drift handing back a non-array `entries` drops honestly rather\n    // than throwing on `push(...nonIterable)` (connectors.md §4).\n    if (Array.isArray(json.entries)) out.push(...json.entries)\n    if (!json.nextPageToken) break\n    pageToken = json.nextPageToken\n  }\n  return out\n}\n","// LogEntry -> ObservedSignal mapping (docs/connectors/firebase.md, ADR-128).\n// One signal per log entry — no aggregation across entries — so each\n// concrete request stays individually traceable back to the raw log line it\n// came from; the shared pipeline (connectors/index.ts) already replays a\n// signal's callCount/errorCount as individual upserts, so nothing is lost by\n// keeping this 1:1.\n//\n// This module never touches Firestore or Firebase Auth data or APIs —\n// out of scope per firebase.md §Scope. It only reads the httpRequest /\n// resource fields off a Cloud Logging LogEntry.\n\nimport type { ObservedSignal } from '../types.js'\nimport { isFirebaseResourceType, type FirebaseResourceType, type LogEntry } from './logging-api.js'\n\n// The provider-vocabulary identity this connector's signals carry through\n// the shared pipeline (targetKind/targetName, per types.ts's ObservedSignal\n// doc comment: \"the provider's own vocabulary\"). Packed into a single string\n// because ObservedSignal.targetName is a plain string field; unpacked only by\n// this connector's own resolveTarget (resolve.ts), never surfaced to the\n// graph. `\\x00` is used as a separator since it cannot appear in an HTTP\n// method token, a GCP resource name, or a URL path.\nconst FIELD_SEP = '\\x00'\n\nexport interface FirebaseTargetIdentity {\n  resourceName: string\n  method: string\n  path: string\n}\n\nexport function packFirebaseTargetName(identity: FirebaseTargetIdentity): string {\n  return [identity.resourceName, identity.method, identity.path].join(FIELD_SEP)\n}\n\nexport function parseFirebaseTargetName(targetName: string): FirebaseTargetIdentity | null {\n  // Split on the first two separators only — a path (always the last field)\n  // may itself carry no separator characters in practice, but splitting\n  // greedily here rather than on every occurrence keeps this correct even if\n  // it ever did.\n  const firstSep = targetName.indexOf(FIELD_SEP)\n  if (firstSep === -1) return null\n  const resourceName = targetName.slice(0, firstSep)\n  const rest = targetName.slice(firstSep + 1)\n  const secondSep = rest.indexOf(FIELD_SEP)\n  if (secondSep === -1) return null\n  const method = rest.slice(0, secondSep)\n  const path = rest.slice(secondSep + 1)\n  if (!resourceName || !method || !path) return null\n  return { resourceName, method, path }\n}\n\n// The resource-identity label Google's own monitored-resource schema carries\n// per type (confirmed at\n// https://cloud.google.com/logging/docs/api/v2/resource-list):\n//   cloud_function      -> labels.function_name\n//   cloud_run_revision   -> labels.service_name\n//   firebase_domain      -> labels.site_name\nfunction resourceNameFor(\n  type: FirebaseResourceType,\n  labels: Record<string, string> | undefined,\n): string | null {\n  if (!labels) return null\n  switch (type) {\n    case 'cloud_function':\n      return labels['function_name'] ?? null\n    case 'cloud_run_revision':\n      return labels['service_name'] ?? null\n    case 'firebase_domain':\n      return labels['site_name'] ?? null\n  }\n}\n\n// `httpRequest.requestUrl` is documented as \"typically without the scheme,\n// host, port, and query portion\" — i.e. usually already a bare path — but a\n// deployment that logs a full absolute URL is handled too. Returns null when\n// the value is neither a bare path nor a parseable absolute URL, the same\n// \"honest miss, never guessed\" discipline `pathOf` uses in\n// extract/calls/route-match.ts.\nfunction pathFromRequestUrl(requestUrl: unknown): string | null {\n  // Typed a string upstream, but this reads a raw Cloud Logging record — a\n  // shape drift handing a number/object here drops honestly rather than\n  // throwing on `.startsWith` (connectors.md §4).\n  if (typeof requestUrl !== 'string' || requestUrl.length === 0) return null\n  if (requestUrl.startsWith('/')) {\n    const withoutQuery = requestUrl.split('?')[0]\n    return withoutQuery && withoutQuery.length > 0 ? withoutQuery : '/'\n  }\n  try {\n    const candidate = requestUrl.startsWith('//') ? `https:${requestUrl}` : requestUrl\n    const parsed = new URL(candidate)\n    return parsed.pathname || '/'\n  } catch {\n    return null\n  }\n}\n\n// A response is counted as an error at the 5xx threshold — the same\n// unambiguous-failure line ingest.ts draws for a failing HTTP response\n// (see the `status >= 500` branch in handleSpan's failing-response-incident\n// logic). A 4xx is a plausible client error, not necessarily a service\n// defect, so it isn't counted here.\nconst ERROR_STATUS_THRESHOLD = 500\n\n// Maps one Cloud Logging LogEntry to one ObservedSignal. Returns null for an\n// entry this connector can't honestly attribute — an unrecognised resource\n// type (filter should already exclude these, but never trust the filter\n// alone), a resource with no identity label, or an httpRequest missing the\n// method/path a signal needs. Nothing here is guessed or fabricated.\nexport function mapLogEntryToSignal(entry: LogEntry | null | undefined): ObservedSignal | null {\n  // A shape-drifted response can carry a null/garbage slot; drop it honestly\n  // rather than throwing on `.resource` (connectors.md §4).\n  if (!entry || typeof entry !== 'object') return null\n  const resourceType = entry.resource?.type\n  if (!resourceType || !isFirebaseResourceType(resourceType)) return null\n\n  const resourceName = resourceNameFor(resourceType, entry.resource?.labels)\n  if (!resourceName) return null\n\n  const req = entry.httpRequest\n  if (!req) return null\n  if (typeof req.requestMethod !== 'string' || req.requestMethod.length === 0) return null\n  const method = req.requestMethod.toUpperCase()\n  const path = pathFromRequestUrl(req.requestUrl)\n  if (path === null) return null\n\n  const timestamp = entry.timestamp\n  if (typeof timestamp !== 'string' || timestamp.length === 0) return null\n\n  const isError = typeof req.status === 'number' && req.status >= ERROR_STATUS_THRESHOLD\n\n  return {\n    targetKind: resourceType,\n    targetName: packFirebaseTargetName({ resourceName, method, path }),\n    callCount: 1,\n    errorCount: isError ? 1 : 0,\n    lastObservedIso: timestamp,\n  }\n}\n\nexport function mapLogEntriesToSignals(entries: LogEntry[]): ObservedSignal[] {\n  const out: ObservedSignal[] = []\n  for (const entry of entries) {\n    const signal = mapLogEntryToSignal(entry)\n    if (signal) out.push(signal)\n  }\n  return out\n}\n","// Target resolution — the Firebase-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning a signal's (resourceName, method,\n// path) into a NEAT node id. Two independent lookups happen here, in order:\n//\n//   1. resourceName -> NEAT manifest service name, via an explicit config-time\n//      mapping (FirebaseServiceMap below) — GCP resource names won't\n//      generally match `package.json#name`, the same gap ADR-127 documents\n//      for Railway's own `serviceId` and resolves the same way: supplied\n//      once at connector setup, never guessed at poll time.\n//   2. (service, method, path) -> a statically-extracted RouteNode, via the\n//      same path-template normalisation extract/calls/route-match.ts already\n//      uses to match a client call site against a server's declared route.\n//\n// A miss at either step returns null — an honest, documented gap (firebase.md\n// §Fusion's \"raw handler, no Express app\" case), never a fabricated edge.\n//\n// This module never mutates the graph (ADR-030) — it only reads RouteNode /\n// ServiceNode attributes already there, matching every other file in\n// packages/core/src/connectors/**.\n\nimport { NodeType, EdgeType, type RouteNode } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { normalizePathTemplate } from '../../extract/routes.js'\nimport { inferServiceName } from '../infer-service.js'\nimport type { ConnectorContext, ObservedSignal } from '../types.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport type { FirebaseResourceType } from './logging-api.js'\nimport { parseFirebaseTargetName } from './map.js'\n\n// Explicit config-time mapping from a GCP hosting-platform resource name to\n// the NEAT manifest service name that resolves `serviceId(name)`\n// (packages/types/src/identity.ts) — the same \"resolved once, never guessed\"\n// discipline ADR-127 states for Railway's serviceId mapping. Keyed by\n// resource type because the same literal name could coincidentally collide\n// across a Cloud Function, a Cloud Run service, and a Hosting site.\nexport interface FirebaseServiceMap {\n  // Cloud Functions (2nd gen) surfaced under the `cloud_function` monitored\n  // resource — function_name -> NEAT service name.\n  functions?: Record<string, string>\n  // Cloud Run services, including 2nd-gen Functions surfaced under\n  // `cloud_run_revision` instead — service_name -> NEAT service name.\n  cloudRun?: Record<string, string>\n  // Firebase Hosting sites (`firebase_domain`) — site_name -> NEAT service\n  // name.\n  hosting?: Record<string, string>\n  // Opt-in (the hosted daemon sets it): when a resource has no explicit entry above, work out its service from\n  // the graph itself instead of leaving it unresolved. First a service whose name matches the resource name\n  // (ignoring case and separators), then the one service that statically declares a route matching the\n  // request's method and path. Ambiguous or absent stays an honest miss. Explicit entries always win, and a\n  // local run never sets this, so its behaviour is unchanged.\n  inferServices?: boolean\n  // Opt-in (the hosted daemon sets it alongside the Cloud Run connector): skip the `cloud_run_revision`\n  // resource type. The Cloud Run connector reads those request logs too, pinned to Cloud Run's own request\n  // log, so leaving both on would count the same request twice. Firebase then covers `cloud_function` and\n  // `firebase_domain` only.\n  excludeCloudRun?: boolean\n}\n\nfunction neatServiceNameFor(\n  resourceType: FirebaseResourceType,\n  resourceName: string,\n  serviceMap: FirebaseServiceMap,\n): string | null {\n  switch (resourceType) {\n    case 'cloud_function':\n      return serviceMap.functions?.[resourceName] ?? null\n    case 'cloud_run_revision':\n      return serviceMap.cloudRun?.[resourceName] ?? null\n    case 'firebase_domain':\n      return serviceMap.hosting?.[resourceName] ?? null\n  }\n}\n\ninterface RouteEntry {\n  method: string\n  normalizedPath: string\n  routeNodeId: string\n}\n\n// Every RouteNode owned by one NEAT service, normalised for matching — the\n// same reduction extract/calls/route-match.ts's buildRouteIndex applies,\n// scoped here to a single service since resolveTarget already knows which\n// service a signal maps to. Rebuilt per call rather than cached: a connector\n// poll tick runs at most once a minute (DEFAULT_POLL_INTERVAL_MS,\n// connectors/index.ts) against a project-sized graph, so a fresh scan per\n// signal is cheap relative to the network round-trip poll() already made,\n// and it never risks matching against a stale route table if static\n// extraction re-ran mid-poll.\nfunction routeEntriesFor(graph: NeatGraph, serviceName: string): RouteEntry[] {\n  const entries: RouteEntry[] = []\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as unknown as { type?: string }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    if (route.service !== serviceName) return\n    entries.push({\n      method: route.method.toUpperCase(),\n      normalizedPath: normalizePathTemplate(route.pathTemplate),\n      routeNodeId: route.id,\n    })\n  })\n  return entries\n}\n\n// Same compatibility rule route-match.ts's findRoute uses: exact normalised-\n// path match, and a method match unless the route is method-agnostic (`ALL`)\n// — a connector signal's method is always known (Cloud Logging's\n// httpRequest.requestMethod), unlike a statically-parsed client call site\n// where the method can be unresolvable, so there's no \"method undetermined\"\n// branch to mirror here.\nfunction findRoute(entries: RouteEntry[], method: string, normalizedPath: string): RouteEntry | undefined {\n  return entries.find(\n    (e) => e.normalizedPath === normalizedPath && (e.method === 'ALL' || e.method === method),\n  )\n}\n\n// Builds the resolveTarget callback runConnectorPoll (connectors/index.ts)\n// calls once per signal. Closes over `graph` because ResolveConnectorTarget's\n// own signature (types.ts) doesn't carry it — the same closure pattern every\n// ConnectorRegistration's resolveTarget is expected to use.\nexport function createFirebaseResolveTarget(\n  graph: NeatGraph,\n  serviceMap: FirebaseServiceMap,\n): ResolveConnectorTarget {\n  return (signal: ObservedSignal, _ctx: ConnectorContext): ResolvedConnectorTarget | null => {\n    const resourceType = signal.targetKind\n    if (resourceType !== 'cloud_function' && resourceType !== 'cloud_run_revision' && resourceType !== 'firebase_domain') {\n      return null\n    }\n    const identity = parseFirebaseTargetName(signal.targetName)\n    if (!identity) return null\n\n    const normalizedPath = normalizePathTemplate(identity.path)\n    const serviceName =\n      neatServiceNameFor(resourceType, identity.resourceName, serviceMap) ??\n      (serviceMap.inferServices\n        ? inferServiceName(graph, identity.resourceName, identity.method, identity.path)\n        : null)\n    // No configured mapping for this resource (and, when inference is on, nothing in the graph pins it\n    // down) — honestly unresolved rather than guessed.\n    if (!serviceName) return null\n\n    const match = findRoute(routeEntriesFor(graph, serviceName), identity.method, normalizedPath)\n    // No static route recognises this path — the \"raw handler, no Express\n    // app\" gap firebase.md §Fusion documents explicitly as an accepted,\n    // honest gap rather than something to route around. Landing this on the\n    // service's own ServiceNode as both source and target would be a\n    // self-loop (the graph disallows them, graph.ts's\n    // `allowSelfLoops: false`), so it's left unresolved rather than forcing\n    // a meaningless edge or inventing a new node type firebase.md's \"no new\n    // NodeType\" explicitly rules out.\n    if (!match) return null\n\n    return {\n      targetNodeId: match.routeNodeId,\n      serviceName,\n      edgeType: EdgeType.CALLS,\n    }\n  }\n}\n","// Graph-derived service inference for the GCP connectors (Firebase, Cloud Run, GCP LB). Their resolvers\n// map a GCP resource name (a function, a Cloud Run service, an LB backend) to the NEAT service that owns it,\n// and GCP names rarely match `package.json#name`. A hosted tenant can't be asked to hand-write that map, so\n// when a connector's config sets `inferServices`, an unmapped resource is worked out from the graph:\n//\n//   1. a service whose name matches the resource name, ignoring case and separators;\n//   2. otherwise the one service that statically declares a route matching the request's method and path.\n//\n// Ambiguous or absent is a null — an honest miss, never a guess. Explicit config always wins because callers\n// consult it first. This module only reads the graph.\n\nimport { NodeType, type RouteNode } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { normalizePathTemplate } from '../extract/routes.js'\n\nfunction normalizeName(name: string): string {\n  return name.toLowerCase().replace(/[^a-z0-9]/g, '')\n}\n\nexport function inferServiceName(\n  graph: NeatGraph,\n  resourceName: string,\n  method: string,\n  path: string,\n): string | null {\n  const wantedMethod = method.toUpperCase()\n  const wantedPath = normalizePathTemplate(path)\n  const services: string[] = []\n  const owners = new Set<string>()\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as unknown as { type?: string; name?: string }\n    if (node.type === NodeType.ServiceNode && typeof node.name === 'string') {\n      services.push(node.name)\n      return\n    }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    if (!route.pathTemplate || normalizePathTemplate(route.pathTemplate) !== wantedPath) return\n    const routeMethod = route.method.toUpperCase()\n    if (routeMethod === 'ALL' || routeMethod === wantedMethod) owners.add(route.service)\n  })\n  const wanted = normalizeName(resourceName)\n  const byName = services.find((s) => normalizeName(s) === wanted)\n  if (byName) return byName\n  return owners.size === 1 ? [...owners][0]! : null\n}\n","// Cloudflare Workers/Pages connector (docs/connectors/cloudflare.md, ADR-129).\n// Ships at whole-file grain by default, sharpening to route grain when a\n// static router recognizer covers the Worker (ADR-133 §5) — see connector.ts\n// and map.ts. Re-exports the module's public surface for daemon/CLI wiring\n// and for tests.\n\nexport { CloudflareConnector, createCloudflareResolveTarget } from './connector.js'\nexport { queryWorkerInvocations, type TelemetryWindow } from './client.js'\nexport { mapEventToSignal, parseHttpMethodFromTrigger, parsePathFromTrigger } from './map.js'\nexport {\n  CLOUDFLARE_TARGET_KIND,\n  type CloudflareConnectorConfig,\n  type CloudflareObservedSignal,\n  type CloudflareTelemetryEvent,\n  type CloudflareTelemetryEventMetadata,\n  type CloudflareTelemetryQueryResponse,\n  type CloudflareTelemetryWorkersMetadata,\n  type CloudflareWorkerMapping,\n} from './types.js'\n","// The Cloudflare Workers/Pages connector (docs/connectors/cloudflare.md,\n// ADR-129). Owns the two provider-specific steps README.md's pipeline\n// diagram assigns to `connectors/<provider>/`: fetching signals off\n// Cloudflare's own API (`poll`, via client.ts + map.ts) and mapping a\n// signal's targetKind/targetName to a NEAT node id\n// (`createCloudflareResolveTarget`). Everything downstream — resolving a\n// static call site, minting the OBSERVED edge — is the shared pipeline in\n// connectors/index.ts; this module never mutates the graph itself (ADR-030 —\n// the honest-fallback case below declares a need via `ensureInfraNode`\n// instead of creating anything directly, docs/contracts/connectors.md §4a).\n\nimport { EdgeType, NodeType, fileId, infraId } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { normalizePathTemplate } from '../../extract/routes.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport type { ConnectorContext, ObservedConnector } from '../types.js'\nimport { queryWorkerInvocations } from './client.js'\nimport { mapEventToSignal } from './map.js'\nimport { CLOUDFLARE_TARGET_KIND, type CloudflareConnectorConfig, type CloudflareObservedSignal } from './types.js'\n\n// Cloudflare's docs don't confirm the Telemetry Query API's own max lookback\n// window (docs/connectors/cloudflare.md needs-endpoint-testing); a\n// conservative hour, same discipline connectors.md's \"Poll cadence and\n// backfill\" requires of every provider — a gap larger than this backfills\n// from `now - maxLookbackMs`, never an unbounded full-history query.\nconst DEFAULT_MAX_LOOKBACK_MS = 60 * 60 * 1000\n\nfunction resolveFromMs(since: string | undefined, maxLookbackMs: number | undefined): number {\n  const cap = maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS\n  const now = Date.now()\n  const floor = now - cap\n  if (!since) return floor\n  const parsed = Date.parse(since)\n  if (Number.isNaN(parsed)) return floor\n  return Math.max(parsed, floor)\n}\n\nexport class CloudflareConnector implements ObservedConnector {\n  readonly provider = 'cloudflare'\n\n  constructor(private readonly config: CloudflareConnectorConfig) {}\n\n  async poll(ctx: ConnectorContext): Promise<CloudflareObservedSignal[]> {\n    const toMs = Date.now()\n    const fromMs = resolveFromMs(ctx.since, this.config.maxLookbackMs)\n    const events = await queryWorkerInvocations(ctx, this.config, { fromMs, toMs })\n\n    const signals: CloudflareObservedSignal[] = []\n    for (const event of events) {\n      const signal = mapEventToSignal(event)\n      if (signal) signals.push(signal)\n    }\n    return signals\n  }\n}\n\n// Scan the live graph for the entry FileNode ADR-133's `extract/infra/\n// cloudflare.ts` tagged with this exact Worker script name\n// (`platform === 'cloudflare' && platformName === workerName`). A plain scan,\n// not a cached index — mirrors `reconcileObservedRelPath`'s own\n// `graph.forEachNode` walk (ingest.ts); per-project Worker counts are small\n// enough that this isn't worth a cache the live graph would have to\n// invalidate on every re-extraction.\nfunction findTaggedWorkerFileNode(graph: NeatGraph, workerName: string): string | null {\n  let found: string | null = null\n  graph.forEachNode((id, attrs) => {\n    if (found) return\n    const a = attrs as { type?: string; platform?: string; platformName?: string }\n    if (a.type === NodeType.FileNode && a.platform === 'cloudflare' && a.platformName === workerName) {\n      found = id\n    }\n  })\n  return found\n}\n\n// Route-grain sharpening (ADR-133 §5): once a Hono (or future-recognized)\n// Worker's routes exist as RouteNodes, an invocation whose parsed\n// (method, path) matches one lands on that RouteNode instead of the whole\n// entry file — the same param-agnostic comparison `route-match.ts` already\n// uses for cross-service HTTP client↔route matching. No match (no route\n// recognizer covers this Worker's router, or the path doesn't line up) keeps\n// the existing whole-file target — sharpens automatically when the static\n// side supports it, stays honest when it doesn't.\nfunction findMatchingRouteNode(\n  graph: NeatGraph,\n  serviceName: string,\n  method: string,\n  path: string,\n): string | null {\n  const normalizedPath = normalizePathTemplate(path)\n  let found: string | null = null\n  graph.forEachNode((id, attrs) => {\n    if (found) return\n    const a = attrs as { type?: string; service?: string; method?: string; pathTemplate?: string }\n    if (a.type !== NodeType.RouteNode || a.service !== serviceName) return\n    if (!a.pathTemplate || normalizePathTemplate(a.pathTemplate) !== normalizedPath) return\n    const routeMethod = (a.method ?? '').toUpperCase()\n    if (routeMethod !== 'ALL' && routeMethod !== method) return\n    found = id\n  })\n  return found\n}\n\n// Provider-specific target resolution (README.md's pipeline step 2). Per\n// docs/connectors/cloudflare.md §Fusion, the signal's target is the Worker's\n// single entry FileNode by default — not the caller, since this API carries\n// no caller identity at all, only \"this script was invoked\". The edge that\n// results, `service --CALLS--> entryFile`, mirrors the WebSocket channel\n// precedent (ADR-125): a liveness signal minted from a service onto its own\n// child node, reusing an existing edge verb rather than inventing one for\n// \"this file got reached\".\n//\n// Resolution order (ADR-133 §3, docs/contracts/connectors.md §4a):\n//   1. `config.workers[scriptName]` — an explicit override, wins outright.\n//   2. The extracted graph's own `platform`/`platformName` tag — the derived\n//      default, no config entry needed at all for a scanned project.\n//   3. Honest fallback — Cloudflare observed a Worker this scan never\n//      declared. Lands a real edge via `ensureInfraNode` (surfacing as a\n//      `missing-extracted` divergence) instead of a silent `null` drop.\n// Whichever of (1)/(2) resolves, a route-grain match (ADR-133 §5) is\n// attempted against that service's own RouteNodes before falling back to the\n// whole-file target — sharpening happens automatically once a static router\n// recognizer covers this Worker, never forced when it doesn't.\nexport function createCloudflareResolveTarget(\n  config: CloudflareConnectorConfig,\n  graph: NeatGraph,\n): ResolveConnectorTarget {\n  return (signal): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== CLOUDFLARE_TARGET_KIND) return null\n    const scriptName = signal.targetName\n    const { method, path } = signal as CloudflareObservedSignal\n\n    const resolveRouteGrain = (serviceName: string, wholeFileId: string): string => {\n      if (!method || !path) return wholeFileId\n      return findMatchingRouteNode(graph, serviceName, method, path) ?? wholeFileId\n    }\n\n    const mapping = config.workers?.[scriptName]\n    if (mapping) {\n      const wholeFileId = fileId(mapping.service, mapping.entryFile)\n      return {\n        targetNodeId: resolveRouteGrain(mapping.service, wholeFileId),\n        serviceName: mapping.service,\n        edgeType: EdgeType.CALLS,\n      }\n    }\n\n    const taggedFileId = findTaggedWorkerFileNode(graph, scriptName)\n    if (taggedFileId) {\n      const fileNode = graph.getNodeAttributes(taggedFileId) as { service: string }\n      return {\n        targetNodeId: resolveRouteGrain(fileNode.service, taggedFileId),\n        serviceName: fileNode.service,\n        edgeType: EdgeType.CALLS,\n      }\n    }\n\n    return {\n      targetNodeId: infraId('cloudflare-worker', scriptName),\n      serviceName: scriptName,\n      edgeType: EdgeType.CALLS,\n      ensureInfraNode: { kind: 'cloudflare-worker', name: scriptName, provider: 'cloudflare' },\n    }\n  }\n}\n","// Workers Observability Telemetry Query API client (docs/connectors/cloudflare.md\n// §Surfaces used #1). Read-only, ambient — this issues exactly one query per\n// poll tick against telemetry Cloudflare already collects when a Worker\n// deploys with `observability.enabled`; it never issues a synthetic request\n// to the Worker itself (connectors.md §2).\n\nimport { randomUUID } from 'node:crypto'\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type { ConnectorContext } from '../types.js'\nimport type { CloudflareConnectorConfig, CloudflareTelemetryEvent, CloudflareTelemetryQueryResponse } from './types.js'\n\nconst DEFAULT_BASE_URL = 'https://api.cloudflare.com/client/v4'\n\n// The API's own per-response event cap isn't documented (needs-endpoint-\n// testing, docs/connectors/cloudflare.md); this is a conservative default\n// kept well under any plausible limit, overridable per connector config.\nconst DEFAULT_EVENT_LIMIT = 1000\n\nexport interface TelemetryWindow {\n  fromMs: number\n  toMs: number\n}\n\n// `fetchImpl` defaults to the platform global (Node 20 ships `fetch`) and is\n// the seam tests inject a fake response through — dependency injection, not\n// a production mock (contracts.md Rule 5 / connectors.md §5 only bar mocks\n// on the runtime poll path itself).\nexport async function queryWorkerInvocations(\n  ctx: ConnectorContext,\n  config: CloudflareConnectorConfig,\n  window: TelemetryWindow,\n  fetchImpl: typeof fetch = fetch,\n): Promise<CloudflareTelemetryEvent[]> {\n  const token = ctx.credentials.apiToken\n  if (typeof token !== 'string' || token.length === 0) {\n    throw new Error('cloudflare connector: ctx.credentials.apiToken must be a non-empty string')\n  }\n\n  const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL\n  const url = `${baseUrl}/accounts/${config.accountId}/workers/observability/telemetry/query`\n\n  const body = {\n    // Cloudflare's schema requires an identifier per query even for an\n    // ad-hoc, unsaved one — a fresh id per tick, never reused.\n    queryId: `neat-connector-${randomUUID()}`,\n    timeframe: { from: window.fromMs, to: window.toMs },\n    view: 'events',\n    limit: config.eventLimit ?? DEFAULT_EVENT_LIMIT,\n    // The inline query definition. WITHOUT `parameters`, the API treats\n    // `queryId` as a reference to a previously *saved* query and answers 400\n    // \"Query not found\" (confirmed against the live endpoint) — omitting it was\n    // the reason the connector never worked against real Cloudflare. Naming the\n    // `cloudflare-workers` dataset runs the invocation-telemetry query ad-hoc.\n    parameters: { datasets: ['cloudflare-workers'] },\n    // Execute without persisting — this is a read, not a saved query\n    // (connectors.md §2's \"never writes on the read path\" applies to\n    // Cloudflare's own query-history state too).\n    dry: true,\n  }\n\n  const res = await junctionFetch(\n    url,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        ...bearerAuthHeader(token),\n      },\n      body: JSON.stringify(body),\n    },\n    // accountKey: the Cloudflare account id (ADR-131's own worked example) —\n    // the Telemetry Query API's ~300/5min limit is enforced per account.\n    { provider: 'cloudflare', accountKey: config.accountId, fetchImpl },\n  )\n\n  if (!res.ok) {\n    throw new Error(\n      `cloudflare connector: telemetry query failed (${res.status} ${res.statusText})`,\n    )\n  }\n\n  const payload = (await res.json()) as CloudflareTelemetryQueryResponse\n  if (!payload.success) {\n    const message = payload.errors?.map((e) => e.message).join('; ') || 'unknown error'\n    throw new Error(`cloudflare connector: telemetry query returned an error (${message})`)\n  }\n\n  // `success: true` with no `result.events.events` array at all is shape\n  // drift — a real API-contract change, not the ordinary \"no events this\n  // window\" case (which arrives as an *empty* array here and warrants no\n  // warning). Silently treating both the same way hid an API change behind a\n  // quiet [] return; this distinguishes them so a real drift is loud. A\n  // non-array `events` (drift handing back an object) is the same class of\n  // change — caught here rather than crashing poll()'s `for..of` on it.\n  const events = payload.result?.events?.events\n  if (!Array.isArray(events)) {\n    console.warn(\n      '[neat connector] cloudflare: telemetry query returned success:true but no result.events.events array — the response shape may have changed; treating as zero events this tick',\n    )\n    return []\n  }\n  return events\n}\n","// Maps one Telemetry Query API invocation record to an ObservedSignal\n// (docs/connectors/cloudflare.md §Fusion, ADR-129).\n//\n// The only route-shaped field this API exposes is `$metadata.trigger`\n// (\"GET /users\", \"POST /orders\", or a non-HTTP trigger like \"queue message\").\n// The leading HTTP method token is parsed off it, and — now that a static\n// route recognizer exists for at least one in-Worker router shape (Hono,\n// ADR-133 §5) — the remainder is carried as `path` too, so\n// `createCloudflareResolveTarget` (connector.ts) can attempt a route-grain\n// match against that Worker's own RouteNodes. When no match resolves, the\n// signal still fuses at whole-file grain — the same \"sharpens automatically\n// once the static side supports it\" pattern the rest of the connectors plane\n// already follows (route-match.ts's own client↔route matching). A trigger\n// that isn't HTTP-shaped (cron, queue, alarm, ...) carries no method to parse\n// and is out of scope for this cut (§Out of scope) — dropped here, honestly,\n// rather than fabricating a method or forcing it through as an unresolvable\n// signal.\n\nimport { CLOUDFLARE_TARGET_KIND, type CloudflareObservedSignal, type CloudflareTelemetryEvent } from './types.js'\n\n// The HTTP methods a `trigger` string's leading token can actually name\n// (RFC 7231 + CONNECT/TRACE). A closed vocabulary, the same discipline\n// routes.ts's own ROUTER_METHODS set applies to router registrations, so a\n// non-HTTP trigger (\"queue message\", a cron expression, \"scheduled\") never\n// misparses its own leading word as a method.\nconst HTTP_METHODS = new Set([\n  'GET',\n  'POST',\n  'PUT',\n  'PATCH',\n  'DELETE',\n  'HEAD',\n  'OPTIONS',\n  'TRACE',\n  'CONNECT',\n])\n\nconst LEADING_TOKEN_RE = /^(\\S+)\\s+\\S/\n\nexport function parseHttpMethodFromTrigger(trigger: unknown): string | null {\n  // `trigger` is typed a string upstream, but this maps a raw JSON response —\n  // a shape drift that hands us a number or object here drops honestly rather\n  // than throwing on `.trim()` (connectors.md §4 honest-miss discipline).\n  if (typeof trigger !== 'string') return null\n  const match = LEADING_TOKEN_RE.exec(trigger.trim())\n  const token = match?.[1]\n  if (!token) return null\n  const method = token.toUpperCase()\n  return HTTP_METHODS.has(method) ? method : null\n}\n\n// The path portion of an HTTP-shaped trigger — everything after the leading\n// method token, e.g. \"GET /users/123\" → \"/users/123\". Only called once\n// `parseHttpMethodFromTrigger` has already confirmed the leading token is a\n// real method, so there's no risk of misreading a non-HTTP trigger's own\n// text as a path. A query string, if present, rides along; route matching\n// canonicalises it away the same way a declared RouteNode template does\n// (routes.ts's `canonicalizeTemplate`).\nexport function parsePathFromTrigger(trigger: string): string | undefined {\n  const trimmed = trigger.trim()\n  const spaceIdx = trimmed.indexOf(' ')\n  if (spaceIdx === -1) return undefined\n  const rest = trimmed.slice(spaceIdx + 1).trim()\n  return rest.length > 0 ? rest : undefined\n}\n\n// 5xx is treated as the unambiguous failure threshold for this connector's\n// own errorCount, mirroring the span-derived `isError` convention elsewhere\n// in ingest.ts (a bare 4xx is often correct app behavior — an auth probe, a\n// conditional fetch — and isn't held against the edge's own error tally).\nconst ERROR_STATUS_THRESHOLD = 500\n\nexport function mapEventToSignal(event: CloudflareTelemetryEvent | null | undefined): CloudflareObservedSignal | null {\n  // A shape-drifted response can hand a poll tick a null/garbage array slot;\n  // drop it honestly rather than throwing on `.$metadata` (connectors.md §4).\n  if (!event || typeof event !== 'object') return null\n  const metadata = event.$metadata\n  const workers = event.$workers\n\n  const method = parseHttpMethodFromTrigger(metadata?.trigger)\n  if (!method) return null\n\n  // `$workers.scriptName` and `$metadata.service` are both documented as\n  // \"Worker script name\" — prefer the Workers-Runtime-specific field when\n  // present, fall back to the always-present metadata field. A non-string\n  // value (shape drift) drops honestly rather than riding through as a\n  // non-string targetName the graph would then have to carry.\n  const scriptName = workers?.scriptName ?? metadata?.service\n  if (typeof scriptName !== 'string' || scriptName.length === 0) return null\n\n  const timestampMs = event.timestamp ?? metadata?.startTime\n  if (typeof timestampMs !== 'number' || !Number.isFinite(timestampMs)) return null\n  // A finite-but-out-of-range epoch (a value in ns/µs, or a bogus one) makes\n  // an Invalid Date whose `.toISOString()` throws — drop it honestly rather\n  // than fabricating a timestamp or crashing the whole tick.\n  const observedAt = new Date(timestampMs)\n  if (Number.isNaN(observedAt.getTime())) return null\n\n  const statusCode = metadata?.statusCode\n  const isError = typeof statusCode === 'number' && statusCode >= ERROR_STATUS_THRESHOLD\n  const path = metadata?.trigger ? parsePathFromTrigger(metadata.trigger) : undefined\n\n  return {\n    targetKind: CLOUDFLARE_TARGET_KIND,\n    targetName: scriptName,\n    callCount: 1,\n    errorCount: isError ? 1 : 0,\n    lastObservedIso: observedAt.toISOString(),\n    method,\n    ...(path ? { path } : {}),\n    ...(typeof statusCode === 'number' ? { statusCode } : {}),\n    ...(typeof metadata?.duration === 'number' ? { duration: metadata.duration } : {}),\n  }\n}\n","// Cloudflare Workers/Pages connector — provider-specific shapes\n// (docs/connectors/cloudflare.md, ADR-129; resolution rewired onto the\n// extracted graph's platform tag by ADR-133).\n\nimport type { ObservedSignal } from '../types.js'\n\n// Provider vocabulary for ObservedSignal.targetKind (connectors.md §1 — \"the\n// provider's own vocabulary\", same shape as Supabase's 'supabase-table' /\n// 'supabase-rpc').\nexport const CLOUDFLARE_TARGET_KIND = 'cloudflare-worker-invocation'\n\n// One Cloudflare Worker/Pages script's mapping onto a NEAT service + file.\n// ADR-133's `extract/infra/cloudflare.ts` now derives this pairing\n// automatically — it reads the Worker's `wrangler.toml`/`wrangler.jsonc`\n// `name` field and stamps it (`platformName`) on the entry FileNode\n// `createCloudflareResolveTarget` resolves against directly. This shape\n// survives as the explicit *override* for the config entries below: a repo\n// NEAT hasn't scanned, or a naming edge case auto-discovery can't cover.\nexport interface CloudflareWorkerMapping {\n  service: string\n  entryFile: string\n}\n\nexport interface CloudflareConnectorConfig {\n  accountId: string\n  // Explicit override, checked before the graph's own platform tag (see\n  // createCloudflareResolveTarget in connector.ts). Optional — most projects\n  // need no entry here at all now that extraction auto-discovers the pairing;\n  // scripts with neither an override nor a tagged match fall back to an\n  // honest placeholder InfraNode rather than being silently dropped.\n  workers?: Record<string, CloudflareWorkerMapping>\n  // Cap on how far an absent `since` backfills, ms. Cloudflare's docs don't\n  // confirm the Telemetry Query API's own max lookback window\n  // (docs/connectors/cloudflare.md flags this needs-endpoint-testing); default\n  // below is a conservative hour, capped the same way connectors.md's\n  // \"Poll cadence and backfill\" section requires for every provider.\n  maxLookbackMs?: number\n  // Events requested per query. The API's own per-response cap isn't\n  // documented either; kept well under any plausible limit until a live\n  // check confirms one. Pagination (the `offset` cursor) isn't implemented in\n  // v1 — same needs-endpoint-testing gap, since the docs surveyed don't spell\n  // out the cursor's exact semantics.\n  eventLimit?: number\n  // Override for tests; defaults to Cloudflare's real API host.\n  baseUrl?: string\n}\n\n// --- Workers Observability Telemetry Query API response shapes ---\n//\n// Confirmed against\n// developers.cloudflare.com/api/resources/workers/subresources/observability/subresources/telemetry/methods/query/\n// (fetched 2026-07-03) rather than assumed. Only the fields this connector\n// actually reads are typed here — the live response carries substantially\n// more (the `traces`/`calculations`/`invocations` views, per-event\n// diagnostics-channel data, etc.) that v1 has no use for.\n//\n// Two fields name the Worker script per event: `$metadata.service` (present\n// on every event type) and `$workers.scriptName` (present only when the\n// `$workers` sub-object is, i.e. for genuine Workers Runtime events). Both\n// are documented as \"Worker script name\" — map.ts prefers `$workers.scriptName`\n// when present and falls back to `$metadata.service`.\nexport interface CloudflareTelemetryEventMetadata {\n  service?: string\n  trigger?: string\n  url?: string\n  statusCode?: number\n  duration?: number\n  traceDuration?: number\n  startTime?: number\n  endTime?: number\n}\n\nexport interface CloudflareTelemetryWorkersMetadata {\n  eventType?: string\n  scriptName?: string\n  outcome?: string\n}\n\nexport interface CloudflareTelemetryEvent {\n  timestamp?: number\n  dataset?: string\n  $metadata?: CloudflareTelemetryEventMetadata\n  $workers?: CloudflareTelemetryWorkersMetadata\n}\n\nexport interface CloudflareTelemetryQueryResponse {\n  success: boolean\n  errors?: { message: string }[]\n  messages?: { message: string }[]\n  result?: {\n    events?: {\n      count?: number\n      events: CloudflareTelemetryEvent[]\n    }\n  }\n}\n\n// ObservedSignal, widened with the fields this connector's own mapping step\n// carries — `method` and `path` (parsed from `trigger`), `statusCode`,\n// `duration`. None of these are read by the generic connectors pipeline\n// (connectors/index.ts only consumes the base ObservedSignal shape); `method`/\n// `statusCode`/`duration` exist for metadata/testing purposes, while `path` is\n// read by this provider's own `createCloudflareResolveTarget` (connector.ts)\n// to attempt a route-grain match against the Worker's RouteNodes (ADR-133 §5)\n// before falling back to the whole-file target ADR-129 shipped.\nexport interface CloudflareObservedSignal extends ObservedSignal {\n  method: string\n  path?: string\n  statusCode?: number\n  duration?: number\n}\n","// Vercel connector barrel (docs/contracts/connectors.md §9, ADR-146). Vercel is\n// the connectors plane's first *push* provider — it provisions a Drain instead\n// of exposing a `poll()`, so this dir carries a Drains REST client and its\n// types, not the client/connector/map/resolve split a pull provider has. The\n// push dispatch entry that wires these into `neat connector add/remove/test`\n// lives in `connectors/registry.ts` (`PUSH_PROVIDER_DISPATCH`), mirroring how\n// the pull providers register.\nexport { createVercelDrain, deleteVercelDrain, testVercelDrainDelivery } from './client.js'\nexport type {\n  VercelConnectorConfig,\n  VercelCredentials,\n  VercelDrainCreated,\n  VercelDrainTestResult,\n} from './types.js'\n","// Vercel Drains REST API client (docs/contracts/connectors.md §9, ADR-146).\n// Three calls, all through the shared junction (ADR-131) with a `vercel` rate\n// bucket and the `fetchImpl` DI seam every connector uses for tests:\n//\n//   createDrain    POST   /v1/drains        provision the trace drain\n//   deleteDrain    DELETE /v1/drains/{id}   deprovision it (idempotent)\n//   testDelivery   POST   /v1/drains/test   validate config + endpoint reachability\n//\n// Unlike a pull client this issues no telemetry query — it configures the\n// provider to push. The drain forwards traces as OTLP/HTTP `encoding: 'json'`\n// (`{ resourceSpans: [...] }`) to `config.endpoint`, which the daemon's\n// `/v1/traces` receiver decodes on its `application/json` path (otel.ts).\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type {\n  VercelConnectorConfig,\n  VercelCredentials,\n  VercelDrainCreated,\n  VercelDrainTestResult,\n} from './types.js'\n\nconst DEFAULT_API_BASE_URL = 'https://api.vercel.com'\nconst DEFAULT_DRAIN_NAME = 'neat-otlp'\n\n// `schemas: { trace: { version: 'v1' } }` is how POST /v1/drains selects\n// distributed traces in OpenTelemetry format (verified against the live API).\nconst TRACE_SCHEMAS = { trace: { version: 'v1' } } as const\n\nfunction apiBase(config: VercelConnectorConfig): string {\n  return config.apiBaseUrl ?? DEFAULT_API_BASE_URL\n}\n\n// teamId rides as a query param on every Drains call (Drains are team-scoped).\nfunction teamQuery(config: VercelConnectorConfig): string {\n  return `?teamId=${encodeURIComponent(config.teamId)}`\n}\n\n// The delivery block, shared by create and test so both describe the exact same\n// sink. `type: 'http'` + `encoding: 'json'` is the custom-endpoint OTLP/JSON\n// variant (verified live: `type` is a per-variant constant, `encoding` for a\n// trace drain is `json`/`ndjson`). The daemon's OTLP bearer travels as a custom\n// delivery header — the receiver requires it (ADR-073 §4).\nfunction drainDelivery(config: VercelConnectorConfig, otelToken: string): Record<string, unknown> {\n  return {\n    type: 'http',\n    endpoint: config.endpoint,\n    encoding: 'json',\n    headers: bearerAuthHeader(otelToken),\n    ...(config.secret ? { secret: config.secret } : {}),\n  }\n}\n\n// Pull a short, secret-free message out of a Vercel error body (`{ error: {\n// code, message } }`). The message names validation/HTTP detail — never the\n// token, which only ever rode in the Authorization header.\nasync function describeError(res: Response): Promise<string> {\n  try {\n    const data = (await res.json()) as { error?: { message?: unknown } }\n    const message = data?.error?.message\n    return typeof message === 'string' && message.length > 0 ? ` — ${message}` : ''\n  } catch {\n    return ''\n  }\n}\n\n/**\n * Provision the trace drain. Returns the created drain's id (stored back into\n * the entry's `options.drainId` so `remove` can tear it down) and its status.\n * Throws on any non-2xx or a response missing the id — a missing id is shape\n * drift, not a silent success (the #841 discipline).\n */\nexport async function createVercelDrain(\n  config: VercelConnectorConfig,\n  credentials: VercelCredentials,\n  fetchImpl: typeof fetch = fetch,\n): Promise<VercelDrainCreated> {\n  const projectIds = config.projectIds ?? []\n  const body = {\n    name: config.drainName ?? DEFAULT_DRAIN_NAME,\n    projects: projectIds.length > 0 ? 'some' : 'all',\n    ...(projectIds.length > 0 ? { projectIds } : {}),\n    schemas: TRACE_SCHEMAS,\n    delivery: drainDelivery(config, credentials.otelToken),\n    source: { kind: 'self-served' },\n  }\n\n  const res = await junctionFetch(\n    `${apiBase(config)}/v1/drains${teamQuery(config)}`,\n    {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json', ...bearerAuthHeader(credentials.token) },\n      body: JSON.stringify(body),\n    },\n    { provider: 'vercel', accountKey: config.teamId, fetchImpl },\n  )\n\n  if (!res.ok) {\n    throw new Error(\n      `vercel connector: create drain failed (${res.status} ${res.statusText}${await describeError(res)})`,\n    )\n  }\n  const payload = (await res.json().catch(() => null)) as Partial<VercelDrainCreated> | null\n  if (!payload || typeof payload.id !== 'string' || payload.id.length === 0) {\n    throw new Error(\n      'vercel connector: create drain returned no drain id — the Drains API response shape may have changed',\n    )\n  }\n  return {\n    id: payload.id,\n    ...(payload.status ? { status: payload.status } : {}),\n    ...(payload.disabledReason ? { disabledReason: payload.disabledReason } : {}),\n  }\n}\n\n/**\n * Tear the drain down. Idempotent by contract (connectors.md §9): a 404 —\n * already gone — is success, not an error, so a re-run of `remove` (or a drain\n * a human deleted in the dashboard) never wedges.\n */\nexport async function deleteVercelDrain(\n  config: VercelConnectorConfig,\n  drainId: string,\n  credentials: VercelCredentials,\n  fetchImpl: typeof fetch = fetch,\n): Promise<void> {\n  const res = await junctionFetch(\n    `${apiBase(config)}/v1/drains/${encodeURIComponent(drainId)}${teamQuery(config)}`,\n    { method: 'DELETE', headers: { ...bearerAuthHeader(credentials.token) } },\n    { provider: 'vercel', accountKey: config.teamId, fetchImpl },\n  )\n  if (res.ok || res.status === 404) return\n  throw new Error(\n    `vercel connector: delete drain failed (${res.status} ${res.statusText}${await describeError(res)})`,\n  )\n}\n\n/**\n * Validate the drain configuration without provisioning anything. Vercel's\n * `POST /v1/drains/test` both authenticates the API token and pings the\n * endpoint with a sample event, so a `status: 'success'` verdict means the\n * token is live *and* the daemon's OTLP endpoint is reachable and accepted the\n * drain's bearer. A bad token (401/403) and a bad request (4xx) are mapped to\n * `failure` with a distinct, secret-free reason; a reachable-but-rejecting\n * endpoint comes back in the 200 body's own `status`/`error`.\n */\nexport async function testVercelDrainDelivery(\n  config: VercelConnectorConfig,\n  credentials: VercelCredentials,\n  fetchImpl: typeof fetch = fetch,\n): Promise<VercelDrainTestResult> {\n  const res = await junctionFetch(\n    `${apiBase(config)}/v1/drains/test${teamQuery(config)}`,\n    {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json', ...bearerAuthHeader(credentials.token) },\n      body: JSON.stringify({ schemas: TRACE_SCHEMAS, delivery: drainDelivery(config, credentials.otelToken) }),\n    },\n    { provider: 'vercel', accountKey: config.teamId, fetchImpl },\n  )\n\n  if (res.status === 401 || res.status === 403) {\n    return { status: 'failure', error: `vercel rejected the API token (HTTP ${res.status})` }\n  }\n  if (!res.ok) {\n    return {\n      status: 'failure',\n      error: `vercel drain validation failed (${res.status} ${res.statusText}${await describeError(res)})`,\n    }\n  }\n  const payload = (await res.json().catch(() => null)) as VercelDrainTestResult | null\n  return {\n    ...(payload?.status ? { status: payload.status } : {}),\n    ...(payload?.error ? { error: payload.error } : {}),\n    ...(payload?.endpoint ? { endpoint: payload.endpoint } : {}),\n  }\n}\n","import type { ResolveConnectorTarget } from '../index.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport { DEFAULT_NEON_STATEMENT_LIMIT, fetchNeonStatements } from './client.js'\nimport { diffNeonStatementsToSignals, type NeonStatementBaseline } from './map.js'\nimport { createNeonResolveTarget } from './resolve.js'\nimport { readNeonCredentials, type NeonConnectorConfig } from './types.js'\n\nexport * from './client.js'\nexport * from './map.js'\nexport * from './resolve.js'\nexport * from './types.js'\n\nexport interface NeonConnectorDeps {\n  fetchStatements?: typeof fetchNeonStatements\n  now?: () => Date\n}\n\nexport class NeonConnector implements ObservedConnector {\n  readonly provider = 'neon'\n  private readonly baselines = new Map<string, NeonStatementBaseline>()\n\n  constructor(\n    private readonly config: NeonConnectorConfig,\n    private readonly deps: NeonConnectorDeps = {},\n  ) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const credentials = readNeonCredentials(ctx.credentials)\n    const fetchStatements = this.deps.fetchStatements ?? fetchNeonStatements\n    const rows = await fetchStatements(\n      credentials.connectionString,\n      this.config.projectId,\n      this.config.statementLimit ?? DEFAULT_NEON_STATEMENT_LIMIT,\n    )\n    return diffNeonStatementsToSignals(\n      rows,\n      this.baselines,\n      (this.deps.now?.() ?? new Date()).toISOString(),\n    )\n  }\n}\n\nexport function createNeonConnector(\n  config: NeonConnectorConfig,\n  deps: NeonConnectorDeps = {},\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new NeonConnector(config, deps),\n    resolveTarget: createNeonResolveTarget(config),\n  }\n}\n","import pg from 'pg'\nimport { dbJunction } from '../junction.js'\nimport type { NeonStatementRow } from './types.js'\n\nconst { Client } = pg\n\nexport const DEFAULT_NEON_STATEMENT_LIMIT = 500\n\nconst NEON_STATEMENTS_QUERY = `\n  select queryid::text, query, calls\n  from pg_stat_statements\n  where query ~* '^\\\\s*(select|insert|update|delete)\\\\b'\n  order by calls desc\n  limit $1\n`\n\nexport interface NeonPgClientLike {\n  connect(): Promise<void>\n  query<T>(text: string, values?: unknown[]): Promise<{ rows: T[] }>\n  end(): Promise<void>\n}\n\nexport async function fetchNeonStatements(\n  connectionString: string,\n  projectId: string,\n  limit: number = DEFAULT_NEON_STATEMENT_LIMIT,\n  clientFactory: (connectionString: string) => NeonPgClientLike = (value) =>\n    new Client({ connectionString: value }),\n): Promise<NeonStatementRow[]> {\n  return dbJunction(\n    async () => {\n      const client = clientFactory(connectionString)\n      await client.connect()\n      try {\n        await client.query('SET default_transaction_read_only = on')\n        const result = await client.query<NeonStatementRow>(NEON_STATEMENTS_QUERY, [\n          Math.max(1, Math.trunc(limit) || DEFAULT_NEON_STATEMENT_LIMIT),\n        ])\n        return result.rows\n      } finally {\n        await client.end()\n      }\n    },\n    { provider: 'neon', accountKey: projectId },\n  )\n}\n","import { columnsFromSqlStatement, tableFromSqlStatement } from '../../otel.js'\nimport type { ObservedSignal } from '../types.js'\nimport { NEON_SQL_TABLE_TARGET_KIND, type NeonStatementRow } from './types.js'\n\nexport interface NeonStatementBaseline {\n  calls: number\n}\n\nexport function diffNeonStatementsToSignals(\n  rows: NeonStatementRow[],\n  previous: Map<string, NeonStatementBaseline>,\n  observedAtIso: string,\n): ObservedSignal[] {\n  const signals: ObservedSignal[] = []\n  const seen = new Set<string>()\n  if (!Array.isArray(rows)) return signals\n\n  for (const row of rows) {\n    if (\n      !row ||\n      typeof row !== 'object' ||\n      typeof row.queryid !== 'string' ||\n      typeof row.query !== 'string'\n    ) {\n      continue\n    }\n    const calls = Number(row.calls)\n    if (!Number.isFinite(calls)) continue\n\n    seen.add(row.queryid)\n    const prior = previous.get(row.queryid)\n    previous.set(row.queryid, { calls })\n    if (!prior || calls <= prior.calls) continue\n\n    const table = tableFromSqlStatement(row.query)\n    if (!table) continue\n    // ADR-157 — the same query text names the columns it touched; carry them so\n    // the shared pipeline merges them onto the `sql-table` node as OBSERVED\n    // column attributes. Empty for a shape the parser degrades on.\n    const columns = columnsFromSqlStatement(row.query)\n    signals.push({\n      targetKind: NEON_SQL_TABLE_TARGET_KIND,\n      targetName: table,\n      callCount: calls - prior.calls,\n      errorCount: 0,\n      lastObservedIso: observedAtIso,\n      ...(columns.length > 0 ? { columns } : {}),\n    })\n  }\n\n  for (const queryid of previous.keys()) {\n    if (!seen.has(queryid)) previous.delete(queryid)\n  }\n  return signals\n}\n","export const NEON_SQL_TABLE_TARGET_KIND = 'sql-table'\n\nexport interface NeonConnectorConfig {\n  projectId: string\n  serviceName: string\n  statementLimit?: number\n}\n\nexport interface NeonCredentials {\n  connectionString: string\n}\n\nexport interface NeonStatementRow {\n  queryid: string\n  query: string\n  calls: string | number\n}\n\nexport function readNeonCredentials(input: Record<string, unknown>): NeonCredentials {\n  const connectionString = input.connectionString\n  if (typeof connectionString !== 'string' || connectionString.length === 0) {\n    throw new Error('neon connector: credentials.connectionString is required')\n  }\n  return { connectionString }\n}\n","import { EdgeType, infraId } from '@neat.is/types'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport { NEON_SQL_TABLE_TARGET_KIND, type NeonConnectorConfig } from './types.js'\n\nexport function createNeonResolveTarget(config: NeonConnectorConfig): ResolveConnectorTarget {\n  return (signal) => {\n    if (signal.targetKind !== NEON_SQL_TABLE_TARGET_KIND || !signal.targetName) return null\n    return {\n      targetNodeId: infraId('sql-table', signal.targetName),\n      serviceName: config.serviceName,\n      edgeType: EdgeType.CALLS,\n      ensureInfraNode: { kind: 'sql-table', name: signal.targetName, provider: 'neon' },\n    }\n  }\n}\n","// The Cloud Run connector (docs/connectors/cloud-run.md, ADR-165) — sixth\n// connectors-plane pull provider.\n//\n// poll() pulls Cloud Logging's `entries.list` (client.ts), filtered to Cloud\n// Run's own request log (`run.googleapis.com/requests`), and maps each entry to\n// an ObservedSignal (map.ts). Target resolution — a mapped service's RouteNode\n// via the shared route normalisation, or an honest `cloud-run-service` InfraNode\n// fallback when none resolves — lives in resolve.ts. Everything downstream of\n// resolution (minting the OBSERVED edge, the `ensureInfraNode` fallback) is the\n// shared connectors/index.ts pipeline; this module never touches the graph\n// directly (ADR-030).\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport { DEFAULT_LOOKBACK_MS, fetchCloudRunRequestLogEntries } from './client.js'\nimport { mapLogEntriesToSignals } from './map.js'\nimport { createCloudRunResolveTarget } from './resolve.js'\nimport { readCloudRunCredentials, type CloudRunConnectorConfig } from './types.js'\n\nexport * from './client.js'\nexport * from './map.js'\nexport * from './resolve.js'\nexport * from './types.js'\n\nexport class CloudRunConnector implements ObservedConnector {\n  readonly provider = 'cloud-run'\n\n  constructor(private readonly config: CloudRunConnectorConfig = {}) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const creds = readCloudRunCredentials(ctx.credentials)\n    const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_LOOKBACK_MS\n    const sinceIso = boundedSinceIso(ctx.since, new Date(), maxLookbackMs)\n    const entries = await fetchCloudRunRequestLogEntries(creds, sinceIso, this.config.apiUrl)\n    return mapLogEntriesToSignals(entries)\n  }\n}\n\n// `since` bounded by the provider's max lookback window (connectors.md \"Poll\n// cadence and backfill\") — a gap wider than the window (a laptop off for a\n// week) backfills from `now - maxLookbackMs`, never an unbounded full-history\n// replay. An absent or unparseable `since` (no prior poll) gets the same floor.\nexport function boundedSinceIso(since: string | undefined, now: Date, maxLookbackMs: number): string {\n  const floor = new Date(now.getTime() - maxLookbackMs)\n  if (!since) return floor.toISOString()\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return floor.toISOString()\n  return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString()\n}\n\n/**\n * Wires up a ready-to-register Cloud Run connector: the `ObservedConnector`\n * plus the `resolveTarget` callback the shared pipeline needs alongside it.\n * Both are built together because `resolveTarget` closes over `graph` — the\n * shared scaffold's `ResolveConnectorTarget` signature never receives it\n * directly.\n */\nexport function createCloudRunConnector(\n  graph: NeatGraph,\n  config: CloudRunConnectorConfig = {},\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new CloudRunConnector(config),\n    resolveTarget: createCloudRunResolveTarget(graph, config),\n  }\n}\n","// Cloud Logging `entries.list` — the fetch half of the Cloud Run connector\n// (docs/connectors/cloud-run.md, ADR-165). This file owns the wire shape and\n// the HTTP call; mapping a `LogEntry` to an `ObservedSignal` lives in map.ts,\n// and target resolution in resolve.ts — the same fetch/map/resolve split every\n// other provider module keeps (connectors.md §Authority). Passive and ambient\n// only (connectors.md §2): one read-only query, never a mutation, never a\n// synthetic request.\n//\n// Every field name below was confirmed live against Google's own docs rather\n// than recalled from training data (ADR-165 §Context, ADR-150/152 discipline):\n//   - request/response envelope + endpoint:\n//     https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list\n//   - LogEntry + HttpRequest field names:\n//     https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry\n//   - cloud_run_revision monitored-resource labels:\n//     https://cloud.google.com/logging/docs/api/v2/resource-list\n//   - the request log name (run.googleapis.com%2Frequests) + auto-emission:\n//     https://cloud.google.com/run/docs/logging\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type { CloudRunCredentials } from './types.js'\n\n// ── Cloud Logging wire types ─────────────────────────────────────────────\n\n// MonitoredResource (LogEntry.resource). For a Cloud Run request log the type\n// is `cloud_run_revision` and `labels` carries service_name / revision_name /\n// location / configuration_name / project_id (resource-list docs above). This\n// connector reads `service_name`.\nexport interface MonitoredResource {\n  type: string\n  labels?: Record<string, string>\n}\n\n// HttpRequest (LogEntry.httpRequest), field names confirmed against the\n// LogEntry reference page. Every field is optional in the wire type — a request\n// log is expected to carry requestMethod/requestUrl/status, but nothing here is\n// guaranteed present, so the mapper (map.ts) treats an absent field as an\n// honest miss rather than guessing a default.\nexport interface HttpRequest {\n  requestMethod?: string\n  requestUrl?: string\n  requestSize?: string\n  status?: number\n  responseSize?: string\n  userAgent?: string\n  remoteIp?: string\n  serverIp?: string\n  referer?: string\n  latency?: string\n  protocol?: string\n}\n\n// LogEntry, the subset this connector reads. `timestamp` is the request's own\n// event time (a string RFC3339/Timestamp field) — used as\n// `ObservedSignal.lastObservedIso`, never `receiveTimestamp` (ingest time),\n// matching the \"provider's own event time, never poll-arrival time\" rule\n// (connectors/README.md §Poll cadence and backfill).\nexport interface LogEntry {\n  logName?: string\n  resource?: MonitoredResource\n  timestamp?: string\n  receiveTimestamp?: string\n  severity?: string\n  insertId?: string\n  httpRequest?: HttpRequest\n}\n\nexport interface EntriesListRequest {\n  resourceNames: string[]\n  filter?: string\n  orderBy?: string\n  pageSize?: number\n  pageToken?: string\n}\n\nexport interface EntriesListResponse {\n  entries?: LogEntry[]\n  nextPageToken?: string\n}\n\n// ── filter construction ──────────────────────────────────────────────────\n\n// The Cloud Run request log's own name (confirmed at cloud.google.com/run/docs/\n// logging): `projects/<id>/logs/run.googleapis.com%2Frequests`. The `/` inside\n// the log id is URL-encoded `%2F`, and the Logging query-language filter carries\n// that encoded form. Pinning the log name is what separates this connector from\n// Firebase's broader `cloud_run_revision` sweep — it reads exactly Cloud Run's\n// own request record, never an app's stdout/stderr on the same resource.\nexport function cloudRunRequestLogName(projectId: string): string {\n  return `projects/${projectId}/logs/run.googleapis.com%2Frequests`\n}\n\n// Cloud Logging query-language operators confirmed against\n// https://cloud.google.com/logging/docs/view/logging-query-language:\n//   - `logName = \"...\"` pins the request log\n//   - `resource.type = \"...\"` pins the monitored resource\n//   - `httpRequest.requestMethod != \"\"` requires a request (an httpRequest that\n//     actually carries a method), rather than any entry on the resource\n//   - `timestamp >= \"<RFC3339>\"` for the watermark lower bound\n// Joined with explicit `AND`.\nexport function buildCloudRunEntriesFilter(projectId: string, sinceIso: string): string {\n  return [\n    `logName = \"${cloudRunRequestLogName(projectId)}\"`,\n    `resource.type = \"${CLOUD_RUN_RESOURCE_TYPE}\"`,\n    'httpRequest.requestMethod != \"\"',\n    `timestamp >= \"${sinceIso}\"`,\n  ].join(' AND ')\n}\n\nconst CLOUD_RUN_RESOURCE_TYPE = 'cloud_run_revision'\n\n// No documented lookback cap surfaced for `entries.list` itself (bounded only\n// by the log bucket's retention, typically 30 days on `_Default`) — a\n// conservative 24h default for a first poll with no prior high-water mark, the\n// same convention Firebase and Supabase keep, never an unbounded first query\n// (connectors.md \"Poll cadence and backfill\").\nexport const DEFAULT_LOOKBACK_MS = 24 * 60 * 60 * 1000\n\nconst ENTRIES_LIST_URL = 'https://logging.googleapis.com/v2/entries:list'\nconst PAGE_SIZE = 1000\n// Defensive cap on pagination — entries.list documents no page-count limit, so\n// this bounds the loop rather than trusting an unbounded while(true), the same\n// way STITCH_MAX_DEPTH bounds trace-stitch BFS elsewhere.\nconst MAX_PAGES = 20\n\nexport async function fetchCloudRunRequestLogEntries(\n  creds: CloudRunCredentials,\n  sinceIso: string,\n  apiUrl: string = ENTRIES_LIST_URL,\n): Promise<LogEntry[]> {\n  const filter = buildCloudRunEntriesFilter(creds.projectId, sinceIso)\n  const out: LogEntry[] = []\n  let pageToken: string | undefined\n  for (let page = 0; page < MAX_PAGES; page++) {\n    const body: EntriesListRequest = {\n      resourceNames: [`projects/${creds.projectId}`],\n      filter,\n      orderBy: 'timestamp asc',\n      pageSize: PAGE_SIZE,\n      ...(pageToken ? { pageToken } : {}),\n    }\n    const res = await junctionFetch(\n      apiUrl,\n      {\n        method: 'POST',\n        headers: {\n          ...bearerAuthHeader(creds.accessToken),\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify(body),\n      },\n      // accountKey: the GCP project id — one customer's Cloud Logging quota is\n      // scoped per GCP project (ADR-131's per-(provider, accountKey) rate-limit\n      // bucket), the same key Firebase's connector uses.\n      { provider: 'cloud-run', accountKey: creds.projectId },\n    )\n    if (!res.ok) {\n      throw new Error(`Cloud Logging entries.list failed: ${res.status} ${res.statusText}`)\n    }\n    const json = (await res.json()) as EntriesListResponse\n    // A well-formed page carries an array (absent when the window is empty); a\n    // shape drift handing back a non-array `entries` drops honestly rather than\n    // throwing on `push(...nonIterable)` (connectors.md §4).\n    if (Array.isArray(json.entries)) out.push(...json.entries)\n    if (!json.nextPageToken) break\n    pageToken = json.nextPageToken\n  }\n  return out\n}\n","// LogEntry -> ObservedSignal mapping (docs/connectors/cloud-run.md, ADR-165).\n// One signal per request-log entry — no aggregation — so each concrete request\n// stays traceable back to the raw log line it came from; the shared pipeline\n// (connectors/index.ts) already replays a signal's callCount/errorCount as\n// individual upserts, so nothing is lost by keeping this 1:1.\n\nimport type { ObservedSignal } from '../types.js'\nimport type { LogEntry } from './client.js'\nimport { CLOUD_RUN_TARGET_KIND, packCloudRunTargetName } from './types.js'\n\n// Only the Cloud Run request-log resource. The filter (client.ts) already pins\n// `resource.type = \"cloud_run_revision\"`, but the mapper never trusts the\n// filter alone — a shape drift or a hand-supplied fixture entry of another\n// resource type drops honestly rather than being mis-attributed.\nconst CLOUD_RUN_RESOURCE_TYPE = 'cloud_run_revision'\n\n// `httpRequest.requestUrl` is documented as \"typically without the scheme,\n// host, port, and query portion\" — usually already a bare path — but a\n// deployment that logs a full absolute URL is handled too. Returns null when\n// the value is neither a bare path nor a parseable absolute URL, the same\n// \"honest miss, never guessed\" discipline `pathOf` uses in\n// extract/calls/route-match.ts.\nfunction pathFromRequestUrl(requestUrl: unknown): string | null {\n  // Typed a string upstream, but this reads a raw Cloud Logging record — a\n  // shape drift handing a number/object here drops honestly rather than\n  // throwing on `.startsWith` (connectors.md §4).\n  if (typeof requestUrl !== 'string' || requestUrl.length === 0) return null\n  if (requestUrl.startsWith('/')) {\n    const withoutQuery = requestUrl.split('?')[0]\n    return withoutQuery && withoutQuery.length > 0 ? withoutQuery : '/'\n  }\n  try {\n    const candidate = requestUrl.startsWith('//') ? `https:${requestUrl}` : requestUrl\n    const parsed = new URL(candidate)\n    return parsed.pathname || '/'\n  } catch {\n    return null\n  }\n}\n\n// A response is counted as an error at the 5xx threshold — the same\n// unambiguous-failure line ingest.ts draws for a failing HTTP response. A 4xx\n// is a plausible client error, not necessarily a service defect, so it isn't\n// counted here.\nconst ERROR_STATUS_THRESHOLD = 500\n\n// Maps one Cloud Logging LogEntry to one ObservedSignal. Returns null for an\n// entry this connector can't honestly attribute — a non-Cloud-Run resource, a\n// resource with no `service_name` label, or an httpRequest missing the\n// method/path a signal needs. Nothing here is guessed or fabricated.\nexport function mapLogEntryToSignal(entry: LogEntry | null | undefined): ObservedSignal | null {\n  // A shape-drifted response can carry a null/garbage slot; drop it honestly\n  // rather than throwing on `.resource` (connectors.md §4).\n  if (!entry || typeof entry !== 'object') return null\n  if (entry.resource?.type !== CLOUD_RUN_RESOURCE_TYPE) return null\n\n  const serviceName = entry.resource?.labels?.['service_name']\n  if (typeof serviceName !== 'string' || serviceName.length === 0) return null\n\n  const req = entry.httpRequest\n  if (!req) return null\n  if (typeof req.requestMethod !== 'string' || req.requestMethod.length === 0) return null\n  const method = req.requestMethod.toUpperCase()\n  const path = pathFromRequestUrl(req.requestUrl)\n  if (path === null) return null\n\n  const timestamp = entry.timestamp\n  if (typeof timestamp !== 'string' || timestamp.length === 0) return null\n\n  const isError = typeof req.status === 'number' && req.status >= ERROR_STATUS_THRESHOLD\n\n  return {\n    targetKind: CLOUD_RUN_TARGET_KIND,\n    targetName: packCloudRunTargetName({ serviceName, method, path }),\n    callCount: 1,\n    errorCount: isError ? 1 : 0,\n    lastObservedIso: timestamp,\n  }\n}\n\nexport function mapLogEntriesToSignals(entries: LogEntry[]): ObservedSignal[] {\n  const out: ObservedSignal[] = []\n  for (const entry of entries) {\n    const signal = mapLogEntryToSignal(entry)\n    if (signal) out.push(signal)\n  }\n  return out\n}\n","// Cloud Run connector — provider-specific types (docs/connectors/cloud-run.md,\n// ADR-165). Sixth connectors-plane pull provider, following the\n// hosting-platform pattern ADR-127 (Railway) established and ADR-128 (Firebase)\n// already applies to `cloud_run_revision` request logs.\n//\n// Cloud Run names nothing in application code: the signal comes entirely from\n// Google's own request-logging pipeline (Cloud Logging), so fusion binds onto\n// the RouteNode `extract/routes.ts` already builds — the same node an OBSERVED\n// server span would fuse onto if the app were OTel-instrumented.\n\n// ── credentials ────────────────────────────────────────────────────────────\n\n// `ConnectorContext.credentials` is opaque at the shared-scaffold layer\n// (connectors/types.ts) — this is the Cloud-Run-specific shape it must carry.\n// `projectId` is not a secret (it names the GCP project); `accessToken` is a\n// short-lived OAuth token scoped to `roles/logging.viewer`, minted from a\n// service-account key or ADC. `poll()` only ever consumes an already-minted\n// token, never performing its own auth handshake — the same way Firebase's\n// connector consumes an already-minted `accessToken` and Railway's an\n// already-minted `Project-Access-Token` (docs/connectors/cloud-run.md\n// §Credential + least privilege, connectors.md §3).\nexport interface CloudRunCredentials {\n  projectId: string\n  accessToken: string\n}\n\nexport function readCloudRunCredentials(raw: Record<string, unknown>): CloudRunCredentials {\n  const projectId = raw['projectId']\n  const accessToken = raw['accessToken']\n  if (typeof projectId !== 'string' || projectId.length === 0) {\n    throw new Error('cloud-run connector: credentials.projectId must be a non-empty string')\n  }\n  if (typeof accessToken !== 'string' || accessToken.length === 0) {\n    throw new Error('cloud-run connector: credentials.accessToken must be a non-empty string')\n  }\n  return { projectId, accessToken }\n}\n\n// ── config ─────────────────────────────────────────────────────────────────\n\n/**\n * Config resolved once at connector setup (docs/connectors/cloud-run.md\n * §Fusion, \"resolved once, never guessed\") — never re-derived from a Cloud\n * Logging response at poll time.\n */\nexport interface CloudRunConnectorConfig {\n  // GCP `service_name` (resource.labels.service_name) -> the NEAT manifest\n  // service name that resolves `serviceId(name)` (packages/types/src/identity.ts).\n  // A Cloud Run service name need not match `package.json#name`, so the mapping\n  // is supplied once at setup, never inferred from a log record. An unmapped\n  // service still produces honest service-grained edges (resolve.ts tier 2),\n  // so this is optional — a connector added before the map is filled stays\n  // coarse rather than silent.\n  serviceMap?: Record<string, string>\n  // Opt-in (the hosted daemon sets it): for a service with no `serviceMap` entry, work out the NEAT service\n  // from the graph (a name match, else the one service declaring the requested route) instead of leaving it\n  // coarse. Explicit entries win, and a local run never sets this.\n  inferServices?: boolean\n  // Bounded lookback cap in ms for a first poll (no prior `since`) or a gap\n  // wider than this window. Overridable; defaults to 24h\n  // (connectors.md \"Poll cadence and backfill\").\n  maxLookbackMs?: number\n  // Cloud Logging API base. Defaults to the public endpoint; overridable for\n  // tests and any proxy in front of it.\n  apiUrl?: string\n}\n\n// ── target identity (the provider's own vocabulary) ─────────────────────────\n\n// A signal's `targetKind` for this provider (connectors/types.ts's\n// ObservedSignal doc: \"the provider's own vocabulary\" — the shared pipeline\n// never inspects this string itself). Cloud Run has exactly one monitored\n// resource type for request logs, so this is a single constant rather than a\n// set the way Firebase carries three.\nexport const CLOUD_RUN_TARGET_KIND = 'cloud_run_revision'\n\n// The (service_name, method, path) identity a signal carries through the shared\n// pipeline, packed into ObservedSignal.targetName (a plain string field) and\n// unpacked only by this connector's own resolveTarget (resolve.ts), never\n// surfaced to the graph. `\\x00` is the separator: it cannot appear in an HTTP\n// method token, a GCP service name, or a URL path.\nconst FIELD_SEP = '\\x00'\n\nexport interface CloudRunTargetIdentity {\n  serviceName: string\n  method: string\n  path: string\n}\n\nexport function packCloudRunTargetName(identity: CloudRunTargetIdentity): string {\n  return [identity.serviceName, identity.method, identity.path].join(FIELD_SEP)\n}\n\nexport function parseCloudRunTargetName(targetName: string): CloudRunTargetIdentity | null {\n  // Split on the first two separators only — a path (always the last field)\n  // carries no separator in practice, but splitting non-greedily keeps this\n  // correct even if it ever did.\n  const firstSep = targetName.indexOf(FIELD_SEP)\n  if (firstSep === -1) return null\n  const serviceName = targetName.slice(0, firstSep)\n  const rest = targetName.slice(firstSep + 1)\n  const secondSep = rest.indexOf(FIELD_SEP)\n  if (secondSep === -1) return null\n  const method = rest.slice(0, secondSep)\n  const path = rest.slice(secondSep + 1)\n  if (!serviceName || !method || !path) return null\n  return { serviceName, method, path }\n}\n","// Target resolution — the Cloud-Run-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning a signal's (service_name, method, path)\n// into a NEAT node id. Two tiers, in order (docs/connectors/cloud-run.md\n// §Fusion):\n//\n//   1. Route grain — map the GCP `service_name` to a NEAT manifest service via\n//      the config-time `serviceMap` (resolved once, never guessed), then match\n//      (method, path) against a RouteNode that service declares, using the same\n//      path-template normalisation extract/routes.ts uses. A match lands the\n//      OBSERVED CALLS edge on that RouteNode; the shared pipeline sharpens it to\n//      the route's own definition file/line (ADR-143). This file precision is\n//      drawn from the STATIC route definition, not a runtime code.* stamp.\n//   2. Service grain, honestly — no static route resolves. The connector does\n//      not fabricate a route. It declares an honest fallback via\n//      `ensureInfraNode` (connectors.md §4a, ADR-133): the edge lands on\n//      `infraId('cloud-run-service', service_name)`, the Cloud Run service the\n//      log's own `resource.labels.service_name` names — a real platform\n//      resource — surfacing as a `missing-extracted` divergence rather than a\n//      silent drop. An unmapped service sources the edge from that service's own\n//      name, so a connector added before the serviceMap is filled stays coarse\n//      rather than silent.\n//\n// This module never mutates the graph (ADR-030) — it reads RouteNode attributes\n// already there and declares the infra-node need for the shared pipeline to\n// enact, matching every other file in packages/core/src/connectors/**.\n\nimport { EdgeType, NodeType, infraId, type RouteNode } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { normalizePathTemplate } from '../../extract/routes.js'\nimport { inferServiceName } from '../infer-service.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport {\n  CLOUD_RUN_TARGET_KIND,\n  parseCloudRunTargetName,\n  type CloudRunConnectorConfig,\n} from './types.js'\n\n// The InfraNode kind the tier-2 honest fallback lands on. A future Cloud Run\n// service-manifest extractor (the analog of Cloudflare's\n// extract/infra/cloudflare.ts) should mint the same `infraId('cloud-run-service',\n// name)` so declared and observed fuse rather than twin.\nconst CLOUD_RUN_SERVICE_INFRA_KIND = 'cloud-run-service'\n\n// Scan the polled service's own RouteNodes for one whose normalised\n// (method, path) matches this request — the same param-agnostic comparison\n// route-match.ts uses for cross-service HTTP client↔route matching, and the\n// same per-call graph scan Firebase's connector and ingest.ts's\n// reconcileObservedRelPath already use (per-project route counts are small\n// enough not to warrant a cache the live graph would have to invalidate on\n// every re-extraction).\nfunction findMatchingRouteNode(\n  graph: NeatGraph,\n  serviceName: string,\n  method: string,\n  normalizedPath: string,\n): string | null {\n  let found: string | null = null\n  graph.forEachNode((_id, attrs) => {\n    if (found) return\n    const node = attrs as unknown as { type?: string }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    if (route.service !== serviceName || !route.pathTemplate) return\n    if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return\n    const routeMethod = route.method.toUpperCase()\n    if (routeMethod !== 'ALL' && routeMethod !== method) return\n    found = route.id\n  })\n  return found\n}\n\n// Builds the resolveTarget callback runConnectorPoll (connectors/index.ts)\n// calls once per signal. Closes over `graph` because ResolveConnectorTarget's\n// own signature (connectors/types.ts) doesn't carry it — the same closure\n// pattern every ConnectorRegistration's resolveTarget uses.\nexport function createCloudRunResolveTarget(\n  graph: NeatGraph,\n  config: CloudRunConnectorConfig,\n): ResolveConnectorTarget {\n  return (signal): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== CLOUD_RUN_TARGET_KIND) return null\n    const identity = parseCloudRunTargetName(signal.targetName)\n    if (!identity) return null\n    const { serviceName: gcpServiceName, method, path } = identity\n\n    const mappedService =\n      config.serviceMap?.[gcpServiceName] ??\n      (config.inferServices ? (inferServiceName(graph, gcpServiceName, method, path) ?? undefined) : undefined)\n\n    // Tier 1 — mapped service + a matching static route → route grain.\n    if (mappedService) {\n      const routeNodeId = findMatchingRouteNode(\n        graph,\n        mappedService,\n        method,\n        normalizePathTemplate(path),\n      )\n      if (routeNodeId) {\n        return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: EdgeType.CALLS }\n      }\n    }\n\n    // Tier 2 — no static route resolved (or the service is unmapped). Land an\n    // honest service-grained edge on the Cloud Run service's own InfraNode\n    // rather than fabricating a route or dropping the observation. The source\n    // is the mapped NEAT service when known, else the Cloud Run service name\n    // itself (auto-created by the shared pipeline the same way Cloudflare's own\n    // fallback auto-creates its source).\n    return {\n      targetNodeId: infraId(CLOUD_RUN_SERVICE_INFRA_KIND, gcpServiceName),\n      serviceName: mappedService ?? gcpServiceName,\n      edgeType: EdgeType.CALLS,\n      ensureInfraNode: {\n        kind: CLOUD_RUN_SERVICE_INFRA_KIND,\n        name: gcpServiceName,\n        provider: 'cloud-run',\n      },\n    }\n  }\n}\n","// The GCP HTTP(S) Load Balancer connector (docs/connectors/gcp-lb.md, ADR-218)\n// — eleventh connectors-plane pull provider and the second GCP request-log\n// surface after Cloud Run (ADR-165).\n//\n// poll() pulls Cloud Logging's `entries.list` (client.ts), filtered to the\n// external ALB's own request log (`http_load_balancer`), and maps each entry to\n// an ObservedSignal (map.ts). Target resolution — a mapped backend's RouteNode\n// via the shared route normalisation, or an honest `gcp-lb-backend` InfraNode\n// fallback when none resolves — lives in resolve.ts. Everything downstream of\n// resolution (minting the OBSERVED edge, the `ensureInfraNode` fallback) is the\n// shared connectors/index.ts pipeline; this module never touches the graph\n// directly (ADR-030).\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport { DEFAULT_LOOKBACK_MS, fetchGcpLbRequestLogEntries } from './client.js'\nimport { mapLogEntriesToSignals } from './map.js'\nimport { createGcpLbResolveTarget } from './resolve.js'\nimport { readGcpLbCredentials, type GcpLbConnectorConfig } from './types.js'\n\nexport * from './client.js'\nexport * from './map.js'\nexport * from './resolve.js'\nexport * from './types.js'\n\nexport class GcpLbConnector implements ObservedConnector {\n  readonly provider = 'gcp-lb'\n\n  constructor(private readonly config: GcpLbConnectorConfig = {}) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const creds = readGcpLbCredentials(ctx.credentials)\n    const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_LOOKBACK_MS\n    const sinceIso = boundedSinceIso(ctx.since, new Date(), maxLookbackMs)\n    const entries = await fetchGcpLbRequestLogEntries(creds, sinceIso, this.config.apiUrl)\n    return mapLogEntriesToSignals(entries)\n  }\n}\n\n// `since` bounded by the provider's max lookback window (connectors.md \"Poll\n// cadence and backfill\") — a gap wider than the window (a laptop off for a\n// week) backfills from `now - maxLookbackMs`, never an unbounded full-history\n// replay. An absent or unparseable `since` (no prior poll) gets the same floor.\nexport function boundedSinceIso(since: string | undefined, now: Date, maxLookbackMs: number): string {\n  const floor = new Date(now.getTime() - maxLookbackMs)\n  if (!since) return floor.toISOString()\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return floor.toISOString()\n  return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString()\n}\n\n/**\n * Wires up a ready-to-register GCP LB connector: the `ObservedConnector` plus\n * the `resolveTarget` callback the shared pipeline needs alongside it. Both are\n * built together because `resolveTarget` closes over `graph` — the shared\n * scaffold's `ResolveConnectorTarget` signature never receives it directly.\n */\nexport function createGcpLbConnector(\n  graph: NeatGraph,\n  config: GcpLbConnectorConfig = {},\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new GcpLbConnector(config),\n    resolveTarget: createGcpLbResolveTarget(graph, config),\n  }\n}\n","// Cloud Logging `entries.list` — the fetch half of the GCP HTTP(S) Load\n// Balancer connector (docs/connectors/gcp-lb.md, ADR-218). This file owns the\n// wire shape and the HTTP call; mapping a `LogEntry` to an `ObservedSignal`\n// lives in map.ts, and target resolution in resolve.ts — the same\n// fetch/map/resolve split every other provider module keeps (connectors.md\n// §Authority). Passive and ambient only (connectors.md §2): one read-only\n// query, never a mutation, never a synthetic request.\n//\n// This is the same Cloud Logging surface the Cloud Run connector (ADR-165)\n// reads; only the log name and monitored-resource type differ. Every field name\n// below was confirmed live against Google's own docs rather than recalled from\n// training data (ADR-218 §Context, ADR-150/152 discipline):\n//   - request/response envelope + endpoint:\n//     https://cloud.google.com/logging/docs/reference/v2/rest/v2/entries/list\n//   - LogEntry + HttpRequest field names:\n//     https://cloud.google.com/logging/docs/reference/v2/rest/v2/LogEntry\n//   - http_load_balancer monitored-resource labels:\n//     https://cloud.google.com/logging/docs/api/v2/resource-list\n//   - the external ALB request log (logName \".../logs/requests\", resource type\n//     http_load_balancer, and httpRequest.protocol NOT populated for it):\n//     https://cloud.google.com/load-balancing/docs/https/https-logging-monitoring\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type { GcpLbCredentials } from './types.js'\n\n// ── Cloud Logging wire types ─────────────────────────────────────────────\n\n// MonitoredResource (LogEntry.resource). For an external HTTP(S) Load Balancer\n// request log the type is `http_load_balancer` and `labels` carries\n// backend_service_name / forwarding_rule_name / target_proxy_name / url_map_name\n// / zone / project_id (resource-list docs above). This connector reads\n// `backend_service_name` — the backend the LB routed the request to, the fusion\n// key onto a NEAT service.\nexport interface MonitoredResource {\n  type: string\n  labels?: Record<string, string>\n}\n\n// HttpRequest (LogEntry.httpRequest), field names confirmed against the\n// LogEntry reference page. Every field is optional in the wire type — a request\n// log is expected to carry requestMethod/requestUrl/status, but nothing here is\n// guaranteed present, so the mapper (map.ts) treats an absent field as an honest\n// miss rather than guessing a default. `protocol` is documented as NOT populated\n// for `resource.type = \"http_load_balancer\"`, so it is deliberately absent from\n// the fields this connector reads.\nexport interface HttpRequest {\n  requestMethod?: string\n  requestUrl?: string\n  requestSize?: string\n  status?: number\n  responseSize?: string\n  userAgent?: string\n  remoteIp?: string\n  serverIp?: string\n  referer?: string\n  latency?: string\n}\n\n// LogEntry, the subset this connector reads. `timestamp` is the request's own\n// event time (a string RFC3339/Timestamp field) — used as\n// `ObservedSignal.lastObservedIso`, never `receiveTimestamp` (ingest time),\n// matching the \"provider's own event time, never poll-arrival time\" rule\n// (connectors/README.md §Poll cadence and backfill).\nexport interface LogEntry {\n  logName?: string\n  resource?: MonitoredResource\n  timestamp?: string\n  receiveTimestamp?: string\n  severity?: string\n  insertId?: string\n  httpRequest?: HttpRequest\n}\n\nexport interface EntriesListRequest {\n  resourceNames: string[]\n  filter?: string\n  orderBy?: string\n  pageSize?: number\n  pageToken?: string\n}\n\nexport interface EntriesListResponse {\n  entries?: LogEntry[]\n  nextPageToken?: string\n}\n\n// ── filter construction ──────────────────────────────────────────────────\n\n// The external HTTP(S) Load Balancer request log's own name (confirmed at\n// cloud.google.com/load-balancing/docs/https/https-logging-monitoring):\n// `projects/<id>/logs/requests`. Unlike Cloud Run's `run.googleapis.com%2Frequests`,\n// the LB log id is a plain `requests` with no `/` to URL-encode. Pinning the log\n// name + the `http_load_balancer` resource type is what scopes this connector to\n// exactly the LB's own request record.\nexport function gcpLbRequestLogName(projectId: string): string {\n  return `projects/${projectId}/logs/requests`\n}\n\n// Cloud Logging query-language operators confirmed against\n// https://cloud.google.com/logging/docs/view/logging-query-language:\n//   - `logName = \"...\"` pins the request log\n//   - `resource.type = \"...\"` pins the monitored resource (the external ALB)\n//   - `httpRequest.requestMethod != \"\"` requires a request (an httpRequest that\n//     actually carries a method), rather than any entry on the resource\n//   - `timestamp >= \"<RFC3339>\"` for the watermark lower bound\n// Joined with explicit `AND`.\nexport function buildGcpLbEntriesFilter(projectId: string, sinceIso: string): string {\n  return [\n    `logName = \"${gcpLbRequestLogName(projectId)}\"`,\n    `resource.type = \"${GCP_LB_RESOURCE_TYPE}\"`,\n    'httpRequest.requestMethod != \"\"',\n    `timestamp >= \"${sinceIso}\"`,\n  ].join(' AND ')\n}\n\nconst GCP_LB_RESOURCE_TYPE = 'http_load_balancer'\n\n// No documented lookback cap surfaced for `entries.list` itself (bounded only\n// by the log bucket's retention, typically 30 days on `_Default`) — a\n// conservative 24h default for a first poll with no prior high-water mark, the\n// same convention Cloud Run, Firebase, and Supabase keep, never an unbounded\n// first query (connectors.md \"Poll cadence and backfill\").\nexport const DEFAULT_LOOKBACK_MS = 24 * 60 * 60 * 1000\n\nconst ENTRIES_LIST_URL = 'https://logging.googleapis.com/v2/entries:list'\nconst PAGE_SIZE = 1000\n// Defensive cap on pagination — entries.list documents no page-count limit, so\n// this bounds the loop rather than trusting an unbounded while(true), the same\n// way Cloud Run's client and STITCH_MAX_DEPTH bound their loops elsewhere.\nconst MAX_PAGES = 20\n\nexport async function fetchGcpLbRequestLogEntries(\n  creds: GcpLbCredentials,\n  sinceIso: string,\n  apiUrl: string = ENTRIES_LIST_URL,\n): Promise<LogEntry[]> {\n  const filter = buildGcpLbEntriesFilter(creds.projectId, sinceIso)\n  const out: LogEntry[] = []\n  let pageToken: string | undefined\n  for (let page = 0; page < MAX_PAGES; page++) {\n    const body: EntriesListRequest = {\n      resourceNames: [`projects/${creds.projectId}`],\n      filter,\n      orderBy: 'timestamp asc',\n      pageSize: PAGE_SIZE,\n      ...(pageToken ? { pageToken } : {}),\n    }\n    const res = await junctionFetch(\n      apiUrl,\n      {\n        method: 'POST',\n        headers: {\n          ...bearerAuthHeader(creds.accessToken),\n          'Content-Type': 'application/json',\n        },\n        body: JSON.stringify(body),\n      },\n      // accountKey: the GCP project id — one customer's Cloud Logging quota is\n      // scoped per GCP project (ADR-131's per-(provider, accountKey) rate-limit\n      // bucket), the same key Cloud Run's and Firebase's connectors use.\n      { provider: 'gcp-lb', accountKey: creds.projectId },\n    )\n    if (!res.ok) {\n      throw new Error(`Cloud Logging entries.list failed: ${res.status} ${res.statusText}`)\n    }\n    const json = (await res.json()) as EntriesListResponse\n    // A well-formed page carries an array (absent when the window is empty); a\n    // shape drift handing back a non-array `entries` drops honestly rather than\n    // throwing on `push(...nonIterable)` (connectors.md §4).\n    if (Array.isArray(json.entries)) out.push(...json.entries)\n    if (!json.nextPageToken) break\n    pageToken = json.nextPageToken\n  }\n  return out\n}\n","// LogEntry -> ObservedSignal mapping (docs/connectors/gcp-lb.md, ADR-218). One\n// signal per request-log entry — no aggregation — so each concrete request stays\n// traceable back to the raw log line it came from; the shared pipeline\n// (connectors/index.ts) already replays a signal's callCount/errorCount as\n// individual upserts, so nothing is lost by keeping this 1:1. This mirrors Cloud\n// Run's mapper (ADR-165) exactly, differing only in the resource type it accepts\n// and the label it keys on.\n\nimport type { ObservedSignal } from '../types.js'\nimport type { LogEntry } from './client.js'\nimport { GCP_LB_TARGET_KIND, packGcpLbTargetName } from './types.js'\n\n// Only the external HTTP(S) Load Balancer request-log resource. The filter\n// (client.ts) already pins `resource.type = \"http_load_balancer\"`, but the\n// mapper never trusts the filter alone — a shape drift or a hand-supplied\n// fixture entry of another resource type drops honestly rather than being\n// mis-attributed.\nconst GCP_LB_RESOURCE_TYPE = 'http_load_balancer'\n\n// `httpRequest.requestUrl` on an external LB request log is typically a full\n// absolute URL (scheme + host + path), unlike Cloud Run's usually-bare path —\n// both are handled. Returns null when the value is neither a bare path nor a\n// parseable absolute URL, the same \"honest miss, never guessed\" discipline\n// `pathOf` uses in extract/calls/route-match.ts.\nfunction pathFromRequestUrl(requestUrl: unknown): string | null {\n  // Typed a string upstream, but this reads a raw Cloud Logging record — a\n  // shape drift handing a number/object here drops honestly rather than\n  // throwing on `.startsWith` (connectors.md §4).\n  if (typeof requestUrl !== 'string' || requestUrl.length === 0) return null\n  if (requestUrl.startsWith('/')) {\n    const withoutQuery = requestUrl.split('?')[0]\n    return withoutQuery && withoutQuery.length > 0 ? withoutQuery : '/'\n  }\n  try {\n    const candidate = requestUrl.startsWith('//') ? `https:${requestUrl}` : requestUrl\n    const parsed = new URL(candidate)\n    return parsed.pathname || '/'\n  } catch {\n    return null\n  }\n}\n\n// A response is counted as an error at the 5xx threshold — the same\n// unambiguous-failure line ingest.ts draws for a failing HTTP response. A 4xx\n// is a plausible client error, not necessarily a service defect, so it isn't\n// counted here. (An LB can itself synthesize a 5xx — e.g. 502/503 with no\n// healthy backend — but such an entry carries no `backend_service_name` and is\n// dropped below, so only backend-attributable failures are counted.)\nconst ERROR_STATUS_THRESHOLD = 500\n\n// Maps one Cloud Logging LogEntry to one ObservedSignal. Returns null for an\n// entry this connector can't honestly attribute — a non-LB resource, a resource\n// with no `backend_service_name` label (an LB-synthesized response that never\n// reached a backend), or an httpRequest missing the method/path a signal needs.\n// Nothing here is guessed or fabricated.\nexport function mapLogEntryToSignal(entry: LogEntry | null | undefined): ObservedSignal | null {\n  // A shape-drifted response can carry a null/garbage slot; drop it honestly\n  // rather than throwing on `.resource` (connectors.md §4).\n  if (!entry || typeof entry !== 'object') return null\n  if (entry.resource?.type !== GCP_LB_RESOURCE_TYPE) return null\n\n  const backendServiceName = entry.resource?.labels?.['backend_service_name']\n  if (typeof backendServiceName !== 'string' || backendServiceName.length === 0) return null\n\n  const req = entry.httpRequest\n  if (!req) return null\n  if (typeof req.requestMethod !== 'string' || req.requestMethod.length === 0) return null\n  const method = req.requestMethod.toUpperCase()\n  const path = pathFromRequestUrl(req.requestUrl)\n  if (path === null) return null\n\n  const timestamp = entry.timestamp\n  if (typeof timestamp !== 'string' || timestamp.length === 0) return null\n\n  const isError = typeof req.status === 'number' && req.status >= ERROR_STATUS_THRESHOLD\n\n  return {\n    targetKind: GCP_LB_TARGET_KIND,\n    targetName: packGcpLbTargetName({ backendServiceName, method, path }),\n    callCount: 1,\n    errorCount: isError ? 1 : 0,\n    lastObservedIso: timestamp,\n  }\n}\n\nexport function mapLogEntriesToSignals(entries: LogEntry[]): ObservedSignal[] {\n  const out: ObservedSignal[] = []\n  for (const entry of entries) {\n    const signal = mapLogEntryToSignal(entry)\n    if (signal) out.push(signal)\n  }\n  return out\n}\n","// GCP HTTP(S) Load Balancer connector — provider-specific types\n// (docs/connectors/gcp-lb.md, ADR-218). Eleventh connectors-plane pull provider,\n// the second GCP request-log surface after Cloud Run (ADR-165) and the direct\n// sibling of it: both pull Cloud Logging's `entries.list` and fuse onto the\n// RouteNode `extract/routes.ts` already builds.\n//\n// An external Application Load Balancer names nothing in application code: the\n// signal comes entirely from Google's own load-balancing request-logging\n// pipeline (Cloud Logging), so fusion binds onto the RouteNode — the same node\n// an OBSERVED server span would fuse onto if the backend app were OTel-\n// instrumented. Where Cloud Run keys its signal on the GCP `service_name`, the\n// LB keys on the log's `backend_service_name` label (the backend the LB routed\n// to) — the fusion vocabulary this file packs and the resolve step unpacks.\n\n// ── credentials ────────────────────────────────────────────────────────────\n\n// `ConnectorContext.credentials` is opaque at the shared-scaffold layer\n// (connectors/types.ts) — this is the GCP-LB-specific shape it must carry.\n// `projectId` is not a secret (it names the GCP project); `accessToken` is a\n// short-lived OAuth token scoped to `roles/logging.viewer`, minted from a\n// service-account key or ADC. `poll()` only ever consumes an already-minted\n// token, never performing its own auth handshake — identical to Cloud Run's and\n// Firebase's connectors (docs/connectors/gcp-lb.md §Credential + least\n// privilege, connectors.md §3).\nexport interface GcpLbCredentials {\n  projectId: string\n  accessToken: string\n}\n\nexport function readGcpLbCredentials(raw: Record<string, unknown>): GcpLbCredentials {\n  const projectId = raw['projectId']\n  const accessToken = raw['accessToken']\n  if (typeof projectId !== 'string' || projectId.length === 0) {\n    throw new Error('gcp-lb connector: credentials.projectId must be a non-empty string')\n  }\n  if (typeof accessToken !== 'string' || accessToken.length === 0) {\n    throw new Error('gcp-lb connector: credentials.accessToken must be a non-empty string')\n  }\n  return { projectId, accessToken }\n}\n\n// ── config ─────────────────────────────────────────────────────────────────\n\n/**\n * Config resolved once at connector setup (docs/connectors/gcp-lb.md §Fusion,\n * \"resolved once, never guessed\") — never re-derived from a Cloud Logging\n * response at poll time.\n */\nexport interface GcpLbConnectorConfig {\n  // GCP `backend_service_name` (resource.labels.backend_service_name) -> the\n  // NEAT manifest service name that resolves `serviceId(name)`\n  // (packages/types/src/identity.ts). A backend service name (the GCE/GKE/NEG\n  // backend the LB fronts) need not match `package.json#name`, so the mapping\n  // is supplied once at setup, never inferred from a log record. An unmapped\n  // backend still produces honest backend-grained edges (resolve.ts tier 2),\n  // so this is optional — a connector added before the map is filled stays\n  // coarse rather than silent.\n  backendServiceMap?: Record<string, string>\n  // Opt-in (the hosted daemon sets it): for a backend with no `backendServiceMap` entry, work out the NEAT\n  // service from the graph (a name match, else the one service declaring the requested route) instead of\n  // leaving it coarse. Explicit entries win, and a local run never sets this.\n  inferServices?: boolean\n  // Bounded lookback cap in ms for a first poll (no prior `since`) or a gap\n  // wider than this window. Overridable; defaults to 24h\n  // (connectors.md \"Poll cadence and backfill\").\n  maxLookbackMs?: number\n  // Cloud Logging API base. Defaults to the public endpoint; overridable for\n  // tests and any proxy in front of it.\n  apiUrl?: string\n}\n\n// ── target identity (the provider's own vocabulary) ─────────────────────────\n\n// A signal's `targetKind` for this provider (connectors/types.ts's\n// ObservedSignal doc: \"the provider's own vocabulary\" — the shared pipeline\n// never inspects this string itself). An external HTTP(S) Load Balancer writes\n// exactly one monitored resource type for request logs.\nexport const GCP_LB_TARGET_KIND = 'http_load_balancer'\n\n// The (backend_service_name, method, path) identity a signal carries through\n// the shared pipeline, packed into ObservedSignal.targetName (a plain string\n// field) and unpacked only by this connector's own resolveTarget (resolve.ts),\n// never surfaced to the graph. `\\x00` is the separator: it cannot appear in an\n// HTTP method token, a GCP backend-service name, or a URL path.\nconst FIELD_SEP = '\\x00'\n\nexport interface GcpLbTargetIdentity {\n  backendServiceName: string\n  method: string\n  path: string\n}\n\nexport function packGcpLbTargetName(identity: GcpLbTargetIdentity): string {\n  return [identity.backendServiceName, identity.method, identity.path].join(FIELD_SEP)\n}\n\nexport function parseGcpLbTargetName(targetName: string): GcpLbTargetIdentity | null {\n  // Split on the first two separators only — a path (always the last field)\n  // carries no separator in practice, but splitting non-greedily keeps this\n  // correct even if it ever did.\n  const firstSep = targetName.indexOf(FIELD_SEP)\n  if (firstSep === -1) return null\n  const backendServiceName = targetName.slice(0, firstSep)\n  const rest = targetName.slice(firstSep + 1)\n  const secondSep = rest.indexOf(FIELD_SEP)\n  if (secondSep === -1) return null\n  const method = rest.slice(0, secondSep)\n  const path = rest.slice(secondSep + 1)\n  if (!backendServiceName || !method || !path) return null\n  return { backendServiceName, method, path }\n}\n","// Target resolution — the GCP-LB-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning a signal's (backend_service_name, method,\n// path) into a NEAT node id. Two tiers, in order (docs/connectors/gcp-lb.md\n// §Fusion), mirroring Cloud Run's resolver exactly:\n//\n//   1. Route grain — map the GCP `backend_service_name` to a NEAT manifest\n//      service via the config-time `backendServiceMap` (resolved once, never\n//      guessed), then match (method, path) against a RouteNode that service\n//      declares, using the same path-template normalisation extract/routes.ts\n//      uses. A match lands the OBSERVED CALLS edge on that RouteNode; the shared\n//      pipeline sharpens it to the route's own definition file/line (ADR-143).\n//      This file precision is drawn from the STATIC route definition, not a\n//      runtime code.* stamp (an LB fronts un-instrumented backends).\n//   2. Backend grain, honestly — no static route resolves. The connector does\n//      not fabricate a route. It declares an honest fallback via\n//      `ensureInfraNode` (connectors.md §4a, ADR-133): the edge lands on\n//      `infraId('gcp-lb-backend', backend_service_name)`, the LB backend service\n//      the log's own `resource.labels.backend_service_name` names — a real\n//      platform resource — surfacing as a `missing-extracted` divergence rather\n//      than a silent drop. An unmapped backend sources the edge from that\n//      backend's own name, so a connector added before the backendServiceMap is\n//      filled stays coarse rather than silent.\n//\n// This module never mutates the graph (ADR-030) — it reads RouteNode attributes\n// already there and declares the infra-node need for the shared pipeline to\n// enact, matching every other file in packages/core/src/connectors/**.\n\nimport { EdgeType, NodeType, infraId, type RouteNode } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { normalizePathTemplate } from '../../extract/routes.js'\nimport { inferServiceName } from '../infer-service.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport {\n  GCP_LB_TARGET_KIND,\n  parseGcpLbTargetName,\n  type GcpLbConnectorConfig,\n} from './types.js'\n\n// The InfraNode kind the tier-2 honest fallback lands on. A future GCP\n// load-balancing / backend-service extractor (the analog of Cloudflare's\n// extract/infra/cloudflare.ts) should mint the same `infraId('gcp-lb-backend',\n// name)` so declared and observed fuse rather than twin.\nconst GCP_LB_BACKEND_INFRA_KIND = 'gcp-lb-backend'\n\n// Scan the polled service's own RouteNodes for one whose normalised\n// (method, path) matches this request — the same param-agnostic comparison\n// route-match.ts uses for cross-service HTTP client↔route matching, and the\n// same per-call graph scan Cloud Run's connector and ingest.ts's\n// reconcileObservedRelPath already use (per-project route counts are small\n// enough not to warrant a cache the live graph would have to invalidate on\n// every re-extraction).\nfunction findMatchingRouteNode(\n  graph: NeatGraph,\n  serviceName: string,\n  method: string,\n  normalizedPath: string,\n): string | null {\n  let found: string | null = null\n  graph.forEachNode((_id, attrs) => {\n    if (found) return\n    const node = attrs as unknown as { type?: string }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    if (route.service !== serviceName || !route.pathTemplate) return\n    if (normalizePathTemplate(route.pathTemplate) !== normalizedPath) return\n    const routeMethod = route.method.toUpperCase()\n    if (routeMethod !== 'ALL' && routeMethod !== method) return\n    found = route.id\n  })\n  return found\n}\n\n// Builds the resolveTarget callback runConnectorPoll (connectors/index.ts)\n// calls once per signal. Closes over `graph` because ResolveConnectorTarget's\n// own signature (connectors/types.ts) doesn't carry it — the same closure\n// pattern every ConnectorRegistration's resolveTarget uses.\nexport function createGcpLbResolveTarget(\n  graph: NeatGraph,\n  config: GcpLbConnectorConfig,\n): ResolveConnectorTarget {\n  return (signal): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== GCP_LB_TARGET_KIND) return null\n    const identity = parseGcpLbTargetName(signal.targetName)\n    if (!identity) return null\n    const { backendServiceName, method, path } = identity\n\n    const mappedService =\n      config.backendServiceMap?.[backendServiceName] ??\n      (config.inferServices\n        ? (inferServiceName(graph, backendServiceName, method, path) ?? undefined)\n        : undefined)\n\n    // Tier 1 — mapped service + a matching static route → route grain.\n    if (mappedService) {\n      const routeNodeId = findMatchingRouteNode(\n        graph,\n        mappedService,\n        method,\n        normalizePathTemplate(path),\n      )\n      if (routeNodeId) {\n        return { targetNodeId: routeNodeId, serviceName: mappedService, edgeType: EdgeType.CALLS }\n      }\n    }\n\n    // Tier 2 — no static route resolved (or the backend is unmapped). Land an\n    // honest backend-grained edge on the LB backend service's own InfraNode\n    // rather than fabricating a route or dropping the observation. The source is\n    // the mapped NEAT service when known, else the backend service name itself\n    // (auto-created by the shared pipeline the same way Cloud Run's own fallback\n    // auto-creates its source).\n    return {\n      targetNodeId: infraId(GCP_LB_BACKEND_INFRA_KIND, backendServiceName),\n      serviceName: mappedService ?? backendServiceName,\n      edgeType: EdgeType.CALLS,\n      ensureInfraNode: {\n        kind: GCP_LB_BACKEND_INFRA_KIND,\n        name: backendServiceName,\n        provider: 'gcp-lb',\n      },\n    }\n  }\n}\n","// Render connector (ADR-166, docs/connectors/render.md) — a pull provider on\n// the connectors plane (ADR-124, connectors/index.ts). Render is a hosting\n// platform, so like Railway (ADR-127) it names nothing in application code:\n// the signal comes entirely from Render's own edge-layer HTTP request logs\n// (`GET /v1/logs?type=request`), and fusion binds onto the RouteNode\n// `extract/routes.ts` already builds — the same node an OBSERVED server span\n// would fuse onto if the app were OTel-instrumented. This is the second\n// route-fusion connector, after Railway's `httpLogs`.\n\nimport type { RouteNode } from '@neat.is/types'\nimport { EdgeType, NodeType } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { normalizePathTemplate } from '../../extract/routes.js'\nimport type {\n  ConnectorCallSite,\n  ConnectorContext,\n  ObservedConnector,\n  ObservedSignal,\n  ResolveConnectorTarget,\n} from '../index.js'\nimport type { RenderConnectorConfig, RenderLogEntry } from './types.js'\nimport { readRenderToken, renderLabelValue } from './types.js'\nimport {\n  DEFAULT_MAX_LOOKBACK_MS,\n  boundedRenderStartTime,\n  fetchRenderRequestLogs,\n} from './client.js'\n\nexport type { RenderConnectorConfig, RenderLogEntry, RenderLogLabel, RenderLogsResponse } from './types.js'\nexport { DEFAULT_RENDER_API_URL } from './client.js'\n\n// A signal's `targetKind` for this provider (connectors/index.ts never inspects\n// these strings itself):\n//\n// - 'route'           — the log's (method, path) normalised onto an existing\n//                        RouteNode (extract/routes.ts). targetName already\n//                        carries that RouteNode's own graph id.\n// - 'unmatched-route' — no RouteNode resolved. createRenderResolveTarget drops\n//                        it honestly rather than fabricating a target (a\n//                        RouteNode's `path` is a required real source location,\n//                        packages/types/src/nodes.ts).\nconst ROUTE_TARGET_KIND = 'route'\nconst UNMATCHED_ROUTE_TARGET_KIND = 'unmatched-route'\n\n// ── route index (read-only graph query) ────────────────────────────────────\n//\n// Mirrors railway/index.ts's own buildRailwayRouteIndex/findRailwayRoute,\n// which in turn mirrors extract/calls/route-match.ts — none is imported, since\n// none is exported for reuse; each connector rolls the same (method,\n// normalised-path) match against its polled service's RouteNodes. Only\n// normalizePathTemplate is shared (from routes.ts) so the path-template\n// normalisation rules can't drift between the two sides.\n\ninterface RenderRouteIndexEntry {\n  method: string\n  normalizedPath: string\n  routeNodeId: string\n  path: string\n  line?: number\n}\n\nexport function buildRenderRouteIndex(graph: NeatGraph, serviceName: string): RenderRouteIndexEntry[] {\n  const out: RenderRouteIndexEntry[] = []\n  graph.forEachNode((_id, attrs) => {\n    const node = attrs as unknown as { type?: string }\n    if (node.type !== NodeType.RouteNode) return\n    const route = attrs as unknown as RouteNode\n    if (route.service !== serviceName) return\n    out.push({\n      method: route.method.toUpperCase(),\n      normalizedPath: normalizePathTemplate(route.pathTemplate),\n      routeNodeId: route.id,\n      path: route.path,\n      line: route.line,\n    })\n  })\n  return out\n}\n\n// A request log always carries a concrete method — so, like Railway's\n// findRailwayRoute (and unlike route-match.ts's client-call-site case), there's\n// no \"caller method unknown\" passthrough, only the route's own `ALL` wildcard.\nfunction findRenderRoute(\n  entries: RenderRouteIndexEntry[],\n  method: string,\n  normalizedPath: string,\n): RenderRouteIndexEntry | undefined {\n  return entries.find(\n    (e) => e.normalizedPath === normalizedPath && (e.method === 'ALL' || e.method === method),\n  )\n}\n\nfunction bucketKey(method: string, normalizedPath: string): string {\n  return `${method} ${normalizedPath}`\n}\n\nfunction isHttpErrorStatus(status: number): boolean {\n  return status >= 400\n}\n\ninterface SignalBucket {\n  callCount: number\n  errorCount: number\n  lastObservedIso: string\n  targetKind: string\n  targetName: string\n  callSite?: ConnectorCallSite\n}\n\nfunction upsertBucket(\n  buckets: Map<string, SignalBucket>,\n  key: string,\n  isError: boolean,\n  timestamp: string,\n  build: () => Omit<SignalBucket, 'callCount' | 'errorCount' | 'lastObservedIso'>,\n): void {\n  const existing = buckets.get(key)\n  if (existing) {\n    existing.callCount += 1\n    if (isError) existing.errorCount += 1\n    if (timestamp > existing.lastObservedIso) existing.lastObservedIso = timestamp\n    return\n  }\n  buckets.set(key, { callCount: 1, errorCount: isError ? 1 : 0, lastObservedIso: timestamp, ...build() })\n}\n\n// ── request logs → ObservedSignal[] ─────────────────────────────────────────\n//\n// Route-grain fusion (docs/connectors/render.md §Fusion): read each request\n// log's method/path/statusCode from its `labels` (Render's log object shape),\n// normalise the path the same way route-match.ts normalises a client call\n// site's URL path, and match against the polled service's own RouteNodes. A\n// match carries the matched RouteNode's own `path`/`line` as this signal's\n// callSite — reconciled onto the EXTRACTED service-relative path by the shared\n// fuse step (connectors/index.ts) the same way every other OBSERVED surface\n// lands file-grained, because that path IS the extracted path routes.ts walked.\nexport function mapRenderRequestLogsToSignals(\n  entries: RenderLogEntry[],\n  routeIndex: RenderRouteIndexEntry[],\n): ObservedSignal[] {\n  const buckets = new Map<string, SignalBucket>()\n  if (!Array.isArray(entries)) return []\n\n  for (const entry of entries) {\n    // Drop a null/garbage slot, or a row missing the timestamp/method/path a\n    // signal needs, honestly rather than throwing (connectors.md §4). The\n    // request attributes live in `labels`; a request log with none isn't one\n    // this connector can place on a route.\n    if (!entry || typeof entry !== 'object') continue\n    if (typeof entry.timestamp !== 'string') continue\n    const method = renderLabelValue(entry, 'method')\n    const rawPath = renderLabelValue(entry, 'path')\n    if (typeof method !== 'string' || method.length === 0) continue\n    if (typeof rawPath !== 'string' || rawPath.length === 0) continue\n\n    const methodUpper = method.toUpperCase()\n    // Strip any query string — the route template is a path, never `?...`.\n    const pathOnly = rawPath.split('?')[0]\n    const normalizedPath = normalizePathTemplate(pathOnly)\n    const statusCode = Number.parseInt(renderLabelValue(entry, 'statusCode') ?? '', 10)\n    // A missing/garbage statusCode is not an error signal — treat it as a\n    // non-error observation rather than fabricating a 4xx/5xx.\n    const isError = Number.isFinite(statusCode) && isHttpErrorStatus(statusCode)\n    const match = findRenderRoute(routeIndex, methodUpper, normalizedPath)\n\n    if (match) {\n      upsertBucket(buckets, `route:${match.routeNodeId}`, isError, entry.timestamp, () => ({\n        targetKind: ROUTE_TARGET_KIND,\n        targetName: match.routeNodeId,\n        // RouteNode.line is optional in the schema (packages/types/src/\n        // nodes.ts) even though routes.ts always sets it today — skip the\n        // callSite rather than fabricate a line when it's ever absent\n        // (file-awareness.md §6).\n        ...(match.line !== undefined ? { callSite: { file: match.path, line: match.line } } : {}),\n      }))\n    } else {\n      // No RouteNode resolves — the app's framework/router isn't one routes.ts\n      // recognises yet, or the path matches no declared template. This drops\n      // honestly (createRenderResolveTarget returns null for it) rather than\n      // fabricating a route target.\n      upsertBucket(\n        buckets,\n        `unmatched:${bucketKey(methodUpper, normalizedPath)}`,\n        isError,\n        entry.timestamp,\n        () => ({\n          targetKind: UNMATCHED_ROUTE_TARGET_KIND,\n          targetName: bucketKey(methodUpper, normalizedPath),\n        }),\n      )\n    }\n  }\n\n  return [...buckets.values()].map((b) => ({\n    targetKind: b.targetKind,\n    targetName: b.targetName,\n    callCount: b.callCount,\n    errorCount: b.errorCount,\n    lastObservedIso: b.lastObservedIso,\n    ...(b.callSite ? { callSite: b.callSite } : {}),\n  }))\n}\n\n// ── target resolution (provider-specific id-shape mapping) ──────────────────\n//\n// A pure function of the signal — the route matching already happened in\n// poll()/the route index above; resolveTarget's job here is only the\n// id-shape mapping (targetKind/targetName → NEAT node id).\nexport function createRenderResolveTarget(config: RenderConnectorConfig): ResolveConnectorTarget {\n  return (signal: ObservedSignal) => {\n    if (signal.targetKind === ROUTE_TARGET_KIND) {\n      // targetName is already the exact RouteNode graph id the route index\n      // resolved — the OBSERVED half of the two-sided divergence, landing on\n      // the same node the EXTRACTED client↔route CALLS edge (route-match.ts)\n      // and a future OBSERVED server span would.\n      return { targetNodeId: signal.targetName, serviceName: config.serviceName, edgeType: EdgeType.CALLS }\n    }\n\n    // UNMATCHED_ROUTE_TARGET_KIND (and anything unrecognised): no RouteNode\n    // resolved. The shared pipeline (connectors/index.ts) has no primitive to\n    // auto-vivify a RouteNode — and RouteNode.path is a required field naming a\n    // real source location (packages/types/src/nodes.ts), so minting one here\n    // would fabricate provenance (file-awareness.md §6). Returning null routes\n    // this through the scaffold's honest-miss path\n    // (ConnectorPollResult.unresolved). The gap it leaves — a route Render\n    // observes but no static extractor recognises today — belongs to routes.ts's\n    // framework coverage, and shrinks as routes.ts grows, the same as Railway.\n    return null\n  }\n}\n\n// ── connector ────────────────────────────────────────────────────────────────\n//\n// Constructed with a `graph` reference so poll() can read (never mutate, per\n// ADR-030 — every write flows back through connectors/index.ts's ingest.ts\n// primitives) the polled service's existing RouteNodes to match request logs\n// against, the same read-only access extract/calls/route-match.ts has for the\n// identical purpose on the static-extraction side.\nexport function createRenderConnector(graph: NeatGraph, config: RenderConnectorConfig): ObservedConnector {\n  return {\n    provider: 'render',\n    async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n      const token = readRenderToken(ctx.credentials)\n      const now = new Date()\n      const maxLookbackMs = config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS\n      const startTime = boundedRenderStartTime(ctx.since, now, maxLookbackMs)\n      const endTime = now.toISOString()\n\n      const logs = await fetchRenderRequestLogs(config, token, startTime, endTime)\n      const routeIndex = buildRenderRouteIndex(graph, config.serviceName)\n      return mapRenderRequestLogsToSignals(logs, routeIndex)\n    },\n  }\n}\n","// Render connector — provider-specific types (docs/connectors/render.md,\n// ADR-166). Render is a hosting platform, so like Railway (ADR-127) it names\n// nothing in application code: the signal comes entirely from Render's own\n// edge layer (its HTTP request logs), and fusion binds onto the RouteNode\n// `extract/routes.ts` already builds. Render is SaaS-only, so there is no\n// self-hosted-vs-Cloud branch to carry through these types.\n//\n// Surface + field names are sourced from Render's public API docs\n// (api-docs.render.com/reference/list-logs; render.com/docs/logging and\n// render.com/docs/log-streams), not from a live authenticated introspection —\n// this connector has no Render account to probe against. The request-log\n// attributes (method / statusCode / path / host) are the documented log-query\n// filter parameters, carried on each entry as `labels` per Render's log\n// object shape; where the real entry layout differs from the documented one,\n// the mapping layer (index.ts) drops the row honestly rather than guessing.\n// See docs/connectors/render.md §\"What is verified\" for exactly what remains\n// unconfirmed pending a live project.\n\n/**\n * Config resolved once at connector setup (docs/connectors/render.md §Fusion,\n * \"resolved once, never guessed\") — never re-derived from a Render API\n * response at poll time.\n */\nexport interface RenderConnectorConfig {\n  // Render's REST API base. Defaults to the public API\n  // (api-docs.render.com/reference/introduction confirms\n  // `https://api.render.com/v1`); overridable for tests and any proxy.\n  apiUrl?: string\n  // The Render workspace (owner) id the `GET /v1/logs` query is scoped to —\n  // `ownerId` is a required query parameter (api-docs.render.com/reference/\n  // list-logs). Also this connector's rate-limit bucket key (ADR-131), the\n  // closest thing Render's config carries to \"one customer's account\".\n  ownerId: string\n  // The Render service id whose request logs this connector instance polls —\n  // the `resource` filter on the logs query. Render names a service by its own\n  // `srv-...` id, which carries no relationship to NEAT's manifest-derived\n  // `serviceId(name)` (packages/types/src/identity.ts); the two are different\n  // naming authorities with no shared source of truth.\n  resourceId: string\n  // The NEAT manifest service name this connector fuses onto — the name that\n  // resolves `serviceId(name)` and owns the RouteNodes a request log lands on.\n  // Supplied once at connector setup; never inferred from a Render API\n  // response (docs/connectors/render.md §Fusion).\n  serviceName: string\n  // Max rows requested per page. Render caps `limit` at 100\n  // (api-docs.render.com/reference/list-logs); values above are clamped.\n  limit?: number\n  // Bounded number of pages to follow per poll — Render paginates request logs\n  // by `hasMore` + `nextStartTime`/`nextEndTime`, so an unbounded follow could\n  // walk the whole window on a busy service. Capped so a single tick stays\n  // bounded (docs/contracts/connectors.md §\"Poll cadence and backfill\").\n  maxPages?: number\n  // Bounded lookback cap in ms for a first poll (no prior `since`) or a gap\n  // wider than this window. Render's request-log retention varies by plan and\n  // isn't published as a single number; 24h is a conservative chosen default,\n  // not a provider-confirmed value — overridable once a live project confirms\n  // the real window.\n  maxLookbackMs?: number\n}\n\n// ── raw provider response shapes ────────────────────────────────────────────\n//\n// Sourced from Render's public API docs (api-docs.render.com/reference/\n// list-logs), not from a live introspection. `GET /v1/logs` returns a page of\n// entries plus timestamp cursors; each entry carries a `labels` array, and a\n// request log's method/statusCode/path/host live in those labels (the same\n// names the log-query filter parameters use). What remains unconfirmed against\n// a real response — whether every request attribute is a label vs a top-level\n// field, and the exact retention window — is flagged in docs/connectors/\n// render.md §\"What is verified\".\n\n/** One `{ name, value }` label on a Render log entry. */\nexport interface RenderLogLabel {\n  name: string\n  value: string\n}\n\n/** One entry in the `logs` array of a `GET /v1/logs` response. */\nexport interface RenderLogEntry {\n  // Render's own event time for the log line — never poll-arrival time.\n  timestamp: string\n  // The formatted log line; unused for fusion (the structured attributes come\n  // from `labels`), carried for the LogEntry emit (ADR-132) a later cut adds.\n  message?: string\n  id?: string\n  // Structured attributes. For a request log: `type=request`, `method`,\n  // `statusCode`, `path`, `host` (render.com/docs/logging). Absent or\n  // partial → the row is dropped honestly by the mapping layer.\n  labels?: RenderLogLabel[]\n}\n\n/** A `GET /v1/logs` response page. */\nexport interface RenderLogsResponse {\n  hasMore: boolean\n  // Timestamp cursors for the next page — passed back as the next query's\n  // `startTime`/`endTime` (api-docs.render.com/reference/list-logs).\n  nextStartTime?: string\n  nextEndTime?: string\n  logs: RenderLogEntry[]\n}\n\n// A Render API key is the single credential this connector carries — a Bearer\n// token created from Render's account settings (render.com/docs/api). Read from\n// `ConnectorContext.credentials` at poll time, never logged, never written into\n// a node or edge (docs/contracts/connectors.md §6).\nexport function readRenderToken(credentials: Record<string, unknown>): string {\n  const token = credentials.token\n  if (typeof token !== 'string' || token.length === 0) {\n    throw new Error('Render connector requires ctx.credentials.token (a Render API key)')\n  }\n  return token\n}\n\n// Read a single label's value off an entry, or undefined when absent. The\n// request-log attributes (method/statusCode/path/host) live here per Render's\n// log object shape; a missing label means the mapping layer drops the row\n// rather than guessing (connectors.md §4).\nexport function renderLabelValue(entry: RenderLogEntry, name: string): string | undefined {\n  if (!Array.isArray(entry.labels)) return undefined\n  const label = entry.labels.find((l) => l && typeof l === 'object' && l.name === name)\n  return label && typeof label.value === 'string' ? label.value : undefined\n}\n","// Render REST client — the fetch half of this connector's poll() (ADR-166,\n// docs/connectors/render.md). Passive and ambient only (docs/contracts/\n// connectors.md §2): one read-only query against Render's own request-log\n// surface, never a mutation, never a synthetic request to the observed app.\n//\n// Render exposes its edge-layer HTTP request logs through `GET /v1/logs`\n// (api-docs.render.com/reference/list-logs), filterable to `type=request` and\n// scoped by `ownerId` + `resource`. Auth is a Bearer API key\n// (render.com/docs/api). This is the pull path chosen for Render because its\n// push surfaces don't reach NEAT's OTLP ingest: log streams forward RFC5424\n// syslog (render.com/docs/log-streams), and metrics streams forward OTLP\n// *metrics*, not traces (render.com/docs/metrics-streams) — neither is a\n// trace-drain the daemon's `/v1/traces` receiver accepts, so a Vercel-style\n// drain (ADR-146) has nothing to point at. See ADR-166 for the full argument.\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type { RenderConnectorConfig, RenderLogEntry, RenderLogsResponse } from './types.js'\n\nexport const DEFAULT_RENDER_API_URL = 'https://api.render.com/v1'\n\n// Render caps `limit` at 100 rows per page (api-docs.render.com/reference/\n// list-logs); a poll follows `hasMore`/`nextStartTime`/`nextEndTime` up to\n// DEFAULT_RENDER_MAX_PAGES so a busy service's window stays bounded per tick.\nexport const DEFAULT_RENDER_LOG_LIMIT = 100\nexport const RENDER_MAX_LOG_LIMIT = 100\nexport const DEFAULT_RENDER_MAX_PAGES = 20\n\n// Render's request-log retention varies by plan and isn't published as a single\n// number; 24h is a conservative bounded default for a first poll or a wide gap,\n// never an unbounded full-history query regardless (docs/contracts/\n// connectors.md §\"Poll cadence and backfill\").\nexport const DEFAULT_MAX_LOOKBACK_MS = 24 * 60 * 60 * 1000\n\nfunction clampLimit(limit: number | undefined): number {\n  const raw = Math.trunc(limit ?? DEFAULT_RENDER_LOG_LIMIT)\n  if (!Number.isFinite(raw) || raw < 1) return DEFAULT_RENDER_LOG_LIMIT\n  return Math.min(raw, RENDER_MAX_LOG_LIMIT)\n}\n\n// `since` bounded by the provider's max lookback window (docs/contracts/\n// connectors.md §\"Poll cadence and backfill\") — a gap wider than the window\n// (a laptop off for a week) backfills from `now - maxLookbackMs`, never an\n// unbounded full-history replay. An absent or unparseable `since` (no prior\n// poll) gets the same treatment as too-old a `since`.\nexport function boundedRenderStartTime(since: string | undefined, now: Date, maxLookbackMs: number): string {\n  const floor = new Date(now.getTime() - maxLookbackMs)\n  if (!since) return floor.toISOString()\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return floor.toISOString()\n  return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString()\n}\n\nasync function fetchRenderLogPage(\n  config: RenderConnectorConfig,\n  token: string,\n  startTime: string,\n  endTime: string,\n  limit: number,\n  fetchImpl?: typeof fetch,\n): Promise<RenderLogsResponse> {\n  const url = new URL(`${config.apiUrl ?? DEFAULT_RENDER_API_URL}/logs`)\n  url.searchParams.set('ownerId', config.ownerId)\n  url.searchParams.set('resource', config.resourceId)\n  // Only the edge-layer HTTP request logs — the surface that carries method /\n  // path / statusCode and fuses onto a RouteNode. App/build logs are free-text\n  // stdout with no structured route to bind to (render.com/docs/logging).\n  url.searchParams.set('type', 'request')\n  url.searchParams.set('startTime', startTime)\n  url.searchParams.set('endTime', endTime)\n  // Newest-first, matching Render's own default; pagination walks backward\n  // through the window via the cursors below.\n  url.searchParams.set('direction', 'backward')\n  url.searchParams.set('limit', String(limit))\n\n  const res = await junctionFetch(\n    url,\n    { method: 'GET', headers: { ...bearerAuthHeader(token) } },\n    { provider: 'render', accountKey: config.ownerId, ...(fetchImpl ? { fetchImpl } : {}) },\n  )\n  if (!res.ok) {\n    throw new Error(`Render logs request failed: ${res.status} ${res.statusText}`)\n  }\n  return (await res.json()) as RenderLogsResponse\n}\n\n/**\n * Fetch the request logs in [startTime, endTime], following Render's\n * timestamp-cursor pagination up to `maxPages`. Render returns\n * `hasMore` + `nextStartTime`/`nextEndTime` and expects those passed back as\n * the next query's `startTime`/`endTime` (api-docs.render.com/reference/\n * list-logs). A malformed page (no `logs` array) ends the walk honestly\n * rather than throwing.\n */\nexport async function fetchRenderRequestLogs(\n  config: RenderConnectorConfig,\n  token: string,\n  startTime: string,\n  endTime: string,\n  fetchImpl?: typeof fetch,\n): Promise<RenderLogEntry[]> {\n  const limit = clampLimit(config.limit)\n  const maxPages = Math.max(1, Math.trunc(config.maxPages ?? DEFAULT_RENDER_MAX_PAGES))\n  const out: RenderLogEntry[] = []\n  let pageStart = startTime\n  let pageEnd = endTime\n\n  for (let page = 0; page < maxPages; page++) {\n    const body = await fetchRenderLogPage(config, token, pageStart, pageEnd, limit, fetchImpl)\n    if (Array.isArray(body.logs)) out.push(...body.logs)\n    if (!body.hasMore || !body.nextStartTime || !body.nextEndTime) break\n    pageStart = body.nextStartTime\n    pageEnd = body.nextEndTime\n  }\n  return out\n}\n","// PlanetScale connector (ADR-175, docs/connectors/planetscale.md) — a data-grain\n// pull provider on the connectors plane (ADR-124, connectors/index.ts). Reads\n// PlanetScale's own Query Insights telemetry and fuses per-table query stats\n// onto the `sql-table` nodes the static SQL/ORM extractor already builds, the\n// same fusion target Neon and Supabase's table-grain connectors use.\n//\n// The connector owns only poll() (fetch + map); the graph-reading target\n// resolution is a separate `resolveTarget` built with the graph, mirroring the\n// Supabase pairing the registry normalizes.\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport {\n  DEFAULT_MAX_LOOKBACK_MS,\n  boundedPlanetscaleStartTime,\n  fetchPlanetscaleInsights,\n} from './client.js'\nimport { mapInsightsToSignals } from './map.js'\nimport { createPlanetscaleResolveTarget } from './resolve.js'\nimport { readPlanetscaleCredentials, type PlanetscaleConnectorConfig } from './types.js'\n\nexport * from './client.js'\nexport * from './map.js'\nexport * from './resolve.js'\nexport * from './types.js'\n\nexport interface PlanetscaleConnectorDeps {\n  fetchImpl?: typeof fetch\n  now?: () => Date\n}\n\nexport class PlanetscaleConnector implements ObservedConnector {\n  readonly provider = 'planetscale'\n\n  constructor(\n    private readonly config: PlanetscaleConnectorConfig,\n    private readonly deps: PlanetscaleConnectorDeps = {},\n  ) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const credentials = readPlanetscaleCredentials(ctx.credentials)\n    const now = this.deps.now?.() ?? new Date()\n    const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS\n    const from = boundedPlanetscaleStartTime(ctx.since, now, maxLookbackMs)\n    const to = now.toISOString()\n    const rows = await fetchPlanetscaleInsights(this.config, credentials, from, to, this.deps.fetchImpl)\n    return mapInsightsToSignals(rows, to)\n  }\n}\n\nexport function createPlanetscaleConnector(\n  graph: NeatGraph,\n  config: PlanetscaleConnectorConfig,\n  deps: PlanetscaleConnectorDeps = {},\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new PlanetscaleConnector(config, deps),\n    resolveTarget: createPlanetscaleResolveTarget(graph, config),\n  }\n}\n","// PlanetScale REST client — the fetch half of this connector's poll() (ADR-175,\n// docs/connectors/planetscale.md). Passive and ambient only (connectors.md §2):\n// one read-only query against PlanetScale's own Query Insights surface, never a\n// mutation, never a synthetic query to the observed database.\n//\n// PlanetScale exposes per-fingerprint query telemetry through\n//   GET /v1/organizations/{org}/databases/{db}/branches/{branch}/insights\n// (planetscale.com/docs/api/reference/list_branch_queries), bounded by a\n// `from`/`to` time window and paginated by `page`/`per_page`. Auth is a\n// service token in the NON-Bearer `id:token` header form (types.ts,\n// planetscale.com/docs/api/reference/service-tokens). The query is always\n// bounded by the poll window — never an unbounded full-history read.\n\nimport { junctionFetch } from '../junction.js'\nimport {\n  planetscaleAuthHeader,\n  type PlanetscaleConnectorConfig,\n  type PlanetscaleCredentials,\n  type PlanetscaleInsightRow,\n  type PlanetscaleInsightsResponse,\n} from './types.js'\n\nexport const DEFAULT_PLANETSCALE_API_URL = 'https://api.planetscale.com/v1'\n\n// PlanetScale's Insights default `per_page` is 25; 100 keeps a busy branch's\n// window bounded in fewer round-trips without over-fetching.\nexport const DEFAULT_PLANETSCALE_PER_PAGE = 100\n// Bounded page-follow per poll — `next_page` could otherwise walk the whole\n// window on a busy branch (connectors.md §\"Poll cadence and backfill\").\nexport const DEFAULT_PLANETSCALE_MAX_PAGES = 20\n\n// PlanetScale's Insights retention varies and isn't published as a single\n// number; 24h is a conservative bounded default for a first poll or a wide\n// gap, never an unbounded full-history query regardless.\nexport const DEFAULT_MAX_LOOKBACK_MS = 24 * 60 * 60 * 1000\n\nfunction clampPerPage(perPage: number | undefined): number {\n  const raw = Math.trunc(perPage ?? DEFAULT_PLANETSCALE_PER_PAGE)\n  if (!Number.isFinite(raw) || raw < 1) return DEFAULT_PLANETSCALE_PER_PAGE\n  return Math.min(raw, DEFAULT_PLANETSCALE_PER_PAGE)\n}\n\n// `since` bounded by the provider's max lookback window (connectors.md §\"Poll\n// cadence and backfill\") — a gap wider than the window (a laptop off for a\n// week) backfills from `now - maxLookbackMs`, never an unbounded full-history\n// replay. An absent or unparseable `since` (no prior poll) gets the same\n// treatment as too-old a `since`. Mirrors render/client.ts's own bounding.\nexport function boundedPlanetscaleStartTime(\n  since: string | undefined,\n  now: Date,\n  maxLookbackMs: number,\n): string {\n  const floor = new Date(now.getTime() - maxLookbackMs)\n  if (!since) return floor.toISOString()\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return floor.toISOString()\n  return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString()\n}\n\nfunction insightsUrl(\n  config: PlanetscaleConnectorConfig,\n  from: string,\n  to: string,\n  perPage: number,\n  page: number,\n): URL {\n  const base = config.apiUrl ?? DEFAULT_PLANETSCALE_API_URL\n  const url = new URL(\n    `${base}/organizations/${encodeURIComponent(config.organization)}/databases/${encodeURIComponent(\n      config.database,\n    )}/branches/${encodeURIComponent(config.branch)}/insights`,\n  )\n  // Always bounded by the poll window — never an unbounded read.\n  url.searchParams.set('from', from)\n  url.searchParams.set('to', to)\n  url.searchParams.set('per_page', String(perPage))\n  url.searchParams.set('page', String(page))\n  return url\n}\n\nasync function fetchInsightsPage(\n  config: PlanetscaleConnectorConfig,\n  credentials: PlanetscaleCredentials,\n  from: string,\n  to: string,\n  perPage: number,\n  page: number,\n  fetchImpl?: typeof fetch,\n): Promise<PlanetscaleInsightsResponse> {\n  const res = await junctionFetch(\n    insightsUrl(config, from, to, perPage, page),\n    {\n      method: 'GET',\n      headers: {\n        ...planetscaleAuthHeader(credentials.serviceTokenId, credentials.serviceToken),\n        Accept: 'application/json',\n      },\n    },\n    { provider: 'planetscale', accountKey: config.database, ...(fetchImpl ? { fetchImpl } : {}) },\n  )\n  if (!res.ok) {\n    throw new Error(`PlanetScale insights request failed: ${res.status} ${res.statusText}`)\n  }\n  return (await res.json()) as PlanetscaleInsightsResponse\n}\n\n/**\n * Fetch the Query Insights rows for `[from, to]`, following PlanetScale's\n * `next_page` pagination up to `maxPages`. A page with no `data` array ends\n * the walk honestly rather than throwing (connectors.md §4). The window is\n * fixed for the whole walk — every page reads the same `from`/`to`, only\n * `page` advances.\n */\nexport async function fetchPlanetscaleInsights(\n  config: PlanetscaleConnectorConfig,\n  credentials: PlanetscaleCredentials,\n  from: string,\n  to: string,\n  fetchImpl?: typeof fetch,\n): Promise<PlanetscaleInsightRow[]> {\n  const perPage = clampPerPage(config.perPage)\n  const maxPages = Math.max(1, Math.trunc(config.maxPages ?? DEFAULT_PLANETSCALE_MAX_PAGES))\n  const out: PlanetscaleInsightRow[] = []\n  let page = 1\n\n  for (let i = 0; i < maxPages; i++) {\n    const body = await fetchInsightsPage(config, credentials, from, to, perPage, page, fetchImpl)\n    if (Array.isArray(body.data)) out.push(...body.data)\n    // `next_page` is null on the last page; a missing/garbage cursor also ends\n    // the walk rather than looping forever.\n    if (typeof body.next_page !== 'number' || body.next_page <= page) break\n    page = body.next_page\n  }\n  return out\n}\n","// PlanetScale connector — provider-specific types (docs/connectors/planetscale.md,\n// ADR-175). PlanetScale is a hosted MySQL/Vitess platform that runs its own\n// query telemetry (Query Insights), so like Neon (ADR-156) it is a data-grain\n// connector: the signal fuses onto the `sql-table` nodes the static SQL/ORM\n// extractor already builds. It is *simpler* than Neon's `pg_stat_statements`\n// path in two ways the Insights API hands us for free:\n//\n//   - tables come already parsed (the `tables` array), so there is no\n//     FROM-clause regex, and\n//   - counts are windowed to the poll interval (`query_count` is the count\n//     over `[from, to]`), so there is no cumulative-counter delta bookkeeping.\n//\n// Surface + field names are sourced from PlanetScale's public API reference\n// (planetscale.com/docs/api/reference/list_branch_queries;\n// planetscale.com/changelog/query-insights-api-endpoints), not from a live\n// authenticated introspection — PlanetScale is a paid product with no free\n// tier, so this connector carries no live account to probe against. Where the\n// real response layout differs from the documented one, the mapping layer\n// (map.ts) drops the row honestly rather than guessing. See\n// docs/connectors/planetscale.md §\"What is verified\" for exactly what remains\n// unconfirmed pending a real branch.\n\nexport const PLANETSCALE_SQL_TABLE_TARGET_KIND = 'sql-table'\n\n/**\n * Config resolved once at connector setup (docs/connectors/planetscale.md\n * §Fusion, \"resolved once, never guessed\") — the `(organization, database,\n * branch)` triple that scopes the Insights query, plus the NEAT service the\n * signals fuse onto. Never re-derived from a PlanetScale API response at poll\n * time, the same way Railway resolves `(environmentId, serviceId)` once.\n */\nexport interface PlanetscaleConnectorConfig {\n  // PlanetScale's REST API base. Defaults to the public API\n  // (planetscale.com/docs/api); overridable for tests and any proxy.\n  apiUrl?: string\n  // The PlanetScale organization slug the Insights path is scoped to.\n  organization: string\n  // The PlanetScale database the Insights path is scoped to. Also this\n  // connector's rate-limit bucket key (ADR-131), the closest thing\n  // PlanetScale's config carries to \"one customer's account\".\n  database: string\n  // The database branch whose Insights this connector polls (e.g. `main`).\n  branch: string\n  // The NEAT manifest service name this connector fuses onto — the name that\n  // owns the `sql-table` nodes a query row lands on. Supplied once at\n  // connector setup; never inferred from a PlanetScale API response.\n  serviceName: string\n  // Rows requested per page. Insights paginates `page`/`per_page`; 100 keeps a\n  // busy branch's window bounded per tick without over-fetching.\n  perPage?: number\n  // Bounded number of pages to follow per poll — Insights paginates by\n  // `next_page`, so an unbounded follow could walk the whole window on a busy\n  // branch. Capped so a single tick stays bounded (connectors.md §\"Poll\n  // cadence and backfill\").\n  maxPages?: number\n  // Bounded lookback cap in ms for a first poll (no prior `since`) or a gap\n  // wider than this window. PlanetScale's Insights retention isn't published\n  // as a single number; 24h is a conservative chosen default, not a\n  // provider-confirmed value — overridable once a live branch confirms the\n  // real window.\n  maxLookbackMs?: number\n}\n\n// ── credential ──────────────────────────────────────────────────────────────\n//\n// A PlanetScale service token is two parts: an id and the secret itself. The\n// least-privilege grant is a per-database `read_database` scope, read-only\n// (planetscale.com/docs/api/reference/service-tokens). Both parts are read\n// from `ConnectorContext.credentials` at poll time, never logged, never\n// written into a node or edge (connectors.md §6).\nexport interface PlanetscaleCredentials {\n  serviceTokenId: string\n  serviceToken: string\n}\n\nexport function readPlanetscaleCredentials(input: Record<string, unknown>): PlanetscaleCredentials {\n  const serviceTokenId = input.serviceTokenId\n  const serviceToken = input.serviceToken\n  if (typeof serviceTokenId !== 'string' || serviceTokenId.length === 0) {\n    throw new Error('planetscale connector: credentials.serviceTokenId is required')\n  }\n  if (typeof serviceToken !== 'string' || serviceToken.length === 0) {\n    throw new Error('planetscale connector: credentials.serviceToken is required')\n  }\n  return { serviceTokenId, serviceToken }\n}\n\n/**\n * PlanetScale's service-token auth header is NOT a Bearer token — it is the\n * token id, a colon, then the token\n * (planetscale.com/docs/api/reference/service-tokens). This is the one place\n * that shape is constructed, shared between the poll path (client.ts) and the\n * add-time auth probe (registry.ts) so the two can't drift.\n *\n * (The auto-generated API reference renders a generic `Bearer {token}`\n * example for its OAuth2 flow; a service token uses this `id:token` form.\n * docs/connectors/planetscale.md §\"What is verified\" records that this is\n * taken from the docs, not confirmed against a live token.)\n */\nexport function planetscaleAuthHeader(\n  serviceTokenId: string,\n  serviceToken: string,\n): { Authorization: string } {\n  return { Authorization: `${serviceTokenId}:${serviceToken}` }\n}\n\n// ── raw provider response shapes ────────────────────────────────────────────\n//\n// One entry in the `data[]` array of a Query Insights response\n// (planetscale.com/docs/api/reference/list_branch_queries). Only the fields\n// this connector reads are typed; the response carries many more latency /\n// bytes / shard metrics this connector ignores. Every field is optional here\n// because the mapping layer treats a missing/garbage field as \"drop this row\n// honestly\" rather than trusting the documented shape blindly.\nexport interface PlanetscaleInsightRow {\n  // The tables this query fingerprint touched, already parsed by PlanetScale —\n  // the fusion key. One ObservedSignal is emitted per name. A multi-table\n  // query genuinely touched each table, so it fans out.\n  tables?: string[]\n  // Keyspace-qualified table names (`keyspace.table`) — the fallback fusion\n  // key when `tables` is absent or empty.\n  qualified_tables?: string[]\n  // The keyspace this fingerprint ran in — disambiguates table identity across\n  // keyspaces; carried for diagnostics.\n  keyspace?: string\n  // The normalized (literal-stripped) SQL — diagnostic only; this connector\n  // does not parse it (Insights already parsed `tables`), and stays at table\n  // grain (ADR-175 — no column grain).\n  normalized_sql?: string\n  // The number of times this fingerprint ran over the poll window → callCount.\n  // Windowed, not cumulative — read directly, no baseline.\n  query_count?: number\n  // How many of those runs errored over the window → errorCount. A real\n  // failure signal the pg_stat_statements path (Neon/Supabase) has none of.\n  error_count?: number\n  // PlanetScale's own last-run time for this fingerprint → lastObservedIso.\n  // Provider event time, never poll-arrival time (README.md §Poll cadence).\n  last_run_at?: string | null\n}\n\n/** One Query Insights response page. */\nexport interface PlanetscaleInsightsResponse {\n  data?: PlanetscaleInsightRow[]\n  // The next page number, or null on the last page — the pagination cursor\n  // this connector follows up to `maxPages`.\n  next_page?: number | null\n  current_page?: number\n}\n","// PlanetScale Query Insights → ObservedSignal[] (ADR-175,\n// docs/connectors/planetscale.md §Fusion). This is the whole mapping layer,\n// and it is deliberately small: PlanetScale already did the two hard parts the\n// pg_stat_statements path (Neon/Supabase) has to do by hand.\n//\n//   - No FROM-clause regex. `tables` is already the parsed table set. One\n//     signal per table name — a multi-table query genuinely touched each, so\n//     it fans out. `qualified_tables` is the keyspace-qualified fallback when\n//     `tables` is bare.\n//   - No cumulative-delta bookkeeping. `query_count` is windowed to the poll\n//     interval, so it IS the count for this tick — read directly, no baseline,\n//     no reset detection.\n//\n// Table grain only (ADR-175): `normalized_sql` is carried in the raw row for\n// diagnostics but never parsed for columns — Insights aggregates per\n// fingerprint, so there is no honest column or row grain to emit.\n//\n// Like Neon (connectors.md §7's bounded exception), an Insights row is an\n// aggregate counter snapshot, not an individual invocation record, so this\n// layer emits only the counter ObservedSignal and no LogEntry — turning a\n// windowed fingerprint aggregate into a per-event log line would fabricate\n// events that never individually existed.\n\nimport type { ObservedSignal } from '../types.js'\nimport { PLANETSCALE_SQL_TABLE_TARGET_KIND, type PlanetscaleInsightRow } from './types.js'\n\n// The table set for one row: prefer the bare `tables`, fall back to the\n// keyspace-qualified names when `tables` is absent or empty. Filters to\n// non-empty strings so a garbage entry never becomes a signal.\nfunction tablesFor(row: PlanetscaleInsightRow): string[] {\n  const bare = Array.isArray(row.tables) ? row.tables.filter((t) => typeof t === 'string' && t.length > 0) : []\n  if (bare.length > 0) return bare\n  return Array.isArray(row.qualified_tables)\n    ? row.qualified_tables.filter((t) => typeof t === 'string' && t.length > 0)\n    : []\n}\n\n/**\n * Map one page-set of Insights rows to signals. `observedAtIso` is the poll's\n * own `to` time, used only as the fallback event time when a row's own\n * `last_run_at` is absent — the provider's event time is preferred whenever it\n * carries one (README.md §Poll cadence and backfill).\n */\nexport function mapInsightsToSignals(\n  rows: PlanetscaleInsightRow[],\n  observedAtIso: string,\n): ObservedSignal[] {\n  const signals: ObservedSignal[] = []\n  if (!Array.isArray(rows)) return signals\n\n  for (const row of rows) {\n    if (!row || typeof row !== 'object') continue\n\n    const callCount = Number(row.query_count)\n    // A non-finite or non-positive count is not an observation — drop it\n    // rather than minting a phantom zero-call edge (connectors.md §4).\n    if (!Number.isFinite(callCount) || callCount < 1) continue\n\n    const rawErrors = Number(row.error_count)\n    const errorCount = Number.isFinite(rawErrors) && rawErrors > 0 ? Math.trunc(rawErrors) : 0\n\n    // The provider's own last-run time is the observation instant; fall back\n    // to the poll's `to` only when the row carries none.\n    const lastObservedIso =\n      typeof row.last_run_at === 'string' && row.last_run_at.length > 0 ? row.last_run_at : observedAtIso\n\n    for (const table of tablesFor(row)) {\n      signals.push({\n        targetKind: PLANETSCALE_SQL_TABLE_TARGET_KIND,\n        targetName: table,\n        callCount: Math.trunc(callCount),\n        errorCount,\n        lastObservedIso,\n      })\n    }\n  }\n\n  return signals\n}\n","// Target resolution — the PlanetScale-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning a signal's (targetKind, targetName) into\n// a NEAT node id. A pure lookup against the graph; no mutation authority of its\n// own (ADR-030), so the honest fallback is *declared* via `ensureInfraNode`\n// (connectors.md §4a, ADR-133) for the shared pipeline to enact.\n//\n// The fusion target is the `sql-table` node the static SQL/ORM extractor\n// already mints (`infraId('sql-table', <table>)`) — the exact id the Neon and\n// Supabase table-grain connectors resolve onto, and the id the SQLAlchemy /\n// Django / Drizzle / Prisma table extractors build. Landing here means the\n// OBSERVED edge sharpens to file grain automatically wherever that node\n// carries a real file:line static call site (the shared pipeline's\n// staticCallSiteFor), the ADR-124 compounding payoff — no connector-side\n// change when the extractor grows.\n//\n// Honest miss (connectors.md §4a): when no `sql-table` node exists yet — the\n// static extractor hasn't run against this code, or doesn't parse the shape —\n// the signal must NOT fabricate a table node. Instead it stays honestly at the\n// PROVIDER level: a `planetscale-database` InfraNode declared observed-but-\n// undeclared, so the traffic surfaces as a `missing-extracted` divergence\n// rather than a silent drop. A future PlanetScale schema extractor that mints\n// the `sql-table` node makes these edges sharpen onto it with no change here.\n\nimport { EdgeType, infraId } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport type { ConnectorContext, ObservedSignal } from '../types.js'\nimport { PLANETSCALE_SQL_TABLE_TARGET_KIND, type PlanetscaleConnectorConfig } from './types.js'\n\n// The provider-level fallback node's stable identity: the org/database pair the\n// connector polls. Never a table — a database (connectors.md §4a's honest\n// provider-node fallback, like Cloud Run's `cloud-run-service`).\nconst PLANETSCALE_DATABASE_KIND = 'planetscale-database'\n\nexport function createPlanetscaleResolveTarget(\n  graph: NeatGraph,\n  config: PlanetscaleConnectorConfig,\n): ResolveConnectorTarget {\n  const databaseName = `${config.organization}/${config.database}`\n  return (signal: ObservedSignal, _ctx: ConnectorContext): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== PLANETSCALE_SQL_TABLE_TARGET_KIND || !signal.targetName) return null\n\n    // Prefer the existing canonical sql-table node the static extractor minted.\n    // Landing on it lets the observation fuse onto the file→table static call\n    // site for file grain, rather than collapsing to the provider node.\n    const tableId = infraId('sql-table', signal.targetName)\n    if (graph.hasNode(tableId)) {\n      return { targetNodeId: tableId, serviceName: config.serviceName, edgeType: EdgeType.CALLS }\n    }\n\n    // No such table node — honest miss. Fall back to the provider-level\n    // database node (never a fabricated table), declared for the shared\n    // pipeline to ensure (ADR-030 / §4a). `targetNodeId` MUST equal\n    // `infraId(kind, name)` when `ensureInfraNode` is set.\n    const providerId = infraId(PLANETSCALE_DATABASE_KIND, databaseName)\n    return {\n      targetNodeId: providerId,\n      serviceName: config.serviceName,\n      edgeType: EdgeType.CALLS,\n      ensureInfraNode: { kind: PLANETSCALE_DATABASE_KIND, name: databaseName, provider: 'planetscale' },\n    }\n  }\n}\n","// The EAS build-failure connector (ADR-185, docs/plans/eas-build-connector-plan.md)\n// — the first incident-emitting connector (connectors.md §10).\n//\n// poll() pulls the Expo app's `ERRORED` builds (client.ts), keeps the ones newer\n// than the last watermark, fetches-and-caps each one's logs, and maps each to an\n// incident-bearing ObservedSignal (map.ts). Target resolution — the\n// buildPhase → ConfigNode/ServiceNode table through the fused-node lookup — lives\n// in resolve.ts. Everything downstream (writing the incident to the ledger) is\n// the shared connectors/index.ts pipeline; this module never touches the graph or\n// the ledger directly (ADR-030).\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport {\n  DEFAULT_MAX_LOG_BYTES,\n  DEFAULT_MAX_LOOKBACK_MS,\n  fetchBuildLogs,\n  fetchErroredBuilds,\n} from './client.js'\nimport { buildEventTime, mapBuildsToSignals } from './map.js'\nimport { createEasResolveTarget } from './resolve.js'\nimport { readEasCredentials, type EasBuild, type EasConnectorConfig } from './types.js'\n\nexport * from './client.js'\nexport * from './map.js'\nexport * from './resolve.js'\nexport * from './types.js'\n\n// Whether a build's own event time is strictly after the poll watermark. An\n// unparseable time (or watermark) can't be compared, so the build is kept rather\n// than dropped — an honest miss favours surfacing the failure. Re-minting the\n// same build across ticks is harmless: the incident id (`eas:build:<id>`)\n// collapses it on read (ingest.ts `dedupeIncidents`).\nfunction isBuildSince(build: EasBuild, sinceIso: string): boolean {\n  const t = Date.parse(buildEventTime(build))\n  const s = Date.parse(sinceIso)\n  if (Number.isNaN(t) || Number.isNaN(s)) return true\n  return t > s\n}\n\n// `since` bounded by the connector's max lookback window (connectors.md §Poll\n// cadence and backfill) — a gap wider than the window backfills from\n// `now - maxLookbackMs`, never an unbounded full-history replay; an absent or\n// unparseable `since` (no prior poll) gets the same floor. Same shape\n// cloud-run's `boundedSinceIso` keeps.\nexport function boundedSinceIso(since: string | undefined, now: Date, maxLookbackMs: number): string {\n  const floor = new Date(now.getTime() - maxLookbackMs)\n  if (!since) return floor.toISOString()\n  const sinceMs = new Date(since).getTime()\n  if (Number.isNaN(sinceMs)) return floor.toISOString()\n  return sinceMs < floor.getTime() ? floor.toISOString() : new Date(sinceMs).toISOString()\n}\n\nexport class EasConnector implements ObservedConnector {\n  readonly provider = 'eas'\n\n  constructor(\n    private readonly config: EasConnectorConfig,\n    // Test seam — a fake `fetch` stands in for the live Expo API and the log\n    // URLs so poll() never needs a real account. Production leaves it undefined\n    // and the connector uses the global fetch (through the junction for the API).\n    private readonly fetchImpl?: typeof fetch,\n  ) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const creds = readEasCredentials(ctx.credentials)\n    // The mapped NEAT service, or the app id when unmapped (stays coarse, and a\n    // native-phase incident then drops honestly since there's no extracted\n    // service to land on — connector-config.md §7.1).\n    const serviceName = this.config.serviceName ?? this.config.appId\n    const maxLookbackMs = this.config.maxLookbackMs ?? DEFAULT_MAX_LOOKBACK_MS\n    const sinceIso = boundedSinceIso(ctx.since, new Date(), maxLookbackMs)\n\n    const builds = await fetchErroredBuilds(creds.token, this.config, this.fetchImpl)\n    const fresh = builds.filter((b) => isBuildSince(b, sinceIso))\n\n    // Fetch-and-cap logs only for the fresh failures — the signed URLs are\n    // time-limited, so this is the one moment they're readable (client.ts).\n    const maxLogBytes = this.config.maxLogBytes ?? DEFAULT_MAX_LOG_BYTES\n    for (const build of fresh) {\n      build.logsText = await fetchBuildLogs(build.logFileUrls, maxLogBytes, this.fetchImpl)\n    }\n\n    return mapBuildsToSignals(fresh, serviceName)\n  }\n}\n\n/**\n * Wires up a ready-to-register EAS connector: the `ObservedConnector` plus the\n * `resolveTarget` callback the shared pipeline needs alongside it. Both are built\n * together because `resolveTarget` closes over `graph` — the shared scaffold's\n * `ResolveConnectorTarget` signature never receives it directly.\n */\nexport function createEasConnector(\n  graph: NeatGraph,\n  config: EasConnectorConfig,\n  fetchImpl?: typeof fetch,\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new EasConnector(config, fetchImpl),\n    resolveTarget: createEasResolveTarget(graph),\n  }\n}\n","// The Expo GraphQL client — the fetch half of the EAS connector's poll()\n// (ADR-185, docs/plans/eas-build-connector-plan.md). Passive and ambient only\n// (connectors.md §2): one read-only `builds` query per page, never a mutation,\n// never a synthetic build.\n//\n// The Expo public GraphQL API (`POST https://api.expo.dev/graphql`) is\n// undocumented and unversioned. The query below is PINNED and reconstructed from\n// `expo/eas-cli`'s generated schema — deliberately NOT a shell to\n// `eas build:view --json`, whose own `BuildFragment` omits `error.buildPhase`\n// (the strict-enum classifier this connector needs) and selects a deprecated\n// logs field. A schema/shape error surfaces as a thrown connector error (the\n// drift signal §8's status tracker records), never a silent drop of builds.\n\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type { EasBuild, EasConnectorConfig } from './types.js'\nimport { EAS_STATUS_ERRORED } from './types.js'\n\nexport const DEFAULT_EAS_API_URL = 'https://api.expo.dev/graphql'\nexport const DEFAULT_PAGE_SIZE = 50\n// Defensive cap on offset pagination — bounds the loop rather than trusting an\n// unbounded while(true), the same discipline cloud-run/client.ts's MAX_PAGES and\n// the trace-stitch BFS depth cap hold. Build failures are low-frequency, so a few\n// pages of newest-first covers any realistic poll window.\nexport const DEFAULT_MAX_PAGES = 10\n// Stored log slice cap. Xcode logs reach ~10MB; a 16KB tail is enough to carry\n// the failure reason (which sits at the end of a build log) to an agent.\nexport const DEFAULT_MAX_LOG_BYTES = 16 * 1024\nexport const DEFAULT_MAX_LOOKBACK_MS = 7 * 24 * 60 * 60 * 1000\n\ninterface EasGraphQLError {\n  message: string\n}\n\ninterface EasGraphQLResponse<T> {\n  data?: T\n  errors?: EasGraphQLError[]\n}\n\n// The PINNED query. `app.byId(appId:)` scopes to one Expo app; `builds` is\n// offset-paginated, newest-first, server-filtered to `status: ERRORED`; the\n// selection set names exactly the fields types.ts reads — including\n// `error { buildPhase errorCode message docsUrl }`, the fragment the CLI omits.\nconst BUILDS_QUERY = `\n  query NeatEasErroredBuilds($appId: String!, $offset: Int!, $limit: Int!) {\n    app {\n      byId(appId: $appId) {\n        builds(offset: $offset, limit: $limit, filter: { status: ERRORED }) {\n          id\n          status\n          platform\n          buildProfile\n          gitCommitHash\n          gitCommitMessage\n          gitRef\n          isGitWorkingTreeDirty\n          createdAt\n          completedAt\n          error {\n            buildPhase\n            errorCode\n            message\n            docsUrl\n          }\n          logFileUrls\n        }\n      }\n    }\n  }\n`\n\ninterface BuildsQueryData {\n  app?: {\n    byId?: {\n      builds?: EasBuild[]\n    }\n  }\n}\n\nasync function easGraphQL<T>(\n  apiUrl: string,\n  token: string,\n  query: string,\n  variables: Record<string, unknown>,\n  accountKey: string,\n  fetchImpl?: typeof fetch,\n): Promise<T> {\n  const res = await junctionFetch(\n    apiUrl,\n    {\n      method: 'POST',\n      headers: {\n        'Content-Type': 'application/json',\n        ...bearerAuthHeader(token),\n      },\n      body: JSON.stringify({ query, variables }),\n    },\n    // accountKey: the Expo app id — the per-(provider, accountKey) rate-limit\n    // bucket (ADR-131), the closest thing this connector carries to \"one account\".\n    { provider: 'eas', accountKey, ...(fetchImpl ? { fetchImpl } : {}) },\n  )\n  if (!res.ok) {\n    throw new Error(`Expo GraphQL request failed: ${res.status} ${res.statusText}`)\n  }\n  const body = (await res.json()) as EasGraphQLResponse<T>\n  // Drift is loud (connectors.md §10, guardrail 3): a GraphQL-level error (a\n  // renamed field, a changed filter arg) throws here rather than being read as\n  // \"no builds\".\n  if (body.errors && body.errors.length > 0) {\n    throw new Error(`Expo GraphQL errors: ${body.errors.map((e) => e.message).join('; ')}`)\n  }\n  if (!body.data) throw new Error('Expo GraphQL response carried no data')\n  return body.data\n}\n\n/**\n * Pull the app's `ERRORED` builds, newest-first, paginated by offset and deduped\n * by `id` across pages (offset pagination can shift when a build is created\n * mid-page). The mapper never trusts the server filter alone (§4) — this also\n * drops any row whose `status` isn't `ERRORED`, in case the filter arg drifts.\n */\nexport async function fetchErroredBuilds(\n  token: string,\n  config: EasConnectorConfig,\n  fetchImpl?: typeof fetch,\n): Promise<EasBuild[]> {\n  const apiUrl = config.apiUrl ?? DEFAULT_EAS_API_URL\n  const pageSize = config.pageSize ?? DEFAULT_PAGE_SIZE\n  const maxPages = config.maxPages ?? DEFAULT_MAX_PAGES\n  const out: EasBuild[] = []\n  const seen = new Set<string>()\n  for (let page = 0; page < maxPages; page++) {\n    const data = await easGraphQL<BuildsQueryData>(\n      apiUrl,\n      token,\n      BUILDS_QUERY,\n      { appId: config.appId, offset: page * pageSize, limit: pageSize },\n      config.appId,\n      fetchImpl,\n    )\n    const builds = data.app?.byId?.builds\n    // A well-formed page carries an array (absent when the window is empty); a\n    // shape drift handing back a non-array drops honestly rather than throwing on\n    // a spread of a non-iterable (connectors.md §4).\n    if (!Array.isArray(builds)) break\n    let added = 0\n    for (const b of builds) {\n      if (!b || typeof b.id !== 'string' || b.id.length === 0) continue\n      if (b.status !== EAS_STATUS_ERRORED) continue\n      if (seen.has(b.id)) continue\n      seen.add(b.id)\n      out.push(b)\n      added++\n    }\n    // A short page is the last page.\n    if (builds.length < pageSize) break\n    // A full page that contributed nothing new (all duplicates / all non-ERRORED)\n    // won't get better deeper — stop rather than page to the cap.\n    if (added === 0) break\n  }\n  return out\n}\n\n/**\n * Fetch a build's logs and keep a bounded tail. The signed `logFileUrls` are\n * time-limited, so this runs on the poll (never later) and stores a size-capped\n * slice — the failure reason sits at the end of a build log, so the TAIL is\n * kept. A URL that fails to fetch is skipped honestly rather than failing the\n * whole poll (a log is context, not the incident itself).\n */\nexport async function fetchBuildLogs(\n  logFileUrls: string[] | null | undefined,\n  maxBytes: number = DEFAULT_MAX_LOG_BYTES,\n  fetchImpl?: typeof fetch,\n): Promise<string> {\n  if (!Array.isArray(logFileUrls) || logFileUrls.length === 0) return ''\n  const doFetch = fetchImpl ?? fetch\n  const chunks: string[] = []\n  for (const url of logFileUrls) {\n    if (typeof url !== 'string' || url.length === 0) continue\n    try {\n      const res = await doFetch(url)\n      if (!res.ok) continue\n      chunks.push(await res.text())\n    } catch {\n      // A time-expired or unreachable log URL is an honest miss, not a poll\n      // failure — the incident still carries the phase, commit, and message.\n    }\n  }\n  const joined = chunks.join('\\n')\n  return joined.length > maxBytes ? joined.slice(joined.length - maxBytes) : joined\n}\n","// EAS build-failure connector — provider-specific types (ADR-185,\n// docs/plans/eas-build-connector-plan.md). The first incident-emitting\n// connector (connectors.md §10): it pulls `ERRORED` Expo/EAS builds from the\n// Expo GraphQL API and mints one build-failure incident per build, not an\n// OBSERVED edge.\n//\n// The Expo GraphQL API is undocumented and unversioned — every field below is\n// reconstructed from `expo/eas-cli`'s generated schema, and treated as the top\n// drift risk: the query is pinned (client.ts) and a shape error fails loud\n// rather than dropping builds silently (connectors.md §10, ADR-150/152).\n\n// ── credentials ──────────────────────────────────────────────────────────\n\n// `ConnectorContext.credentials` is opaque at the shared-scaffold layer\n// (connectors/types.ts). The EAS credential is a single robot-user `EXPO_TOKEN`\n// carried into `Authorization: Bearer` and nowhere else (connector-config.md\n// §7.1, connectors.md §6) — a robot user, not a personal token, is the\n// least-privilege grant for a server connector.\nexport interface EasCredentials {\n  token: string\n}\n\nexport function readEasCredentials(raw: Record<string, unknown>): EasCredentials {\n  const token = raw['token']\n  if (typeof token !== 'string' || token.length === 0) {\n    throw new Error('eas connector: credentials.token (EXPO_TOKEN) must be a non-empty string')\n  }\n  return { token }\n}\n\n// ── config ─────────────────────────────────────────────────────────────────\n\n/**\n * Config resolved once at connector setup (connector-config.md §7.1) — never\n * re-derived from a build response at poll time.\n */\nexport interface EasConnectorConfig {\n  // The Expo app's `projectId` (a UUID) — the id `app.byId(appId:)` keys on.\n  // Not a secret (it names the app), so it rides in `options`, not `credential`.\n  appId: string\n  // The NEAT manifest service the app's repo maps to, so a build incident fuses\n  // onto that service's extracted nodes (resolve.ts). Omitted, the connector\n  // anchors to the app id honestly and stays coarse (a native-phase failure then\n  // drops, since there's no extracted service to land on).\n  serviceName?: string\n  // Expo GraphQL endpoint. Defaults to the public one; overridable for tests.\n  apiUrl?: string\n  // Pagination page size and a defensive page cap (offset-based, newest-first).\n  pageSize?: number\n  maxPages?: number\n  // Cap on the log slice stored in an incident. Xcode logs can reach ~10MB and\n  // the signed URLs are time-limited, so the connector fetches on poll and keeps\n  // a bounded tail (the failure reason is near the end of a build log).\n  maxLogBytes?: number\n  // Bounded lookback for a first poll (no prior `since`) or a gap wider than the\n  // window — never an unbounded full-history replay (connectors.md §Poll cadence\n  // and backfill).\n  maxLookbackMs?: number\n}\n\n// ── the build shape (the subset this connector reads) ────────────────────────\n\n// `Build.error` — `buildPhase` is a strict enum (the reliable structured\n// classifier); `errorCode` is free-text (a hint only, never a strict switch);\n// `message`/`docsUrl` are the human-facing failure text.\nexport interface EasBuildError {\n  buildPhase?: string | null\n  errorCode?: string | null\n  message?: string | null\n  docsUrl?: string | null\n}\n\n// One `Build`. Every field is optional in the wire type — the query pins them,\n// but nothing here is trusted present, so the mapper treats an absent field as an\n// honest miss rather than guessing (connectors.md §4).\nexport interface EasBuild {\n  id: string\n  status?: string | null\n  platform?: string | null\n  buildProfile?: string | null\n  gitCommitHash?: string | null\n  gitCommitMessage?: string | null\n  gitRef?: string | null\n  isGitWorkingTreeDirty?: boolean | null\n  createdAt?: string | null\n  completedAt?: string | null\n  error?: EasBuildError | null\n  logFileUrls?: string[] | null\n  // Populated by client.ts after fetch-and-cap; not part of the wire query.\n  logsText?: string\n}\n\n// ── build-status + phase classification (the honesty of the feature) ────────\n\n// The one build status this connector mints for: a build that ran and failed.\n// CANCELED (aborted) and FINISHED (success) and the in-flight states are skipped.\nexport const EAS_STATUS_ERRORED = 'ERRORED'\n\n// Build phases whose failure is NOT a repo bug — the builder infra, credentials,\n// cache restore, archive upload. An incident here would turn an EAS outage into a\n// false repo divergence (connectors.md §10), so map.ts mints nothing for them.\n// This is a conservative EXCLUSION set: excluding is safe (never a false\n// incident), so when a phase clearly names infra it's dropped.\nexport const TRANSIENT_BUILD_PHASES = new Set<string>([\n  'SPIN_UP_BUILDER',\n  'PREPARE_CREDENTIALS',\n  'RESTORE_CACHE',\n  'UPLOAD_APPLICATION_ARCHIVE',\n])\n\n// `buildPhase` is the stable classifier, but the free-text `errorCode` is still\n// usable as an additional EXCLUSION signal — never to attribute, only to filter\n// out an EAS-internal failure the phase enum didn't already name. Conservative on\n// purpose: a match drops the build, it never mints one.\nconst INTERNAL_ERROR_CODE = /INTERNAL_SERVER_ERROR|EAS_BUILD_.*INTERNAL|_INTERNAL_ERROR|UNKNOWN_ERROR/i\n\n// Whether a failure is transient/infra and must mint nothing (connectors.md §10,\n// guardrail 1). Switches on the stable `buildPhase` enum plus the conservative\n// `errorCode` heuristic; when in doubt (an unrecognized phase) it is NOT\n// transient — the app-node + log fallback in resolve.ts handles it honestly.\nexport function isTransientFailure(err: EasBuildError | null | undefined): boolean {\n  if (!err) return false\n  const phase = typeof err.buildPhase === 'string' ? err.buildPhase : undefined\n  if (phase) {\n    if (TRANSIENT_BUILD_PHASES.has(phase)) return true\n    if (/^SPIN_UP|_CREDENTIALS$|^RESTORE_CACHE/i.test(phase)) return true\n  }\n  const code = typeof err.errorCode === 'string' ? err.errorCode : undefined\n  if (code && INTERNAL_ERROR_CODE.test(code)) return true\n  return false\n}\n\n// The provider-vocabulary identity a signal carries through the shared pipeline,\n// packed into `ObservedSignal.targetName` and unpacked only by this connector's\n// own resolveTarget (resolve.ts), never surfaced to the graph. `\\x00` separates\n// the fields: it can't appear in a NEAT service name or a build-phase enum token.\nconst FIELD_SEP = '\\x00'\n\nexport const EAS_TARGET_KIND = 'eas-build'\n\nexport interface EasTargetIdentity {\n  serviceName: string\n  // The build phase, or '' when the failure carried no phase (a native/unknown\n  // failure → the app-node fallback in resolve.ts).\n  phase: string\n}\n\nexport function packEasTargetName(identity: EasTargetIdentity): string {\n  return [identity.serviceName, identity.phase].join(FIELD_SEP)\n}\n\nexport function parseEasTargetName(targetName: string): EasTargetIdentity | null {\n  const sep = targetName.indexOf(FIELD_SEP)\n  if (sep === -1) return null\n  const serviceName = targetName.slice(0, sep)\n  const phase = targetName.slice(sep + 1)\n  if (!serviceName) return null\n  return { serviceName, phase }\n}\n","// EasBuild -> ObservedSignal mapping (ADR-185, connectors.md §10). One signal\n// per ERRORED build, each carrying an `incident` payload (not an edge count):\n// the shared pipeline writes it as an OBSERVED build-failure incident on the\n// node resolve.ts resolves. The firebase/cloud-run mappers turn a log row into a\n// counted edge signal; this one turns a build failure into an incident signal —\n// the same interface, a different terminal write.\n\nimport type { ObservedSignal } from '../types.js'\nimport type { SpanAttributes } from '@neat.is/types'\nimport type { EasBuild } from './types.js'\nimport {\n  EAS_STATUS_ERRORED,\n  EAS_TARGET_KIND,\n  isTransientFailure,\n  packEasTargetName,\n} from './types.js'\n\n// A build's own event time — completion when it has one, else creation, else\n// now. Used as the incident timestamp and the signal's `lastObservedIso` (never\n// poll-arrival time, connectors.md §Poll cadence and backfill).\nexport function buildEventTime(build: EasBuild): string {\n  if (typeof build.completedAt === 'string' && build.completedAt.length > 0) return build.completedAt\n  if (typeof build.createdAt === 'string' && build.createdAt.length > 0) return build.createdAt\n  return new Date().toISOString()\n}\n\n// The failure line the incident surface shows: the phase (the structured\n// classifier) plus the provider's own `message`, falling back to the free-text\n// `errorCode` and then a generic line. A dirty working tree is called out inline\n// — the commit may not represent what built (connectors.md §10, guardrail 2).\nfunction incidentMessage(build: EasBuild): string {\n  const err = build.error ?? {}\n  const phase = typeof err.buildPhase === 'string' && err.buildPhase.length > 0 ? ` at ${err.buildPhase}` : ''\n  const detail =\n    (typeof err.message === 'string' && err.message.trim().length > 0 && err.message.trim()) ||\n    (typeof err.errorCode === 'string' && err.errorCode.length > 0 && err.errorCode) ||\n    'no error detail reported'\n  let msg = `EAS build failed${phase}: ${detail}`\n  if (build.isGitWorkingTreeDirty === true) {\n    msg += ' (built from a dirty working tree — the commit may not represent what built)'\n  }\n  return msg\n}\n\n// The provider context an agent reads off the incident. Only fields that are\n// actually present land — an absent field is an honest miss, never a guessed\n// default. `logsText` is the fetched-and-capped log tail (client.ts).\nfunction incidentAttributes(build: EasBuild): SpanAttributes {\n  const attrs: SpanAttributes = {}\n  const err = build.error ?? {}\n  const put = (k: string, v: string | number | boolean | null | undefined): void => {\n    if (typeof v === 'string' && v.length === 0) return\n    if (v !== undefined && v !== null) attrs[k] = v\n  }\n  put('eas.buildId', build.id)\n  put('eas.platform', build.platform ?? undefined)\n  put('eas.buildProfile', build.buildProfile ?? undefined)\n  put('eas.buildPhase', err.buildPhase ?? undefined)\n  put('eas.errorCode', err.errorCode ?? undefined)\n  put('eas.docsUrl', err.docsUrl ?? undefined)\n  put('eas.gitCommitHash', build.gitCommitHash ?? undefined)\n  put('eas.gitRef', build.gitRef ?? undefined)\n  put('eas.gitCommitMessage', build.gitCommitMessage ?? undefined)\n  if (typeof build.isGitWorkingTreeDirty === 'boolean') {\n    attrs['eas.gitWorkingTreeDirty'] = build.isGitWorkingTreeDirty\n    // A dirty-tree build is lower-confidence — the agent should weight it as such\n    // (connectors.md §10, guardrail 2). Surfaced as an attribute since the\n    // ErrorEvent shape carries no confidence field of its own.\n    if (build.isGitWorkingTreeDirty) attrs['eas.confidence'] = 'low'\n  }\n  put('eas.createdAt', build.createdAt ?? undefined)\n  put('eas.completedAt', build.completedAt ?? undefined)\n  if (typeof build.logsText === 'string' && build.logsText.length > 0) {\n    attrs['eas.logs'] = build.logsText\n  }\n  return attrs\n}\n\n/**\n * One build -> one incident-bearing signal, or `null` when the connector must\n * mint nothing: a non-ERRORED row (the server filter is never trusted alone,\n * §4), a build with no error object to classify, or a transient/infra failure an\n * EAS outage produces (connectors.md §10, guardrail 1 — never a false repo\n * divergence). `serviceName` is the mapped NEAT service (or the app id when\n * unmapped); it rides the packed target name so resolve.ts scopes the fusion to\n * it, and the incident's `service` field so a service-anchored incident attributes\n * to it.\n */\nexport function mapBuildToSignal(build: EasBuild | null | undefined, serviceName: string): ObservedSignal | null {\n  if (!build || typeof build !== 'object') return null\n  if (build.status !== EAS_STATUS_ERRORED) return null\n  if (!build.error) return null\n  if (isTransientFailure(build.error)) return null\n\n  const timestamp = buildEventTime(build)\n  const phase = typeof build.error.buildPhase === 'string' ? build.error.buildPhase : ''\n\n  return {\n    targetKind: EAS_TARGET_KIND,\n    targetName: packEasTargetName({ serviceName, phase }),\n    // Incident-only — no edge, so no call/error count to replay.\n    callCount: 0,\n    errorCount: 0,\n    lastObservedIso: timestamp,\n    incident: {\n      id: `eas:build:${build.id}`,\n      timestamp,\n      service: serviceName,\n      errorType: 'eas-build-failure',\n      errorMessage: incidentMessage(build),\n      attributes: incidentAttributes(build),\n    },\n  }\n}\n\nexport function mapBuildsToSignals(builds: EasBuild[], serviceName: string): ObservedSignal[] {\n  const out: ObservedSignal[] = []\n  for (const build of builds) {\n    const signal = mapBuildToSignal(build, serviceName)\n    if (signal) out.push(signal)\n  }\n  return out\n}\n","// Target resolution — the EAS-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning a build failure's `(serviceName,\n// buildPhase)` into the NEAT node the incident lands on (ADR-185, connectors.md\n// §10). `buildPhase` is a strict enum, so the mapping is deterministic:\n//\n//   READ_EAS_JSON                            -> eas.json ConfigNode\n//   READ_APP_CONFIG / CONFIGURE_EXPO_UPDATES  -> app.json / app.config.json ConfigNode\n//     / CALCULATE_EXPO_UPDATES_RUNTIME_VERSION\n//   READ_PACKAGE_JSON / INSTALL_DEPENDENCIES  -> the app's ServiceNode\n//   everything else (native compile, unknown) -> the app's ServiceNode + logs\n//\n// A config phase lands on the ConfigNode the extractor mints for that file\n// (ADR-185 added JSON build-config extraction), scoped to the emitting service so\n// a monorepo doesn't cross-attribute. Everything else lands on the app's\n// ServiceNode, resolved through the SAME fused-service lookup the OTLP incident\n// path uses (`resolveFusedServiceId`, #988/#992) so a build incident fuses onto\n// the extracted service, never a connector twin. The build logs ride in the\n// incident's own attributes (map.ts), so the ServiceNode anchor still hands the\n// agent what it needs to root-cause a native failure.\n//\n// This module never mutates the graph (ADR-030) — it reads ConfigNode /\n// ServiceNode attributes already there and hands the id back for the shared\n// pipeline to write the incident against, matching every other connectors/**\n// resolveTarget. When neither a ConfigNode nor an extracted ServiceNode resolves,\n// it returns the (possibly not-yet-materialised) service id and the pipeline\n// drops the incident honestly rather than fabricating a node.\n\nimport { EdgeType, NodeType, parseFileId, type GraphEdge } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { resolveFusedServiceId } from '../../ingest.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport { EAS_TARGET_KIND, parseEasTargetName } from './types.js'\n\n// The connectors plane's env-unscoped sentinel (identity.ts's ENV_UNKNOWN) — a\n// build failure carries no `deployment.environment`, so it fuses onto the\n// env-less `service:<name>` the extractor mints.\nconst NO_ENV = 'unknown'\n\n// Which config-file basenames a phase implicates. package.json phases are absent\n// on purpose — package.json is a ServiceNode, not a ConfigNode (ADR-185), so\n// those fall through to the service anchor below.\nconst EAS_JSON_PHASES = new Set<string>(['READ_EAS_JSON'])\nconst APP_CONFIG_PHASES = new Set<string>([\n  'READ_APP_CONFIG',\n  'CONFIGURE_EXPO_UPDATES',\n  'CALCULATE_EXPO_UPDATES_RUNTIME_VERSION',\n])\n\nfunction configBasenamesForPhase(phase: string): string[] {\n  if (EAS_JSON_PHASES.has(phase)) return ['eas.json']\n  if (APP_CONFIG_PHASES.has(phase)) return ['app.json', 'app.config.json']\n  return []\n}\n\n// The service a ConfigNode belongs to, read off its inbound CONFIGURED_BY edge\n// (source `file:<service>:<relPath>`, minted by extract/configs.ts). Null when\n// the node has no such edge (it always does when the extractor made it).\nfunction configNodeService(graph: NeatGraph, configNodeId: string): string | null {\n  for (const edgeId of graph.inboundEdges(configNodeId)) {\n    const edge = graph.getEdgeAttributes(edgeId) as GraphEdge\n    if (edge.type !== EdgeType.CONFIGURED_BY) continue\n    const parsed = parseFileId(edge.source)\n    if (parsed) return parsed.service\n  }\n  return null\n}\n\n// Find the ConfigNode for one of `basenames`, preferring one owned by\n// `serviceName` (so a monorepo's other app.json isn't cross-attributed), then\n// any with the basename (a single-app repo, or an unmapped connector whose\n// serviceName is the app id rather than the package name). Null when the\n// extractor minted no such ConfigNode — the caller then falls back to the\n// service anchor rather than inventing one.\nfunction findConfigNode(graph: NeatGraph, basenames: string[], serviceName: string): string | null {\n  let scoped: string | null = null\n  let anyMatch: string | null = null\n  graph.forEachNode((id, attrs) => {\n    if (scoped) return\n    const node = attrs as { type?: string; name?: string }\n    if (node.type !== NodeType.ConfigNode) return\n    if (typeof node.name !== 'string' || !basenames.includes(node.name)) return\n    if (anyMatch === null) anyMatch = id\n    if (configNodeService(graph, id) === serviceName) scoped = id\n  })\n  return scoped ?? anyMatch\n}\n\n/**\n * Builds the resolveTarget callback runConnectorPoll (connectors/index.ts) calls\n * once per signal. Closes over `graph` because ResolveConnectorTarget's own\n * signature doesn't carry it — the same closure pattern every connector's\n * resolveTarget uses. `edgeType` is required by ResolvedConnectorTarget but\n * unused on the incident path (the pipeline writes an ErrorEvent, not an edge);\n * it's set to a stable placeholder.\n */\nexport function createEasResolveTarget(graph: NeatGraph): ResolveConnectorTarget {\n  return (signal): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== EAS_TARGET_KIND) return null\n    const identity = parseEasTargetName(signal.targetName)\n    if (!identity) return null\n    const { serviceName, phase } = identity\n\n    // Config/dependency-of-config phase → the ConfigNode the extractor minted for\n    // that file, when it exists. The fusion assertion: the incident lands on a\n    // node the EXTRACTOR produced for the same repo, not a connector twin.\n    const basenames = configBasenamesForPhase(phase)\n    if (basenames.length > 0) {\n      const configNodeId = findConfigNode(graph, basenames, serviceName)\n      if (configNodeId) {\n        return { targetNodeId: configNodeId, serviceName, edgeType: EdgeType.CALLS }\n      }\n      // No ConfigNode for the file (the repo uses app.config.js, say) — fall\n      // through to the service anchor rather than dropping the failure.\n    }\n\n    // Everything else — package.json phases, native compile, unknown — anchors to\n    // the app's ServiceNode through the shared fused-service lookup, so the\n    // incident fuses onto the extracted node. The pipeline drops it honestly if\n    // this id names no node yet (an unmapped app id, an un-extracted service).\n    return {\n      targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV),\n      serviceName,\n      edgeType: EdgeType.CALLS,\n    }\n  }\n}\n","import type { ErrorEvent } from '@neat.is/types'\nimport { EdgeType } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { nodeContext, isBoundaryTimeoutSymptom, resolveHangHop } from './traverse.js'\nimport { readErrorEvents, promoteFrontierEdges, stageFrontierEdge } from './ingest.js'\n\n// How many recent incidents the reconciliation reads per tick. The newest sit at\n// the tail of the append-only ledger and are the only ones a live hang is in.\nconst RECONCILE_INCIDENT_LIMIT = 500\n\n// ADR-226 — the hang sensor. A post-ingest analysis pass that stages a FRONTIER\n// surface on the unobservable hop of a boundary-timeout hang: the edge NEAT\n// reached toward but cannot see because its far end hung and exported no span.\n//\n// This is the ONLY hang-specific piece of the feature (the redstone rule): what it\n// stages is a general FRONTIER edge, and promotion (which graduates it when the\n// service recovers) and the reader (which surfaces it) never know the word \"hang.\"\n// It runs in the reconciliation sweep (the daemon's staleness-loop `onReconcile`),\n// never the OTLP hot path — a span that never exports can't be seen from ingest,\n// so there is nothing to do inline.\n//\n// The staged surface is self-correcting alongside promotion: a surface is added\n// only while the hop is genuinely unobservable (no OBSERVED twin), and dropped by\n// `promoteFrontierEdges` once the twin arrives — so a FRONTIER hang edge exists\n// exactly while the hang does.\nexport function stageHangSurfaces(graph: NeatGraph, incidents: ErrorEvent[]): number {\n  // The only candidates are nodes carrying an incident — a boundary that timed out.\n  const boundaries = new Set<string>()\n  for (const ev of incidents) {\n    if (ev.affectedNode && graph.hasNode(ev.affectedNode)) boundaries.add(ev.affectedNode)\n  }\n\n  let staged = 0\n  for (const boundary of boundaries) {\n    const ctx = nodeContext(graph, boundary, incidents)\n    if (!isBoundaryTimeoutSymptom(ctx)) continue\n\n    const hop = resolveHangHop(graph, boundary, incidents)\n    if (!hop) continue // honest-coarse — no declared serving path resolves\n\n    // The graph write goes through ingest's lifecycle authority (ADR-030), which\n    // also guards against staging an already-OBSERVED hop (the service is up, not\n    // hung) or a duplicate — so the sensor here is pure detection + resolution.\n    if (stageFrontierEdge(graph, hop.source, hop.target, EdgeType.CALLS)) staged++\n  }\n  return staged\n}\n\n// ADR-226 — the FRONTIER reconciliation step, wired to the staleness loop's\n// `onReconcile` (the periodic post-ingest point) in both the daemon and `neat\n// watch`. First graduate any surface whose OBSERVED twin has arrived (a hang that\n// recovered), then stage surfaces for the current hangs, reading the same errors\n// ledger the incident queries do. Kept here so ingest.ts never imports the sensor\n// (which would cycle through traverse).\nexport async function reconcileFrontierSurfaces(\n  graph: NeatGraph,\n  errorsPath: string,\n): Promise<void> {\n  promoteFrontierEdges(graph)\n  let incidents: ErrorEvent[] = []\n  try {\n    incidents = await readErrorEvents(errorsPath, { limit: RECONCILE_INCIDENT_LIMIT })\n  } catch {\n    incidents = []\n  }\n  stageHangSurfaces(graph, incidents)\n}\n","// The Kubernetes deploy-state connector (ADR-224, #1124) — the second\n// incident-emitting connector (connectors.md §10) after EAS.\n//\n// poll() resolves the cluster transport from the credential (a token +\n// apiServerUrl, or a kubeconfig), reads Deployments + Pods in one namespace\n// (client.ts), and maps each *unhealthy* workload to an incident-bearing\n// ObservedSignal (map.ts): a bad image, zero replicas, a crashloop. Target\n// resolution — the workload's service node via the shared fused-service lookup —\n// lives in resolve.ts. Everything downstream (writing the incident to the\n// ledger) is the shared connectors/index.ts pipeline; this module never touches\n// the graph or the ledger directly (ADR-030).\n//\n// Why this connector exists: a workload down for a deployment reason emits no\n// spans (the pod never starts, or is gone), so the graph is blind to it. Pulling\n// cluster state turns that blind spot into a first-class OBSERVED incident on the\n// service node, fused with the code deps and the observed connection-refused\n// edges already there (#1124).\n\nimport type { NeatGraph } from '../../graph.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from '../types.js'\nimport type { ResolveConnectorTarget } from '../index.js'\nimport type { ResolvedK8sTransport } from './kubeconfig.js'\nimport { fetchDeployments, fetchPodProcessLog, fetchPods, fetchServices } from './client.js'\nimport { resolveK8sTransport } from './kubeconfig.js'\nimport { faultedPods, mapWorkloadsToSignals, podLogKey, type K8sPodLogs } from './map.js'\nimport { createK8sResolveTarget } from './resolve.js'\nimport { readK8sCredentials, type Deployment, type K8sConnectorConfig, type Pod } from './types.js'\n\n// How many lines of a faulted pod's stdout to pull (ADR-237). A traceback /\n// panic / OOM line sits at the tail, so a bounded tail carries the cause;\n// process-context.ts caps it further by lines and bytes before it reaches the\n// incident ledger.\nconst PROCESS_LOG_TAIL_LINES = 200\n// …and a byte ceiling on the read itself, so one enormous line (a minified\n// stack, a dumped payload) can't pull an unbounded body before the caps apply.\nconst PROCESS_LOG_LIMIT_BYTES = 64 * 1024\n\nexport * from './client.js'\nexport * from './kubeconfig.js'\nexport * from './map.js'\nexport * from './resolve.js'\nexport * from './substrate.js'\nexport * from './types.js'\n\nexport class KubernetesConnector implements ObservedConnector {\n  readonly provider = 'kubernetes'\n\n  constructor(\n    private readonly config: K8sConnectorConfig,\n    // Test seam — a fake `fetch` stands in for the live k8s API so poll() never\n    // needs a real cluster. Production leaves it undefined and the client builds\n    // the TLS-configured https adapter from the transport.\n    private readonly fetchImpl?: typeof fetch,\n  ) {}\n\n  async poll(ctx: ConnectorContext): Promise<ObservedSignal[]> {\n    const creds = readK8sCredentials(ctx.credentials)\n    const transport = resolveK8sTransport(creds, this.config)\n    const namespace = this.config.namespace\n    const opts = {\n      ...(this.config.apiUrl ? { apiUrl: this.config.apiUrl } : {}),\n      ...(this.fetchImpl ? { fetchImpl: this.fetchImpl } : {}),\n    }\n    // Three read-only list calls; a deployment fault is a current-state fact, so\n    // there is no watermark to honour (unlike the request-log / build connectors)\n    // — each poll reads the whole namespace's current state. The Services list\n    // (ADR-248) degrades to undefined on a missing grant instead of failing.\n    const [deployments, pods, services] = await Promise.all([\n      fetchDeployments(transport, namespace, opts),\n      fetchPods(transport, namespace, opts),\n      fetchServices(transport, namespace, opts),\n    ])\n    // Pull process logs ONLY for the pods of faulted workloads (ADR-237) — a\n    // handful of unhealthy pods, never the whole namespace — so the extra read\n    // stays cheap and the `pods/log` RBAC stays minimal. A missing grant degrades\n    // to no log, never a failed poll (fetchPodLog swallows it to undefined).\n    const logs = await this.fetchFaultedPodLogs(transport, namespace, deployments, pods, opts)\n    return mapWorkloadsToSignals(deployments, pods, this.config, logs, services)\n  }\n\n  private async fetchFaultedPodLogs(\n    transport: ResolvedK8sTransport,\n    namespace: string,\n    deployments: Deployment[],\n    pods: Pod[],\n    opts: { apiUrl?: string; fetchImpl?: typeof fetch },\n  ): Promise<K8sPodLogs> {\n    const logs: K8sPodLogs = new Map()\n    const targets = faultedPods(deployments, pods, this.config)\n    await Promise.all(\n      targets.map(async (t) => {\n        // Prefer the LAST terminated instance's stdout (previous=true) — the\n        // traceback a crash-looped container left behind — but fall back to the\n        // current instance when that read is empty: a runtime that doesn't serve\n        // the previous log (containerd under kind), or a bootstrap livelock that\n        // never terminates, both leave the cause in the running instance (ADR-239).\n        const text = await fetchPodProcessLog(transport, namespace, t.podName, {\n          ...(t.container ? { container: t.container } : {}),\n          tailLines: PROCESS_LOG_TAIL_LINES,\n          limitBytes: PROCESS_LOG_LIMIT_BYTES,\n          ...opts,\n        })\n        if (typeof text === 'string' && text.length > 0) logs.set(podLogKey(t.podName, t.container), text)\n      }),\n    )\n    return logs\n  }\n}\n\n/**\n * Wires up a ready-to-register k8s connector: the `ObservedConnector` plus the\n * `resolveTarget` callback the shared pipeline needs alongside it. Both are built\n * together because `resolveTarget` closes over `graph` — the shared scaffold's\n * `ResolveConnectorTarget` signature never receives it directly.\n */\nexport function createKubernetesConnector(\n  graph: NeatGraph,\n  config: K8sConnectorConfig,\n  fetchImpl?: typeof fetch,\n): { connector: ObservedConnector; resolveTarget: ResolveConnectorTarget } {\n  return {\n    connector: new KubernetesConnector(config, fetchImpl),\n    resolveTarget: createK8sResolveTarget(graph),\n  }\n}\n","// The Kubernetes API client — the fetch half of the connector's poll() (ADR-224).\n// Passive and ambient only (connectors.md §2): read-only `GET` list calls on\n// Deployments and Pods in one namespace, never a mutation, never a synthetic\n// workload. Mirrors the fetch/map/resolve split every provider module keeps.\n//\n// The k8s API server usually presents a cluster-CA-signed cert (or, for a local\n// cluster, a self-signed one), and kind-style access authenticates with a client\n// cert — neither of which the platform `fetch` handles from a PEM string. So the\n// outbound call uses a Node `https` agent (native `ca`/`cert`/`key` support)\n// wrapped as a `fetchImpl`, and still routes through the shared junction for the\n// per-call timeout/retry/rate-limit discipline every connector holds (ADR-131).\n// No k8s SDK and no new dependency.\n//\n// Endpoint paths are the stable Kubernetes REST API (apps/v1 Deployments, core/v1\n// Pods), confirmed against the API reference (ADR-150/152 discipline).\n\nimport { Agent, request as httpsRequest } from 'node:https'\nimport { bearerAuthHeader, junctionFetch } from '../junction.js'\nimport type { ResolvedK8sTransport } from './kubeconfig.js'\nimport type { Deployment, K8sList, Pod, Service } from './types.js'\n\n// A k8s API server is infrastructure the operator runs, not a quota-metered\n// vendor API, and one poll legitimately bursts several reads — Deployments +\n// Pods, plus a process-log read per faulted pod (ADR-237). So the client holds a\n// roomier token bucket than the generic vendor default while still routing every\n// call through the junction for the timeout / retry / self-throttle discipline\n// (ADR-131). The same config on every k8s call keeps the `(provider, accountKey)`\n// bucket from being reconfigured mid-poll.\nconst K8S_RATE_LIMIT = { capacity: 120, refillMs: 1_000 }\n\n// One namespace's list endpoints.\nexport function deploymentsPath(namespace: string): string {\n  return `/apis/apps/v1/namespaces/${namespace}/deployments`\n}\nexport function podsPath(namespace: string): string {\n  return `/api/v1/namespaces/${namespace}/pods`\n}\nexport function servicesPath(namespace: string): string {\n  return `/api/v1/namespaces/${namespace}/services`\n}\n\n// One pod's log sub-resource (ADR-237). `previous=true` is the essential bit for\n// a crash-looped container: the current instance is empty (it's between restarts\n// or waiting), while `previous` returns the LAST terminated instance's stdout —\n// the traceback / panic / OOM line that names the boot-time cause.\nexport function podLogPath(\n  namespace: string,\n  podName: string,\n  opts: { container?: string; tailLines?: number; limitBytes?: number; previous?: boolean } = {},\n): string {\n  const params = new URLSearchParams()\n  if (opts.container) params.set('container', opts.container)\n  if (typeof opts.tailLines === 'number' && Number.isFinite(opts.tailLines)) params.set('tailLines', String(Math.trunc(opts.tailLines)))\n  if (typeof opts.limitBytes === 'number' && Number.isFinite(opts.limitBytes)) params.set('limitBytes', String(Math.trunc(opts.limitBytes)))\n  if (opts.previous) params.set('previous', 'true')\n  const qs = params.toString()\n  return `${podsPath(namespace)}/${podName}/log${qs ? `?${qs}` : ''}`\n}\n\n// A `fetch`-shaped adapter over Node `https`, so the request carries the cluster\n// CA / client cert the k8s API needs. It honours `init.method`, `init.headers`,\n// and the junction's `init.signal` (abort on the per-attempt timeout), and hands\n// back the minimal `Response` surface junctionFetch reads (`ok`/`status`/\n// `statusText`/`json`). Built per transport (its TLS material never changes over\n// the connector's life), reused across list calls.\nexport function makeK8sFetchImpl(transport: ResolvedK8sTransport): typeof fetch {\n  const agent = new Agent({\n    ...(transport.ca ? { ca: transport.ca } : {}),\n    ...(transport.clientCert ? { cert: transport.clientCert } : {}),\n    ...(transport.clientKey ? { key: transport.clientKey } : {}),\n    rejectUnauthorized: !transport.insecureSkipTlsVerify,\n  })\n  return ((url: string | URL, init?: RequestInit): Promise<Response> =>\n    new Promise<Response>((resolve, reject) => {\n      const u = new URL(String(url))\n      const req = httpsRequest(\n        u,\n        {\n          method: (init?.method ?? 'GET').toUpperCase(),\n          headers: (init?.headers as Record<string, string>) ?? {},\n          agent,\n        },\n        (res) => {\n          const chunks: Buffer[] = []\n          res.on('data', (c: Buffer) => chunks.push(c))\n          res.on('end', () => {\n            const body = Buffer.concat(chunks).toString('utf8')\n            const status = res.statusCode ?? 0\n            resolve({\n              ok: status >= 200 && status < 300,\n              status,\n              statusText: res.statusMessage ?? '',\n              json: async () => JSON.parse(body),\n              text: async () => body,\n            } as Response)\n          })\n        },\n      )\n      req.on('error', reject)\n      // The junction sets an AbortController signal per attempt for its timeout;\n      // destroying the request surfaces as the same rejected fetch it expects.\n      const signal = init?.signal\n      if (signal) {\n        if (signal.aborted) req.destroy(new Error('aborted'))\n        else signal.addEventListener('abort', () => req.destroy(new Error('aborted')), { once: true })\n      }\n      req.end()\n    })) as unknown as typeof fetch\n}\n\n// One authenticated GET of a namespaced list, through the junction. `fetchImpl`\n// is the test seam (a stub k8s API); production builds the https adapter from the\n// transport. `apiUrl` overrides the server base for a test/proxy in front.\nasync function listResource<T>(\n  transport: ResolvedK8sTransport,\n  namespace: string,\n  path: string,\n  opts: { apiUrl?: string; fetchImpl?: typeof fetch } = {},\n): Promise<T[]> {\n  const base = opts.apiUrl ?? transport.server\n  const url = `${base.replace(/\\/$/, '')}${path}`\n  const fetchImpl = opts.fetchImpl ?? makeK8sFetchImpl(transport)\n  const res = await junctionFetch(\n    url,\n    { method: 'GET', headers: { ...(transport.token ? bearerAuthHeader(transport.token) : {}), Accept: 'application/json' } },\n    // accountKey: the (cluster, namespace) pair — an identifier, safe to log, the\n    // rate-limit bucket for one namespace on one cluster (ADR-131).\n    { provider: 'kubernetes', accountKey: `${safeHost(transport.server)}/${namespace}`, rateLimit: K8S_RATE_LIMIT, fetchImpl },\n  )\n  if (!res.ok) {\n    throw new Error(`kubernetes ${path} failed: ${res.status} ${res.statusText}`)\n  }\n  const json = (await res.json()) as K8sList<T>\n  // A well-formed list carries an array; a shape drift handing back a non-array\n  // `items` drops honestly rather than throwing (connectors.md §4).\n  return Array.isArray(json.items) ? json.items : []\n}\n\nfunction safeHost(server: string): string {\n  try {\n    return new URL(server).host\n  } catch {\n    return 'cluster'\n  }\n}\n\nexport async function fetchDeployments(\n  transport: ResolvedK8sTransport,\n  namespace: string,\n  opts: { apiUrl?: string; fetchImpl?: typeof fetch } = {},\n): Promise<Deployment[]> {\n  return listResource<Deployment>(transport, namespace, deploymentsPath(namespace), opts)\n}\n\nexport async function fetchPods(\n  transport: ResolvedK8sTransport,\n  namespace: string,\n  opts: { apiUrl?: string; fetchImpl?: typeof fetch } = {},\n): Promise<Pod[]> {\n  return listResource<Pod>(transport, namespace, podsPath(namespace), opts)\n}\n\n// The namespace's Services, for the ClusterIP join (ADR-248). Like the log read, a\n// missing `services` list grant (or any failure) degrades to `undefined` rather\n// than failing the poll: the addresses are a join aid, never the fault itself.\n// `undefined` (not read) is kept distinct from `[]` (read, none), so a node's\n// addresses are only replaced by a read that actually happened.\nexport async function fetchServices(\n  transport: ResolvedK8sTransport,\n  namespace: string,\n  opts: { apiUrl?: string; fetchImpl?: typeof fetch } = {},\n): Promise<Service[] | undefined> {\n  try {\n    return await listResource<Service>(transport, namespace, servicesPath(namespace), opts)\n  } catch {\n    return undefined\n  }\n}\n\n// Fetch one pod container's log tail, through the same junction the list reads\n// use — the response is text (makeK8sFetchImpl exposes `.text()`), not JSON\n// (ADR-237). DEGRADE HONESTLY: a missing `pods/log` RBAC grant returns 403, a\n// gone pod or a container with no `previous` instance returns 404/400, and a\n// request that outright fails throws through the junction; all of those come\n// back as `undefined` here so the caller drops only the log attribute and keeps\n// the incident. The log is context for a fault, never the fault itself — it must\n// never fail the poll.\nexport async function fetchPodLog(\n  transport: ResolvedK8sTransport,\n  namespace: string,\n  podName: string,\n  opts: {\n    container?: string\n    tailLines?: number\n    limitBytes?: number\n    previous?: boolean\n    apiUrl?: string\n    fetchImpl?: typeof fetch\n  } = {},\n): Promise<string | undefined> {\n  const base = opts.apiUrl ?? transport.server\n  const path = podLogPath(namespace, podName, {\n    ...(opts.container ? { container: opts.container } : {}),\n    ...(opts.tailLines !== undefined ? { tailLines: opts.tailLines } : {}),\n    ...(opts.limitBytes !== undefined ? { limitBytes: opts.limitBytes } : {}),\n    ...(opts.previous ? { previous: true } : {}),\n  })\n  const url = `${base.replace(/\\/$/, '')}${path}`\n  const fetchImpl = opts.fetchImpl ?? makeK8sFetchImpl(transport)\n  try {\n    const res = await junctionFetch(\n      url,\n      { method: 'GET', headers: { ...(transport.token ? bearerAuthHeader(transport.token) : {}), Accept: 'text/plain' } },\n      { provider: 'kubernetes', accountKey: `${safeHost(transport.server)}/${namespace}`, rateLimit: K8S_RATE_LIMIT, fetchImpl },\n    )\n    // 403 (no pods/log grant), 404 (pod gone), 400 (no previous instance) — all\n    // non-retryable, all honest misses. Keep the incident, drop the log.\n    if (!res.ok) return undefined\n    return await res.text()\n  } catch {\n    return undefined\n  }\n}\n\n// Is a fetched log body worth keeping, or just whitespace? A `pods/log` read can\n// return 200 with an empty (or whitespace-only) body — a container that started\n// but printed nothing, or a runtime that answers the previous-instance read with\n// an empty body instead of a 4xx. Either way there's no cause to carry.\nfunction hasLogContent(text: string | undefined): text is string {\n  return typeof text === 'string' && text.trim().length > 0\n}\n\n// Fetch a crash-looped container's process log, preferring the previous instance\n// but falling back to the current one (ADR-239, amends ADR-237). `previous=true`\n// is the sharpest source for a clean crash-and-restart — the LAST terminated\n// instance's traceback, while the fresh instance is still empty. But two common\n// shapes leave that read empty while the cause sits in the CURRENT instance:\n//   1. a runtime where the previous-instance read is unavailable — containerd\n//      under kind answers `pods/log?previous=true` with 404, not the last log;\n//   2. a bootstrap LIVELOCK — a process that retries a bad dependency forever\n//      (connect, fail, log the traceback, sleep, retry) never terminates, so its\n//      cause is in the running instance's stdout, not a previous one.\n// So when the previous-instance read comes back empty (undefined on 4xx, or a\n// blank body), read the current instance instead. The previous read is tried\n// first and its result used when present, so the common crash-and-restart case\n// still gets the terminated-instance traceback and makes only one call. Returns\n// the first log with content, or undefined when neither has any — the same honest\n// degrade `fetchPodLog` makes, so the incident keeps and only the log drops.\nexport async function fetchPodProcessLog(\n  transport: ResolvedK8sTransport,\n  namespace: string,\n  podName: string,\n  opts: {\n    container?: string\n    tailLines?: number\n    limitBytes?: number\n    apiUrl?: string\n    fetchImpl?: typeof fetch\n  } = {},\n): Promise<string | undefined> {\n  const previous = await fetchPodLog(transport, namespace, podName, { ...opts, previous: true })\n  if (hasLogContent(previous)) return previous\n  const current = await fetchPodLog(transport, namespace, podName, { ...opts, previous: false })\n  return hasLogContent(current) ? current : undefined\n}\n","// Kubeconfig → transport resolution (ADR-224). The k8s connector accepts the\n// same access `kubectl` has: a kubeconfig's current context supplies the API\n// server, the cluster CA, and the auth (a bearer token, or a client cert/key —\n// kind's default). Parsed with the `yaml` dep already in the tree; no k8s SDK.\n//\n// This never logs or echoes the secret material (a token, a client key); it\n// reads it into the in-memory transport that `client.ts` hands to the TLS agent,\n// and nowhere else (connectors.md §6).\n\nimport { readFileSync } from 'node:fs'\nimport { parse as parseYaml } from 'yaml'\nimport type { K8sConnectorConfig, K8sCredentials } from './types.js'\n\n/** The resolved connection — what `client.ts` needs to make an authenticated read. */\nexport interface ResolvedK8sTransport {\n  server: string\n  ca?: string\n  token?: string\n  clientCert?: string\n  clientKey?: string\n  insecureSkipTlsVerify: boolean\n}\n\ninterface KubeconfigNamed<T> {\n  name?: string\n  cluster?: T\n  context?: T\n  user?: T\n}\n\n// A base64 `*-data` field decodes to PEM; a path field (`certificate-authority`,\n// `client-certificate`, `client-key`) is read from disk. Absent → undefined.\nfunction pemFrom(dataField: unknown, pathField: unknown): string | undefined {\n  if (typeof dataField === 'string' && dataField.length > 0) {\n    return Buffer.from(dataField, 'base64').toString('utf8')\n  }\n  if (typeof pathField === 'string' && pathField.length > 0) {\n    return readFileSync(pathField, 'utf8')\n  }\n  return undefined\n}\n\nfunction named<T>(list: unknown, name: string): T | undefined {\n  if (!Array.isArray(list)) return undefined\n  const hit = (list as Array<KubeconfigNamed<Record<string, unknown>>>).find((e) => e && e.name === name)\n  return hit as T | undefined\n}\n\n/**\n * Resolve a kubeconfig (an absolute path, or the YAML itself) to a transport,\n * using its `current-context`. Throws a clear, secret-free error when the config\n * is malformed or names a context/cluster/user it doesn't define.\n */\nexport function parseKubeconfig(kubeconfig: string): ResolvedK8sTransport {\n  // A path (no newline, starts with / or ~ or a drive) is read; anything with\n  // YAML structure is parsed inline. The cheap discriminator: inline kubeconfig\n  // always contains `apiVersion`/`clusters`, a path never does.\n  const looksInline = /\\n/.test(kubeconfig) || /(^|\\s)clusters\\s*:/.test(kubeconfig)\n  const text = looksInline ? kubeconfig : readFileSync(kubeconfig, 'utf8')\n\n  let doc: Record<string, unknown>\n  try {\n    doc = parseYaml(text) as Record<string, unknown>\n  } catch {\n    throw new Error('kubernetes connector: kubeconfig is not valid YAML')\n  }\n  if (!doc || typeof doc !== 'object') {\n    throw new Error('kubernetes connector: kubeconfig is empty or malformed')\n  }\n\n  const currentContext = doc['current-context']\n  if (typeof currentContext !== 'string' || currentContext.length === 0) {\n    throw new Error('kubernetes connector: kubeconfig has no current-context')\n  }\n  const ctxEntry = named<KubeconfigNamed<Record<string, unknown>>>(doc['contexts'], currentContext)\n  const ctx = ctxEntry?.context\n  if (!ctx) {\n    throw new Error(`kubernetes connector: kubeconfig context \"${currentContext}\" not found`)\n  }\n  const clusterEntry = named<KubeconfigNamed<Record<string, unknown>>>(doc['clusters'], String(ctx['cluster'] ?? ''))\n  const cluster = clusterEntry?.cluster\n  if (!cluster || typeof cluster['server'] !== 'string') {\n    throw new Error('kubernetes connector: kubeconfig current context has no cluster server')\n  }\n  const userEntry = named<KubeconfigNamed<Record<string, unknown>>>(doc['users'], String(ctx['user'] ?? ''))\n  const user = userEntry?.user ?? {}\n\n  const transport: ResolvedK8sTransport = {\n    server: cluster['server'] as string,\n    insecureSkipTlsVerify: cluster['insecure-skip-tls-verify'] === true,\n  }\n  const ca = pemFrom(cluster['certificate-authority-data'], cluster['certificate-authority'])\n  if (ca) transport.ca = ca\n  if (typeof user['token'] === 'string' && user['token'].length > 0) transport.token = user['token']\n  const clientCert = pemFrom(user['client-certificate-data'], user['client-certificate'])\n  const clientKey = pemFrom(user['client-key-data'], user['client-key'])\n  if (clientCert) transport.clientCert = clientCert\n  if (clientKey) transport.clientKey = clientKey\n  return transport\n}\n\n/**\n * Resolve either credential shape into a transport: a kubeconfig (path or inline)\n * wins when present; otherwise the direct `{ token, apiServerUrl, caCert }` path.\n * The token path requires an API-server URL — a token with nowhere to send it is\n * a config error caught here, before any request.\n */\nexport function resolveK8sTransport(creds: K8sCredentials, config: K8sConnectorConfig): ResolvedK8sTransport {\n  if (creds.kubeconfig) return parseKubeconfig(creds.kubeconfig)\n  if (!config.apiServerUrl) {\n    throw new Error('kubernetes connector: options.apiServerUrl is required with a token credential')\n  }\n  const transport: ResolvedK8sTransport = {\n    server: config.apiServerUrl,\n    insecureSkipTlsVerify: config.insecureSkipTlsVerify === true,\n  }\n  if (creds.token) transport.token = creds.token\n  if (config.caCert) transport.ca = config.caCert\n  return transport\n}\n","// Deployment + Pod state -> ObservedSignal mapping (ADR-224, connectors.md §10).\n// One incident-bearing signal per *unhealthy* workload — a bad image, zero\n// replicas, a crashloop — carrying the concrete cause the shared pipeline writes\n// as an OBSERVED incident on the service node (not an edge). A healthy workload\n// mints nothing in v1: the bench value is the incidents, the faults a dead pod\n// emits no span for (#1124). The EAS mapper turns a build failure into an\n// incident signal; this turns a deployment fault into one — same interface,\n// same terminal write.\n\nimport type { ObservedSignal } from '../types.js'\nimport type { SpanAttributes, DeployContext } from '@neat.is/types'\nimport type {\n  Container,\n  ContainerStatus,\n  Deployment,\n  K8sConnectorConfig,\n  K8sFaultKind,\n  Pod,\n  Service,\n} from './types.js'\nimport {\n  CRASH_LOOP_REASON,\n  IMAGE_PULL_REASONS,\n  K8S_DEPLOY_STATE,\n  K8S_TARGET_KIND,\n  packK8sTargetName,\n} from './types.js'\nimport { buildProcessContext } from './process-context.js'\n\n// The NEAT service a workload maps to: an explicit config map wins (a workload\n// whose name doesn't equal the OTel `service.name`), else the deployment name\n// itself — resolved once, never guessed (resolve.ts drops honestly if the id\n// names no extracted node, so a wrong guess never fabricates one).\nfunction serviceNameFor(deployment: Deployment, config: K8sConnectorConfig): string {\n  const name = deployment.metadata?.name ?? ''\n  return config.serviceMap?.[name] ?? name\n}\n\n// Does a pod belong to this deployment? A Deployment selects its pods by\n// `spec.selector.matchLabels` — a pod belongs when its labels are a superset of\n// that selector (the same subset match the API server itself uses). An empty or\n// absent selector matches nothing rather than everything, so a malformed\n// deployment never sweeps in unrelated pods.\nfunction podMatchesSelector(pod: Pod, selector: Record<string, string> | undefined): boolean {\n  if (!selector || Object.keys(selector).length === 0) return false\n  const labels = pod.metadata?.labels ?? {}\n  return Object.entries(selector).every(([k, v]) => labels[k] === v)\n}\n\nfunction podsForDeployment(deployment: Deployment, pods: Pod[]): Pod[] {\n  const selector = deployment.spec?.selector?.matchLabels\n  return pods.filter((p) => podMatchesSelector(p, selector))\n}\n\n// The ClusterIP join (ADR-248). A client span that dials a Service by its virtual\n// IP names the callee only as that IP. A Service selects pods by label, so the\n// workload behind an IP is the one deployment whose pods (or, with none running,\n// whose own selector) the Service's selector covers. A Service that covers more\n// than one deployment, has no selector, or is headless names no single workload\n// and contributes nothing: an address is recorded only where it is unambiguous.\nfunction serviceIps(service: Service): string[] {\n  const spec = service.spec\n  const ips = spec?.clusterIPs && spec.clusterIPs.length > 0 ? spec.clusterIPs : spec?.clusterIP ? [spec.clusterIP] : []\n  return ips.filter((ip) => ip.length > 0 && ip !== 'None')\n}\n\nfunction serviceSelects(deployment: Deployment, pods: Pod[], selector: Record<string, string>): boolean {\n  if (podsForDeployment(deployment, pods).some((p) => podMatchesSelector(p, selector))) return true\n  const own = deployment.spec?.selector?.matchLabels ?? {}\n  return Object.entries(selector).every(([k, v]) => own[k] === v)\n}\n\n// deployment name → the ClusterIPs that reach only it.\nexport function addressesByDeployment(\n  deployments: Deployment[],\n  pods: Pod[],\n  services: Service[],\n): Map<string, string[]> {\n  const out = new Map<string, string[]>()\n  for (const service of services) {\n    const selector = service.spec?.selector\n    if (!selector || Object.keys(selector).length === 0) continue\n    const ips = serviceIps(service)\n    if (ips.length === 0) continue\n    const owners = deployments.filter((d) => serviceSelects(d, pods, selector))\n    if (owners.length !== 1) continue\n    const name = owners[0]!.metadata?.name\n    if (typeof name !== 'string' || name.length === 0) continue\n    out.set(name, [...(out.get(name) ?? []), ...ips])\n  }\n  for (const [name, ips] of out) out.set(name, [...new Set(ips)].sort())\n  return out\n}\n\ninterface FaultFinding {\n  fault: K8sFaultKind\n  message: string\n  timestamp: string\n  attributes: SpanAttributes\n  // The pod + container the fault was diagnosed from, for the process-&-config\n  // fusion (ADR-237). Set for the pod-level faults (`image-pull`, `crash-loop`)\n  // so the poll knows whose log to pull and whose container spec (env/args) to\n  // read; absent for the deployment-level faults (`scaled-to-zero`,\n  // `no-ready-replicas`), which have no single faulted pod. Never serialized —\n  // only `attributes` reaches the signal.\n  pod?: Pod\n  container?: string\n}\n\nfunction nowIso(): string {\n  return new Date().toISOString()\n}\n\n// A fetched process-log tail keyed by `(podName, container)` — the output of the\n// poll's log fetch (index.ts), threaded into the map so a faulted finding can\n// fuse its process log in. Keyed through `podLogKey` so the fetch side and the\n// merge side agree on the key regardless of container name presence.\nexport type K8sPodLogs = Map<string, string>\n\nexport function podLogKey(podName: string, container?: string): string {\n  return container ? `${podName}\\u0000${container}` : podName\n}\n\n// Scan a deployment's pods for the first container whose state names an\n// image-pull failure or a crashloop — the two pod-level faults. Returns the\n// concrete finding (image / restart count / last-terminated line) or null.\nfunction podLevelFault(deployment: Deployment, pods: Pod[]): FaultFinding | null {\n  const name = deployment.metadata?.name ?? ''\n  const owned = podsForDeployment(deployment, pods)\n  let crash: { cs: ContainerStatus; pod: Pod } | null = null\n\n  for (const pod of owned) {\n    for (const cs of pod.status?.containerStatuses ?? []) {\n      const reason = cs.state?.waiting?.reason\n      if (typeof reason !== 'string') continue\n      // Image-pull is the sharpest, most actionable fault — return immediately.\n      if (IMAGE_PULL_REASONS.has(reason)) {\n        const image = typeof cs.image === 'string' ? cs.image : 'unknown image'\n        const attrs: SpanAttributes = { 'k8s.image': image, 'k8s.waitingReason': reason }\n        const wm = cs.state?.waiting?.message\n        if (typeof wm === 'string' && wm.length > 0) attrs['k8s.waitingMessage'] = wm\n        return {\n          fault: 'image-pull',\n          message: `Deployment ${name} cannot pull image ${image} (${reason})`,\n          timestamp: pod.status?.startTime ?? nowIso(),\n          attributes: attrs,\n          pod,\n          ...(typeof cs.name === 'string' && cs.name.length > 0 ? { container: cs.name } : {}),\n        }\n      }\n      // Remember a crashloop but keep scanning in case an image-pull outranks it.\n      if (reason === CRASH_LOOP_REASON && !crash) crash = { cs, pod }\n    }\n  }\n\n  if (crash) {\n    const { cs, pod } = crash\n    const term = cs.lastState?.terminated\n    const termReason = typeof term?.reason === 'string' ? term.reason : undefined\n    const termMsg = typeof term?.message === 'string' ? term.message.trim() : undefined\n    const restarts = typeof cs.restartCount === 'number' ? cs.restartCount : 0\n    const detail = termReason\n      ? `last terminated: ${termReason}${termMsg ? ` — ${termMsg}` : ''}${typeof term?.exitCode === 'number' ? ` (exit ${term.exitCode})` : ''}`\n      : 'no last-termination detail reported'\n    const attrs: SpanAttributes = { 'k8s.waitingReason': CRASH_LOOP_REASON, 'k8s.restartCount': restarts }\n    if (termReason) attrs['k8s.terminatedReason'] = termReason\n    if (termMsg) attrs['k8s.terminatedMessage'] = termMsg\n    if (typeof term?.exitCode === 'number') attrs['k8s.exitCode'] = term.exitCode\n    if (typeof cs.image === 'string') attrs['k8s.image'] = cs.image\n    return {\n      fault: 'crash-loop',\n      message: `Deployment ${name} is crashlooping (restarts: ${restarts}); ${detail}`,\n      timestamp: term?.finishedAt ?? pod.status?.startTime ?? nowIso(),\n      attributes: attrs,\n      pod,\n      ...(typeof cs.name === 'string' && cs.name.length > 0 ? { container: cs.name } : {}),\n    }\n  }\n  return null\n}\n\n// The pod spec container a fault was diagnosed from — the env/args source for\n// process-&-config fusion (ADR-237). Match by the faulted container's name,\n// falling back to the sole container when the spec names exactly one (a\n// single-container pod, the common case), else nothing — never a wrong guess.\nfunction faultedContainer(finding: FaultFinding): Container | undefined {\n  const containers = finding.pod?.spec?.containers\n  if (!Array.isArray(containers) || containers.length === 0) return undefined\n  if (finding.container) {\n    const named = containers.find((c) => c.name === finding.container)\n    if (named) return named\n  }\n  return containers.length === 1 ? containers[0] : undefined\n}\n\n/**\n * Merge the process-&-config fusion block onto a faulted finding's attributes\n * (ADR-237) — the OBSERVED \"why\" for a workload that failed before its first\n * span: `k8s.processLog` (the last-terminated stdout tail), `k8s.containerArgs`,\n * and `k8s.containerEnv` (both redacted + bounded by process-context.ts). Only\n * the pod-level faults carry a `pod`, so the deployment-level faults\n * (scaled-to-zero, no-ready-replicas) grow nothing; a healthy workload has no\n * finding at all, so it still mints nothing. Additive to `attributes`, so the\n * fault classification, its message, and the dedupe id are untouched.\n */\nfunction mergeProcessContext(finding: FaultFinding, logs?: K8sPodLogs): void {\n  const container = faultedContainer(finding)\n  const podName = finding.pod?.metadata?.name\n  const log = logs && podName ? logs.get(podLogKey(podName, finding.container)) : undefined\n  if (!container && log === undefined) return\n  const ctx = buildProcessContext({\n    ...(log !== undefined ? { log } : {}),\n    ...(container ? { container } : {}),\n  })\n  if (ctx.processLog !== undefined) finding.attributes['k8s.processLog'] = ctx.processLog\n  if (ctx.containerArgs !== undefined) finding.attributes['k8s.containerArgs'] = ctx.containerArgs\n  if (ctx.containerEnv !== undefined) finding.attributes['k8s.containerEnv'] = ctx.containerEnv\n}\n\n/**\n * The faulted (pod, container) pairs whose process LOG is worth pulling — what\n * the poll fetches, and nothing else (index.ts), so the `pods/log` read stays\n * scoped to a handful of pods and its RBAC stays minimal. Only `crash-loop`\n * contributes: a crashed container has a LAST terminated instance whose stdout\n * (`previous=true`) holds the traceback. An `image-pull` container never started,\n * so there's no process log to read — its env/args still ride (from the pod spec,\n * no extra call), but a log fetch would only 400. Deployment-level faults\n * (scaled-to-zero, no-ready-replicas) and healthy workloads yield nothing.\n */\nexport function faultedPods(\n  deployments: Deployment[],\n  pods: Pod[],\n  config: K8sConnectorConfig,\n): Array<{ podName: string; container?: string }> {\n  const out: Array<{ podName: string; container?: string }> = []\n  const expectedZero = config.expectedZero ? new Set(config.expectedZero) : undefined\n  for (const deployment of deployments) {\n    const finding = classifyDeployment(deployment, pods, expectedZero)\n    if (!finding || finding.fault !== 'crash-loop') continue\n    const podName = finding.pod?.metadata?.name\n    if (typeof podName !== 'string' || podName.length === 0) continue\n    out.push({ podName, ...(finding.container ? { container: finding.container } : {}) })\n  }\n  return out\n}\n\n/**\n * Classify one deployment's health. Returns the fault to mint an incident for,\n * or null when the workload is healthy (fully ready) — so a healthy deployment\n * mints nothing. Order: an explicit `replicas: 0` is scaled-to-zero; a\n * not-fully-ready deployment is diagnosed by its pods (image-pull / crashloop),\n * falling back to an un-classified `no-ready-replicas` when the deployment is\n * down but no pod names a cause.\n */\nexport function classifyDeployment(\n  deployment: Deployment,\n  pods: Pod[],\n  expectedZero?: ReadonlySet<string>,\n): FaultFinding | null {\n  const name = deployment.metadata?.name ?? ''\n  const desired = typeof deployment.spec?.replicas === 'number' ? deployment.spec.replicas : 1\n  const ready = typeof deployment.status?.readyReplicas === 'number' ? deployment.status.readyReplicas : 0\n\n  if (desired === 0) {\n    // A workload intentionally scaled to zero (a demo load-generator, a paused\n    // job) is expected, not an outage — mint nothing rather than noise.\n    if (expectedZero?.has(name)) return null\n    return {\n      fault: 'scaled-to-zero',\n      message: `Deployment ${name} is scaled to 0 — no running pods (desired 0)`,\n      timestamp: nowIso(),\n      attributes: { 'k8s.desiredReplicas': 0, 'k8s.readyReplicas': ready },\n    }\n  }\n\n  // Fully ready → healthy, no incident.\n  if (ready >= desired) return null\n\n  const podFault = podLevelFault(deployment, pods)\n  if (podFault) {\n    podFault.attributes['k8s.desiredReplicas'] = desired\n    podFault.attributes['k8s.readyReplicas'] = ready\n    return podFault\n  }\n\n  // Down, but no pod named a cause (pending scheduling, quota, an evicted pod) —\n  // honestly report the degraded state without guessing the reason.\n  return {\n    fault: 'no-ready-replicas',\n    message: `Deployment ${name} has no ready replicas (desired ${desired}, ready ${ready})`,\n    timestamp: nowIso(),\n    attributes: { 'k8s.desiredReplicas': desired, 'k8s.readyReplicas': ready },\n  }\n}\n\n/**\n * One deployment -> one incident-bearing signal, or null when the workload is\n * healthy (classifyDeployment returned null) or unnamed (no metadata.name to\n * key an id / service on). The incident id is stable per (namespace, deployment,\n * fault) so re-polling the same fault collapses to one incident on read\n * (ingest.ts dedupeIncidents), and a changed fault mints a distinct one.\n */\nexport function mapDeploymentToSignal(\n  deployment: Deployment,\n  pods: Pod[],\n  config: K8sConnectorConfig,\n  logs?: K8sPodLogs,\n): ObservedSignal | null {\n  const name = deployment.metadata?.name\n  if (typeof name !== 'string' || name.length === 0) return null\n  const expectedZero = config.expectedZero ? new Set(config.expectedZero) : undefined\n  const finding = classifyDeployment(deployment, pods, expectedZero)\n  if (!finding) return null\n\n  // Fuse the OBSERVED \"why\" (process log + redacted env/args) onto the faulted\n  // finding before it becomes the incident (ADR-237). Pod-level faults only.\n  mergeProcessContext(finding, logs)\n\n  const serviceName = serviceNameFor(deployment, config)\n  const namespace = deployment.metadata?.namespace ?? config.namespace\n\n  // The deploy context goes to the workload node, not the incident (ADR-243): the\n  // incident keeps only its identity and the raw messages.\n  const { deployContext, rest } = splitDeployContext(finding.fault, finding.attributes)\n  const attributes: SpanAttributes = {\n    'k8s.namespace': namespace,\n    'k8s.deployment': name,\n    ...rest,\n  }\n\n  return {\n    targetKind: K8S_TARGET_KIND,\n    targetName: packK8sTargetName({ serviceName, fault: finding.fault }),\n    // Incident-only — no edge, so no call/error count to replay.\n    callCount: 0,\n    errorCount: 0,\n    lastObservedIso: finding.timestamp,\n    incident: {\n      id: `k8s:deploy:${namespace}:${name}:${finding.fault}`,\n      timestamp: finding.timestamp,\n      service: serviceName,\n      errorType: 'k8s-deploy-failure',\n      errorMessage: finding.message,\n      attributes,\n      deployContext,\n    },\n  }\n}\n\n// The finding's attributes that make up the workload's deploy context (ADR-243),\n// lifted into the typed block the pipeline fuses onto the node. Everything else\n// stays an incident attribute.\nfunction splitDeployContext(\n  fault: string,\n  attrs: SpanAttributes,\n): { deployContext: DeployContext; rest: SpanAttributes } {\n  const rest: SpanAttributes = { ...attrs }\n  const take = (k: string): unknown => {\n    const v = rest[k]\n    delete rest[k]\n    return v\n  }\n  const str = (v: unknown): string | undefined => (typeof v === 'string' && v.length > 0 ? v : undefined)\n  const int = (v: unknown): number | undefined =>\n    typeof v === 'number' && Number.isFinite(v) ? Math.trunc(v) : undefined\n  const strs = (v: unknown): string[] | undefined =>\n    Array.isArray(v) && v.length > 0 && v.every((x) => typeof x === 'string') ? (v as string[]) : undefined\n  const waitingReason = str(take('k8s.waitingReason'))\n  const image = str(take('k8s.image'))\n  const restartCount = int(take('k8s.restartCount'))\n  const terminatedReason = str(take('k8s.terminatedReason'))\n  const exitCode = int(take('k8s.exitCode'))\n  const containerEnv = strs(take('k8s.containerEnv'))\n  const containerArgs = strs(take('k8s.containerArgs'))\n  const processLog = str(take('k8s.processLog'))\n  const deployContext: DeployContext = {\n    fault,\n    ...(waitingReason ? { waitingReason } : {}),\n    ...(image ? { image } : {}),\n    ...(restartCount !== undefined ? { restartCount } : {}),\n    ...(terminatedReason ? { terminatedReason } : {}),\n    ...(exitCode !== undefined ? { exitCode } : {}),\n    ...(containerEnv ? { containerEnv } : {}),\n    ...(containerArgs ? { containerArgs } : {}),\n    ...(processLog ? { processLog } : {}),\n  }\n  return { deployContext, rest }\n}\n\n// The observed deploy state of a workload: the container image its pods are\n// actually running (a *running* container is serving that image right now — for a\n// stuck rollout that is the OLD image, even though the manifest declares a new\n// one), and the count of ready replicas. This is the observed half of the\n// declared-vs-observed deploy compare (ADR-225) — recorded for every workload,\n// healthy included, so the divergence sees a stuck rollout that fires no incident.\nfunction observedDeployState(\n  deployment: Deployment,\n  pods: Pod[],\n): { image?: string; readyReplicas: number; addresses?: string[] } {\n  const readyReplicas =\n    typeof deployment.status?.readyReplicas === 'number' ? deployment.status.readyReplicas : 0\n  let image: string | undefined\n  for (const pod of podsForDeployment(deployment, pods)) {\n    for (const cs of pod.status?.containerStatuses ?? []) {\n      if (cs.state?.running && typeof cs.image === 'string' && cs.image.length > 0) {\n        image = cs.image\n        break\n      }\n    }\n    if (image) break\n  }\n  return image !== undefined ? { image, readyReplicas } : { readyReplicas }\n}\n\n/**\n * One deploy-state signal per workload (healthy included), carrying the running\n * image + ready replicas to stamp as OBSERVED on the service node (ADR-225). It\n * mints no edge and no incident — `callCount: 0`, `deployState` set — it exists\n * purely so the declared-vs-observed compare has an observed side even when the\n * workload is up (the stuck-rollout case). Null for an unnamed workload.\n */\nexport function deployStateSignal(\n  deployment: Deployment,\n  pods: Pod[],\n  config: K8sConnectorConfig,\n  // The ClusterIPs that reach this workload (ADR-248), present only when the\n  // poll read the Services list — `[]` then means it has none.\n  addresses?: string[],\n): ObservedSignal | null {\n  const name = deployment.metadata?.name\n  if (typeof name !== 'string' || name.length === 0) return null\n  const serviceName = serviceNameFor(deployment, config)\n  return {\n    targetKind: K8S_TARGET_KIND,\n    targetName: packK8sTargetName({ serviceName, fault: K8S_DEPLOY_STATE }),\n    callCount: 0,\n    errorCount: 0,\n    lastObservedIso: nowIso(),\n    deployState: {\n      ...observedDeployState(deployment, pods),\n      ...(addresses !== undefined ? { addresses } : {}),\n    },\n  }\n}\n\nexport function mapWorkloadsToSignals(\n  deployments: Deployment[],\n  pods: Pod[],\n  config: K8sConnectorConfig,\n  logs?: K8sPodLogs,\n  services?: Service[],\n): ObservedSignal[] {\n  const out: ObservedSignal[] = []\n  const addresses = services ? addressesByDeployment(deployments, pods, services) : undefined\n  for (const deployment of deployments) {\n    // Deploy-state for every workload (the observed side of the divergence)...\n    const name = deployment.metadata?.name ?? ''\n    const deployState = deployStateSignal(\n      deployment,\n      pods,\n      config,\n      addresses ? (addresses.get(name) ?? []) : undefined,\n    )\n    if (deployState) out.push(deployState)\n    // ...plus an incident only when the workload is unhealthy — carrying the\n    // process-&-config fusion (ADR-237) when a process log was fetched for it.\n    const incident = mapDeploymentToSignal(deployment, pods, config, logs)\n    if (incident) out.push(incident)\n  }\n  return out\n}\n","// Kubernetes deploy-state connector — provider-specific types (ADR-224, #1124).\n// The second incident-emitting connector (connectors.md §10) after EAS (ADR-185):\n// it pulls read-only cluster state and mints an OBSERVED incident on a service\n// node when a workload is down for a *deployment* reason — a bad image, zero\n// replicas, a crashloop — a fault a dead pod emits no span for, so the graph is\n// otherwise blind to it. One `poll()` reads Deployments + Pods in one namespace;\n// the shared pipeline (connectors/index.ts) writes each unhealthy workload's\n// incident to the same ledger OTLP-derived incidents land in.\n//\n// Every field name below is a stable part of the Kubernetes API (apps/v1\n// Deployment, core/v1 Pod), confirmed against the API reference rather than\n// recalled (ADR-150/152 discipline). Nothing here is trusted present — a partial\n// object drops honestly rather than throwing (connectors.md §4).\n\n// ── credentials ──────────────────────────────────────────────────────────────\n\n// `ConnectorContext.credentials` is opaque at the shared-scaffold layer\n// (connectors/types.ts). The k8s credential carries the secret-bearing auth: a\n// bearer token (an in-cluster / hosted service-account token) OR a kubeconfig\n// (path or inline YAML, the \"same access kubectl has\" local path). Non-secret\n// transport config (the API-server URL, the CA, the namespace, the service map)\n// rides in `options` (K8sConnectorConfig), never here — the token flows into\n// `Authorization: Bearer` and nowhere else (connectors.md §6, connector-config.md\n// §7). Read-only RBAC only: get/list on deployments + pods.\nexport interface K8sCredentials {\n  // A service-account bearer token. Paired with `options.apiServerUrl`.\n  token?: string\n  // A kubeconfig: an absolute path, or the YAML itself. Its current-context\n  // supplies the server, CA, and auth (a token, or a client cert/key — kind's\n  // default). When set it takes precedence over `token`.\n  kubeconfig?: string\n}\n\nexport function readK8sCredentials(raw: Record<string, unknown>): K8sCredentials {\n  const token = typeof raw['token'] === 'string' && raw['token'].length > 0 ? (raw['token'] as string) : undefined\n  const kubeconfig =\n    typeof raw['kubeconfig'] === 'string' && raw['kubeconfig'].length > 0 ? (raw['kubeconfig'] as string) : undefined\n  if (!token && !kubeconfig) {\n    throw new Error('kubernetes connector: credentials must carry a token or a kubeconfig')\n  }\n  const out: K8sCredentials = {}\n  if (token) out.token = token\n  if (kubeconfig) out.kubeconfig = kubeconfig\n  return out\n}\n\n// ── config ─────────────────────────────────────────────────────────────────\n\n/**\n * Non-secret config resolved once at connector setup (connector-config.md §7) —\n * never re-derived from an API response at poll time.\n */\nexport interface K8sConnectorConfig {\n  // The namespace to read. One namespace per connector entry, so RBAC stays\n  // scoped and a multi-tenant cluster maps to one connector per tenant namespace.\n  namespace: string\n  // The API-server base URL (`https://host:6443`). Required with the token\n  // credential; supplied by the kubeconfig otherwise.\n  apiServerUrl?: string\n  // The cluster CA certificate (PEM) to verify the API server's TLS. Supplied by\n  // the kubeconfig otherwise; absent means the system trust store (a public cert).\n  caCert?: string\n  // Skip TLS verification — a dogfood escape hatch for a self-signed local\n  // cluster with no CA to hand. Opt-in, never a default; a hosted deployment\n  // supplies the CA instead.\n  insecureSkipTlsVerify?: boolean\n  // Deployment name -> NEAT manifest service name, for when a workload's name /\n  // `app` label doesn't equal the OTel `service.name` the extractor keyed on\n  // (resolved once, never guessed — the same map cloud-run/eas keep). An unmapped\n  // workload falls back to its own name/label and stays honest.\n  serviceMap?: Record<string, string>\n  // Deployment names that are *intentionally* scaled to zero — a demo\n  // load-generator, a manually-paused job, a cron-style workload. A\n  // `scaled-to-zero` fault on one of these is expected, not an outage, so it\n  // mints no incident (the noise the live run surfaced). Only suppresses the\n  // scaled-to-zero classification; a real image-pull / crashloop on one of these\n  // still reports.\n  expectedZero?: string[]\n  // API base override for tests (a stub k8s API); production uses apiServerUrl /\n  // the kubeconfig server.\n  apiUrl?: string\n}\n\n// ── the workload shapes (the subset this connector reads) ────────────────────\n\nexport interface OwnerReference {\n  kind?: string\n  name?: string\n}\n\nexport interface ObjectMeta {\n  name?: string\n  namespace?: string\n  labels?: Record<string, string>\n  ownerReferences?: OwnerReference[]\n  creationTimestamp?: string\n}\n\nexport interface LabelSelector {\n  matchLabels?: Record<string, string>\n}\n\nexport interface DeploymentSpec {\n  // Desired replica count. Absent defaults to 1 (the API default); `0` is the\n  // explicit scaled-to-zero signal.\n  replicas?: number\n  selector?: LabelSelector\n}\n\nexport interface DeploymentStatus {\n  replicas?: number\n  readyReplicas?: number\n  availableReplicas?: number\n  unavailableReplicas?: number\n}\n\nexport interface Deployment {\n  metadata?: ObjectMeta\n  spec?: DeploymentSpec\n  status?: DeploymentStatus\n}\n\n// A Service (core/v1), only the fields the ClusterIP join reads (ADR-248): the\n// virtual IPs it is reachable at and the pod selector that says which workload\n// is behind them.\nexport interface ServiceSpec {\n  clusterIP?: string\n  clusterIPs?: string[]\n  selector?: Record<string, string>\n}\n\nexport interface Service {\n  metadata?: ObjectMeta\n  spec?: ServiceSpec\n}\n\nexport interface ContainerStateWaiting {\n  reason?: string\n  message?: string\n}\n\nexport interface ContainerStateTerminated {\n  reason?: string\n  message?: string\n  exitCode?: number\n  finishedAt?: string\n}\n\nexport interface ContainerState {\n  waiting?: ContainerStateWaiting\n  terminated?: ContainerStateTerminated\n  running?: { startedAt?: string }\n}\n\nexport interface ContainerStatus {\n  name?: string\n  image?: string\n  ready?: boolean\n  restartCount?: number\n  state?: ContainerState\n  lastState?: ContainerState\n}\n\nexport interface PodStatus {\n  phase?: string\n  containerStatuses?: ContainerStatus[]\n  startTime?: string\n  reason?: string\n}\n\n// ── the pod spec (the env/args half of process-&-config fusion, ADR-237) ──────\n// Read only for a *faulted* workload (map.ts), to fuse the WHY of a boot-time\n// failure — the process args and the (redacted) env — alongside the process log.\n// Every field is a stable part of the core/v1 Pod spec, confirmed against the API\n// reference (ADR-150/152 discipline); a partial object drops honestly (§4).\n\n// An env var's `valueFrom` source. Captured as a REFERENCE DESCRIPTOR only\n// (process-context.ts) — never resolved: NEAT reads no ConfigMap or Secret to\n// expand it, so a secretKeyRef's value never enters the graph at all.\nexport interface EnvVarSource {\n  configMapKeyRef?: { name?: string; key?: string }\n  secretKeyRef?: { name?: string; key?: string }\n  fieldRef?: { fieldPath?: string }\n  resourceFieldRef?: { resource?: string }\n}\n\n// A single container env var — a literal `value`, or a `valueFrom` reference to a\n// ConfigMap / Secret / downward-API field.\nexport interface EnvVar {\n  name?: string\n  value?: string\n  valueFrom?: EnvVarSource\n}\n\nexport interface Container {\n  name?: string\n  image?: string\n  command?: string[]\n  args?: string[]\n  env?: EnvVar[]\n}\n\nexport interface PodSpec {\n  containers?: Container[]\n}\n\nexport interface Pod {\n  metadata?: ObjectMeta\n  spec?: PodSpec\n  status?: PodStatus\n}\n\nexport interface K8sList<T> {\n  items?: T[]\n}\n\n// ── fault classification (the honesty of the feature) ────────────────────────\n\n// The deployment-fault vocabulary — stable strings that key the incident's\n// dedupe id and name its kind on the card. Each is a fault a dead pod can't emit\n// a span for, which is exactly why the connector exists (#1124).\nexport type K8sFaultKind = 'image-pull' | 'crash-loop' | 'scaled-to-zero' | 'no-ready-replicas'\n\n// Container `waiting.reason` values that mean the image can't be pulled. These\n// are the stable kubelet reason strings (image-pull backoff / hard failure).\nexport const IMAGE_PULL_REASONS = new Set<string>(['ImagePullBackOff', 'ErrImagePull', 'InvalidImageName'])\nexport const CRASH_LOOP_REASON = 'CrashLoopBackOff'\n\n// The provider-vocabulary identity a signal carries through the shared pipeline,\n// packed into `ObservedSignal.targetName` and unpacked only by this connector's\n// own resolveTarget (resolve.ts), never surfaced to the graph. `\\x00` separates\n// the fields: it can't appear in a NEAT service name or a fault-kind token.\nconst FIELD_SEP = '\\x00'\n\nexport const K8S_TARGET_KIND = 'k8s-workload'\n\n// A deploy-state signal's marker in place of a fault (ADR-225). Not a fault — it\n// carries the running image/ready-replicas for a workload (healthy included) so\n// the declared-vs-observed deploy compare has an observed side. resolve.ts keys\n// only on the service name, so this marker never needs its own resolution.\nexport const K8S_DEPLOY_STATE = 'deploy-state'\n\nexport interface K8sTargetIdentity {\n  serviceName: string\n  fault: K8sFaultKind | typeof K8S_DEPLOY_STATE\n}\n\nexport function packK8sTargetName(identity: K8sTargetIdentity): string {\n  return [identity.serviceName, identity.fault].join(FIELD_SEP)\n}\n\nexport function parseK8sTargetName(targetName: string): K8sTargetIdentity | null {\n  const sep = targetName.indexOf(FIELD_SEP)\n  if (sep === -1) return null\n  const serviceName = targetName.slice(0, sep)\n  const fault = targetName.slice(sep + 1)\n  if (!serviceName || !fault) return null\n  return { serviceName, fault: fault as K8sFaultKind | typeof K8S_DEPLOY_STATE }\n}\n","// Process & config fusion — the OBSERVED \"why\" for a workload that fails BEFORE\n// it emits its first span (ADR-237). A crash-loop, a bootstrap hang, an OOM, a\n// panic-on-boot, a wrong config value: the fault classifier (map.ts) already\n// sees *that* the workload is down, but the reason lives only in the pod's\n// process stdout (the traceback the dead process left in its last terminated\n// instance) and the container's env/args. This module turns those two raw inputs\n// into a bounded, redacted `{ processLog, containerArgs, containerEnv }` block\n// the fault finding carries as live OBSERVED runtime state on the incident\n// ledger (map.ts → appendConnectorIncident).\n//\n// It is a pure, side-effect-free module: no fetch, no graph, no disk — just the\n// secret redactor and the bounded builder, so the redaction rules and the caps\n// are unit-testable in isolation (kubernetes-process-context.test.ts).\n//\n// SECRET DISCIPLINE (ADR-237, connectors.md §6/§10). This is the one carve-out\n// from the \"never write .env contents\" rule (contracts.md Rule 13): it records\n// REDACTED env values as *live runtime state on the incident ledger*, never a\n// raw secret, never a ConfigNode, never a persisted node attribute. Two\n// redaction gates run before any value leaves this module:\n//   1. by KEY — an env var or flag whose name carries a secret stem\n//      (SECRET_KEY_RE) has its value masked whole.\n//   2. by VALUE SHAPE — every other value, arg, and the process log go through\n//      `redactText`: credential URLs, secret-named pairs, auth-scheme\n//      credentials, private keys, and self-identifying token formats.\n// A `valueFrom` reference is never resolved — only its descriptor is captured —\n// so a `secretKeyRef`'s actual value is never read in the first place.\n\nimport type { Container, EnvVar } from './types.js'\n\n// ── caps (byte-bounded, honoring incident-serialization-cap.test.ts) ──────────\n\n// The process log keeps its TAIL — a traceback / panic / OOM line sits at the\n// END of the output, so the last lines are the ones that carry the cause.\nexport const DEFAULT_MAX_LOG_LINES = 50\nexport const DEFAULT_MAX_LOG_BYTES = 2 * 1024\n// Bound the env/args lists so a container with hundreds of env vars can't bloat\n// one incident, and cap each individual value so a single long value can't\n// either.\nexport const DEFAULT_MAX_ENTRIES = 64\nexport const DEFAULT_MAX_VALUE_CHARS = 512\n\nconst REDACTED = '***REDACTED***'\n\n// ── redaction ─────────────────────────────────────────────────────────────────\n\n// Env var / flag names whose value is a secret by convention. Case-insensitive\n// substring match — `DB_PASSWORD`, `API_TOKEN`, `STRIPE_SECRET_KEY`,\n// `JWT_SIGNING_KEY`, `MYSQL_PWD`, `DB_PASS`, `SENTRY_DSN`, `GCP_CREDENTIALS`,\n// `SESSION_COOKIE_SALT` all hit. Over-masking a benign name (`BYPASS_CACHE`)\n// costs a little context; under-masking costs a secret, so the stems are broad.\nconst SECRET_KEY_RE =\n  /TOKEN|SECRET|KEY|PASSW(?:OR)?D|PWD|(?:^|[^A-Z])PASS(?:$|[^A-Z])|CREDENTIAL|(?:^|[^A-Z])AUTH|PRIVATE|DSN|COOKIE|SESSION|SALT|SIGNATURE|CERT|CONN(?:ECTION)?_?STR/i\n\n// A URL carrying inline credentials: `scheme://user:password@host`. The password\n// between the first `:` after the authority's userinfo and the `@` is the secret;\n// the scheme/host/path around it are safe context worth keeping. Global so every\n// occurrence in a value is masked.\nconst CREDENTIAL_URL_RE = /([a-zA-Z][a-zA-Z0-9+.-]*:\\/\\/[^\\s:/@]+:)([^\\s/@]+)(@)/g\n\n/** Does this env var / flag name mark its value as a secret? */\nexport function isSecretKey(name: string): boolean {\n  return SECRET_KEY_RE.test(name)\n}\n\n/** Mask the inline password inside any credential URL embedded in `value`. */\nexport function maskCredentialUrls(value: string): string {\n  return value.replace(CREDENTIAL_URL_RE, (_m, prefix: string, _pw: string, at: string) => `${prefix}${REDACTED}${at}`)\n}\n\n// The value-shape gates every free-text value goes through — a non-secret-named\n// env value, a process arg, and the process log alike. A traceback prints\n// whatever the process held, so the log needs the same gates as the env.\n//\n// A PEM private key block, whole.\nconst PRIVATE_KEY_BLOCK_RE = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\\s\\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g\n// The tail of a key block whose BEGIN line fell outside the fetched log.\nconst PRIVATE_KEY_TAIL_RE = /(?:^[A-Za-z0-9+/=]{32,}\\r?\\n)+-----END [A-Z ]*PRIVATE KEY-----/gm\n// Any URL userinfo: `scheme://user:pass@` keeps the user and masks the password;\n// `scheme://:pass@` (Redis) and `scheme://<key>@` (a Sentry-style DSN, where the\n// userinfo IS the credential) are masked whole.\nconst URL_USERINFO_RE = /([a-zA-Z][a-zA-Z0-9+.-]*:\\/\\/)([^\\s/@]*)@/g\n// A secret-named key followed by a value: `Password=x;` (ADO.NET), `password=x`\n// (libpq / a query string), `DB_PASSWORD=x` (an env dump in a log), `\"token\": \"x\"`\n// (JSON), `api_key: x` (YAML). The key stems are word-bounded so a log line like\n// `3 tests passed: 12` keeps its number.\nconst SECRET_PAIR_RE =\n  /((?:^|[\\s?&;,{(\"'])[A-Za-z0-9_.-]*?(?:passw(?:or)?d|pwd|(?<![a-z])pass(?![a-z])|secret|token|api[_-]?key|access[_-]?key|private[_-]?key|client[_-]?key|credentials?|(?<![a-z])auth(?![a-z])|(?<![a-z])dsn(?![a-z]))[A-Za-z0-9_.-]*[\"']?\\s*[=:]\\s*[\"']?)([^\\s&;,\"'})]+)/gi\n// An HTTP auth scheme with its credential, e.g. a logged `Authorization: Bearer …`.\nconst AUTH_SCHEME_RE = /\\b(Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{8,}/g\n// Self-identifying token formats that can ride in an innocuous-looking value.\nconst KNOWN_TOKEN_RE =\n  /\\beyJ[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}\\.[A-Za-z0-9_-]{8,}|\\bAKIA[0-9A-Z]{16}\\b|\\bgh[pousr]_[A-Za-z0-9]{20,}|\\bgithub_pat_[A-Za-z0-9_]{20,}|\\bsk_(?:live|test)_[A-Za-z0-9]{10,}|\\bxox[abprs]-[A-Za-z0-9-]{10,}|\\bglpat-[A-Za-z0-9_-]{16,}|\\bAIza[0-9A-Za-z_-]{30,}|\\bneat_pat_[A-Za-z0-9_-]{16,}/g\n\n/** Run every value-shape redaction gate over free text (a value, an arg, a log). */\nexport function redactText(text: string): string {\n  return text\n    .replace(PRIVATE_KEY_BLOCK_RE, REDACTED)\n    .replace(PRIVATE_KEY_TAIL_RE, REDACTED)\n    .replace(URL_USERINFO_RE, (_m, scheme: string, userinfo: string) => {\n      const colon = userinfo.indexOf(':')\n      return colon > 0 ? `${scheme}${userinfo.slice(0, colon)}:${REDACTED}@` : `${scheme}${REDACTED}@`\n    })\n    .replace(SECRET_PAIR_RE, (_m, key: string) => `${key}${REDACTED}`)\n    .replace(AUTH_SCHEME_RE, (_m, scheme: string) => `${scheme} ${REDACTED}`)\n    .replace(KNOWN_TOKEN_RE, REDACTED)\n}\n\n/**\n * Redact one env var's literal value: masked whole when the NAME is a secret,\n * otherwise kept with any embedded credential-URL password masked by shape.\n */\nexport function redactValue(name: string, value: string): string {\n  if (isSecretKey(name)) return REDACTED\n  return redactText(value)\n}\n\n/**\n * Redact one process arg. An arg has no separate key, so two shapes are handled:\n * a `KEY=value` / `--key=value` flag whose key is secret has its value masked;\n * otherwise a credential URL embedded anywhere in the arg is masked by shape.\n */\nexport function redactArg(arg: string): string {\n  const eq = /^(--?)?([A-Za-z0-9_.-]+)=([\\s\\S]*)$/.exec(arg)\n  if (eq && isSecretKey(eq[2]!)) {\n    return `${eq[1] ?? ''}${eq[2]}=${REDACTED}`\n  }\n  return redactText(arg)\n}\n\n// A bare flag naming a secret (`--password`, `--api-token`) whose value is the\n// NEXT arg, as in `[\"--password\", \"hunter2\"]`.\nfunction isSecretFlag(arg: string): boolean {\n  const m = /^--?([A-Za-z0-9_.-]+)$/.exec(arg)\n  return m !== null && isSecretKey(m[1]!)\n}\n\nfunction capValue(s: string, max: number = DEFAULT_MAX_VALUE_CHARS): string {\n  return s.length > max ? `${s.slice(0, max)}…` : s\n}\n\n// ── env / args descriptors ────────────────────────────────────────────────────\n\n/**\n * One env var → a `NAME=…` descriptor. A literal value is redacted and capped; a\n * `valueFrom` is captured as a reference descriptor only, never resolved — a\n * `secretKeyRef` drops its key (the key name can hint at the secret), a\n * `configMapKeyRef` keeps `name key <key>` (config references are not secrets).\n * Returns undefined for an unnamed var (nothing to anchor on).\n */\nexport function describeEnvVar(ev: EnvVar): string | undefined {\n  const name = typeof ev.name === 'string' ? ev.name : ''\n  if (name.length === 0) return undefined\n  if (typeof ev.value === 'string') {\n    return `${name}=${capValue(redactValue(name, ev.value))}`\n  }\n  const from = ev.valueFrom\n  if (from) {\n    if (from.secretKeyRef) {\n      const ref = typeof from.secretKeyRef.name === 'string' && from.secretKeyRef.name.length > 0 ? from.secretKeyRef.name : '<unnamed>'\n      return `${name}=<from secret ${ref}>`\n    }\n    if (from.configMapKeyRef) {\n      const ref = typeof from.configMapKeyRef.name === 'string' && from.configMapKeyRef.name.length > 0 ? from.configMapKeyRef.name : '<unnamed>'\n      const key = typeof from.configMapKeyRef.key === 'string' && from.configMapKeyRef.key.length > 0 ? ` key ${from.configMapKeyRef.key}` : ''\n      return `${name}=<from configMap ${ref}${key}>`\n    }\n    if (from.fieldRef && typeof from.fieldRef.fieldPath === 'string' && from.fieldRef.fieldPath.length > 0) {\n      return `${name}=<from field ${from.fieldRef.fieldPath}>`\n    }\n    if (from.resourceFieldRef && typeof from.resourceFieldRef.resource === 'string' && from.resourceFieldRef.resource.length > 0) {\n      return `${name}=<from resource ${from.resourceFieldRef.resource}>`\n    }\n    return `${name}=<from reference>`\n  }\n  // An env var with neither value nor valueFrom — record the name, no value.\n  return `${name}=`\n}\n\nfunction buildContainerEnv(container: Container): string[] {\n  const out: string[] = []\n  for (const ev of container.env ?? []) {\n    const d = describeEnvVar(ev)\n    if (d !== undefined) out.push(d)\n    if (out.length >= DEFAULT_MAX_ENTRIES) break\n  }\n  return out\n}\n\nfunction buildContainerArgs(container: Container): string[] {\n  const raw: string[] = []\n  for (const c of container.command ?? []) if (typeof c === 'string') raw.push(c)\n  for (const a of container.args ?? []) if (typeof a === 'string') raw.push(a)\n  const out: string[] = []\n  for (let i = 0; i < raw.length && out.length < DEFAULT_MAX_ENTRIES; i++) {\n    const arg = raw[i]!\n    out.push(capValue(redactArg(arg)))\n    const next = raw[i + 1]\n    if (isSecretFlag(arg) && next !== undefined && !next.startsWith('-') && out.length < DEFAULT_MAX_ENTRIES) {\n      out.push(REDACTED)\n      i++\n    }\n  }\n  return out\n}\n\n// ── process log ────────────────────────────────────────────────────────────────\n\n/**\n * Keep the TAIL of a process log, line- and byte-bounded. The last lines hold the\n * traceback / panic / OOM message, so trailing whitespace is trimmed, the last\n * `maxLines` lines are kept, then the result is clipped to `maxBytes` from the\n * end. Empty in → empty out.\n */\nexport function capProcessLog(\n  text: string,\n  maxLines: number = DEFAULT_MAX_LOG_LINES,\n  maxBytes: number = DEFAULT_MAX_LOG_BYTES,\n): string {\n  const trimmed = text.replace(/\\s+$/, '')\n  if (trimmed.length === 0) return ''\n  const lines = trimmed.split('\\n')\n  const tail = lines.length > maxLines ? lines.slice(lines.length - maxLines) : lines\n  let out = tail.join('\\n')\n  if (out.length > maxBytes) out = out.slice(out.length - maxBytes)\n  return out\n}\n\n// ── the builder ─────────────────────────────────────────────────────────────────\n\n/**\n * The bounded, redacted OBSERVED runtime-state block a faulted workload's\n * incident carries. Every field is optional — a fault with no readable log, or a\n * pod with no spec, simply omits that field rather than minting an empty one.\n */\nexport interface ProcessContext {\n  processLog?: string\n  containerArgs?: string[]\n  containerEnv?: string[]\n}\n\nexport interface BuildProcessContextInput {\n  // The fetched process stdout (client.ts, `previous=true` for a crash-looped\n  // container so it's the LAST terminated instance's traceback, not the empty\n  // current one). Undefined when the log couldn't be read (no `pods/log` RBAC, a\n  // container that never started) — the block then carries env/args only.\n  log?: string\n  // The faulted pod's spec container, for its args + env. Undefined when the pod\n  // carries no readable spec — the block then carries the log only.\n  container?: Container\n}\n\n/**\n * Build the `{ processLog, containerArgs, containerEnv }` block from a fetched\n * process log and the faulted container's spec. Pure: all redaction and capping\n * happen here, so nothing raw or unbounded ever leaves. Returns an empty object\n * when there's nothing to record (no log, no container) — the caller merges only\n * the fields that are set.\n */\nexport function buildProcessContext(input: BuildProcessContextInput): ProcessContext {\n  const out: ProcessContext = {}\n  if (typeof input.log === 'string') {\n    // Cap to the tail, then mask any credential URL the traceback printed — a\n    // boot failure commonly logs the connection string it died dialing, so the\n    // same value-shape redaction the env takes applies to the log.\n    // Redact the whole fetched text first, so a secret that straddles the cap\n    // boundary is still recognised whole; then keep the tail.\n    const capped = capProcessLog(redactText(input.log))\n    if (capped.length > 0) out.processLog = capped\n  }\n  if (input.container) {\n    const args = buildContainerArgs(input.container)\n    if (args.length > 0) out.containerArgs = args\n    const env = buildContainerEnv(input.container)\n    if (env.length > 0) out.containerEnv = env\n  }\n  return out\n}\n","// Target resolution — the k8s-specific half of the pull/map/fuse split\n// (connectors.md §Authority): turning an unhealthy workload's `serviceName` into\n// the NEAT node the incident lands on (ADR-224, connectors.md §10). A deployment\n// fault belongs to the whole service (the image, the replica count, the crash are\n// service-wide, not route- or file-scoped), so it anchors on the app's\n// ServiceNode — resolved through the SAME fused-service lookup the OTLP incident\n// path uses (`resolveFusedServiceId`, #988/#992) so the incident fuses onto the\n// extracted service the code deps and observed connection-refused edges already\n// hang off, never a connector-minted twin.\n//\n// This module never mutates the graph (ADR-030) — it hands back the resolved id\n// for the shared pipeline to write the incident against. When the service names\n// no node yet (an unmapped deployment name, an un-extracted service), the\n// pipeline drops the incident honestly rather than fabricating a node — the same\n// missing-target discipline EAS's resolver holds.\n\nimport { EdgeType } from '@neat.is/types'\nimport type { NeatGraph } from '../../graph.js'\nimport { resolveFusedServiceId } from '../../ingest.js'\nimport type { ResolveConnectorTarget, ResolvedConnectorTarget } from '../index.js'\nimport { K8S_TARGET_KIND, parseK8sTargetName } from './types.js'\n\n// The connectors plane's env-unscoped sentinel (identity.ts's ENV_UNKNOWN) — a\n// deployment fault carries no `deployment.environment`, so it fuses onto the\n// env-less `service:<name>` the extractor mints.\nconst NO_ENV = 'unknown'\n\n/**\n * Builds the resolveTarget callback runConnectorPoll (connectors/index.ts) calls\n * once per signal. Closes over `graph` because ResolveConnectorTarget's own\n * signature doesn't carry it — the same closure pattern every connector's\n * resolveTarget uses. `edgeType` is required by ResolvedConnectorTarget but\n * unused on the incident path (the pipeline writes an ErrorEvent, not an edge);\n * it's set to a stable placeholder, as EAS's resolver does.\n */\nexport function createK8sResolveTarget(graph: NeatGraph): ResolveConnectorTarget {\n  return (signal): ResolvedConnectorTarget | null => {\n    if (signal.targetKind !== K8S_TARGET_KIND) return null\n    const identity = parseK8sTargetName(signal.targetName)\n    if (!identity) return null\n    const { serviceName } = identity\n    return {\n      targetNodeId: resolveFusedServiceId(graph, serviceName, NO_ENV),\n      serviceName,\n      edgeType: EdgeType.CALLS,\n    }\n  }\n}\n","// The k8s deployment-substrate enable path (ADR-224). Kubernetes is not a SaaS\n// vendor — it is ubiquitous deployment infrastructure with a *declared* side (the\n// repo's manifests) and an *observed* side (live cluster state), whose divergence\n// is the payoff. So it is deliberately NOT a `neat connector` provider (no\n// PROVIDER_DISPATCH entry, no vendor CLI). This module is its enable path: the\n// daemon reads a dedicated `~/.neat/k8s.json` at slot bootstrap and runs the\n// observed cluster-state reader (this connector's poll code) through the SAME\n// `startConnectorPollLoop` plumbing every connector uses — the incident pipeline,\n// the junction, the status tracker — reused, not rebuilt.\n//\n// The declared half (repo manifests → desired image / replicas, a static\n// extractor) and the declared-vs-observed divergence are the substrate's other\n// legs; this file is the observed leg's enable surface.\n\nimport { readFile } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport type { NeatGraph } from '../../graph.js'\nimport { resolveCredential, type CredentialRef } from '../../connectors-config.js'\nimport { startConnectorPollLoop } from '../index.js'\nimport { createKubernetesConnector } from './index.js'\nimport type { K8sConnectorConfig } from './types.js'\n\n/**\n * One entry in `~/.neat/k8s.json` — a project's observed deployment surface. The\n * `credential` is the same env-ref-by-default shape connectors use (a token, or a\n * `{ kubeconfig }` field-map), resolved to a value only at daemon-read time so no\n * secret sits at rest (connector-config.md §2). Everything else is the reader's\n * non-secret config.\n */\nexport interface K8sSubstrateEntry {\n  id: string\n  // Matches a registered project's name; omitted binds to whichever project the\n  // daemon is bootstrapping.\n  project?: string\n  credential: CredentialRef\n  namespace: string\n  apiServerUrl?: string\n  caCert?: string\n  insecureSkipTlsVerify?: boolean\n  serviceMap?: Record<string, string>\n  expectedZero?: string[]\n  intervalMs?: number\n}\n\nexport interface K8sSubstrateConfig {\n  version: number\n  deployments: K8sSubstrateEntry[]\n}\n\nfunction defaultHome(): string {\n  const override = process.env.NEAT_HOME\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(os.homedir(), '.neat')\n}\n\nexport function k8sSubstrateConfigPath(home: string = defaultHome()): string {\n  return path.join(home, 'k8s.json')\n}\n\n/**\n * Read `~/.neat/k8s.json`. A missing or malformed file is an empty config, never\n * a throw — a project with no k8s substrate configured is the common case, the\n * same graceful-absence discipline the connector read-path holds.\n */\nexport async function readK8sSubstrateConfig(home: string = defaultHome()): Promise<K8sSubstrateConfig> {\n  let raw: string\n  try {\n    raw = await readFile(k8sSubstrateConfigPath(home), 'utf8')\n  } catch {\n    return { version: 1, deployments: [] }\n  }\n  try {\n    const parsed = JSON.parse(raw) as K8sSubstrateConfig\n    if (!parsed || !Array.isArray(parsed.deployments)) return { version: 1, deployments: [] }\n    return parsed\n  } catch {\n    return { version: 1, deployments: [] }\n  }\n}\n\nexport interface StartK8sSubstrateInput {\n  project: string\n  graph: NeatGraph\n  projectDir: string\n  errorsPath?: string\n  home?: string\n  env?: NodeJS.ProcessEnv\n  onSkip?: (entry: K8sSubstrateEntry, reason: string) => void\n  // Test seam — a fake `fetch` stands in for the live k8s API so the loop never\n  // reaches a real cluster. Production leaves it undefined and the reader builds\n  // the TLS-configured https adapter from the transport.\n  fetchImpl?: typeof fetch\n}\n\n/**\n * Read the substrate config and start one poll loop per project-matched entry,\n * through the shared `startConnectorPollLoop`. Returns a stop function that tears\n * every loop down — wired into the daemon slot alongside `stopConnectors`. A bad\n * entry (unset env-ref, missing namespace) is skipped with a reason, never fatal\n * to the slot (the same discipline the connector read-path holds).\n */\nexport async function startK8sSubstratePolling(input: StartK8sSubstrateInput): Promise<() => void> {\n  const config = await readK8sSubstrateConfig(input.home)\n  const env = input.env ?? process.env\n  const stops: Array<() => void> = []\n\n  for (const entry of config.deployments) {\n    if (entry.project !== undefined && entry.project !== input.project) continue\n    if (typeof entry.namespace !== 'string' || entry.namespace.length === 0) {\n      input.onSkip?.(entry, 'missing namespace')\n      continue\n    }\n    let credentials: Record<string, unknown>\n    try {\n      const resolved = resolveCredential(entry.credential, env)\n      // A single-string credential is the bearer token; a field-map carries its\n      // own keys (`token` / `kubeconfig`), which readK8sCredentials reads.\n      credentials = resolved.kind === 'fields' ? { ...resolved.fields } : { token: resolved.value }\n    } catch (err) {\n      input.onSkip?.(entry, (err as Error).message)\n      continue\n    }\n\n    const cfg: K8sConnectorConfig = {\n      namespace: entry.namespace,\n      ...(entry.apiServerUrl ? { apiServerUrl: entry.apiServerUrl } : {}),\n      ...(entry.caCert ? { caCert: entry.caCert } : {}),\n      ...(entry.insecureSkipTlsVerify ? { insecureSkipTlsVerify: true } : {}),\n      ...(entry.serviceMap ? { serviceMap: entry.serviceMap } : {}),\n      ...(entry.expectedZero ? { expectedZero: entry.expectedZero } : {}),\n    }\n    const { connector, resolveTarget } = createKubernetesConnector(input.graph, cfg, input.fetchImpl)\n    const stop = startConnectorPollLoop(\n      connector,\n      {\n        projectDir: input.projectDir,\n        project: input.project,\n        credentials,\n        ...(input.errorsPath ? { errorsPath: input.errorsPath } : {}),\n      },\n      input.graph,\n      resolveTarget,\n      { connectorId: `k8s:${entry.id}`, ...(entry.intervalMs ? { intervalMs: entry.intervalMs } : {}) },\n    )\n    stops.push(stop)\n  }\n\n  return () => {\n    for (const stop of stops) stop()\n  }\n}\n","// The flag-store reader's enable path (ADR-242). A feature-flag store is a\n// dependency the services call, not a SaaS vendor, so it is not a `neat connector`\n// provider. Like the k8s substrate (ADR-224), the daemon reads a dedicated\n// `~/.neat/flag-stores.json` at slot bootstrap and polls each entry's endpoint for\n// the definitions the store is serving, folding them onto the flag grain through\n// ingest's `mergeObservedFlags`. The endpoint is configuration: how the daemon\n// reaches the store (in-cluster DNS, a port-forward, a NodePort) is the\n// operator's fact, never inferred.\n\nimport { readFile } from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport type { FlagDefinition } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport { mergeObservedFlags } from '../ingest.js'\nimport { fetchFlagdFlags } from './flagd-sync.js'\n\nexport interface FlagStoreEntry {\n  id: string\n  // Matches a registered project's name; omitted binds to whichever project the\n  // daemon is bootstrapping.\n  project?: string\n  // The provider, as compat.json's `flagStores` names it. Picks the reader.\n  provider: string\n  // How the daemon reaches the store's sync service, `host:port`.\n  endpoint: string\n  intervalMs?: number\n}\n\nexport interface FlagStoresConfig {\n  version: number\n  stores: FlagStoreEntry[]\n}\n\ntype FetchDefinitions = (endpoint: string) => Promise<Map<string, FlagDefinition>>\n\n// Provider → its reader. The one place a provider's protocol is named.\nconst READERS: Record<string, FetchDefinitions> = {\n  flagd: (endpoint) => fetchFlagdFlags(endpoint),\n}\n\nconst DEFAULT_INTERVAL_MS = 15_000\n\nfunction defaultHome(): string {\n  const override = process.env.NEAT_HOME\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(os.homedir(), '.neat')\n}\n\nexport function flagStoresConfigPath(home: string = defaultHome()): string {\n  return path.join(home, 'flag-stores.json')\n}\n\n// A missing or malformed file is an empty config, never a throw: most projects\n// configure no flag store.\nexport async function readFlagStoresConfig(home: string = defaultHome()): Promise<FlagStoresConfig> {\n  try {\n    const parsed = JSON.parse(await readFile(flagStoresConfigPath(home), 'utf8')) as FlagStoresConfig\n    if (!parsed || !Array.isArray(parsed.stores)) return { version: 1, stores: [] }\n    return parsed\n  } catch {\n    return { version: 1, stores: [] }\n  }\n}\n\nexport interface FlagStorePollResult {\n  ok: boolean\n  served?: number\n  undeclared?: string[]\n  error?: string\n}\n\n// One poll: fetch, fold. A failed fetch writes nothing, so the last observed\n// definitions stay as they were rather than being cleared by a network blip.\nexport async function pollFlagStore(\n  graph: NeatGraph,\n  entry: FlagStoreEntry,\n  fetchImpl?: FetchDefinitions,\n  now: () => string = () => new Date().toISOString(),\n): Promise<FlagStorePollResult> {\n  const fetchDefinitions = fetchImpl ?? READERS[entry.provider]\n  if (!fetchDefinitions) return { ok: false, error: `no reader for provider \"${entry.provider}\"` }\n  try {\n    const served = await fetchDefinitions(entry.endpoint)\n    const { undeclared } = mergeObservedFlags(graph, entry.provider, served, now())\n    return { ok: true, served: served.size, undeclared }\n  } catch (err) {\n    return { ok: false, error: (err as Error).message }\n  }\n}\n\nexport interface StartFlagStoresInput {\n  project: string\n  graph: NeatGraph\n  home?: string\n  onSkip?: (entry: FlagStoreEntry, reason: string) => void\n  // Test seam: stands in for the provider's reader.\n  fetchImpl?: FetchDefinitions\n}\n\nexport async function startFlagStorePolling(input: StartFlagStoresInput): Promise<() => void> {\n  const config = await readFlagStoresConfig(input.home)\n  const timers: NodeJS.Timeout[] = []\n  for (const entry of config.stores) {\n    if (entry.project !== undefined && entry.project !== input.project) continue\n    if (typeof entry.endpoint !== 'string' || entry.endpoint.length === 0) {\n      input.onSkip?.(entry, 'missing endpoint')\n      continue\n    }\n    if (!input.fetchImpl && !READERS[entry.provider]) {\n      input.onSkip?.(entry, `no reader for provider \"${entry.provider}\"`)\n      continue\n    }\n    // Report a change of state once, not every failing poll.\n    let lastError: string | undefined\n    const tick = async (): Promise<void> => {\n      const r = await pollFlagStore(input.graph, entry, input.fetchImpl)\n      if (!r.ok && r.error !== lastError) {\n        console.warn(`neat: flag store \"${entry.id}\" (${entry.provider} at ${entry.endpoint}) poll failed — ${r.error}`)\n      }\n      lastError = r.ok ? undefined : r.error\n    }\n    void tick()\n    const timer = setInterval(() => void tick(), entry.intervalMs ?? DEFAULT_INTERVAL_MS)\n    timer.unref?.()\n    timers.push(timer)\n  }\n  return () => {\n    for (const t of timers) clearInterval(t)\n  }\n}\n","import http2 from 'node:http2'\nimport type { FlagDefinition } from '@neat.is/types'\nimport { parseFlagDocument } from '../flags.js'\n\n// flagd's sync service (ADR-242): `flagd.sync.v1.FlagSyncService/FetchAllFlags`,\n// one unary gRPC call that returns every flag flagd is serving as a JSON document\n// in `flag_configuration` (field 1). It describes the flags; it does not evaluate\n// them, so a targeting change reads as the definition that changed rather than\n// as whatever variant one caller's context happened to get. The service has no\n// auth. Hand-rolled over Node's http2 because the whole exchange is one empty\n// request and one string field: no gRPC or protobuf dependency.\n\nconst FETCH_ALL_PATH = '/flagd.sync.v1.FlagSyncService/FetchAllFlags'\nconst DEFAULT_TIMEOUT_MS = 5_000\n\n// An empty FetchAllFlagsRequest, length-prefixed: uncompressed, zero bytes.\nconst EMPTY_REQUEST = Buffer.from([0, 0, 0, 0, 0])\n\nfunction readVarint(buf: Buffer, at: number): { value: number; next: number } {\n  let value = 0\n  let shift = 0\n  let i = at\n  for (;;) {\n    if (i >= buf.length) throw new Error('truncated varint')\n    const b = buf[i++]!\n    value += (b & 0x7f) * 2 ** shift\n    if ((b & 0x80) === 0) break\n    shift += 7\n  }\n  return { value, next: i }\n}\n\n// FetchAllFlagsResponse → its `flag_configuration` string. Unknown fields are\n// skipped by wire type, so a newer flagd that adds fields still decodes.\nexport function decodeFetchAllFlagsResponse(message: Buffer): string {\n  let i = 0\n  while (i < message.length) {\n    const tag = readVarint(message, i)\n    i = tag.next\n    const field = Math.floor(tag.value / 8)\n    const wire = tag.value & 7\n    if (wire === 2) {\n      const len = readVarint(message, i)\n      const start = len.next\n      const end = start + len.value\n      if (end > message.length) throw new Error('truncated field')\n      if (field === 1) return message.subarray(start, end).toString('utf8')\n      i = end\n    } else if (wire === 0) {\n      i = readVarint(message, i).next\n    } else if (wire === 1) {\n      i += 8\n    } else if (wire === 5) {\n      i += 4\n    } else {\n      throw new Error(`unsupported wire type ${wire}`)\n    }\n  }\n  throw new Error('no flag_configuration in response')\n}\n\n// One gRPC response body (possibly several length-prefixed frames) → the first\n// message's bytes.\nfunction firstMessage(body: Buffer): Buffer {\n  if (body.length < 5) throw new Error('empty gRPC response')\n  if (body[0] !== 0) throw new Error('compressed gRPC response not supported')\n  const len = body.readUInt32BE(1)\n  if (5 + len > body.length) throw new Error('truncated gRPC message')\n  return body.subarray(5, 5 + len)\n}\n\n// `host:port` (or a full http:// URL) → the definitions flagd is serving.\nexport async function fetchFlagdFlags(\n  endpoint: string,\n  timeoutMs = DEFAULT_TIMEOUT_MS,\n): Promise<Map<string, FlagDefinition>> {\n  const authority = /^https?:\\/\\//.test(endpoint) ? endpoint : `http://${endpoint}`\n  const body = await new Promise<Buffer>((resolve, reject) => {\n    const client = http2.connect(authority)\n    const timer = setTimeout(() => {\n      client.destroy()\n      reject(new Error(`flagd sync at ${endpoint} timed out after ${timeoutMs}ms`))\n    }, timeoutMs)\n    const fail = (err: Error): void => {\n      clearTimeout(timer)\n      client.destroy()\n      reject(err)\n    }\n    client.on('error', fail)\n    const req = client.request({\n      ':method': 'POST',\n      ':path': FETCH_ALL_PATH,\n      'content-type': 'application/grpc',\n      te: 'trailers',\n    })\n    const chunks: Buffer[] = []\n    let grpcStatus: string | undefined\n    let grpcMessage: string | undefined\n    req.on('response', (headers) => {\n      // A trailers-only error response carries the status in the headers.\n      if (headers['grpc-status'] !== undefined) grpcStatus = String(headers['grpc-status'])\n      if (headers['grpc-message'] !== undefined) grpcMessage = String(headers['grpc-message'])\n    })\n    req.on('trailers', (trailers) => {\n      if (trailers['grpc-status'] !== undefined) grpcStatus = String(trailers['grpc-status'])\n      if (trailers['grpc-message'] !== undefined) grpcMessage = String(trailers['grpc-message'])\n    })\n    req.on('data', (d: Buffer) => chunks.push(d))\n    req.on('error', fail)\n    req.on('end', () => {\n      clearTimeout(timer)\n      client.close()\n      if (grpcStatus !== undefined && grpcStatus !== '0') {\n        reject(new Error(`flagd sync returned grpc-status ${grpcStatus}${grpcMessage ? `: ${grpcMessage}` : ''}`))\n        return\n      }\n      resolve(Buffer.concat(chunks))\n    })\n    req.end(EMPTY_REQUEST)\n  })\n  const doc: unknown = JSON.parse(decodeFetchAllFlagsResponse(firstMessage(body)))\n  return parseFlagDocument(doc) ?? new Map()\n}\n","/**\n * Multi-project daemon (ADR-049).\n *\n * Single long-lived process watching every project in the machine-level registry.\n * Per-project graph isolation: each registered project owns its own\n * `MultiDirectedGraph` slot keyed by name (ADR-026), and a failure during\n * one project's bootstrap is logged + marked `broken` without taking down\n * the rest of the daemon.\n *\n * MVP scope (v0.2.5):\n *  - Read registry; refuse to boot when it's missing.\n *  - Write PID at `~/.neat/neatd.pid` for external supervisors.\n *  - Per project: load any existing snapshot, run initial extraction,\n *    start a per-project persist loop.\n *  - SIGHUP triggers a reload — re-reads the registry, picks up new\n *    projects, drops removed ones, leaves untouched ones in place.\n *  - Provide `routeSpanToProject(serviceName, projects)` for OTel ingest\n *    to dispatch by `service.name` across registered projects, falling\n *    back to `default` for unknown services per ADR-033.\n *\n * Out of MVP scope (deferred):\n *  - Live OTel listener wiring per project — daemon exposes the routing\n *    primitive; the actual receiver attachment lands alongside v0.2.6.\n *  - Policy reload on `policy.json` mtime — `startWatch` already does this\n *    per-project; the daemon-level loop reuses that machinery in a follow-up.\n *  - Auto-restart on crash. PID file is the supervisor handoff.\n */\n\nimport {\n  promises as fs,\n  watch,\n  renameSync,\n  unlinkSync,\n  writeFileSync,\n  type FSWatcher,\n} from 'node:fs'\nimport path from 'node:path'\nimport { createRequire } from 'node:module'\nimport type { FastifyInstance } from 'fastify'\nimport { DEFAULT_PROJECT, getGraph, resetGraph, type NeatGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { loadGraphFromDisk, saveGraphToDisk, startPersistLoop } from './persist.js'\nimport { Projects, pathsForProject, type ProjectPaths } from './projects.js'\nimport { buildApi } from './api.js'\nimport { buildOtelReceiver, listenSteppingOtlp } from './otel.js'\nimport { attachGraphToEventBus } from './events.js'\nimport { handleSpan, makeErrorSpanWriter, startStalenessLoop } from './ingest.js'\nimport { reconcileFrontierSurfaces } from './hang-sensor.js'\nimport type { ConnectorRegistration } from './connectors/index.js'\nimport { startConnectorPolling } from './connectors/registry.js'\nimport { maybeStartHostedConnectors } from './connectors/hosted.js'\nimport { maybeStartRepoSync, type RepoSyncRequestResult } from './connectors/hosted-repos.js'\nimport { startK8sSubstratePolling } from './connectors/kubernetes/index.js'\nimport { startFlagStorePolling } from './flag-stores/index.js'\nimport {\n  listProjects,\n  pruneRegistry,\n  registryPath,\n  setStatus,\n  touchLastSeen,\n  writeAtomically,\n} from './registry.js'\nimport { assertBindAuthority, readAuthEnv } from './auth.js'\nimport {\n  appendUnroutedSpan,\n  buildUnroutedSpanRecord,\n  unroutedErrorsPath,\n} from './unrouted.js'\nimport { NodeType, type RegistryEntry, type ServiceNode } from '@neat.is/types'\n\n// ── Per-project daemon self-description (ADR-096 / project-daemon contract) ──\n//\n// A project's daemon owns one file — `<project>/neat-out/daemon.json` — that\n// records where it bound and what it is serving. This is the single source of\n// truth for \"where is this project's daemon,\" read by the instrumentation (to\n// resolve its OTLP endpoint), the MCP config, the dashboard, and `neat ps`.\n//\n// The shape is pinned: the orchestrator persists `ports` here on first spawn\n// and reuses them on restart (§3), and the generated otel-init reads\n// `ports.otlp` to build its exporter endpoint. Anything that drifts from this\n// shape breaks the OBSERVED layer silently, so the read/write helpers live in\n// one place and every producer/consumer goes through them.\n\nexport interface DaemonPorts {\n  rest: number\n  otlp: number\n  web: number\n}\n\nexport interface DaemonRecord {\n  project: string\n  projectPath: string\n  pid: number\n  status: 'running' | 'stopped'\n  ports: DaemonPorts\n  startedAt: string\n  neatVersion: string\n}\n\n// `<project>/neat-out/daemon.json` — the authoritative per-project record.\nexport function daemonJsonPath(scanPath: string): string {\n  return path.join(scanPath, 'neat-out', 'daemon.json')\n}\n\n// Machine-wide discovery directory. Honors NEAT_HOME exactly as registry.ts /\n// neatHomeFor do so tests sandboxing under a temp home land here too.\nexport function daemonsDiscoveryDir(home?: string): string {\n  const base = home && home.length > 0 ? home : neatHomeFromEnv()\n  return path.join(base, 'daemons')\n}\n\n// `~/.neat/daemons/<project>.json` — a lock-free discovery copy (§6). Each\n// daemon owns only its own file; losing the directory costs `neat ps`\n// convenience, never correctness.\nexport function daemonDiscoveryPath(project: string, home?: string): string {\n  return path.join(daemonsDiscoveryDir(home), `${sanitizeDiscoveryName(project)}.json`)\n}\n\n// Keep the discovery filename to a safe single path segment. Project names are\n// basenames in practice, but a name carrying a separator must never escape the\n// daemons/ directory.\nfunction sanitizeDiscoveryName(project: string): string {\n  return project.replace(/[^A-Za-z0-9._-]/g, '_')\n}\n\nfunction neatHomeFromEnv(): string {\n  const env = process.env.NEAT_HOME\n  if (env && env.length > 0) return path.resolve(env)\n  const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n  return path.join(home, '.neat')\n}\n\n// Best-effort read of a project's daemon.json. Returns null when the file is\n// absent or malformed — callers treat that as \"no daemon recorded here\" rather\n// than failing, so a corrupt record never wedges spawn-vs-reuse.\nexport async function readDaemonRecord(scanPath: string): Promise<DaemonRecord | null> {\n  try {\n    const raw = await fs.readFile(daemonJsonPath(scanPath), 'utf8')\n    const parsed = JSON.parse(raw) as Partial<DaemonRecord>\n    if (\n      typeof parsed.project === 'string' &&\n      parsed.ports &&\n      typeof parsed.ports.rest === 'number' &&\n      typeof parsed.ports.otlp === 'number' &&\n      typeof parsed.ports.web === 'number'\n    ) {\n      return parsed as DaemonRecord\n    }\n    return null\n  } catch {\n    return null\n  }\n}\n\n// Resolve the running @neat.is/core version for the daemon.json stamp. Mirrors\n// neatd.ts#localVersion — NEAT_LOCAL_VERSION overrides for tests, else the\n// bundled package.json, else a safe sentinel.\nexport function resolveNeatVersion(): string {\n  if (process.env.NEAT_LOCAL_VERSION && process.env.NEAT_LOCAL_VERSION.length > 0) {\n    return process.env.NEAT_LOCAL_VERSION\n  }\n  try {\n    const req = createRequire(import.meta.url)\n    const pkg = req('../package.json') as { version?: string }\n    return typeof pkg.version === 'string' ? pkg.version : '0.0.0'\n  } catch {\n    return '0.0.0'\n  }\n}\n\n// Write the authoritative record + the machine-wide discovery copy, both\n// atomically (tmp + rename, §2). Best-effort on the discovery copy: it is a\n// read-optimization, so a failure to write it is logged but never aborts the\n// daemon. The neat-out/ record is the one that matters and bubbles its error.\nexport async function writeDaemonRecord(record: DaemonRecord, home?: string): Promise<void> {\n  const body = JSON.stringify(record, null, 2) + '\\n'\n  await writeAtomically(daemonJsonPath(record.projectPath), body)\n  try {\n    await writeAtomically(daemonDiscoveryPath(record.project, home), body)\n  } catch (err) {\n    console.warn(\n      `neatd: could not write discovery copy for \"${record.project}\" — ${(err as Error).message}`,\n    )\n  }\n}\n\n// Mark the record stopped (neat-out/) and clear the discovery copy on graceful\n// shutdown (§2/§6). The neat-out/ record is kept with status:\"stopped\" so a\n// later read can tell \"shut down cleanly\" from \"never ran\"; the discovery copy\n// is removed so `neat ps` stops listing a dead daemon. Both best-effort —\n// shutdown must not throw on a missing file.\nexport async function clearDaemonRecord(record: DaemonRecord, home?: string): Promise<void> {\n  try {\n    const stopped: DaemonRecord = { ...record, status: 'stopped' }\n    await writeAtomically(daemonJsonPath(record.projectPath), JSON.stringify(stopped, null, 2) + '\\n')\n  } catch {\n    // best-effort\n  }\n  try {\n    await fs.unlink(daemonDiscoveryPath(record.project, home))\n  } catch {\n    // best-effort — already gone is fine.\n  }\n}\n\n// Reconcile a daemon's self-description synchronously on an unsupervised exit\n// (project-daemon contract §2). The graceful `stop()` path already marks the\n// record stopped and clears the discovery copy; this is the backstop for a\n// crash or a fatal signal, where there's no chance to await async fs. A\n// process-exit handler runs synchronously, so we mark the neat-out/ record\n// `stopped` (tmp + renameSync keeps it atomic) and remove the discovery copy\n// with sync calls. Best-effort throughout: a missing or already-reconciled\n// file is fine, and a failure here must never throw out of an exit handler.\nexport function reconcileDaemonRecordSync(record: DaemonRecord, home?: string): void {\n  try {\n    const stopped: DaemonRecord = { ...record, status: 'stopped' }\n    const target = daemonJsonPath(record.projectPath)\n    const tmp = `${target}.${process.pid}.tmp`\n    writeFileSync(tmp, JSON.stringify(stopped, null, 2) + '\\n')\n    renameSync(tmp, target)\n  } catch {\n    // best-effort\n  }\n  try {\n    unlinkSync(daemonDiscoveryPath(record.project, home))\n  } catch {\n    // best-effort — already gone is fine.\n  }\n}\n\nexport interface DaemonOptions {\n  // Defaults to `~/.neat/`. Honors NEAT_HOME the same way registry.ts does.\n  // Tests override via NEAT_HOME and don't pass this directly.\n  neatHome?: string\n  // ADR-096 — when set, this daemon is scoped to exactly one project. It serves\n  // only that project, mounts a bare `/v1/traces` route that assigns every\n  // incoming span to it (no service.name routing), and writes its\n  // `daemon.json` self-description on start. `projectPath` is the project root\n  // (the directory whose `neat-out/` holds the record). Absent → the legacy\n  // multi-project daemon behaviour.\n  project?: string\n  projectPath?: string\n  // Dashboard/web port to record in daemon.json. The daemon doesn't bind this\n  // itself (neatd spawns the web UI), but it owns the record, so it stamps the\n  // allocated value the orchestrator passed through.\n  webPort?: number\n  // ADR-063 — bind targets. Defaults to PORT (8080) / OTEL_PORT (4318) env\n  // vars, matching server.ts. Tests pass 0 to get ephemeral ports.\n  restPort?: number\n  otlpPort?: number\n  // ADR-063 — bind host. Defaults to HOST env (0.0.0.0).\n  host?: string\n  // ADR-063 — opt out of binding entirely (e.g. integration tests that\n  // exercise daemon slots without needing the listeners). Production\n  // `neatd start` never sets this.\n  bindListeners?: boolean\n  // Connectors plane (docs/contracts/connectors.md, ADR-124) — pull-based\n  // OBSERVED connectors polled on an interval alongside every project this\n  // daemon bootstraps, the same way every project gets the staleness loop.\n  // These are applied to every project slot programmatically; on top of them,\n  // each slot also loads its own project-matched connectors from\n  // `~/.neat/connectors.json` at bootstrap (ADR-130, connector-config.md §6 —\n  // resolved through the dispatch table in connectors/registry.ts). The two\n  // sources merge: file-configured connectors join whatever a caller passes\n  // here.\n  connectors?: ConnectorRegistration[]\n}\n\nexport interface ProjectSlot {\n  entry: RegistryEntry\n  graph: NeatGraph\n  outPath: string\n  paths: ProjectPaths\n  stopPersist: () => void\n  // Stops the OBSERVED→STALE clock-decay loop for this slot. Runs on the same\n  // 60s cadence as `neat watch`, so the daemon keeps the STALE provenance state\n  // current: once OBSERVED traffic quiets, edges past their threshold decay to\n  // STALE instead of sitting live forever. Must be stopped alongside\n  // stopPersist so no interval leaks when the slot is torn down or replaced.\n  stopStaleness: () => void\n  // Stops every connector poll loop registered for this slot (connectors/\n  // index.ts's startConnectorPollLoop, one per opts.connectors entry). Same\n  // lifecycle as stopStaleness — must run alongside it wherever the slot is\n  // torn down or replaced.\n  stopConnectors: () => void\n  // Stops every hosted-profile connector poll loop for this slot (connectors/\n  // hosted.ts, INFRA-ADR-011) — the connectors the control plane brokers, active\n  // only when the hosted env is set. No-op on a local daemon. Same lifecycle as\n  // stopConnectors.\n  stopHostedConnectors: () => void\n  // Stops every k8s deployment-substrate poll loop for this slot (ADR-224) —\n  // the observed cluster-state reader, enabled off `~/.neat/k8s.json` rather than\n  // the `neat connector` vendor surface. Same lifecycle as stopConnectors.\n  stopK8sSubstrate: () => void\n  stopFlagStores: () => void\n  // Stops the hosted repo-sync loop for this slot (connectors/hosted-repos.ts,\n  // INFRA-ADR-011 / #19) — the GitHub repos the control plane says are bound to\n  // this project, cloned + extracted into the graph. No-op on a local daemon.\n  // Same lifecycle as stopHostedConnectors.\n  stopRepoSync: () => void\n  // Runs a repo-sync pass now instead of waiting for the timer (#1293). Present\n  // only on a hosted daemon — the REST `repo-sync` route answers from it.\n  syncRepos?: () => RepoSyncRequestResult\n  // #475 — removes the event-bus listeners attachGraphToEventBus installed\n  // on this slot's graph. No-op for broken slots. Must run wherever the slot\n  // is torn down or replaced, or a reloaded slot's old graph keeps emitting.\n  detachEvents: () => void\n  status: 'active' | 'broken'\n  errorReason?: string\n}\n\n// Best-effort slot teardown — stop the persist loop and detach the slot's\n// graph from the event bus (#475). Every path that drops or replaces a slot\n// (registry removal, daemon stop, bind-failure rollback, broken-slot\n// recovery) goes through here so no path leaks listeners.\nfunction teardownSlot(slot: ProjectSlot): void {\n  try {\n    slot.stopPersist()\n  } catch {\n    // best-effort\n  }\n  try {\n    slot.stopStaleness()\n  } catch {\n    // best-effort\n  }\n  try {\n    slot.stopConnectors()\n  } catch {\n    // best-effort\n  }\n  try {\n    slot.stopHostedConnectors()\n  } catch {\n    // best-effort\n  }\n  try {\n    slot.stopK8sSubstrate()\n    slot.stopFlagStores()\n  } catch {\n    // best-effort\n  }\n  try {\n    slot.stopRepoSync()\n  } catch {\n    // best-effort\n  }\n  try {\n    slot.detachEvents()\n  } catch {\n    // best-effort\n  }\n}\n\n// Issue #340 — per-project bootstrap state surface. The REST listener\n// flips to live the moment `app.listen()` returns; per-project routes\n// branch on this rather than waiting for every registered project's\n// extractFromDirectory pass to finish.\nexport type BootstrapPhase = 'bootstrapping' | 'active' | 'broken'\n\nexport interface BootstrapTracker {\n  status: (name: string) => BootstrapPhase | undefined\n  list: () => Array<{ name: string; status: BootstrapPhase; elapsedMs: number }>\n}\n\nexport interface DaemonHandle {\n  // The slots currently being managed, keyed by project name. Tests inspect\n  // this to assert isolation properties.\n  slots: Map<string, ProjectSlot>\n  // Re-read the registry. New entries get bootstrapped, removed ones get\n  // their persist loops stopped, existing ones stay running.\n  reload: () => Promise<void>\n  // Graceful shutdown — stop every project's persist loop and remove the\n  // PID file.\n  stop: () => Promise<void>\n  // Path to the PID file the daemon owns. Useful for test assertions.\n  pidPath: string\n  // ADR-063 — addresses where consumers reach the daemon. Empty string when\n  // bindListeners is false. REST is the Fastify app's listening address;\n  // OTLP is the receiver's.\n  restAddress: string\n  otlpAddress: string\n  // Issue #340 — per-project bootstrap status, surfaced for orchestrator\n  // poll loops and tests.\n  bootstrap: BootstrapTracker\n  // Resolves when the daemon's initial bootstrap pass has settled. Tests\n  // that probe project-scoped routes immediately after startDaemon await\n  // this; production callers use /health.\n  initialBootstrap: Promise<void>\n  // ADR-096 — the per-project self-description this daemon wrote, or null in\n  // the legacy multi-project mode. Tests assert the persisted ports + status.\n  daemonRecord: DaemonRecord | null\n  // The resolved NEAT_HOME this daemon discovers under. The entrypoint needs it\n  // to clear the right discovery copy when it reconciles daemon.json on an\n  // unsupervised exit (project-daemon contract §2).\n  neatHome: string\n}\n\nfunction neatHomeFor(opts: DaemonOptions): string {\n  if (opts.neatHome && opts.neatHome.length > 0) return path.resolve(opts.neatHome)\n  const env = process.env.NEAT_HOME\n  if (env && env.length > 0) return path.resolve(env)\n  const home = process.env.HOME ?? process.env.USERPROFILE ?? ''\n  return path.join(home, '.neat')\n}\n\n/**\n * Resolve which project's graph an OTel span belongs to. Looks up the\n * `service.name` against the registry and returns the matching project's\n * name, or `DEFAULT_PROJECT` for unknown services so the FrontierNode\n * auto-creation flow keeps working per ADR-033.\n *\n * Pure function. Daemon callers pass a snapshot of the registry to avoid\n * per-span fs reads.\n *\n * Matching order (ADR-072 — real-world `service.name` rarely equals project\n * name; monorepos publish per-package names like `brief-api` under a\n * project named `brief`):\n *\n *   1. Exact: `entry.name === serviceName`.\n *   2. Hyphen/underscore-separated prefix: `entry.name` is a leading token\n *      of `serviceName` (`brief` matches `brief-api`, `brief_worker`).\n *      Longest-match wins so `brief-api` beats `brief` when both are\n *      registered.\n *   3. Containment as a separator-delimited token (`api` inside\n *      `brief-api-staging`).\n *\n * Routing eligibility (ADR-071):\n * - `active` matches at every pass (the steady-state path).\n * - `broken` also matches — the daemon needs the span to reach the broken\n *   slot so the ingest-time auto-recover path can attempt a bootstrap and\n *   lift the project back to `active`. The router only chooses the target;\n *   whether the span actually lands is the ingest handler's decision.\n * - `paused` is intentionally not routed; the operator paused it on\n *   purpose, so the span falls through to the default-project flow.\n *\n * Falls back to `DEFAULT_PROJECT` when nothing matches.\n */\nexport function routeSpanToProject(\n  serviceName: string | undefined,\n  projects: ReadonlyArray<RegistryEntry>,\n): string {\n  if (!serviceName) return DEFAULT_PROJECT\n  // Pass 1 — exact match, case-insensitive. `OTEL_SERVICE_NAME` is frequently a\n  // lower-cased or differently-cased form of the registered project name (a\n  // package name vs a display name), and a case-only mismatch used to fall all\n  // the way through to the default/unrouted path — the span silently discarded\n  // on a by-the-book install (#879). The registered `entry.name` is still what\n  // we return, so the canonical casing is preserved downstream.\n  for (const entry of projects) {\n    if (entry.status === 'paused') continue\n    if (entry.name.toLowerCase() === serviceName.toLowerCase()) return entry.name\n  }\n  // Pass 2 — hyphen/underscore-separated prefix. Longest project name wins\n  // so a registered `brief-api` outranks a registered `brief` when the\n  // span's service.name is `brief-api-staging`.\n  const candidates: RegistryEntry[] = []\n  for (const entry of projects) {\n    if (entry.status === 'paused') continue\n    if (isTokenPrefix(entry.name, serviceName)) candidates.push(entry)\n  }\n  if (candidates.length > 0) {\n    candidates.sort((a, b) => b.name.length - a.name.length)\n    return candidates[0]!.name\n  }\n  // Pass 3 — containment as a separator-delimited token. Last-resort match\n  // for `api` inside `brief-api-staging` when only `api` is registered.\n  for (const entry of projects) {\n    if (entry.status === 'paused') continue\n    if (isTokenContained(entry.name, serviceName)) return entry.name\n  }\n  return DEFAULT_PROJECT\n}\n\n// True when `prefix` matches the first hyphen/underscore-separated token(s)\n// of `full`. `brief` matches `brief-api`, `brief_worker`, but not `briefcase`.\n// Case-insensitive (#879) — a span's service.name and the project name routinely\n// differ only in case.\nfunction isTokenPrefix(prefix: string, full: string): boolean {\n  const p = prefix.toLowerCase()\n  const f = full.toLowerCase()\n  if (p.length >= f.length) return false\n  if (!f.startsWith(p)) return false\n  const sep = f.charAt(p.length)\n  return sep === '-' || sep === '_'\n}\n\n// True when `needle` appears in `haystack` bordered by separators on both\n// sides (so it's a complete token, not a substring of a longer word).\n// Case-insensitive (#879), same reasoning as isTokenPrefix.\nfunction isTokenContained(needle: string, haystack: string): boolean {\n  const n = needle.toLowerCase()\n  const h = haystack.toLowerCase()\n  if (!h.includes(n)) return false\n  const tokens = h.split(/[-_]/)\n  return tokens.includes(n)\n}\n\n// Does this span's `service.name` belong to the single project this daemon\n// hosts? Single-project mode (ADR-096) binds the bare `/v1/traces` route to one\n// project, but the OS-default OTLP endpoint (`localhost:4318`) is shared: a\n// sibling service from a *different* project that exports with default settings\n// lands here too. Merging its spans would mint that service's ServiceNode +\n// incidents into this project's graph — cross-project contamination. We scope\n// delivery to the project's owned services and quarantine the rest.\n//\n// A span is owned when:\n//   - it carries no `service.name` (SDK misconfig in this project's own app;\n//     handleSpan routes it to `service:unidentified`, refs #374), or\n//   - its `service.name` matches the project name the same way the multi-\n//     project router matches (exact / token-prefix / token-contained — covers\n//     the monorepo case where `brief` owns `brief-api`, `brief-worker`), or\n//   - a ServiceNode with that name already exists in the project's graph\n//     (statically extracted, or observed-and-adopted on an earlier span).\n//\n// Everything else is foreign and gets quarantined to the unrouted ledger rather\n// than merged. The trade is deliberate: a brand-new service of this project that\n// NEAT can't statically read and whose name doesn't echo the project name has\n// its first spans quarantined until extraction registers it — a far smaller\n// failure than an entire sibling project bleeding into this graph.\nfunction serviceNameMatchesProject(serviceName: string, project: string): boolean {\n  if (serviceName.toLowerCase() === project.toLowerCase()) return true\n  if (isTokenPrefix(project, serviceName)) return true\n  if (isTokenContained(project, serviceName)) return true\n  return false\n}\n\nfunction spanBelongsToSingleProject(\n  graph: NeatGraph,\n  project: string,\n  serviceName: string | undefined,\n): boolean {\n  if (!serviceName) return true\n  if (serviceNameMatchesProject(serviceName, project)) return true\n  return graph.someNode(\n    (_id, attrs) =>\n      attrs.type === NodeType.ServiceNode &&\n      (attrs as ServiceNode).name === serviceName,\n  )\n}\n\nasync function bootstrapProject(\n  entry: RegistryEntry,\n  connectors: ConnectorRegistration[] = [],\n  neatHome?: string,\n): Promise<ProjectSlot> {\n  const paths = pathsForProject(entry.name, path.join(entry.path, 'neat-out'))\n\n  // Path missing on disk → mark broken and surface the reason. Daemon\n  // continues with the rest of the registry.\n  try {\n    const stat = await fs.stat(entry.path)\n    if (!stat.isDirectory()) {\n      throw new Error(`registered path ${entry.path} is not a directory`)\n    }\n  } catch (err) {\n    await setStatus(entry.name, 'broken').catch(() => {})\n    return {\n      entry,\n      // Empty graph is fine — `slots` keeps the entry visible in `status`\n      // output; nothing routes to it because it's not 'active'.\n      graph: getGraph(`__broken__:${entry.name}`),\n      outPath: '',\n      paths,\n      stopPersist: () => {},\n      stopStaleness: () => {},\n      stopConnectors: () => {},\n      stopHostedConnectors: () => {},\n      stopK8sSubstrate: () => {},\n      stopFlagStores: () => {},\n      stopRepoSync: () => {},\n      detachEvents: () => {},\n      status: 'broken',\n      errorReason: (err as Error).message,\n    }\n  }\n\n  // Use the project name as the in-memory graph key. Any prior contents\n  // are wiped because the daemon owns the slot for the lifetime of this\n  // bootstrap (ADR-030 — mutation authority).\n  resetGraph(entry.name)\n  const graph = getGraph(entry.name)\n  const outPath = paths.snapshotPath\n\n  await loadGraphFromDisk(graph, outPath)\n  // #475 — wire graph mutations into the event bus (ADR-051) before extract\n  // begins so the initial pass also produces node/edge events, mirroring\n  // startWatch. Without this the daemon's SSE stream carries heartbeats and\n  // nothing else: handleSse subscribes to a bus no producer feeds, and the\n  // dashboard only catches up on a manual refresh.\n  const detachEvents = attachGraphToEventBus(graph, { project: entry.name })\n  try {\n    // The boot pass names the project as its source (ADR-233). On a hosted\n    // tenant `entry.path` holds no code — the source lives in bound repos that\n    // re-sync *after* boot — so a pass with no source found nothing here and\n    // retired the whole restored EXTRACTED layer (#1291). Naming one keeps the\n    // sweep to files this pass owns, which on a tenant is none of them.\n    await extractFromDirectory(graph, entry.path, { source: entry.name })\n    // The daemon owns shutdown, so the persist loop must not exit the process\n    // on a signal — that would end us before `stop()` clears the daemon.json,\n    // discovery copy, and pid file. `stop()` flushes this graph one last time\n    // as it tears the slot down (see below).\n    const stopPersist = startPersistLoop(graph, outPath, { exitOnSignal: false })\n    // Keep the STALE provenance state maintained on the shipped daemon path,\n    // the same way `neat watch` does. Once OBSERVED traffic quiets, this loop\n    // ticks markStaleEdges so edges past their threshold decay to STALE and the\n    // transition lands in this slot's stale-events.ndjson — exactly where the\n    // REST `/stale-events` route reads them back from.\n    const stopStaleness = startStalenessLoop(graph, {\n      staleEventsPath: paths.staleEventsPath,\n      project: entry.name,\n      // Graduate FRONTIER surfaces whose OBSERVED twin has arrived + stage surfaces\n      // for current hangs (ADR-226), each post-ingest tick — the periodic point\n      // where OBSERVED state has settled and the errors ledger is current.\n      onReconcile: (g) => reconcileFrontierSurfaces(g, paths.errorsPath),\n    })\n    // Connectors plane (docs/contracts/connectors.md, ADR-124; on-ramp\n    // ADR-130) — every project-matched entry in `~/.neat/connectors.json`\n    // becomes a registration here, resolved through\n    // the dispatch table so no provider specifics leak into this file. The\n    // env-ref credential resolves now, into memory only, and never reaches\n    // the snapshot (connector-config.md §6). A bad entry is skipped with a\n    // log, never fatal to the slot; these merge with any registrations a\n    // programmatic caller passed in `opts.connectors`.\n    // One poll loop per registered connector (file-configured + any passed in\n    // opts.connectors), torn down alongside the staleness loop (teardownSlot).\n    // `connectorId` lands each tick in the status tracker the connector-status\n    // endpoint reads (ADR-136); the shared helper is the same path `neat watch`\n    // uses so both serve connectors identically (#871).\n    const stopConnectors = await startConnectorPolling({\n      project: entry.name,\n      graph,\n      projectDir: entry.path,\n      // The slot's incident ledger, so an incident-emitting connector (ADR-185)\n      // writes a build-failure incident onto the same errors.ndjson OTLP-derived\n      // incidents land in.\n      errorsPath: paths.errorsPath,\n      ...(neatHome ? { home: neatHome } : {}),\n      extra: connectors,\n      onSkip: (skipped, reason) =>\n        console.warn(\n          `neatd: connector \"${skipped.id}\" (${skipped.provider}) skipped for project \"${entry.name}\" — ${reason}`,\n        ),\n    })\n    // Hosted-profile connectors (connectors/hosted.ts, INFRA-ADR-011) — the\n    // providers the control plane brokers on the customer's behalf. Active only\n    // when the hosted env is present (NEAT_CP_URL + NEAT_CP_PROJECT_ID +\n    // NEAT_AUTH_TOKEN, injected by the provisioner); a no-op on a local daemon,\n    // so this line is additive and the local path is unchanged. Each discovered\n    // connection runs the SAME poll loop as a file-configured one, differing only\n    // in where the credential comes from — the CP, pulled fresh per tick.\n    const stopHostedConnectors = await maybeStartHostedConnectors({\n      project: entry.name,\n      graph,\n      projectDir: entry.path,\n      errorsPath: paths.errorsPath,\n      onSkip: (provider, reason) =>\n        console.warn(`neatd: hosted connector \"${provider}\" skipped for project \"${entry.name}\" — ${reason}`),\n    })\n    // The k8s deployment substrate (ADR-224) — the observed cluster-state reader,\n    // enabled off `~/.neat/k8s.json` rather than the `neat connector` vendor\n    // surface, run through the same poll/incident plumbing as the connectors.\n    const stopK8sSubstrate = await startK8sSubstratePolling({\n      project: entry.name,\n      graph,\n      projectDir: entry.path,\n      errorsPath: paths.errorsPath,\n      ...(neatHome ? { home: neatHome } : {}),\n      onSkip: (skipped, reason) =>\n        console.warn(`neatd: k8s substrate \"${skipped.id}\" skipped for project \"${entry.name}\" — ${reason}`),\n    })\n    // The flag-store reader (ADR-242): what each configured feature-flag store is\n    // serving, folded onto the flag grain, enabled off `~/.neat/flag-stores.json`.\n    const stopFlagStores = await startFlagStorePolling({\n      project: entry.name,\n      graph,\n      ...(neatHome ? { home: neatHome } : {}),\n      onSkip: (skipped, reason) =>\n        console.warn(`neatd: flag store \"${skipped.id}\" skipped for project \"${entry.name}\" — ${reason}`),\n    })\n    // Hosted repo source (connectors/hosted-repos.ts, INFRA-ADR-011 / #19) — the\n    // GitHub repos the control plane says are bound to this project. Active only\n    // when the hosted env is present (same NEAT_CP_URL + NEAT_CP_PROJECT_ID +\n    // NEAT_AUTH_TOKEN as the hosted connectors); a no-op on a local daemon, which\n    // extracts its mounted /workspace instead. Each bound repo is shallow-cloned\n    // and extracted into this slot's graph, then its status reported back.\n    const stopRepoSync = await maybeStartRepoSync({\n      project: entry.name,\n      graph,\n      onSkip: (repo, reason) =>\n        console.warn(`neatd: repo-sync \"${repo}\" skipped for project \"${entry.name}\" — ${reason}`),\n      onError: (repo, err) =>\n        console.warn(`neatd: repo-sync \"${repo}\" failed for project \"${entry.name}\" — ${err.message}`),\n    })\n    await touchLastSeen(entry.name).catch(() => {})\n\n    return {\n      entry,\n      graph,\n      outPath,\n      paths,\n      stopPersist,\n      stopStaleness,\n      stopConnectors,\n      stopHostedConnectors,\n      stopK8sSubstrate,\n      stopFlagStores,\n      stopRepoSync,\n      ...(stopRepoSync.syncNow ? { syncRepos: stopRepoSync.syncNow } : {}),\n      detachEvents,\n      status: 'active',\n    }\n  } catch (err) {\n    // Bootstrap died after the attach — detach before surfacing so a failed\n    // slot can't leave listeners behind on its orphaned graph.\n    detachEvents()\n    throw err\n  }\n}\n\nfunction resolveRestPort(opts: DaemonOptions): number {\n  if (typeof opts.restPort === 'number') return opts.restPort\n  const env = process.env.PORT\n  if (env && env.length > 0) {\n    const n = Number.parseInt(env, 10)\n    if (Number.isFinite(n)) return n\n  }\n  return 8080\n}\n\nfunction resolveOtlpPort(opts: DaemonOptions): number {\n  if (typeof opts.otlpPort === 'number') return opts.otlpPort\n  const env = process.env.OTEL_PORT\n  if (env && env.length > 0) {\n    const n = Number.parseInt(env, 10)\n    if (Number.isFinite(n)) return n\n  }\n  return 4318\n}\n\n// The web/dashboard port the daemon records in daemon.json. The daemon never\n// binds it (neatd spawns the web child), but it owns the self-description, so\n// it stamps the resolved value. NEAT_WEB_PORT overrides the canonical 6328.\nfunction resolveWebPort(): number {\n  const env = process.env.NEAT_WEB_PORT\n  if (env && env.length > 0) {\n    const n = Number.parseInt(env, 10)\n    if (Number.isFinite(n)) return n\n  }\n  return 6328\n}\n\n// Read the real bound port off a Fastify listen address (`http://host:port`).\n// When the requested port was 0 the kernel chose one, and daemon.json must\n// record what the app should actually reach — not the 0 we asked for. Falls\n// back to the requested port if the address can't be parsed.\nexport function portFromListenAddress(address: string, fallback: number): number {\n  try {\n    const port = new URL(address).port\n    const n = Number.parseInt(port, 10)\n    if (Number.isFinite(n) && n > 0) return n\n  } catch {\n    // fall through\n  }\n  return fallback\n}\n\nexport function resolveHost(opts: DaemonOptions, authTokenSet: boolean): string {\n  if (opts.host && opts.host.length > 0) return opts.host\n  const env = process.env.HOST\n  if (env && env.length > 0) return env\n  // Issue #341 — loopback-only default when the operator hasn't set a token.\n  // Public-bind on a clean install demanded one before binding could\n  // succeed, so the npx-`neat .` first-touch path used to refuse to come up;\n  // pinning to 127.0.0.1 lets that path bind cleanly. Anyone wanting a\n  // public bind sets `NEAT_AUTH_TOKEN` (and `HOST=0.0.0.0` if they want it\n  // spelled out). `assertBindAuthority` stays exactly as it is — the\n  // contract is right; the default was wrong.\n  if (!authTokenSet) return '127.0.0.1'\n  return '0.0.0.0'\n}\n\nexport async function startDaemon(opts: DaemonOptions = {}): Promise<DaemonHandle> {\n  const home = neatHomeFor(opts)\n  const regPath = registryPath()\n\n  // ADR-096 — single-project mode. The orchestrator spawns a daemon scoped to\n  // one project, passing its name + root. In that mode the daemon serves only\n  // that project: it bootstraps the one slot, mounts a bare `/v1/traces` route\n  // that assigns every span to it, and writes its `daemon.json`\n  // self-description. The legacy multi-project path (no opts.project) is left\n  // intact so nothing on main breaks while Wave 2 retires the registry.\n  //\n  // The mode resolves from explicit opts first (the production path: neatd\n  // reads NEAT_PROJECT/NEAT_PROJECT_PATH and passes them through), falling\n  // back to the env directly so a bare `NEAT_PROJECT=… neatd start` works too.\n  const projectArg =\n    typeof opts.project === 'string' && opts.project.length > 0\n      ? opts.project\n      : process.env.NEAT_PROJECT && process.env.NEAT_PROJECT.length > 0\n        ? process.env.NEAT_PROJECT\n        : null\n  const projectPathArg =\n    opts.projectPath && opts.projectPath.length > 0\n      ? opts.projectPath\n      : process.env.NEAT_PROJECT_PATH && process.env.NEAT_PROJECT_PATH.length > 0\n        ? process.env.NEAT_PROJECT_PATH\n        : null\n  const singleProject = projectArg\n  const singleProjectPath =\n    singleProject && projectPathArg ? path.resolve(projectPathArg) : null\n  if (singleProject && !singleProjectPath) {\n    throw new Error(\n      `neatd: project \"${singleProject}\" given without a projectPath; pass NEAT_PROJECT_PATH alongside NEAT_PROJECT.`,\n    )\n  }\n\n  // Graceful degradation per ADR-049 #6: missing registry refuses to boot\n  // with a clear error rather than silently coming up empty. A single-project\n  // daemon takes its project from spawn args, not the registry, so it doesn't\n  // gate on the registry file existing.\n  if (!singleProject) {\n    try {\n      await fs.access(regPath)\n    } catch {\n      throw new Error(\n        `neatd: registry not found at ${regPath}. Run \\`neat init <path>\\` to register a project before starting the daemon.`,\n      )\n    }\n  }\n\n  const pidPath = path.join(home, 'neatd.pid')\n  await writeAtomically(pidPath, `${process.pid}\\n`)\n\n  const slots = new Map<string, ProjectSlot>()\n  // Projects registry mirrors slots for the REST listener (ADR-063). buildApi\n  // reads from this; we keep it in sync as slots come and go.\n  const registry = new Projects()\n  // Issue #340 — per-project bootstrap status. Populated from the registry\n  // before the listener binds so the REST handlers can return 503 instead of\n  // 404 for projects still extracting.\n  const bootstrapStatus = new Map<string, BootstrapPhase>()\n  const bootstrapStartedAt = new Map<string, number>()\n\n  // Rate-limit the dropped-span warning to one log line per project per\n  // 60 seconds. OTel exporters retry on a tight cadence; without this we\n  // flood the console with the same line per batch when a broken project\n  // is sitting in the registry.\n  const DROP_WARN_INTERVAL_MS = 60_000\n  const lastDropWarnAt = new Map<string, number>()\n  function warnDroppedSpan(project: string, reason: string): void {\n    const now = Date.now()\n    const prev = lastDropWarnAt.get(project) ?? 0\n    if (now - prev < DROP_WARN_INTERVAL_MS) return\n    lastDropWarnAt.set(project, now)\n    console.warn(\n      `[neatd] dropping span for project \"${project}\" — project status: broken (${reason}). Run \\`neatd reload\\` to retry bootstrap.`,\n    )\n  }\n\n  // v0.4.1 / refs #339 — when a span's `service.name` doesn't match any\n  // registered project AND no `default` project is registered, the span has\n  // nowhere to land. We still return 200 on the receiver (OTel spec) but the\n  // event lands in <NEAT_HOME>/errors.ndjson so the next operator can see\n  // what happened instead of the daemon's stderr being the only signal.\n  // Same rate limit as the broken-project warning, keyed by service.name.\n  const unroutedPath = unroutedErrorsPath(home)\n  const lastUnroutedWarnAt = new Map<string, number>()\n  async function recordUnroutedSpan(\n    serviceName: string | undefined,\n    traceId: string | undefined,\n  ): Promise<void> {\n    const key = serviceName ?? '<missing>'\n    const now = Date.now()\n    try {\n      await appendUnroutedSpan(home, buildUnroutedSpanRecord(serviceName, traceId, new Date(now)))\n    } catch {\n      // best-effort — failing to log shouldn't cascade into receiver failure.\n    }\n    const prev = lastUnroutedWarnAt.get(key) ?? 0\n    if (now - prev < DROP_WARN_INTERVAL_MS) return\n    lastUnroutedWarnAt.set(key, now)\n    console.warn(\n      `[neatd] dropping span — service.name \"${key}\" matches no registered project and no \\`default\\` project exists. See ${unroutedPath}.`,\n    )\n  }\n\n  function upsertRegistryFromSlot(slot: ProjectSlot): void {\n    if (slot.status !== 'active') return\n    registry.set(slot.entry.name, {\n      scanPath: slot.entry.path,\n      paths: slot.paths,\n      graph: slot.graph,\n    })\n  }\n\n  // Attempt to bring a broken slot back online. Used both on SIGHUP reload\n  // and inline on ingest when a span arrives for a broken project. Returns\n  // the new slot status so callers can decide whether to deliver the span.\n  async function tryRecoverSlot(entry: RegistryEntry): Promise<ProjectSlot> {\n    try {\n      const fresh = await bootstrapProject(entry, opts.connectors ?? [], home)\n      // The slot being replaced must release its graph's bus listeners\n      // (#475) — a stale attach on the prior graph would double-emit.\n      const prior = slots.get(entry.name)\n      if (prior) teardownSlot(prior)\n      slots.set(entry.name, fresh)\n      upsertRegistryFromSlot(fresh)\n      if (fresh.status === 'active') {\n        await setStatus(entry.name, 'active').catch(() => {})\n        console.log(\n          `neatd: project \"${entry.name}\" recovered from broken — active`,\n        )\n      }\n      return fresh\n    } catch (err) {\n      console.warn(\n        `neatd: project \"${entry.name}\" still broken after recovery attempt — ${(err as Error).message}`,\n      )\n      // Leave the existing broken slot in place; nothing changed.\n      return slots.get(entry.name)!\n    }\n  }\n\n  async function bootstrapOne(entry: RegistryEntry): Promise<void> {\n    bootstrapStatus.set(entry.name, 'bootstrapping')\n    bootstrapStartedAt.set(entry.name, Date.now())\n    try {\n      const slot = await bootstrapProject(entry, opts.connectors ?? [], home)\n      // Same replacement rule as tryRecoverSlot (#475).\n      const prior = slots.get(entry.name)\n      if (prior) teardownSlot(prior)\n      slots.set(entry.name, slot)\n      upsertRegistryFromSlot(slot)\n      bootstrapStatus.set(entry.name, slot.status === 'broken' ? 'broken' : 'active')\n      if (slot.status === 'broken') {\n        console.warn(`neatd: project \"${entry.name}\" broken — ${slot.errorReason}`)\n      } else {\n        console.log(`neatd: project \"${entry.name}\" active (${entry.path})`)\n      }\n    } catch (err) {\n      bootstrapStatus.set(entry.name, 'broken')\n      console.warn(\n        `neatd: project \"${entry.name}\" failed to bootstrap — ${(err as Error).message}`,\n      )\n      await setStatus(entry.name, 'broken').catch(() => {})\n    }\n  }\n\n  // The set of projects this daemon manages. Single-project mode (ADR-096)\n  // takes its one project from spawn args and never reads the registry for the\n  // project list; the legacy daemon enumerates every registered project.\n  async function enumerateProjects(): Promise<RegistryEntry[]> {\n    if (singleProject && singleProjectPath) {\n      return [\n        {\n          name: singleProject,\n          path: singleProjectPath,\n          registeredAt: new Date().toISOString(),\n          languages: [],\n          status: 'active',\n        },\n      ]\n    }\n    return listProjects()\n  }\n\n  async function loadAll(): Promise<void> {\n    // #463 — drop long-dead entries before bootstrapping the rest. An entry\n    // whose path is gone (definite ENOENT) and that's been quiet past the TTL\n    // gets removed instead of marked `broken` and logged forever. Conservative\n    // by design: a transient stat error or a fresh ENOENT entry stays, and the\n    // staleness TTL is the safety margin. Best-effort — a prune failure never\n    // blocks the daemon from coming up. A single-project daemon owns no\n    // registry coordination, so it skips the prune entirely.\n    if (!singleProject) {\n      try {\n        const pruned = await pruneRegistry()\n        for (const entry of pruned) {\n          console.log(\n            `neatd: pruned project \"${entry.name}\" — registered path ${entry.path} is gone`,\n          )\n          slots.delete(entry.name)\n          bootstrapStatus.delete(entry.name)\n          bootstrapStartedAt.delete(entry.name)\n        }\n      } catch (err) {\n        console.warn(`neatd: registry prune skipped — ${(err as Error).message}`)\n      }\n    }\n\n    const projects = await enumerateProjects()\n    const seen = new Set<string>()\n    const pending: Promise<void>[] = []\n    for (const entry of projects) {\n      seen.add(entry.name)\n      const existing = slots.get(entry.name)\n      if (existing) {\n        if (existing.status === 'broken') {\n          pending.push(tryRecoverSlot(entry).then(() => {}))\n        }\n        continue\n      }\n      pending.push(bootstrapOne(entry))\n    }\n    for (const [name, slot] of [...slots.entries()]) {\n      if (seen.has(name)) continue\n      teardownSlot(slot)\n      slots.delete(name)\n      bootstrapStatus.delete(name)\n      bootstrapStartedAt.delete(name)\n      console.log(`neatd: project \"${name}\" removed from registry — stopped`)\n    }\n    await Promise.allSettled(pending)\n  }\n\n  // Issue #340 — pre-populate bootstrap status from the registry so the REST\n  // listener can answer 503 for projects whose slot hasn't loaded yet. Actual\n  // bootstrap moves to the background after `listen()` returns.\n  const initialEntries = await enumerateProjects().catch(() => [] as RegistryEntry[])\n  for (const entry of initialEntries) {\n    bootstrapStatus.set(entry.name, 'bootstrapping')\n    bootstrapStartedAt.set(entry.name, Date.now())\n  }\n\n  // ADR-063 — bind the REST host and the OTLP HTTP receiver. One listener\n  // each, multi-tenant by project name in the URL (REST) and by service.name\n  // dispatch (OTLP). Failure on either listen aborts startDaemon with a\n  // surfacing error rather than letting the supervisor sit half-up.\n  const bind = opts.bindListeners !== false\n  let restApp: FastifyInstance | null = null\n  let otlpApp:\n    | (FastifyInstance & { flushPending: () => Promise<void> })\n    | null = null\n  let restAddress = ''\n  let otlpAddress = ''\n  // ADR-096 — the self-description this daemon owns, filled once it binds in\n  // single-project mode. Null in legacy multi-project mode and when listeners\n  // are skipped (bindListeners:false).\n  let daemonRecord: DaemonRecord | null = null\n\n  if (bind) {\n    // ADR-073 §3 — fail-loud before binding. Loopback-only without a token is\n    // fine (laptop dev); a public bind without one is not. Resolved here\n    // ahead of the host so the loopback-default branch (issue #341) reads\n    // the same token state the bind-authority gate does.\n    const auth = readAuthEnv()\n    const host = resolveHost(opts, Boolean(auth.authToken))\n    const restPort = resolveRestPort(opts)\n    const otlpPort = resolveOtlpPort(opts)\n\n    assertBindAuthority(host, auth.authToken)\n\n    try {\n      restApp = await buildApi({\n        projects: registry,\n        authToken: auth.authToken,\n        trustProxy: auth.trustProxy,\n        publicRead: auth.publicRead,\n        bootstrap: {\n          status: (name) => bootstrapStatus.get(name),\n          list: () => {\n            const now = Date.now()\n            return [...bootstrapStatus.entries()].map(([name, status]) => ({\n              name,\n              status,\n              elapsedMs: now - (bootstrapStartedAt.get(name) ?? now),\n            }))\n          },\n        },\n        // ADR-096 §4/§5/§7 — hand the daemon's identity to buildApi so the REST\n        // surface reflects \"the daemon is the project\": `GET /projects` reports\n        // only this project (the dashboard pins to it), and the daemon-wide\n        // `/health` carries it at the top level for the spawn-reuse identity\n        // check. Absent for the legacy multi-project daemon.\n        singleProject:\n          singleProject && singleProjectPath\n            ? { name: singleProject, path: singleProjectPath }\n            : undefined,\n        // ADR-136 — the connector-status endpoint reads ~/.neat/connectors.json\n        // through the same resolved home the slot bootstrap read it from, so a\n        // daemon given an explicit NEAT_HOME serves status for the same file it\n        // polls.\n        connectorsHome: home,\n        // #1293 — \"sync this project's repos now\". Looked up per request: the\n        // slot, and with it the trigger, appears once bootstrap has run.\n        repoSync: (name) => slots.get(name)?.syncRepos,\n        // OTLP answers on this listener too, so a host that routes a single\n        // port still delivers a tenant app's spans. Bound late: the receiver\n        // is built below, once the REST bind has succeeded.\n        otlpReceiver: () => otlpApp ?? undefined,\n      })\n      restAddress = await restApp.listen({ port: restPort, host })\n      // Fastify reports a 0.0.0.0 bind back as http://127.0.0.1:port, so the\n      // raw listen address hides a wildcard bind behind a loopback URL. Log the\n      // host we actually asked for so the line matches what the port allocator\n      // probed (the orchestrator threads this same host into its free check).\n      console.log(\n        `neatd: REST listening on http://${host}:${portFromListenAddress(restAddress, restPort)}`,\n      )\n    } catch (err) {\n      // Roll back anything we started so far before surfacing the error.\n      for (const slot of slots.values()) {\n        teardownSlot(slot)\n      }\n      if (restApp) await restApp.close().catch(() => {})\n      await fs.unlink(pidPath).catch(() => {})\n      throw new Error(\n        `neatd: failed to bind REST on port ${restPort} — ${(err as Error).message}`,\n      )\n    }\n\n    // Resolve a span's target slot — running the broken-state recovery\n    // when the routed slot is currently broken. Returns null when the span\n    // can't be delivered after the recovery attempt; the caller drops with\n    // a rate-limited warning. v0.4.1 / refs #339 — when nothing matches and\n    // no default slot exists, the no-project-match event lands in\n    // <NEAT_HOME>/errors.ndjson before we return null.\n    //\n    // ADR-096 single-project mode short-circuits all of that: the daemon hosts\n    // exactly one project, so every span on the bare `/v1/traces` route is its\n    // span. The 3-pass `routeSpanToProject` heuristic and the unrouted-span\n    // drop are moot here — assigning by service.name could only ever mis-route\n    // or drop a span the daemon definitionally owns, which is precisely the\n    // silent-dark-OBSERVED failure §1 exists to kill. We assign directly,\n    // recovering the slot if it's broken, and never write to errors.ndjson on\n    // the no-match path.\n    async function resolveTargetSlot(\n      serviceName: string | undefined,\n      traceId: string | undefined,\n    ): Promise<ProjectSlot | null> {\n      if (singleProject) {\n        let slot = slots.get(singleProject)\n        if (!slot) {\n          // The sole slot hasn't bootstrapped yet (span arrived during the\n          // initial extraction window). Build it on demand from spawn args so\n          // the span isn't dropped — the OBSERVED layer must not go dark.\n          slot = await tryRecoverSlot({\n            name: singleProject,\n            path: singleProjectPath!,\n            registeredAt: new Date().toISOString(),\n            languages: [],\n            status: 'active',\n          })\n        } else if (slot.status === 'broken') {\n          slot = await tryRecoverSlot(slot.entry)\n        }\n        if (!slot || slot.status !== 'active') {\n          warnDroppedSpan(singleProject, slot?.errorReason ?? 'unknown')\n          return null\n        }\n        // Scope to this project's owned services — quarantine a sibling\n        // project's spans that reached our shared OTLP port instead of merging\n        // them (cross-project contamination). The unrouted ledger records what\n        // we dropped so it isn't silently dark.\n        if (!spanBelongsToSingleProject(slot.graph, singleProject, serviceName)) {\n          await recordUnroutedSpan(serviceName, traceId)\n          return null\n        }\n        return slot\n      }\n      const liveEntries = await listProjects().catch(() => [])\n      const target = routeSpanToProject(serviceName, liveEntries)\n      let slot = slots.get(target) ?? slots.get(DEFAULT_PROJECT)\n      if (!slot) {\n        await recordUnroutedSpan(serviceName, traceId)\n        return null\n      }\n      if (slot.status === 'broken') {\n        const entry = liveEntries.find((e) => e.name === slot!.entry.name)\n        if (entry) {\n          slot = await tryRecoverSlot(entry)\n        }\n        if (slot.status !== 'active') {\n          warnDroppedSpan(slot.entry.name, slot.errorReason ?? 'unknown')\n          return null\n        }\n      }\n      return slot.status === 'active' ? slot : null\n    }\n\n    // #881 — pure routability classifier for the bare `/v1/traces` route.\n    // Answers \"does a slotted project own this span?\" using the SAME rules\n    // resolveTargetSlot routes by, but without recovering slots, mutating the\n    // graph, or writing the unrouted ledger — those stay on the async drain, so\n    // this adds no I/O to the reply path. The receiver calls it before replying\n    // so an unroutable batch comes back as a 200 with partialSuccess.rejectedSpans\n    // set, rather than an empty partialSuccess that reads as full acceptance. The\n    // async onSpan path still drops the span and records it, exactly as before.\n    function bareSpanIsRoutable(serviceName: string | undefined): boolean {\n      if (singleProject) {\n        const slot = slots.get(singleProject)\n        // Cold start (the sole slot isn't built yet): the daemon definitionally\n        // owns its one project, so mirror spanBelongsToSingleProject against an\n        // empty graph — a span with no service.name, or one whose name matches\n        // the project, is routable; only a clearly foreign name is rejected.\n        if (!slot) {\n          return !serviceName || serviceNameMatchesProject(serviceName, singleProject)\n        }\n        return spanBelongsToSingleProject(slot.graph, singleProject, serviceName)\n      }\n      // Multi-project: routable when service.name resolves to a slotted project,\n      // or a DEFAULT_PROJECT slot exists to catch the remainder — mirroring\n      // resolveTargetSlot's `slots.get(target) ?? slots.get(DEFAULT_PROJECT)`.\n      // Routes over the in-memory slot entries rather than a fresh registry read\n      // so the reply path stays disk-free; a registered-but-not-yet-slotted\n      // project can only make this under-report (call an unroutable span\n      // routable), never falsely reject a good span.\n      const entries = [...slots.values()].map((s) => s.entry)\n      const target = routeSpanToProject(serviceName, entries)\n      return slots.has(target) || slots.has(DEFAULT_PROJECT)\n    }\n\n    // Resolve a project slot by its registered name — the path the\n    // project-scoped OTLP route (issue #367) takes. URL-extracted project\n    // names sidestep the service.name heuristic; we still want the broken\n    // -slot recovery + unrouted-span logging so the route's failure modes\n    // match the legacy path's.\n    async function resolveSlotByName(\n      project: string,\n      serviceName: string | undefined,\n      traceId: string | undefined,\n    ): Promise<ProjectSlot | null> {\n      const liveEntries = await listProjects().catch(() => [])\n      let slot = slots.get(project)\n      if (!slot) {\n        // Single-project daemon: the sole slot may not have finished its initial\n        // extraction when the app's first project-scoped span arrives (the\n        // receiver binds before loadAll runs). Build it on demand so the\n        // project-scoped route keeps the same OBSERVED-never-dark guarantee the\n        // bare route has (ADR-096 / #879) instead of dropping the span. The URL\n        // already asserts this project, so no service.name ownership gate\n        // applies — a span on `/projects/<sole>/v1/traces` is definitionally its.\n        if (singleProject && project === singleProject) {\n          slot = await tryRecoverSlot({\n            name: singleProject,\n            path: singleProjectPath!,\n            registeredAt: new Date().toISOString(),\n            languages: [],\n            status: 'active',\n          })\n          if (!slot || slot.status !== 'active') {\n            warnDroppedSpan(singleProject, slot?.errorReason ?? 'unknown')\n            return null\n          }\n          return slot\n        }\n        await recordUnroutedSpan(serviceName, traceId)\n        return null\n      }\n      if (slot.status === 'broken') {\n        const entry = liveEntries.find((e) => e.name === slot!.entry.name)\n        if (entry) {\n          slot = await tryRecoverSlot(entry)\n        }\n        if (slot.status !== 'active') {\n          warnDroppedSpan(slot.entry.name, slot.errorReason ?? 'unknown')\n          return null\n        }\n      }\n      return slot.status === 'active' ? slot : null\n    }\n\n    try {\n      otlpApp = await buildOtelReceiver({\n        authToken: auth.otelToken,\n        trustProxy: auth.trustProxy,\n        onSpan: async (span) => {\n          // ADR-049 OTel routing — dispatch by service.name. Broken slots\n          // get a single inline recovery attempt before the span is dropped\n          // with a rate-limited log line. Unknown services route to\n          // DEFAULT_PROJECT so the FrontierNode auto-creation flow keeps\n          // working (ADR-033); when DEFAULT_PROJECT isn't registered either,\n          // resolveTargetSlot writes a no-project-match event to\n          // <NEAT_HOME>/errors.ndjson (refs #339).\n          const slot = await resolveTargetSlot(span.service, span.traceId)\n          if (!slot) return\n          await handleSpan(\n            {\n              graph: slot.graph,\n              errorsPath: slot.paths.errorsPath,\n              scanPath: slot.entry.path,\n              project: slot.entry.name,\n              // Receiver already wrote the error event synchronously below.\n              writeErrorEventInline: false,\n            },\n            span,\n          )\n        },\n        onErrorSpanSync: async (span) => {\n          const slot = await resolveTargetSlot(span.service, span.traceId)\n          if (!slot) return\n          await makeErrorSpanWriter(\n            slot.paths.errorsPath,\n            slot.graph,\n            slot.entry.path,\n            slot.entry.name,\n          )(span)\n        },\n        // Project-scoped route (issue #367) — the URL already named the\n        // project. Resolution is a direct slot lookup; service.name resolves\n        // the ServiceNode inside the slot's graph instead of which project\n        // owns the span.\n        onProjectSpan: async (project, span) => {\n          const slot = await resolveSlotByName(project, span.service, span.traceId)\n          if (!slot) return\n          await handleSpan(\n            {\n              graph: slot.graph,\n              errorsPath: slot.paths.errorsPath,\n              scanPath: slot.entry.path,\n              project: slot.entry.name,\n              writeErrorEventInline: false,\n            },\n            span,\n          )\n        },\n        onProjectErrorSpanSync: async (project, span) => {\n          const slot = await resolveSlotByName(project, span.service, span.traceId)\n          if (!slot) return\n          await makeErrorSpanWriter(\n            slot.paths.errorsPath,\n            slot.graph,\n            slot.entry.path,\n            slot.entry.name,\n          )(span)\n        },\n        // #881 — 404 a project-scoped POST for a project this daemon doesn't\n        // host, rather than accepting it and dropping the batch. `slots` covers\n        // active/recovering projects, `bootstrapStatus` the ones still\n        // extracting; a foreign or wrong-cased project name matches neither.\n        // A single-project daemon owns exactly one project by definition, so its\n        // own name always counts as registered even before loadAll populates the\n        // slot — otherwise a scoped span arriving during cold-start would 404 and\n        // be lost (OTLP does not retry 4xx). resolveSlotByName then builds it (#879).\n        isProjectRegistered: (project) =>\n          slots.has(project) ||\n          bootstrapStatus.has(project) ||\n          (singleProject !== undefined && project === singleProject),\n        // #881 — the bare `/v1/traces` route replies before the span is routed\n        // (off the queue), so tell the receiver, per batch, how many spans will\n        // land on no project. It keeps the 200 but reports those as\n        // partialSuccess.rejectedSpans instead of an empty partialSuccess that an\n        // exporter reads as full acceptance. Pure — the drop + unrouted-ledger\n        // write still happen on the async onSpan path.\n        classifyBareRoutability: (spans) => {\n          let rejected = 0\n          for (const span of spans) {\n            if (!bareSpanIsRoutable(span.service)) rejected++\n          }\n          if (rejected === 0) return { rejected: 0 }\n          const noun = rejected === 1 ? 'span' : 'spans'\n          const verb = rejected === 1 ? 'was' : 'were'\n          return {\n            rejected,\n            message:\n              `${rejected} ${noun} matched no project on this daemon and ${verb} dropped. ` +\n              `Export to /projects/<project>/v1/traces, or check the exporter's service.name.`,\n          }\n        },\n      })\n      // A held OTLP port steps to the next free one rather than crashing the\n      // daemon (daemon.md §Binding). The recorded daemon.json port below reads\n      // back from otlpAddress, so a stepped port is what otel-init resolves.\n      otlpAddress = await listenSteppingOtlp(otlpApp, otlpPort, host)\n      // As with REST above, log the host that was asked for: Fastify reports a\n      // wildcard bind back as 127.0.0.1, which reads as loopback-only when it isn't.\n      console.log(\n        `neatd: OTLP listening on http://${host}:${portFromListenAddress(otlpAddress, otlpPort)}/v1/traces (also at /v1/traces on the REST port)`,\n      )\n    } catch (err) {\n      for (const slot of slots.values()) {\n        teardownSlot(slot)\n      }\n      if (restApp) await restApp.close().catch(() => {})\n      if (otlpApp) await otlpApp.close().catch(() => {})\n      await fs.unlink(pidPath).catch(() => {})\n      throw new Error(\n        `neatd: failed to bind OTLP on port ${otlpPort} — ${(err as Error).message}`,\n      )\n    }\n\n    // ADR-096 §2 — write the self-description now that both listeners are up\n    // and we know the real bound ports. Reading them back from the listen\n    // addresses (rather than the requested ports) is what makes ephemeral-port\n    // tests and the orchestrator's allocation agree: when the requested port\n    // was 0, the kernel chose one, and the generated otel-init must read THAT.\n    if (singleProject && singleProjectPath) {\n      const ports: DaemonPorts = {\n        rest: portFromListenAddress(restAddress, restPort),\n        otlp: portFromListenAddress(otlpAddress, otlpPort),\n        // The daemon doesn't bind the web port itself (neatd spawns the web\n        // child); it records the allocated value passed through so the\n        // dashboard and `neat ps` agree on where to look.\n        web: typeof opts.webPort === 'number' ? opts.webPort : resolveWebPort(),\n      }\n      daemonRecord = {\n        project: singleProject,\n        projectPath: singleProjectPath,\n        pid: process.pid,\n        status: 'running',\n        ports,\n        startedAt: new Date().toISOString(),\n        neatVersion: resolveNeatVersion(),\n      }\n      try {\n        await writeDaemonRecord(daemonRecord, home)\n        console.log(\n          `neatd: project \"${singleProject}\" → REST ${ports.rest} / OTLP ${ports.otlp} / web ${ports.web} (daemon.json written)`,\n        )\n      } catch (err) {\n        // The neat-out/ record is load-bearing — without it the instrumented\n        // app can't resolve its OTLP endpoint and the OBSERVED layer goes\n        // dark. Fail loud, rolling back the listeners + pid like the bind\n        // failures above.\n        for (const slot of slots.values()) teardownSlot(slot)\n        if (restApp) await restApp.close().catch(() => {})\n        if (otlpApp) await otlpApp.close().catch(() => {})\n        await fs.unlink(pidPath).catch(() => {})\n        throw new Error(\n          `neatd: failed to write daemon.json for \"${singleProject}\" — ${(err as Error).message}`,\n        )\n      }\n    }\n  }\n\n  // Issue #340 — listeners are live; kick off per-project bootstrap in the\n  // background. Polled callers watch /health for transitions.\n  const initialBootstrap = loadAll().catch((err) => {\n    console.warn(`neatd: initial bootstrap pass failed — ${(err as Error).message}`)\n  })\n\n  let reloading: Promise<void> | null = initialBootstrap\n  const reload = async (): Promise<void> => {\n    if (reloading) return reloading\n    reloading = (async () => {\n      try {\n        await loadAll()\n      } finally {\n        reloading = null\n      }\n    })()\n    return reloading\n  }\n  void initialBootstrap.finally(() => {\n    if (reloading === initialBootstrap) reloading = null\n  })\n\n  const tracker: BootstrapTracker = {\n    status: (name) => bootstrapStatus.get(name),\n    list: () => {\n      const now = Date.now()\n      return [...bootstrapStatus.entries()].map(([name, status]) => ({\n        name,\n        status,\n        elapsedMs: now - (bootstrapStartedAt.get(name) ?? now),\n      }))\n    },\n  }\n\n  // SIGHUP — external \"reload your config\" signal. ADR-049 #2.\n  const sighupHandler = (): void => {\n    void reload().catch((err) => {\n      console.warn(`neatd: SIGHUP reload failed — ${(err as Error).message}`)\n    })\n  }\n  process.on('SIGHUP', sighupHandler)\n\n  // Issue #382 — registry watcher. The orchestrator writes new projects to\n  // the registry file while the daemon is already running; without an explicit\n  // `neatd reload`, the slot map stays stale and every span for the freshly-\n  // registered project gets rejected as no-project-match. Watching the\n  // registry's directory (more robust against the tmp+rename atomic-write\n  // pattern from ADR-048 than file-path watches on some platforms) and\n  // filtering by basename catches every change. Debounce collapses the 2-3\n  // events the rename pattern fires per write into a single reload.\n  const REGISTRY_RELOAD_DEBOUNCE_MS = 500\n  let registryWatcher: FSWatcher | null = null\n  let reloadTimer: NodeJS.Timeout | null = null\n  // A single-project daemon takes its one project from spawn args and never\n  // reads the machine registry for its project list, so there's nothing for\n  // the registry watcher to react to — skip it (ADR-096 §6: no machine-wide\n  // coordination surface).\n  if (!singleProject) try {\n    const regDir = path.dirname(regPath)\n    const regBase = path.basename(regPath)\n    registryWatcher = watch(regDir, (_eventType, filename) => {\n      // filename can be null on some platforms — fall back to firing every\n      // event, the debounce + reload's idempotency cover any over-fire.\n      if (filename !== null && filename !== regBase) return\n      if (reloadTimer) clearTimeout(reloadTimer)\n      reloadTimer = setTimeout(() => {\n        reloadTimer = null\n        void reload().catch((err) => {\n          console.warn(\n            `neatd: registry-watch reload failed — ${(err as Error).message}`,\n          )\n        })\n      }, REGISTRY_RELOAD_DEBOUNCE_MS)\n    })\n  } catch (err) {\n    // Watching the registry is a best-effort optimisation over SIGHUP — if\n    // the kernel refuses (e.g. inotify quota exhausted) we surface the\n    // failure but let the daemon keep running.\n    console.warn(\n      `neatd: failed to watch registry at ${regPath} — ${(err as Error).message}. ` +\n        `Run \\`neatd reload\\` (or send SIGHUP) after registering new projects.`,\n    )\n  }\n\n  let stopped = false\n  const stop = async (): Promise<void> => {\n    if (stopped) return\n    stopped = true\n    process.off('SIGHUP', sighupHandler)\n    if (reloadTimer) {\n      clearTimeout(reloadTimer)\n      reloadTimer = null\n    }\n    if (registryWatcher) {\n      try {\n        registryWatcher.close()\n      } catch {\n        // best-effort\n      }\n      registryWatcher = null\n    }\n    if (otlpApp) await otlpApp.close().catch(() => {})\n    if (restApp) await restApp.close().catch(() => {})\n    // Listeners are down, so the graph is now at its final state. Flush each\n    // active slot once before tearing its persist loop down — the loops run\n    // with `exitOnSignal: false`, so this is where the shutdown save lives now.\n    for (const slot of slots.values()) {\n      if (slot.status === 'active' && slot.outPath) {\n        await saveGraphToDisk(slot.graph, slot.outPath).catch(() => {})\n      }\n    }\n    for (const slot of slots.values()) {\n      teardownSlot(slot)\n    }\n    // ADR-096 §2/§6 — mark the neat-out/ record stopped and remove the\n    // machine-wide discovery copy so `neat ps` stops listing a dead daemon.\n    if (daemonRecord) {\n      await clearDaemonRecord(daemonRecord, home)\n    }\n    await fs.unlink(pidPath).catch(() => {})\n  }\n\n  return {\n    slots,\n    reload,\n    stop,\n    pidPath,\n    restAddress,\n    otlpAddress,\n    bootstrap: tracker,\n    initialBootstrap,\n    daemonRecord,\n    neatHome: home,\n  }\n}\n","// Hosted-profile credential sourcing for the connectors plane (connectors.md §3, INFRA-ADR-011).\n//\n// The local profile reads a connector's credential from ~/.neat/connectors.json (an env-ref resolved at\n// slot bootstrap). The hosted profile has no such file — the credential is brokered on the customer's\n// behalf by the control plane, which holds the sealed OAuth grant and mints a short-lived access token on\n// demand. This module is the daemon's side of that broker: it discovers which providers a project has\n// connected from the CP, and for each runs the SAME lifecycle the local path runs — the poll loop for a\n// pull provider, `validate → provision` for a push provider (a Vercel drain, ADR-146) — differing only in\n// where the credential comes from: the CP delivery endpoint instead of connectors.json.\n//\n// This is exactly the local↔hosted swap point hosted-platform.md names (\"the only swap point is the\n// profile source + the bearer\"): nothing about pull/map/fuse or provision changes, only the credential\n// source. A pull credential lives in `ctx.credentials` for one tick; a push credential is used once to\n// provision and then discarded. Neither reaches the snapshot (connectors.md §6). Delivery auth is the\n// project auth token the daemon was already provisioned with — the same bearer it uses everywhere else —\n// which the CP verifies against the project's sealed auth envelope.\n\nimport { mkdir, readFile, rename, writeFile } from 'node:fs/promises'\nimport { dirname, join } from 'node:path'\nimport type { NeatGraph } from '../graph.js'\nimport type { FirebaseServiceMap } from './firebase/resolve.js'\nimport { startConnectorPollLoop } from './index.js'\nimport { decodeRailwayTargetRef } from './railway/target-ref.js'\nimport { PROVIDER_DISPATCH, getPushProviderDispatch, type PushProviderDispatch } from './registry.js'\n\n// The control-plane delivery shapes (INFRA-ADR-011). Mirror of the CP's DeliveredCredential /\n// DaemonConnectionSummary — kept structural here so neat-core takes no dependency on the CP package.\ninterface DeliveredCredential {\n  provider: string\n  accessToken: string\n  /** ISO expiry for a minted token; null for a long-lived (token-paste) credential. */\n  expiresAt: string | null\n  scopes?: string[]\n  subject?: string\n  projectRef?: string\n}\n\ninterface DaemonConnectionSummary {\n  provider: string\n  subject?: string\n  status?: string\n  scopes?: string[]\n  projectRef?: string\n  /** True when the provider is project-scoped and no project is bound yet — not pullable until it is. */\n  needsProjectSelection?: boolean\n}\n\nexport interface HostedConnectorDeps {\n  /** Control-plane base URL (NEAT_CP_URL). The daemon calls its `/internal` delivery routes here. */\n  cpUrl: string\n  /** The control-plane project id (`prj_…`, NEAT_CP_PROJECT_ID) these connections belong to. */\n  projectId: string\n  /** The project auth token the daemon was provisioned with (NEAT_AUTH_TOKEN) — proves \"I am this\n   *  project's daemon\" to the CP delivery routes. Never logged, never written to the snapshot. */\n  daemonToken: string\n  /** This daemon's externally reachable base URL (NEAT_PUBLIC_URL, injected by the provisioner). A push\n   *  provider's drain delivers to `<publicUrl>/v1/traces`; without it no drain can be provisioned. */\n  publicUrl?: string\n  /** The bearer this daemon's OTLP receiver expects (NEAT_OTEL_TOKEN). Falls back to `daemonToken`, which\n   *  the receiver honours too (one-command-cli.md). */\n  otelToken?: string\n  fetchImpl?: typeof fetch\n}\n\n/** Renew a token this long before its stated expiry, so a poll never fires with a just-expired token. */\nconst CREDENTIAL_REFRESH_SKEW_MS = 60_000\n/** Cap a CP delivery call so a slow control plane can't stall a connector's ticks. */\nconst CP_REQUEST_TIMEOUT_MS = 10_000\n/** Re-list the project's connections on this cadence so a provider connected after boot is picked up without\n *  an instance restart (#1217). One authed GET to the CP; 60s is well within the connect→first-sync budget. */\nconst DEFAULT_RELIST_INTERVAL_MS = 60_000\n\nasync function cpGet<T>(path: string, deps: HostedConnectorDeps): Promise<T> {\n  const f = deps.fetchImpl ?? fetch\n  const res = await f(`${deps.cpUrl.replace(/\\/+$/, '')}${path}`, {\n    headers: { authorization: `Bearer ${deps.daemonToken}`, accept: 'application/json' },\n    signal: AbortSignal.timeout(CP_REQUEST_TIMEOUT_MS),\n  })\n  if (!res.ok) throw new Error(`control plane ${path} → HTTP ${res.status}`)\n  return (await res.json()) as T\n}\n\n/**\n * Map a delivered credential into the credential record the provider's connector reads at poll time — the\n * hosted counterpart of `resolveEntryCredentials` (registry.ts). Provider-specific because the credential\n * *key* is (Supabase's `managementToken`, etc.); the mapping never touches poll/map logic (connectors.md §3).\n */\nfunction credentialRecord(provider: string, cred: DeliveredCredential): Record<string, unknown> {\n  switch (provider) {\n    case 'supabase':\n      return { managementToken: cred.accessToken }\n    case 'gcp':\n      // One Google grant serves the GCP-scoped connectors, and they all read the same `{ projectId,\n      // accessToken }` off the credential; the picked GCP project id rides in `projectRef`. Without it there\n      // is nothing to poll, so fail the tick rather than send a half-credential.\n      if (!cred.projectRef) throw new Error('gcp credential delivered without a project ref')\n      return { projectId: cred.projectRef, accessToken: cred.accessToken }\n    default:\n      // A provider whose hosted delivery lands as a plain bearer under `token` (Railway, etc.).\n      return { token: cred.accessToken }\n  }\n}\n\n/**\n * Derive the connector `options` for a hosted connection from what the CP knows (the picked project) plus\n * the daemon's own project identity. Returns null when the connection can't be turned into a runnable\n * connector yet (e.g. no project picked). Never a profile-branch on mapping logic — only option assembly.\n */\nfunction hostedOptions(\n  provider: string,\n  summary: DaemonConnectionSummary,\n  serviceName: string,\n  firebaseServiceMap?: FirebaseServiceMap,\n  serviceMaps: { cloudRun?: Record<string, string>; gcpLb?: Record<string, string> } = {},\n): Record<string, unknown> | null {\n  switch (provider) {\n    case 'supabase': {\n      const ref = summary.projectRef\n      if (!ref) return null\n      // `nodeRef` is the Supabase host the static `createClient()` extractor keys the project InfraNode on —\n      // `<ref>.supabase.co` in the common case (SupabaseConnectorConfig.nodeRef). `serviceName` is this\n      // project's own service, the origin of the observed edge. If the app connects to a custom host, the\n      // edge simply doesn't resolve — an honest miss, exactly as the local profile's would be.\n      return { apiProjectRef: ref, nodeRef: `${ref}.supabase.co`, serviceName }\n    }\n    case 'railway': {\n      // Railway's pull target is an (environmentId, serviceId) pair, not a single ref — the picker packs both\n      // into `projectRef` as a base64url composite (railway/target-ref.ts). Decode it into the two ids the\n      // connector needs; `serviceNameById` maps the *Railway* serviceId to this daemon's own NEAT service name\n      // (`serviceName`, the observed edge's origin), the same role the Supabase case's `serviceName` plays —\n      // never the Railway service's own label, which names a different authority (railway/types.ts §Fusion).\n      const target = summary.projectRef ? decodeRailwayTargetRef(summary.projectRef) : null\n      if (!target) return null\n      return {\n        environmentId: target.environmentId,\n        serviceId: target.serviceId,\n        serviceNameById: { [target.serviceId]: serviceName },\n      }\n    }\n    case 'firebase': {\n      // No per-tenant setup: the connector works out which service a resource belongs to from the graph\n      // (`inferServices`: a name match, else the one service that declares the requested route), and an\n      // ambiguous or unknown resource stays an honest miss. NEAT_FIREBASE_SERVICE_MAP is only an optional\n      // override for a tenant whose resource names can't be inferred; its explicit entries win.\n      // Cloud Run (also fanned out from a gcp grant) reads the `cloud_run_revision` request logs, so\n      // Firebase leaves that resource type to it rather than counting each request twice.\n      return { inferServices: true, excludeCloudRun: true, ...(firebaseServiceMap ?? {}) }\n    }\n    // Same no-setup rule as Firebase: infer the owning service from the graph; an unknown one stays coarse.\n    // NEAT_CLOUD_RUN_SERVICE_MAP / NEAT_GCP_LB_BACKEND_SERVICE_MAP are optional overrides whose entries win.\n    case 'cloud-run':\n      return { inferServices: true, ...(serviceMaps.cloudRun ? { serviceMap: serviceMaps.cloudRun } : {}) }\n    case 'gcp-lb':\n      return { inferServices: true, ...(serviceMaps.gcpLb ? { backendServiceMap: serviceMaps.gcpLb } : {}) }\n    default:\n      return null\n  }\n}\n\n/** Parse the optional NEAT_FIREBASE_SERVICE_MAP override (JSON: { functions?, cloudRun?, hosting? }, each name\n *  -> NEAT service). Returns undefined for absent or malformed input rather than throwing — a bad override is\n *  ignored and inference still runs; it never takes the daemon slot down. */\nexport function parseFirebaseServiceMap(raw: string | undefined): FirebaseServiceMap | undefined {\n  if (!raw) return undefined\n  try {\n    const parsed: unknown = JSON.parse(raw)\n    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return undefined\n    const out: FirebaseServiceMap = {}\n    for (const key of ['functions', 'cloudRun', 'hosting'] as const) {\n      const group = (parsed as Record<string, unknown>)[key]\n      if (group === undefined) continue\n      if (!group || typeof group !== 'object' || Array.isArray(group)) return undefined\n      const entries = Object.entries(group as Record<string, unknown>)\n      // An empty group is no mapping at all — treat it as absent so inference still runs.\n      if (entries.length === 0) continue\n      if (entries.some(([, v]) => typeof v !== 'string' || v.length === 0)) return undefined\n      out[key] = Object.fromEntries(entries) as Record<string, string>\n    }\n    return Object.keys(out).length > 0 ? out : undefined\n  } catch {\n    return undefined\n  }\n}\n\n/** Parse an optional flat `{ \"<resource name>\": \"<NEAT service>\" }` override (NEAT_CLOUD_RUN_SERVICE_MAP,\n *  NEAT_GCP_LB_BACKEND_SERVICE_MAP). Same forgiving rule as parseFirebaseServiceMap: absent, empty or\n *  malformed input is undefined, so inference still runs and a bad override never takes the slot down. */\nexport function parseServiceNameMap(raw: string | undefined): Record<string, string> | undefined {\n  if (!raw) return undefined\n  try {\n    const parsed: unknown = JSON.parse(raw)\n    if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return undefined\n    const entries = Object.entries(parsed as Record<string, unknown>)\n    if (entries.length === 0) return undefined\n    if (entries.some(([, v]) => typeof v !== 'string' || v.length === 0)) return undefined\n    return Object.fromEntries(entries) as Record<string, string>\n  } catch {\n    return undefined\n  }\n}\n\n// ── Push providers (a drain, not a poll) ────────────────────────────────────────────────────────────────\n//\n// A push provider has no `poll()`. Its lifecycle is `validate → provision` once, after which the provider\n// forwards telemetry to this daemon's OTLP receiver on its own (connectors.md, push section). The hosted\n// path runs that lifecycle through the SAME dispatch `neat connector add` uses (PUSH_PROVIDER_DISPATCH),\n// with the credential brokered by the CP. The one thing it must remember across restarts is the handle\n// `provision` returned — Vercel's `{ drainId }` — so a restarted daemon re-validates the existing drain\n// instead of creating a second one.\n\n/** The handle a push provider's `provision` returned, kept per provider beside the snapshot. Holds no\n *  credential (connectors.md §6) — only the provider-side resource id and the endpoint it delivers to. */\ninterface HostedPushHandle {\n  endpoint: string\n  options: Record<string, unknown>\n  provisionedAt: string\n}\n\nfunction pushHandlesPath(projectDir: string): string {\n  return join(projectDir, 'neat-out', 'connectors-hosted.json')\n}\n\nasync function readPushHandles(projectDir: string): Promise<Record<string, HostedPushHandle>> {\n  try {\n    const parsed = JSON.parse(await readFile(pushHandlesPath(projectDir), 'utf8')) as unknown\n    return parsed && typeof parsed === 'object' ? (parsed as Record<string, HostedPushHandle>) : {}\n  } catch {\n    return {}\n  }\n}\n\nasync function writePushHandle(projectDir: string, provider: string, handle: HostedPushHandle): Promise<void> {\n  const path = pushHandlesPath(projectDir)\n  const handles = await readPushHandles(projectDir)\n  handles[provider] = handle\n  await mkdir(dirname(path), { recursive: true })\n  const tmp = `${path}.${process.pid}.tmp`\n  await writeFile(tmp, `${JSON.stringify(handles, null, 2)}\\n`, 'utf8')\n  await rename(tmp, path)\n}\n\n/**\n * The credential record a push provider's dispatch reads. Vercel's drain needs two secrets: the customer's\n * Vercel token (brokered by the CP) and the bearer the drain presents to this daemon's OTLP receiver — the\n * daemon's own, never the customer's.\n */\nfunction pushCredentialRecord(\n  provider: string,\n  cred: DeliveredCredential,\n  deps: HostedConnectorDeps,\n): Record<string, unknown> {\n  switch (provider) {\n    case 'vercel':\n      return { token: cred.accessToken, otelToken: deps.otelToken ?? deps.daemonToken }\n    default:\n      return { token: cred.accessToken }\n  }\n}\n\n/**\n * Options for a push provider's provision. A Vercel drain is team-scoped and delivers to a URL, so both\n * must be known: the CP captures the team id at connect time (delivered as `projectRef`), and the\n * provisioner tells this daemon its own public URL. Absent either, the drain has no scope or nowhere to\n * deliver — the caller skips with the reason rather than provisioning something half-addressed.\n */\nfunction hostedPushOptions(\n  provider: string,\n  summary: DaemonConnectionSummary,\n  deps: HostedConnectorDeps,\n): { options: Record<string, unknown>; endpoint: string } | { skip: string } {\n  switch (provider) {\n    case 'vercel': {\n      if (!deps.publicUrl) {\n        return { skip: 'no public URL for this daemon (NEAT_PUBLIC_URL) — a drain has nowhere to deliver' }\n      }\n      if (!summary.projectRef) return { skip: 'no Vercel team selected yet — drains are team-scoped' }\n      const endpoint = `${deps.publicUrl.replace(/\\/+$/, '')}/v1/traces`\n      return { options: { teamId: summary.projectRef, endpoint }, endpoint }\n    }\n    default:\n      return { skip: 'no hosted option mapping for this push provider' }\n  }\n}\n\n/**\n * Run a push provider's lifecycle for one hosted connection: the SAME `validate → provision` that\n * `neat connector add <provider>` runs locally, with the credential brokered by the control plane. Provisions\n * once — a recorded handle for the same endpoint means the drain already exists, so a restart only\n * re-validates delivery. Never throws; every failure lands in `onSkip` with its reason, and `onProvisioned`\n * fires only once the provider has confirmed the drain reaches this daemon.\n */\nasync function provisionHostedPushProvider(\n  summary: DaemonConnectionSummary,\n  dispatch: PushProviderDispatch,\n  input: StartHostedConnectorsInput,\n): Promise<void> {\n  const { deps, projectDir, onSkip, onProvisioned } = input\n  const provider = summary.provider\n  const mapped = hostedPushOptions(provider, summary, deps)\n  if ('skip' in mapped) {\n    onSkip?.(provider, mapped.skip)\n    return\n  }\n  let cred: DeliveredCredential\n  try {\n    cred = await cpGet<DeliveredCredential>(\n      `/internal/projects/${deps.projectId}/connections/${provider}/credential`,\n      deps,\n    )\n  } catch (err) {\n    onSkip?.(provider, `credential delivery failed — ${(err as Error).message}`)\n    return\n  }\n  const credentials = pushCredentialRecord(provider, cred, deps)\n  const existing = (await readPushHandles(projectDir))[provider]\n  const alreadyProvisioned = existing !== undefined && existing.endpoint === mapped.endpoint\n  const options = alreadyProvisioned ? { ...mapped.options, ...existing.options } : mapped.options\n  const seam = deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}\n\n  const validation = await dispatch.validate({ credentials, options, ...seam })\n  if (!validation.ok) {\n    onSkip?.(provider, `drain delivery test failed — ${validation.reason}`)\n    return\n  }\n  if (alreadyProvisioned) {\n    onProvisioned?.(provider, 'drain already provisioned — delivery re-validated')\n    return\n  }\n  const result = await dispatch.provision({ credentials, options, ...seam })\n  if (!result.ok) {\n    onSkip?.(provider, `drain provisioning failed — ${result.reason}`)\n    return\n  }\n  await writePushHandle(projectDir, provider, {\n    endpoint: mapped.endpoint,\n    options: result.options ?? {},\n    provisionedAt: new Date().toISOString(),\n  })\n  onProvisioned?.(provider, result.note)\n}\n\n/**\n * The pull connectors one control-plane connection drives. The control plane holds a single `gcp` grant for\n * the whole provider (INFRA-ADR-010: one consent, not one per connector), so the daemon fans it out to every\n * GCP connector, all of which read Cloud Logging `entries.list` with the same `{ projectId, accessToken }`.\n * A tenant with no load balancer, say, simply gets an empty poll from that one.\n */\nconst HOSTED_CONNECTORS_FOR: Record<string, readonly string[]> = {\n  gcp: ['firebase', 'cloud-run', 'gcp-lb'],\n}\n\n/**\n * A per-tick credential source for one hosted provider: pull a short-lived credential from the CP and\n * cache it until just before its expiry, so a poll always runs with a live token but the CP is hit only\n * when the token is (near) stale, not every tick. A token-paste credential carries no expiry and is fetched\n * once. Handed to `startConnectorPollLoop` as `refreshCredentials`.\n */\nexport function createHostedCredentialSource(\n  provider: string,\n  deps: HostedConnectorDeps,\n): () => Promise<Record<string, unknown>> {\n  let cached: { record: Record<string, unknown>; expiresAtMs: number } | null = null\n  return async () => {\n    if (cached && cached.expiresAtMs - CREDENTIAL_REFRESH_SKEW_MS > Date.now()) return cached.record\n    const cred = await cpGet<DeliveredCredential>(\n      `/internal/projects/${deps.projectId}/connections/${provider}/credential`,\n      deps,\n    )\n    const record = credentialRecord(provider, cred)\n    const parsed = cred.expiresAt ? Date.parse(cred.expiresAt) : Number.NaN\n    cached = { record, expiresAtMs: Number.isFinite(parsed) ? parsed : Number.POSITIVE_INFINITY }\n    return record\n  }\n}\n\nexport interface StartHostedConnectorsInput {\n  deps: HostedConnectorDeps\n  graph: NeatGraph\n  /** The project's working directory, handed to each poll as ctx.projectDir. */\n  projectDir: string\n  /** The daemon's project name — ctx.project and the derived serviceName the observed edge originates from. */\n  project: string\n  /** The slot's incident ledger, for an incident-emitting connector (ADR-185). */\n  errorsPath?: string\n  /** Optional explicit Firebase resource-name -> NEAT-service overrides; inference covers the rest. */\n  firebaseServiceMap?: FirebaseServiceMap\n  /** Optional explicit Cloud Run service -> NEAT-service overrides (`serviceMap`). */\n  cloudRunServiceMap?: Record<string, string>\n  /** Optional explicit GCP load balancer backend service -> NEAT-service overrides (`backendServiceMap`). */\n  gcpLbBackendServiceMap?: Record<string, string>\n  onSkip?: (provider: string, reason: string) => void\n  /** Test seam: the poll-loop starter (defaults to startConnectorPollLoop), so wiring can be asserted\n   *  without firing a real provider poll. Mirrors api.ts's injectable `runPoll`. */\n  startLoop?: typeof startConnectorPollLoop\n  /** Test seam: the push-dispatch lookup (defaults to getPushProviderDispatch), so a drain's\n   *  `validate → provision` can be asserted without a real provider call. */\n  pushDispatch?: typeof getPushProviderDispatch\n  /** Fires once a push provider's drain is confirmed reaching this daemon — provisioned, or re-validated on\n   *  a restart. The signal the hosted side reads as \"connected\", as opposed to \"a token is stored\". */\n  onProvisioned?: (provider: string, note?: string) => void\n  /** How often to re-list connections from the control plane (default 60s). Test seam / tunable. */\n  intervalMs?: number\n}\n\n/** A connection currently running its loops, tracked so a re-list pass can diff against it (#1217). */\ninterface RunningConnection {\n  /** The project-selection fields whose change forces a stop-and-restart; see `connectionSignature`. */\n  signature: string\n  /** Tears down every loop this connection drives. */\n  stop: () => void\n}\n\n/**\n * The fields that decide whether a connection is runnable and against which project. When this changes for a\n * provider already running (the customer picked a different project, or a pending selection resolved), the\n * connection is torn down and restarted against the new target. Provider is the running-map key, so it isn't\n * part of the signature.\n */\nfunction connectionSignature(c: DaemonConnectionSummary): string {\n  return `${c.projectRef ?? ''}|${c.needsProjectSelection ? 1 : 0}`\n}\n\n/**\n * Start every poll loop one control-plane connection drives, and return a single stop that tears them all\n * down. This is the per-connection body of a discovery pass, factored out so the re-list loop can start and\n * stop connections one at a time (#1217). A connection that starts zero loops (no project picked, unknown\n * provider) still returns a no-op stop and is still recorded by the caller, so its skip is logged once rather\n * than on every re-list, and a later project pick registers as a signature change.\n */\nfunction startConnectionLoops(\n  c: DaemonConnectionSummary,\n  input: StartHostedConnectorsInput,\n  startLoop: typeof startConnectorPollLoop,\n): () => void {\n  const { deps, graph, projectDir, project, errorsPath, onSkip } = input\n  const stops: Array<() => void> = []\n  // One credential source per connection, shared by every connector it drives, so a fan-out of three\n  // connectors is one control-plane fetch per token lifetime, not three.\n  const credentialSource = createHostedCredentialSource(c.provider, deps)\n  for (const name of HOSTED_CONNECTORS_FOR[c.provider] ?? [c.provider]) {\n    const dispatch = PROVIDER_DISPATCH[name]\n    if (!dispatch) {\n      onSkip?.(name, 'no pull connector for this provider')\n      continue\n    }\n    if (c.needsProjectSelection || !c.projectRef) {\n      onSkip?.(name, 'no project selected yet — not pullable')\n      continue\n    }\n    const options = hostedOptions(name, c, project, input.firebaseServiceMap, {\n      ...(input.cloudRunServiceMap ? { cloudRun: input.cloudRunServiceMap } : {}),\n      ...(input.gcpLbBackendServiceMap ? { gcpLb: input.gcpLbBackendServiceMap } : {}),\n    })\n    if (!options) {\n      onSkip?.(name, 'no hosted option mapping for this provider')\n      continue\n    }\n    let built\n    try {\n      built = dispatch.build(graph, options)\n    } catch (err) {\n      onSkip?.(name, (err as Error).message)\n      continue\n    }\n    stops.push(\n      startLoop(\n        built.connector,\n        { projectDir, project, credentials: {}, ...(errorsPath ? { errorsPath } : {}) },\n        graph,\n        built.resolveTarget,\n        {\n          connectorId: `hosted:${name}`,\n          // The credential is fetched by the CONNECTION's provider (`gcp`), not the connector's name.\n          refreshCredentials: credentialSource,\n        },\n      ),\n    )\n  }\n  return () => {\n    for (const stop of stops) stop()\n  }\n}\n\n/**\n * One discovery pass: list the project's connections from the control plane and reconcile them against the\n * running set — start loops for new connections, stop loops for removed ones, restart a connection whose\n * project selection changed, and leave unchanged ones running (#1217). Never throws: a control-plane read\n * failure logs via `onSkip` and leaves the running set intact, so a transient CP blip doesn't tear down\n * working loops — the slot survives exactly as it does a malformed connectors.json.\n */\nasync function runHostedConnectorsPass(\n  input: StartHostedConnectorsInput,\n  startLoop: typeof startConnectorPollLoop,\n  running: Map<string, RunningConnection>,\n): Promise<void> {\n  const { deps, onSkip } = input\n  let connections: DaemonConnectionSummary[]\n  try {\n    connections = await cpGet<DaemonConnectionSummary[]>(`/internal/projects/${deps.projectId}/connections`, deps)\n  } catch (err) {\n    onSkip?.('(all)', `control plane connection list unreadable — ${(err as Error).message}`)\n    return\n  }\n  if (!Array.isArray(connections)) return\n\n  const lookupPush = input.pushDispatch ?? getPushProviderDispatch\n  const seen = new Set<string>()\n  for (const c of connections) {\n    // Keyed by provider: the CP models one grant per provider (INFRA-ADR-010), and the credential route is\n    // per-provider too. A duplicate provider in the list is degenerate — the last one seen wins.\n    seen.add(c.provider)\n    const signature = connectionSignature(c)\n    const existing = running.get(c.provider)\n    if (existing && existing.signature === signature) continue\n    if (existing) existing.stop() // signature changed (e.g. project re-picked) — restart against the new one\n    // A push provider provisions a drain instead of being polled — the same dispatch `neat connector add`\n    // uses. There is nothing to tear down afterwards, because the drain lives provider-side until it is\n    // deprovisioned; it still enters the running set so a later pass whose signature is unchanged re-validates\n    // nothing and leaves the provider's API alone (#1217).\n    const push = lookupPush(c.provider)\n    if (push) {\n      await provisionHostedPushProvider(c, push, input)\n      running.set(c.provider, { signature, stop: () => {} })\n      continue\n    }\n    running.set(c.provider, { signature, stop: startConnectionLoops(c, input, startLoop) })\n  }\n  for (const [provider, rc] of running) {\n    if (seen.has(provider)) continue\n    rc.stop() // gone from the control plane — stop its loops\n    running.delete(provider)\n  }\n}\n\n/**\n * Discover this project's connected providers from the control plane and start a poll loop for each, then\n * re-list on a cadence so a provider connected (or disconnected, or re-pointed at another project) after boot\n * is reconciled without an instance restart (#1217). Every connector's credential is still sourced from the\n * CP per tick (INFRA-ADR-011). Returns one stop that halts the schedule and tears every loop down. Never\n * throws: a discovery failure logs via `onSkip` and starts nothing that pass, and the next re-list recovers —\n * so the daemon slot survives a briefly unreachable control plane exactly as it survives a bad connectors.json.\n */\nexport async function startHostedConnectors(input: StartHostedConnectorsInput): Promise<() => void> {\n  const startLoop = input.startLoop ?? startConnectorPollLoop\n  const intervalMs = input.intervalMs ?? DEFAULT_RELIST_INTERVAL_MS\n  const running = new Map<string, RunningConnection>()\n  let stopped = false\n  let inPass = false\n  const tick = async () => {\n    if (stopped || inPass) return\n    inPass = true\n    try {\n      await runHostedConnectorsPass(input, startLoop, running)\n    } finally {\n      inPass = false\n    }\n  }\n  // The boot pass is awaited (unlike hosted-repos' fire-and-forget boot) so the caller — and the tests, which\n  // assert the started set synchronously — see the first discovery's loops up by the time this resolves.\n  await tick()\n  const timer = setInterval(() => {\n    void tick()\n  }, intervalMs)\n  if (typeof timer.unref === 'function') timer.unref()\n  return () => {\n    stopped = true\n    clearInterval(timer)\n    for (const rc of running.values()) rc.stop()\n    running.clear()\n  }\n}\n\nexport interface MaybeStartHostedConnectorsInput {\n  graph: NeatGraph\n  projectDir: string\n  project: string\n  errorsPath?: string\n  env?: NodeJS.ProcessEnv\n  fetchImpl?: typeof fetch\n  onSkip?: (provider: string, reason: string) => void\n  /** How often to re-list connections (default 60s). Test seam; daemon.ts leaves it at the default. */\n  intervalMs?: number\n}\n\n/**\n * The daemon slot calls this unconditionally; it starts hosted connectors only when the hosted-profile env\n * is present (NEAT_CP_URL + NEAT_CP_PROJECT_ID + NEAT_AUTH_TOKEN, all injected by the provisioner). Absent\n * — the local daemon — it's a no-op stop. This keeps daemon.ts one additive line rather than a hosted\n * branch inside the slot (hosted-platform.md: hosted wraps, never forks).\n */\nexport async function maybeStartHostedConnectors(input: MaybeStartHostedConnectorsInput): Promise<() => void> {\n  const env = input.env ?? process.env\n  const cpUrl = env.NEAT_CP_URL\n  const projectId = env.NEAT_CP_PROJECT_ID\n  const daemonToken = env.NEAT_AUTH_TOKEN\n  if (!cpUrl || !projectId || !daemonToken) return () => {}\n  return startHostedConnectors({\n    deps: {\n      cpUrl,\n      projectId,\n      daemonToken,\n      ...(env.NEAT_PUBLIC_URL ? { publicUrl: env.NEAT_PUBLIC_URL } : {}),\n      ...(env.NEAT_OTEL_TOKEN ? { otelToken: env.NEAT_OTEL_TOKEN } : {}),\n      ...(input.fetchImpl ? { fetchImpl: input.fetchImpl } : {}),\n    },\n    graph: input.graph,\n    projectDir: input.projectDir,\n    project: input.project,\n    ...(parseFirebaseServiceMap(env.NEAT_FIREBASE_SERVICE_MAP)\n      ? { firebaseServiceMap: parseFirebaseServiceMap(env.NEAT_FIREBASE_SERVICE_MAP) }\n      : {}),\n    ...(parseServiceNameMap(env.NEAT_CLOUD_RUN_SERVICE_MAP)\n      ? { cloudRunServiceMap: parseServiceNameMap(env.NEAT_CLOUD_RUN_SERVICE_MAP) }\n      : {}),\n    ...(parseServiceNameMap(env.NEAT_GCP_LB_BACKEND_SERVICE_MAP)\n      ? { gcpLbBackendServiceMap: parseServiceNameMap(env.NEAT_GCP_LB_BACKEND_SERVICE_MAP) }\n      : {}),\n    ...(input.errorsPath ? { errorsPath: input.errorsPath } : {}),\n    ...(input.onSkip ? { onSkip: input.onSkip } : {}),\n    ...(input.intervalMs !== undefined ? { intervalMs: input.intervalMs } : {}),\n  })\n}\n","// Railway hosted target ref (docs/contracts/connectors.md §3, ADR-127) — the daemon's decode half of the\n// composite ref the control-plane picker produces.\n//\n// A Supabase project is one opaque 20-char ref, so its hosted `projectRef` is that ref verbatim. Railway's\n// pull target isn't: httpLogs/networkFlowLogs are scoped by an (environmentId, serviceId) pair (railway/\n// client.ts), which is two ids, not one. The hosted broker's project picker (neat-infra's RailwayConnectDriver\n// .listProjects) therefore packs both — plus the Railway service's own display name, for the picker label —\n// into one opaque string so `RemoteProject.ref` stays flat, exactly as every other provider's does:\n//\n//   ref = base64url(JSON.stringify({ environmentId, serviceId, serviceName }))\n//\n// The control plane stores that string as the connection's `projectRef` and delivers it unchanged; the daemon\n// decodes it here into the pull options railway/index.ts's connector needs. This is the local↔hosted swap\n// point and nothing more — the credential source and the pull options differ between profiles, the pull/map/\n// fuse logic does not (connectors.md §3). The encode side lives in neat-infra and is mirrored structurally\n// (no shared package across the plane), so the field shape below is the contract both sides hold to.\n\n/** The (environment, service) target a hosted Railway connection is bound to, recovered from its `projectRef`. */\nexport interface RailwayTargetRef {\n  environmentId: string\n  serviceId: string\n  /** The Railway service's own display name — carried for the picker label; the daemon's pull options don't\n   *  need it (serviceNameById maps the Railway serviceId to the NEAT service name, not this one). Present when\n   *  the encoder set it, absent otherwise. */\n  serviceName?: string\n}\n\nfunction nonEmptyString(v: unknown): v is string {\n  return typeof v === 'string' && v.length > 0\n}\n\n/**\n * Decode a hosted Railway `projectRef` into its (environmentId, serviceId) target. Returns null on anything\n * malformed — not base64url, not JSON, or missing the two ids the pull path needs — so a foreign or corrupted\n * ref drops honestly (the same \"null/garbage in drops, never throws\" discipline connectors.md §4 holds for a\n * provider row), never crashing the hosted discovery loop. `serviceName` is echoed through when present but is\n * not required: the daemon only needs the two ids to poll.\n */\nexport function decodeRailwayTargetRef(ref: string): RailwayTargetRef | null {\n  if (typeof ref !== 'string' || ref.length === 0) return null\n  let json: string\n  try {\n    json = Buffer.from(ref, 'base64url').toString('utf8')\n  } catch {\n    return null\n  }\n  let parsed: unknown\n  try {\n    parsed = JSON.parse(json)\n  } catch {\n    return null\n  }\n  if (!parsed || typeof parsed !== 'object') return null\n  const obj = parsed as Record<string, unknown>\n  if (!nonEmptyString(obj.environmentId) || !nonEmptyString(obj.serviceId)) return null\n  return {\n    environmentId: obj.environmentId,\n    serviceId: obj.serviceId,\n    ...(nonEmptyString(obj.serviceName) ? { serviceName: obj.serviceName } : {}),\n  }\n}\n","/**\n * Unrouted-span logging (v0.4.1 — refs #339).\n *\n * When the daemon's routing layer can't deliver a span — service.name\n * matches no registered project AND no `default` project exists — we still\n * return 200 on the receiver (OTLP spec), but the dropped event lands here\n * so the next operator can see what happened. The log lives at\n * `<NEAT_HOME>/errors.ndjson` because the unrouted span doesn't belong to\n * any project's neat-out directory.\n *\n * Owner: this module. Daemon imports the appender + warner; no other code\n * writes to the no-project-match log path. Keeping the writes here keeps\n * daemon.ts free of direct `fs.appendFile` calls (asserted by the daemon\n * contract test).\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nexport interface UnroutedSpanRecord {\n  timestamp: string\n  reason: 'no-project-match'\n  service_name: string | null\n  traceId: string | null\n}\n\nexport function buildUnroutedSpanRecord(\n  serviceName: string | undefined,\n  traceId: string | undefined,\n  now: Date = new Date(),\n): UnroutedSpanRecord {\n  return {\n    timestamp: now.toISOString(),\n    reason: 'no-project-match',\n    service_name: serviceName ?? null,\n    traceId: traceId ?? null,\n  }\n}\n\nexport async function appendUnroutedSpan(\n  neatHome: string,\n  record: UnroutedSpanRecord,\n): Promise<void> {\n  const target = path.join(neatHome, 'errors.ndjson')\n  await fs.mkdir(neatHome, { recursive: true })\n  await fs.appendFile(target, JSON.stringify(record) + '\\n', 'utf8')\n}\n\nexport function unroutedErrorsPath(neatHome: string): string {\n  return path.join(neatHome, 'errors.ndjson')\n}\n","// semantic_search — embedding-based node retrieval with a three-tier\n// fallback chain. The chain is settled in ADR-025; this file is the\n// implementation. Public API:\n//\n//   buildSearchIndex(graph, opts) → SearchIndex\n//   SearchIndex.search(query, limit) → { provider, matches }\n//   SearchIndex.refresh(graph)      → re-embeds new/changed nodes,\n//                                     drops vanished ones\n//\n// The `/search` route in api.ts holds a single SearchIndex, refreshing it\n// after any extraction. MCP's `semantic_search` tool reads the same shape.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { createHash } from 'node:crypto'\nimport type { GraphNode } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport interface ScoredNode {\n  node: GraphNode\n  score: number\n}\n\nexport interface SearchResponse {\n  query: string\n  provider: 'ollama' | 'transformers' | 'substring'\n  matches: ScoredNode[]\n}\n\nexport interface SearchIndex {\n  readonly provider: SearchResponse['provider']\n  search(query: string, limit?: number): Promise<SearchResponse>\n  refresh(graph: NeatGraph): Promise<void>\n}\n\ninterface Embedder {\n  provider: 'ollama' | 'transformers'\n  model: string\n  dim: number\n  embed(texts: string[]): Promise<Float32Array[]>\n}\n\nconst DEFAULT_LIMIT = 10\nconst NOMIC_DIM = 768\nconst MINI_LM_DIM = 384\n\n// FrontierNodes are noise by design (placeholders that should disappear).\n// Embedding them would just clutter results.\nfunction shouldEmbed(node: GraphNode): boolean {\n  return node.type !== 'FrontierNode'\n}\n\n// Deterministic per-node text. Stable keys let the cache hit across\n// extractions when nothing material changed.\nexport function embedText(node: GraphNode): string {\n  const parts: string[] = [node.id]\n  const name = (node as { name?: string }).name\n  if (name) parts.push(name)\n  switch (node.type) {\n    case 'ServiceNode': {\n      const lang = (node as { language?: string }).language\n      if (lang) parts.push(`language=${lang}`)\n      break\n    }\n    case 'DatabaseNode': {\n      const eng = (node as { engine?: string }).engine\n      const ver = (node as { engineVersion?: string }).engineVersion\n      if (eng) parts.push(`engine=${eng}`)\n      if (ver) parts.push(`engineVersion=${ver}`)\n      break\n    }\n    case 'InfraNode': {\n      const kind = (node as { kind?: string }).kind\n      if (kind) parts.push(`kind=${kind}`)\n      break\n    }\n    case 'ConfigNode': {\n      const filePath = (node as { path?: string }).path\n      if (filePath) parts.push(`path=${filePath}`)\n      break\n    }\n    case 'RouteNode': {\n      const method = (node as { method?: string }).method\n      const tmpl = (node as { pathTemplate?: string }).pathTemplate\n      if (method) parts.push(`method=${method}`)\n      if (tmpl) parts.push(`path=${tmpl}`)\n      break\n    }\n    case 'GraphQLOperationNode': {\n      const opType = (node as { operationType?: string }).operationType\n      if (opType) parts.push(`operationType=${opType}`)\n      break\n    }\n    case 'GrpcMethodNode': {\n      const rpcService = (node as { rpcService?: string }).rpcService\n      const rpcMethod = (node as { rpcMethod?: string }).rpcMethod\n      if (rpcService) parts.push(`rpcService=${rpcService}`)\n      if (rpcMethod) parts.push(`rpcMethod=${rpcMethod}`)\n      break\n    }\n    case 'WebSocketChannelNode': {\n      const channel = (node as { channel?: string }).channel\n      if (channel) parts.push(`channel=${channel}`)\n      break\n    }\n    default:\n      break\n  }\n  return parts.join(' ')\n}\n\nfunction attrsHash(node: GraphNode): string {\n  return createHash('sha1').update(embedText(node)).digest('hex').slice(0, 16)\n}\n\nexport function cosine(a: Float32Array, b: Float32Array): number {\n  if (a.length !== b.length) return 0\n  let dot = 0\n  let na = 0\n  let nb = 0\n  for (let i = 0; i < a.length; i++) {\n    const ai = a[i] ?? 0\n    const bi = b[i] ?? 0\n    dot += ai * bi\n    na += ai * ai\n    nb += bi * bi\n  }\n  if (na === 0 || nb === 0) return 0\n  return dot / (Math.sqrt(na) * Math.sqrt(nb))\n}\n\n// ---------------------------------------------------------------- Embedders\n\nfunction ollamaHost(): string | null {\n  return process.env.OLLAMA_HOST ?? null\n}\n\nasync function ollamaReachable(host: string): Promise<boolean> {\n  try {\n    const res = await fetch(`${host.replace(/\\/$/, '')}/api/tags`, {\n      signal: AbortSignal.timeout(500),\n    })\n    return res.ok\n  } catch {\n    return false\n  }\n}\n\nfunction makeOllamaEmbedder(host: string, model = 'nomic-embed-text'): Embedder {\n  const root = host.replace(/\\/$/, '')\n  return {\n    provider: 'ollama',\n    model,\n    dim: NOMIC_DIM,\n    async embed(texts: string[]): Promise<Float32Array[]> {\n      const out: Float32Array[] = []\n      // Ollama's /api/embeddings is one-text-per-request. ≤10K nodes × ~30ms\n      // each is fine for a one-shot index build; if it ever isn't, the API\n      // also accepts batched input on /api/embed (newer routes).\n      for (const text of texts) {\n        const res = await fetch(`${root}/api/embeddings`, {\n          method: 'POST',\n          headers: { 'content-type': 'application/json' },\n          body: JSON.stringify({ model, prompt: text }),\n        })\n        if (!res.ok) {\n          throw new Error(`ollama embeddings: ${res.status} ${res.statusText}`)\n        }\n        const data = (await res.json()) as { embedding: number[] }\n        out.push(Float32Array.from(data.embedding))\n      }\n      return out\n    },\n  }\n}\n\ninterface XenovaPipeline {\n  (text: string | string[], options?: { pooling?: string; normalize?: boolean }): Promise<{\n    data: Float32Array\n  }>\n}\n\nasync function makeTransformersEmbedder(): Promise<Embedder | null> {\n  let pipelineFn: ((task: string, model: string) => Promise<XenovaPipeline>) | null = null\n  try {\n    // Lazy require so server.ts boot doesn't pay the WASM init cost when\n    // Ollama is available. The package is heavy — only load it on demand.\n    // The package is optional so its types may not be installed in every\n    // environment. Use a dynamic specifier so tsc keeps the import dynamic\n    // and doesn't try to resolve types at build time.\n    const specifier = '@xenova/transformers'\n    const mod = (await import(specifier)) as unknown as {\n      pipeline: (task: string, model: string) => Promise<XenovaPipeline>\n    }\n    pipelineFn = mod.pipeline\n  } catch {\n    return null\n  }\n  if (!pipelineFn) return null\n  const model = 'Xenova/all-MiniLM-L6-v2'\n  const extractor = await pipelineFn('feature-extraction', model)\n  return {\n    provider: 'transformers',\n    model,\n    dim: MINI_LM_DIM,\n    async embed(texts: string[]): Promise<Float32Array[]> {\n      const out: Float32Array[] = []\n      for (const text of texts) {\n        // Mean-pooled, L2-normalized → cosine reduces to dot product but\n        // we keep the explicit cosine() for clarity.\n        const result = await extractor(text, { pooling: 'mean', normalize: true })\n        out.push(Float32Array.from(result.data))\n      }\n      return out\n    },\n  }\n}\n\n// Picks the highest-tier embedder available. Returns null when only\n// substring is available (caller decides what to build).\nexport async function pickEmbedder(provider?: 'ollama' | 'transformers'): Promise<Embedder | null> {\n  if (provider !== 'transformers') {\n    const host = ollamaHost()\n    if (host && (await ollamaReachable(host))) {\n      return makeOllamaEmbedder(host)\n    }\n  }\n  if (provider === 'ollama') return null\n  return makeTransformersEmbedder()\n}\n\n// NEAT_SEARCH_PROVIDER narrows the embedder chain. Search is never a gate: an\n// unrecognized value warns and keeps automatic selection rather than stopping\n// the daemon (and with it ingest and every query) from starting.\nexport function searchProviderFromEnv(\n  env: NodeJS.ProcessEnv = process.env,\n  warn: (message: string) => void = console.warn,\n): BuildSearchIndexOptions['forceProvider'] {\n  const value = env.NEAT_SEARCH_PROVIDER\n  if (!value) return undefined\n  if (value === 'substring' || value === 'ollama' || value === 'transformers') return value\n  warn(\n    `semantic_search: NEAT_SEARCH_PROVIDER=\"${value}\" is not substring, ollama, or transformers; using automatic selection`,\n  )\n  return undefined\n}\n\n// ------------------------------------------------------------------ Cache\n\ninterface CacheEntry {\n  nodeId: string\n  attrsHash: string\n  vector: number[]\n}\n\ninterface CacheFile {\n  version: 1\n  provider: 'ollama' | 'transformers'\n  model: string\n  dim: number\n  entries: CacheEntry[]\n}\n\nasync function readCache(cachePath: string): Promise<CacheFile | null> {\n  try {\n    const raw = await fs.readFile(cachePath, 'utf8')\n    const parsed = JSON.parse(raw) as CacheFile\n    if (parsed.version !== 1) return null\n    return parsed\n  } catch {\n    return null\n  }\n}\n\nasync function writeCache(cachePath: string, cache: CacheFile): Promise<void> {\n  await fs.mkdir(path.dirname(cachePath), { recursive: true })\n  await fs.writeFile(cachePath, JSON.stringify(cache))\n}\n\n// ----------------------------------------------------------------- Indexes\n\nclass VectorIndex implements SearchIndex {\n  readonly provider: 'ollama' | 'transformers'\n  private vectors = new Map<string, { node: GraphNode; vector: Float32Array; hash: string }>()\n\n  constructor(\n    private embedder: Embedder,\n    private cachePath: string | null,\n  ) {\n    this.provider = embedder.provider\n  }\n\n  async search(query: string, limit = DEFAULT_LIMIT): Promise<SearchResponse> {\n    const trimmed = query.trim()\n    if (!trimmed || this.vectors.size === 0) {\n      return { query: trimmed, provider: this.provider, matches: [] }\n    }\n    const embedded = await this.embedder.embed([trimmed])\n    const qv = embedded[0]\n    if (!qv) {\n      return { query: trimmed, provider: this.provider, matches: [] }\n    }\n    const scored: ScoredNode[] = []\n    for (const { node, vector } of this.vectors.values()) {\n      const score = cosine(qv, vector)\n      scored.push({ node, score })\n    }\n    scored.sort((a, b) => b.score - a.score)\n    return { query: trimmed, provider: this.provider, matches: scored.slice(0, limit) }\n  }\n\n  async refresh(graph: NeatGraph): Promise<void> {\n    const present = new Set<string>()\n    const toEmbed: { id: string; node: GraphNode; hash: string; text: string }[] = []\n\n    graph.forEachNode((id, attrs) => {\n      const node = attrs as GraphNode\n      if (!shouldEmbed(node)) return\n      present.add(id)\n      const hash = attrsHash(node)\n      const cached = this.vectors.get(id)\n      if (cached && cached.hash === hash) {\n        cached.node = node\n        return\n      }\n      toEmbed.push({ id, node, hash, text: embedText(node) })\n    })\n\n    // Drop vanished nodes\n    for (const id of [...this.vectors.keys()]) {\n      if (!present.has(id)) this.vectors.delete(id)\n    }\n\n    if (toEmbed.length > 0) {\n      const vectors = await this.embedder.embed(toEmbed.map((e) => e.text))\n      toEmbed.forEach((entry, i) => {\n        const v = vectors[i]\n        if (!v) return\n        this.vectors.set(entry.id, { node: entry.node, vector: v, hash: entry.hash })\n      })\n    }\n\n    if (this.cachePath) {\n      const entries: CacheEntry[] = []\n      for (const [id, { vector, hash }] of this.vectors) {\n        entries.push({ nodeId: id, attrsHash: hash, vector: Array.from(vector) })\n      }\n      await writeCache(this.cachePath, {\n        version: 1,\n        provider: this.embedder.provider,\n        model: this.embedder.model,\n        dim: this.embedder.dim,\n        entries,\n      })\n    }\n  }\n\n  // Hydrate the in-memory map from a previously-written cache. Validates\n  // shape against the current embedder; mismatch → empty start.\n  loadFromCache(cache: CacheFile, graph: NeatGraph): void {\n    if (\n      cache.provider !== this.embedder.provider ||\n      cache.model !== this.embedder.model ||\n      cache.dim !== this.embedder.dim\n    ) {\n      return\n    }\n    const present = new Map<string, GraphNode>()\n    graph.forEachNode((id, attrs) => {\n      const node = attrs as GraphNode\n      if (shouldEmbed(node)) present.set(id, node)\n    })\n    for (const entry of cache.entries) {\n      const node = present.get(entry.nodeId)\n      if (!node) continue\n      // Skip cache entries whose attrs no longer match — they'll be\n      // re-embedded by the next refresh().\n      if (attrsHash(node) !== entry.attrsHash) continue\n      if (entry.vector.length !== this.embedder.dim) continue\n      this.vectors.set(entry.nodeId, {\n        node,\n        hash: entry.attrsHash,\n        vector: Float32Array.from(entry.vector),\n      })\n    }\n  }\n}\n\nclass SubstringIndex implements SearchIndex {\n  readonly provider = 'substring' as const\n  private graph: NeatGraph | null = null\n\n  async search(query: string, limit = DEFAULT_LIMIT): Promise<SearchResponse> {\n    const q = query.trim().toLowerCase()\n    const out: ScoredNode[] = []\n    if (!q || !this.graph) {\n      return { query: q, provider: 'substring', matches: [] }\n    }\n    this.graph.forEachNode((id, attrs) => {\n      const node = attrs as GraphNode\n      const name = (node as { name?: string }).name ?? ''\n      if (id.toLowerCase().includes(q) || name.toLowerCase().includes(q)) {\n        out.push({ node, score: 1 })\n      }\n    })\n    return { query: q, provider: 'substring', matches: out.slice(0, limit) }\n  }\n\n  async refresh(graph: NeatGraph): Promise<void> {\n    this.graph = graph\n  }\n}\n\n// --------------------------------------------------------- Bounded init (#819)\n\n// How long to wait for the embedder to initialize before giving up and falling\n// back to the substring index. `pickEmbedder` reaches makeTransformersEmbedder,\n// which loads an ONNX/WASM runtime and — on a cold cache — downloads the model.\n// Either can stall: an offline or throttled network on first run, or a\n// pathological native-init on a runtime NEAT doesn't target (the Node-26 report\n// in #819). Left unbounded, that stall hangs the whole `neat watch` / dev-server\n// bring-up with no output — the worst UX, since the operator sees neither the\n// receiver come up nor an error. Bounding it turns the stall into one warning\n// line plus a substring-search fallback, so the graph stays queryable and the\n// daemon still comes up. Generous by default so a legitimately slow first-run\n// model download still lands; NEAT_SEARCH_INIT_TIMEOUT_MS overrides, and `0`\n// restores the old wait-forever behaviour for anyone who wants it.\nconst DEFAULT_SEARCH_INIT_TIMEOUT_MS = 30_000\n\nfunction searchInitTimeoutMs(): number {\n  const env = process.env.NEAT_SEARCH_INIT_TIMEOUT_MS\n  if (env !== undefined && env.length > 0) {\n    const n = Number.parseInt(env, 10)\n    if (Number.isFinite(n) && n >= 0) return n\n  }\n  return DEFAULT_SEARCH_INIT_TIMEOUT_MS\n}\n\n// Resolve an embedder, bounded by `timeoutMs`. A non-positive timeout means no\n// bound (wait for the factory however long it takes). On timeout we log a single\n// warning naming the stall and return null — the caller then builds the\n// substring index instead of hanging. The factory promise is left to settle in\n// the background (harmless: nothing downstream awaits it, and a later refresh\n// rebuilds the vector index if the process is still up); the point is that the\n// bring-up never blocks on it past the bound. A factory that rejects propagates\n// unchanged — that's an already-handled failure mode (buildSearchIndex's callers\n// fall back to substring on a throw); only the never-settles case is new here.\nasync function resolveEmbedderBounded(\n  factory: () => Promise<Embedder | null>,\n  timeoutMs: number,\n): Promise<Embedder | null> {\n  if (timeoutMs <= 0) return factory()\n  let timer: ReturnType<typeof setTimeout> | undefined\n  const TIMED_OUT = Symbol('embedder-init-timeout')\n  const timeout = new Promise<typeof TIMED_OUT>((resolve) => {\n    timer = setTimeout(() => resolve(TIMED_OUT), timeoutMs)\n    // Don't let the fallback timer keep the event loop alive on its own.\n    timer.unref?.()\n  })\n  try {\n    const result = await Promise.race([factory(), timeout])\n    if (result === TIMED_OUT) {\n      console.warn(\n        `semantic_search: embedder init exceeded ${timeoutMs}ms; falling back to substring search. ` +\n          `Set NEAT_SEARCH_INIT_TIMEOUT_MS to raise the bound (or 0 to wait indefinitely).`,\n      )\n      return null\n    }\n    return result\n  } finally {\n    if (timer) clearTimeout(timer)\n  }\n}\n\n// ------------------------------------------------------------ Public factory\n\nexport interface BuildSearchIndexOptions {\n  // Where to read/write the embedding cache. Falls back to in-memory only\n  // if not provided. Pass `null` to explicitly disable caching.\n  cachePath?: string | null\n  // Override the embedder selection. Useful for tests (substring-only mode\n  // skips the Ollama probe + the Transformers.js download).\n  forceProvider?: 'ollama' | 'transformers' | 'substring'\n  // Pre-built embedder (test injection). Wins over forceProvider.\n  embedder?: Embedder\n  // Override the embedder resolver (defaults to `pickEmbedder`, the\n  // Ollama → transformers chain). Test seam for the init-timeout fallback\n  // below — inject a factory that stalls to prove the bring-up degrades to\n  // substring instead of hanging (#819), without a real model load.\n  embedderFactory?: () => Promise<Embedder | null>\n  // Upper bound on embedder init before falling back to substring (#819).\n  // Defaults to NEAT_SEARCH_INIT_TIMEOUT_MS or 30s; `0` waits indefinitely.\n  initTimeoutMs?: number\n}\n\nexport async function buildSearchIndex(\n  graph: NeatGraph,\n  options: BuildSearchIndexOptions = {},\n): Promise<SearchIndex> {\n  let embedder: Embedder | null = null\n  if (options.embedder) {\n    embedder = options.embedder\n  } else if (options.forceProvider !== 'substring') {\n    // Bound the embedder init so a stalled model load / native init can't hang\n    // the bring-up — it degrades to substring instead (#819).\n    const forcedProvider = options.forceProvider\n    const factory = options.embedderFactory ?? (() => pickEmbedder(forcedProvider))\n    embedder = await resolveEmbedderBounded(\n      factory,\n      options.initTimeoutMs ?? searchInitTimeoutMs(),\n    )\n    if (options.forceProvider === 'ollama' && embedder?.provider !== 'ollama') {\n      embedder = null\n    }\n    if (options.forceProvider === 'transformers' && embedder?.provider !== 'transformers') {\n      embedder = null\n    }\n  }\n\n  if (!embedder) {\n    const idx = new SubstringIndex()\n    await idx.refresh(graph)\n    return idx\n  }\n\n  const cachePath = options.cachePath === undefined ? null : options.cachePath\n  const idx = new VectorIndex(embedder, cachePath)\n  if (cachePath) {\n    const cache = await readCache(cachePath)\n    if (cache) idx.loadFromCache(cache, graph)\n  }\n  await idx.refresh(graph)\n  return idx\n}\n","/**\n * `neat deploy` substrate detection + artifact generation (ADR-073 §2).\n *\n * Three substrates, detected in order:\n *\n *   1. Docker + `docker compose` present → emit `docker-compose.neat.yml`.\n *   2. Bare machine with `systemctl` available → emit `neat.service`.\n *   3. Fallback → print a `docker run` snippet to stdout.\n *\n * Every branch generates a fresh `NEAT_AUTH_TOKEN` (32 bytes, base64url),\n * prints it once, and never embeds it in the on-disk artifact — the file\n * names the env-var, the operator stores the value out of band.\n *\n * Every branch also prints the OTel env-vars block the operator pastes into\n * their application services' deploy platform.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport { randomBytes } from 'node:crypto'\nimport { otlpBearerHeader } from '../otlp-headers.js'\n\nexport type Substrate = 'docker-compose' | 'systemd' | 'docker-run'\n\nexport interface DetectOptions {\n  cwd?: string\n  // Detection is shellable-out by injected probes; tests pass these to avoid\n  // depending on the local docker / systemctl installation.\n  hasDocker?: () => Promise<boolean>\n  hasSystemd?: () => Promise<boolean>\n}\n\nexport interface DeployArtifact {\n  substrate: Substrate\n  // Path written to disk; undefined for the docker-run fallback (stdout-only).\n  artifactPath?: string\n  // The newly generated bearer token. Printed once by the caller, never\n  // re-read from disk.\n  token: string\n  // The body of the artifact. Always returned so callers (and tests) can\n  // inspect what was written without re-reading the file.\n  contents: string\n  // The shell command the operator runs to bring NEAT up on this substrate.\n  startCommand: string\n}\n\nexport function generateToken(): string {\n  // 32 bytes → 43-byte base64url (no padding). Plenty of entropy; URL-safe\n  // so the operator can paste it into env-var dashboards that escape `=`.\n  return randomBytes(32).toString('base64url')\n}\n\nasync function probeBinary(binary: string, arg: string): Promise<boolean> {\n  return new Promise((resolve) => {\n    const child = spawn(binary, [arg], { stdio: 'ignore' })\n    const timer = setTimeout(() => {\n      child.kill('SIGKILL')\n      resolve(false)\n    }, 2000)\n    child.once('error', () => {\n      clearTimeout(timer)\n      resolve(false)\n    })\n    child.once('exit', (code) => {\n      clearTimeout(timer)\n      resolve(code === 0)\n    })\n  })\n}\n\nexport async function detectSubstrate(opts: DetectOptions = {}): Promise<Substrate> {\n  const hasDocker = opts.hasDocker ?? (() => probeBinary('docker', 'version'))\n  const hasSystemd = opts.hasSystemd ?? (() => probeBinary('systemctl', '--version'))\n  if (await hasDocker()) return 'docker-compose'\n  if (await hasSystemd()) return 'systemd'\n  return 'docker-run'\n}\n\nconst IMAGE = 'ghcr.io/neat-technologies/neat:latest'\n\nexport function emitDockerCompose(cwd: string): string {\n  // Compose v3 — declares the three documented ports + a data volume. The\n  // operator's deploy platform supplies `NEAT_AUTH_TOKEN`; the file names\n  // the var with no default, so a missing env stops the container from\n  // coming up rather than running unauthenticated.\n  return [\n    'services:',\n    '  neat:',\n    `    image: ${IMAGE}`,\n    '    restart: unless-stopped',\n    '    environment:',\n    '      NEAT_AUTH_TOKEN: ${NEAT_AUTH_TOKEN:?NEAT_AUTH_TOKEN must be set}',\n    '    ports:',\n    '      - \"8080:8080\"',\n    '      - \"4318:4318\"',\n    '      - \"6328:6328\"',\n    '    volumes:',\n    `      - ${cwd}:/workspace`,\n    '      - ./neat-data:/neat-out',\n    '',\n  ].join('\\n')\n}\n\nexport function emitSystemdUnit(cwd: string): string {\n  // Token lives in /etc/neat/neatd.env (NEAT_AUTH_TOKEN=...) so it's readable\n  // only by root and the service user. The unit itself stays version-\n  // controllable without leaking the secret.\n  return [\n    '# NEAT_AUTH_TOKEN is read from /etc/neat/neatd.env at startup.',\n    '# Put `NEAT_AUTH_TOKEN=<value>` in that file with mode 0640 root:root.',\n    '[Unit]',\n    'Description=NEAT daemon',\n    'After=network-online.target',\n    'Wants=network-online.target',\n    '',\n    '[Service]',\n    'Type=simple',\n    'ExecStart=/usr/local/bin/neatd start --foreground',\n    `WorkingDirectory=${cwd}`,\n    'EnvironmentFile=/etc/neat/neatd.env',\n    'Restart=always',\n    'RestartSec=5',\n    '',\n    '[Install]',\n    'WantedBy=multi-user.target',\n    '',\n  ].join('\\n')\n}\n\nexport function emitDockerRunSnippet(): string {\n  // Single-line `docker run` for substrates we can't detect. Operator pastes\n  // their own token in; the variable name keeps the bearer-token-must-be-set\n  // shape consistent across all three branches.\n  return [\n    '#!/usr/bin/env bash',\n    'set -euo pipefail',\n    '',\n    '# Generate a fresh token once, then store it where your secrets live.',\n    ': \"${NEAT_AUTH_TOKEN:?NEAT_AUTH_TOKEN must be set}\"',\n    '',\n    `docker run -d --name neat \\\\`,\n    '  -e NEAT_AUTH_TOKEN=\"$NEAT_AUTH_TOKEN\" \\\\',\n    '  -p 8080:8080 -p 4318:4318 -p 6328:6328 \\\\',\n    '  -v \"$PWD\":/workspace -v /var/lib/neat:/neat-out \\\\',\n    `  ${IMAGE}`,\n    '',\n  ].join('\\n')\n}\n\nexport interface RenderDeployBlockOptions {\n  substrate: Substrate\n  // Host the operator's services will reach NEAT at. Defaults to a\n  // placeholder so the operator notices and fills it in.\n  host?: string\n}\n\n// The OTel env-vars block the operator pastes into their deploy platform.\n// Format matches the orchestrator summary so the two never drift.\nexport function renderOtelEnvBlock(token: string, host: string = '<host>'): string {\n  return [\n    `OTEL_EXPORTER_OTLP_ENDPOINT=https://${host}:4318`,\n    `OTEL_EXPORTER_OTLP_HEADERS=${otlpBearerHeader(token)}`,\n    'OTEL_SERVICE_NAME=<service>',\n  ].join('\\n')\n}\n\nexport async function runDeploy(opts: DetectOptions = {}): Promise<DeployArtifact> {\n  const cwd = opts.cwd ?? process.cwd()\n  const substrate = await detectSubstrate(opts)\n  const token = generateToken()\n\n  switch (substrate) {\n    case 'docker-compose': {\n      const artifactPath = path.join(cwd, 'docker-compose.neat.yml')\n      const contents = emitDockerCompose(cwd)\n      await fs.writeFile(artifactPath, contents, 'utf8')\n      return {\n        substrate,\n        artifactPath,\n        token,\n        contents,\n        startCommand: `NEAT_AUTH_TOKEN=${token} docker compose -f ${path.basename(artifactPath)} up -d`,\n      }\n    }\n    case 'systemd': {\n      const artifactPath = path.join(cwd, 'neat.service')\n      const contents = emitSystemdUnit(cwd)\n      await fs.writeFile(artifactPath, contents, 'utf8')\n      return {\n        substrate,\n        artifactPath,\n        token,\n        contents,\n        startCommand: [\n          `sudo install -m 0640 -o root -g root <(echo NEAT_AUTH_TOKEN=${token}) /etc/neat/neatd.env`,\n          `sudo install -m 0644 neat.service /etc/systemd/system/neat.service`,\n          'sudo systemctl daemon-reload && sudo systemctl enable --now neat',\n        ].join(' && '),\n      }\n    }\n    case 'docker-run':\n    default: {\n      const contents = emitDockerRunSnippet()\n      // No on-disk artifact for the fallback — operator copies the snippet.\n      return {\n        substrate: 'docker-run',\n        token,\n        contents,\n        startCommand: `NEAT_AUTH_TOKEN=${token} bash <(cat <<'EOF'\\n${contents}EOF\\n)`,\n      }\n    }\n  }\n}\n","/**\n * Installer registry. v0.2.5 step 2 ships the scaffolding; the JavaScript\n * installer (step 3) and Python installer (step 4) populate `INSTALLERS`.\n */\n\nimport type { Installer, InstallPlan } from './shared.js'\nimport { javascriptInstaller } from './javascript.js'\nimport { pythonInstaller } from './python.js'\nimport { goInstaller } from './go.js'\nimport { rubyInstaller } from './ruby.js'\nimport { phpInstaller } from './php.js'\nexport { isEmptyPlan } from './shared.js'\nexport { javascriptInstaller } from './javascript.js'\nexport { pythonInstaller } from './python.js'\nexport { goInstaller } from './go.js'\nexport { rubyInstaller } from './ruby.js'\nexport { phpInstaller } from './php.js'\nexport type {\n  ApplyOutcome,\n  ApplyResult,\n  DependencyEdit,\n  EntrypointEdit,\n  EnvEdit,\n  GeneratedFile,\n  Installer,\n  InstallPlan,\n} from './shared.js'\n\n// Lockfile basenames installers must never write to (ADR-047 — \"lockfiles\n// never touched\"). Used by the patch renderer's safety check below.\nexport const FORBIDDEN_LOCKFILES: ReadonlySet<string> = new Set([\n  'package-lock.json',\n  'pnpm-lock.yaml',\n  'yarn.lock',\n  'poetry.lock',\n  'Pipfile.lock',\n  'Gemfile.lock',\n  'Cargo.lock',\n  'go.sum',\n  'composer.lock',\n])\n\n// Order is priority — first match wins per service. JavaScript leads because\n// it's the most common shape in the projects NEAT targets; Python, Go, Ruby,\n// and PHP follow. Each keys on a distinct marker (package.json / requirements /\n// go.mod / Gemfile / composer.json), so the order only breaks ties on a\n// polyglot directory that carries more than one.\nexport const INSTALLERS: Installer[] = [\n  javascriptInstaller,\n  pythonInstaller,\n  goInstaller,\n  rubyInstaller,\n  phpInstaller,\n]\n\n/**\n * Resolve the first installer that claims a given service directory. Returns\n * `null` if none match.\n *\n * Per language, the first matching installer wins. Order in `INSTALLERS`\n * defines that priority — declarations are explicit, not alphabetical.\n */\nexport async function pickInstaller(serviceDir: string): Promise<Installer | null> {\n  for (const inst of INSTALLERS) {\n    if (await inst.detect(serviceDir)) return inst\n  }\n  return null\n}\n\nexport interface PatchSection {\n  installer: string\n  plan: InstallPlan\n}\n\n/**\n * Render install plans into a single review-friendly text patch. The format\n * is intentionally human-shaped, not unified-diff: agents and humans both\n * read this. Determinism — same input, byte-identical output — is the\n * load-bearing property (ADR-047 #6).\n */\nexport function renderPatch(sections: PatchSection[]): string {\n  if (sections.length === 0) {\n    return [\n      '# neat install plan',\n      '',\n      'No SDK installers matched the discovered services. Two reasons this',\n      'normally happens:',\n      '  - the project uses a language NEAT does not yet instrument',\n      '    (Java / .NET / Rust are out of scope per ADR-047);',\n      '  - the SDK is already installed, so the installer returned an empty',\n      '    plan.',\n      '',\n      'You can re-run `neat init --apply` later to pick up new services.',\n      '',\n    ].join('\\n')\n  }\n\n  const lines: string[] = ['# neat install plan', '']\n  for (const section of sections) {\n    const { installer, plan } = section\n    lines.push(`## ${installer} (${plan.language}) — ${plan.serviceDir}`)\n    lines.push('')\n\n    if (plan.libOnly) {\n      lines.push('### skipped — no resolvable entry point (lib-only)')\n      lines.push('')\n      continue\n    }\n\n    if (plan.entryFile) {\n      lines.push(`entry: ${plan.entryFile}`)\n      lines.push('')\n    }\n\n    if (plan.dependencyEdits.length > 0) {\n      lines.push('### dependencies')\n      // Group by manifest file so each section names the path the apply phase\n      // will write, satisfying the dry-run/apply path-parity contract\n      // (ADR-069 §8).\n      const byFile = new Map<string, typeof plan.dependencyEdits>()\n      for (const dep of plan.dependencyEdits) {\n        // Hard-fail rather than render a patch that could mislead the user\n        // into thinking NEAT touches lockfiles.\n        const base = dep.file.split(/[\\\\/]/).pop() ?? dep.file\n        if (FORBIDDEN_LOCKFILES.has(base)) {\n          throw new Error(\n            `installer \"${installer}\" produced a dependency edit against a lockfile (${dep.file}); ` +\n              `lockfiles must never be touched (ADR-047).`,\n          )\n        }\n        const existing = byFile.get(dep.file) ?? []\n        existing.push(dep)\n        byFile.set(dep.file, existing)\n      }\n      for (const [file, deps] of byFile) {\n        lines.push(`--- ${file}`)\n        for (const dep of deps) {\n          lines.push(`+ \"${dep.name}\": \"${dep.version}\"`)\n        }\n      }\n      lines.push('')\n    }\n\n    if (plan.generatedFiles && plan.generatedFiles.length > 0) {\n      lines.push('### generated files')\n      for (const gen of plan.generatedFiles) {\n        lines.push(`--- (new file) ${gen.file}`)\n        for (const ln of gen.contents.split(/\\r?\\n/)) {\n          lines.push(`+ ${ln}`)\n        }\n      }\n      lines.push('')\n    }\n\n    if (plan.entrypointEdits.length > 0) {\n      lines.push('### entry-point injection')\n      for (const e of plan.entrypointEdits) {\n        lines.push(`--- ${e.file}`)\n        lines.push(`+ ${e.after}`)\n        lines.push(`  ${e.before}`)\n      }\n      lines.push('')\n    }\n\n    if (plan.envEdits.length > 0) {\n      lines.push('### env (written to <package-dir>/.env.neat)')\n      for (const env of plan.envEdits) {\n        lines.push(`- ${env.key}=${env.value}`)\n      }\n      lines.push('')\n    }\n\n    // ADR-073 §1 — surface the next.config edit in the dry-run patch so the\n    // operator can review the framework-flag change before it lands.\n    if (plan.nextConfigEdit) {\n      lines.push('### next.config (framework flag)')\n      lines.push(`--- ${plan.nextConfigEdit.file}`)\n      lines.push(`+ experimental: { instrumentationHook: true }, // ${plan.nextConfigEdit.reason}`)\n      lines.push('')\n    }\n  }\n  return lines.join('\\n')\n}\n","/**\n * Node / TypeScript SDK installer (ADR-047 + ADR-069).\n *\n * Detects services by the presence of a `package.json` carrying a `name`\n * field — same shape `extract/services.ts` uses to decide what counts as a\n * Node service. The plan adds four OTel-adjacent packages to `dependencies`\n * (api, sdk-node, auto-instrumentations-node, dotenv), writes a generated\n * `otel-init.{js,ts}` adjacent to the resolved entry, and injects the\n * require/import as the first non-shebang line of that entry. Per-package\n * `.env.neat` carries `OTEL_SERVICE_NAME` (scope-preserved) so dashboards\n * joining OBSERVED spans against the EXTRACTED graph use the same key.\n *\n * Lockfiles are never touched (ADR-047 §4). The apply phase writes only to\n * package.json, otel-init.{js,ts}, and .env.neat (ADR-069 §7). After\n * `--apply`, init prints \"run npm install\" so the user owns the lockfile\n * commit.\n *\n * Idempotency (ADR-069 §6): the generated otel-init's presence is the\n * primary signal that a package is instrumented end-to-end — when it\n * exists, the apply phase logs `already instrumented` and skips the file\n * write and the entry-point injection together. Existing `.env.neat` files\n * are preserved (never overwritten).\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport semver from 'semver'\nimport { readPackageVersion } from '../banner.js'\nimport type {\n  ApplyResult,\n  DependencyEdit,\n  EntrypointEdit,\n  EnvEdit,\n  GeneratedFile,\n  Installer,\n  InstallPlan,\n  PlanOptions,\n} from './shared.js'\nimport {\n  ASTRO_MIDDLEWARE_JS,\n  ASTRO_MIDDLEWARE_TS,\n  ASTRO_OTEL_INIT_JS,\n  ASTRO_OTEL_INIT_TS,\n  NEXT_INSTRUMENTATION_EDGE_JS,\n  NEXT_INSTRUMENTATION_EDGE_TS,\n  NEXT_INSTRUMENTATION_HEADER,\n  NEXT_INSTRUMENTATION_JS,\n  NEXT_INSTRUMENTATION_NODE_JS,\n  NEXT_INSTRUMENTATION_NODE_TS,\n  NEXT_INSTRUMENTATION_TS,\n  NUXT_OTEL_INIT_JS,\n  NUXT_OTEL_INIT_TS,\n  NUXT_OTEL_PLUGIN_JS,\n  NUXT_OTEL_PLUGIN_TS,\n  OTEL_INIT_CJS,\n  OTEL_INIT_ESM,\n  OTEL_INIT_HEADER,\n  OTEL_INIT_STAMP,\n  OTEL_INIT_TS,\n  OTEL_INIT_TS_CJS,\n  REMIX_OTEL_SERVER_JS,\n  REMIX_OTEL_SERVER_TS,\n  SVELTEKIT_HOOKS_SERVER_JS,\n  SVELTEKIT_HOOKS_SERVER_TS,\n  SVELTEKIT_OTEL_INIT_JS,\n  SVELTEKIT_OTEL_INIT_TS,\n  renderEnvNeat,\n  renderFrameworkOtelInit,\n  renderNextInstrumentationNode,\n  renderNodeOtelInit,\n} from './templates.js'\nimport { resolve as resolveRegistry } from '@neat.is/instrumentation-registry'\n\n// ADR-069 §5 — three OTel packages land in `dependencies`. `dotenv` was a\n// fourth from v0.3.6 through v0.4.3; the generated `otel-init` templates\n// no longer load `.env.neat` from disk (issue #369), so it's gone from the\n// dep set.\nconst SDK_PACKAGES = [\n  { name: '@opentelemetry/api', version: '^1.9.0' },\n  { name: '@opentelemetry/sdk-node', version: '^0.57.0' },\n  { name: '@opentelemetry/auto-instrumentations-node', version: '^0.55.0' },\n] as const\n\n// ADR-126 — the Next.js edge-runtime file is the first named exception to\n// the four-deps invariant (framework-installers.md §6/§7): the standard Node\n// SDK can't execute inside Next's Edge runtime at all, so\n// instrumentation.edge.{ts,js} depends on `@vercel/otel` instead of the\n// shared SDK_PACKAGES set. Scoped to this one generated file's dependency\n// list — SDK_PACKAGES itself is untouched, and every other framework branch\n// keeps reading only SDK_PACKAGES.\nconst NEXT_EDGE_PACKAGES = [{ name: '@vercel/otel', version: '^2.1.3' }] as const\n\n// Issue #376 — non-bundled instrumentations. The auto-instrumentations-node\n// set covers HTTP, fetch, and the common DB drivers via the wire protocol,\n// but libraries that bypass those wires (Prisma's Rust query engine talks\n// to its own engine binary; LangChain wraps model calls in its own SDK)\n// need their own instrumentation package registered explicitly. The detected\n// entries here compose into the generated otel-init's `instrumentations`\n// array — one `instrumentations.push(...)` line per entry — and join the\n// package.json dep set so the registration line resolves at runtime.\n//\n// v0.4.5 scope is Prisma alone (first library that meaningfully widens\n// NEAT's OBSERVED coverage on real codebases). The function's interface is\n// stable so the v0.5.0 instrumentation registry (ADR-080) can return more\n// entries without revisiting the template.\ninterface NonBundledInstrumentation {\n  pkg: string\n  version: string\n  registration: string\n  // The constructor `pkg` exports — what the attachment preload instantiates\n  // from NEAT_OTEL_INSTRUMENTATIONS (ADR-232).\n  exportName: string\n}\n\n// Pull the leading integer out of a semver range. `^6.2.0`, `~6.2.0`, `6.x`,\n// `>=6.0.0 <7` all return 6. Anything we can't parse (workspace:*, file:…,\n// undefined) returns 0 so the caller falls through to the pre-Prisma-6 path.\nexport function getMajor(versionRange: string | undefined): number {\n  if (!versionRange) return 0\n  const match = versionRange.match(/(\\d+)/)\n  return match ? parseInt(match[1], 10) : 0\n}\n\nexport function detectNonBundledInstrumentations(\n  pkg: PackageJsonShape,\n): NonBundledInstrumentation[] {\n  const deps = allDeps(pkg)\n  const out: NonBundledInstrumentation[] = []\n  if ('@prisma/client' in deps) {\n    // Issue #381 — `@prisma/instrumentation@^5` doesn't speak Prisma 6's\n    // tracing-helper API. Connecting the client throws\n    // `this.getGlobalTracingHelper(...).dispatchEngineSpans is not a function`\n    // before any user query lands. Mirror the Prisma major so the\n    // instrumentation package matches the client surface.\n    const prismaMajor = getMajor(deps['@prisma/client'])\n    const prismaInstrVersion = prismaMajor >= 6 ? '^6.0.0' : '^5.0.0'\n    out.push({\n      pkg: '@prisma/instrumentation',\n      version: prismaInstrVersion,\n      registration:\n        \"instrumentations.push(new (require('@prisma/instrumentation').PrismaInstrumentation)())\",\n      exportName: 'PrismaInstrumentation',\n    })\n  }\n  // The Nest instrumentation bundled by auto-instrumentations-node@0.55 only\n  // supports @nestjs/core <11. Register the current package explicitly for\n  // Nest 11 so SERVER spans retain the framework route template (ADR-155).\n  if (getMajor(deps['@nestjs/core']) >= 11) {\n    out.push({\n      pkg: '@opentelemetry/instrumentation-nestjs-core',\n      version: '^0.67.0',\n      registration:\n        \"instrumentations.push(new (require('@opentelemetry/instrumentation-nestjs-core').NestInstrumentation)())\",\n      exportName: 'NestInstrumentation',\n    })\n  }\n  return out\n}\n\nconst OTEL_ENV: EnvEdit = {\n  // ADR-069 §4 — endpoint moves into the per-package .env.neat (written\n  // by the apply phase). The envEdits surface stays for the dry-run\n  // patch render: it documents the key/value the user can inspect in the\n  // generated .env.neat.\n  file: null,\n  key: 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT',\n  value: 'http://localhost:4318/projects/<project>/v1/traces',\n}\n\ninterface PackageJsonShape {\n  name?: string\n  type?: string\n  main?: string\n  bin?: string | Record<string, string>\n  scripts?: Record<string, string>\n  dependencies?: Record<string, string>\n  devDependencies?: Record<string, string>\n}\n\n// v0.4.4 — `OTEL_SERVICE_NAME` regains its proper semantic role: the\n// ServiceNode id inside the project's graph, not the project name. v0.4.1\n// papered over the missing routing key by writing the project basename here;\n// the project-scoped OTLP URL (issue #367) means the URL carries the routing\n// key and the env var goes back to naming the ServiceNode.\nfunction serviceNodeName(pkg: PackageJsonShape, serviceDir: string): string {\n  return pkg.name ?? path.basename(serviceDir)\n}\n\n// The URL routing key. When the orchestrator threads a project through we use\n// it verbatim; ad-hoc / test usage falls back to the package's own name so\n// the generated file is still well-formed.\nfunction projectToken(\n  pkg: PackageJsonShape,\n  serviceDir: string,\n  project: string | undefined,\n): string {\n  if (project && project.length > 0) return project\n  return pkg.name ?? path.basename(serviceDir)\n}\n\n// Issue #370 — runtime-kind detection. The installer historically treated\n// every JavaScript package as a Node service; Brief's frontend workspace\n// showed that wrong assumption write `instrumentation-node/register` into a\n// Vite browser bundle and an Expo React Native entry, where the Node SDK\n// can't execute. Detection runs after framework dispatch (Next / Remix /\n// SvelteKit / Nuxt / Astro all render server-side, so they classify as\n// `node`); only the framework-less packages reach the bucket here.\ntype RuntimeKind = 'node' | 'browser-bundle' | 'react-native' | 'bun' | 'deno' | 'cloudflare-workers' | 'electron'\n\nasync function readJsonFile(p: string): Promise<unknown> {\n  try {\n    const raw = await fs.readFile(p, 'utf8')\n    return JSON.parse(raw) as unknown\n  } catch {\n    return null\n  }\n}\n\nasync function detectRuntimeKind(\n  pkgRoot: string,\n  pkg: PackageJsonShape,\n): Promise<RuntimeKind> {\n  const deps = allDeps(pkg)\n  if ('react-native' in deps || 'expo' in deps) return 'react-native'\n  // Expo apps sometimes carry the SDK only as a transitive dep but always\n  // ship an `app.json` carrying an `expo` block — that's the canonical Expo\n  // signal.\n  const appJson = await readJsonFile(path.join(pkgRoot, 'app.json'))\n  if (appJson && typeof appJson === 'object' && 'expo' in (appJson as Record<string, unknown>)) {\n    return 'react-native'\n  }\n  if (\n    (await exists(path.join(pkgRoot, 'vite.config.js'))) ||\n    (await exists(path.join(pkgRoot, 'vite.config.ts'))) ||\n    (await exists(path.join(pkgRoot, 'vite.config.mjs'))) ||\n    'vite' in deps\n  ) {\n    return 'browser-bundle'\n  }\n  // Issues #389 #390 — out-of-scope runtime detection for BYO-OTel escape hatch.\n  // Order: wrangler.toml first (Workers projects may also carry package.json),\n  // then bun.lockb (Bun projects often have package.json too), then Deno signals.\n  if (await exists(path.join(pkgRoot, 'wrangler.toml'))) return 'cloudflare-workers'\n  if (await exists(path.join(pkgRoot, 'bun.lockb'))) return 'bun'\n  if (\n    (await exists(path.join(pkgRoot, 'deno.json'))) ||\n    (await exists(path.join(pkgRoot, 'deno.lock')))\n  ) {\n    return 'deno'\n  }\n  const engines = (pkg as { engines?: Record<string, unknown> }).engines ?? {}\n  if ('electron' in engines) return 'electron'\n  return 'node'\n}\n\n// Issue #368 — `OTel deps in package.json` is no longer the signal for\n// `already-instrumented`. The hook file is. Each `plan<Framework>` reads its\n// canonical hook path off disk via `await exists(...)` before queueing the\n// generated-file write, so deps-present-but-hook-absent correctly buckets\n// the package as `instrumented` (the installer writes the hook), not\n// `already-instrumented`. The next-deps-no-hook fixture in the contract\n// suite locks this against regression.\n\nasync function readPackageJson(serviceDir: string): Promise<PackageJsonShape | null> {\n  try {\n    const raw = await fs.readFile(path.join(serviceDir, 'package.json'), 'utf8')\n    return JSON.parse(raw) as PackageJsonShape\n  } catch {\n    return null\n  }\n}\n\nasync function exists(p: string): Promise<boolean> {\n  try {\n    await fs.stat(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\n// Read a file's contents, or null when it doesn't exist. Used by the\n// otel-init migration check (file-awareness.md §4) so a single read decides\n// between write / migrate / preserve.\nasync function readFileMaybe(p: string): Promise<string | null> {\n  try {\n    return await fs.readFile(p, 'utf8')\n  } catch {\n    return null\n  }\n}\n\n// Decide what to do with the generated otel-init at `file`, given its rendered\n// current contents. A missing file is written (skipIfExists honours a race\n// where it appears between plan and apply). A NEAT-owned file (carries\n// OTEL_INIT_HEADER) on an older template — no current stamp — is regenerated so\n// a re-run upgrades the install. A current-stamp NEAT file is already current,\n// and a hand-written init (no header) is never touched.\nasync function planOtelInitGeneration(\n  file: string,\n  contents: string,\n): Promise<GeneratedFile | null> {\n  const existing = await readFileMaybe(file)\n  if (existing === null) {\n    return { file, contents, skipIfExists: true }\n  }\n  if (existing.includes(OTEL_INIT_HEADER) && !existing.includes(OTEL_INIT_STAMP)) {\n    return { file, contents, skipIfExists: false }\n  }\n  return null\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n  const pkg = await readPackageJson(serviceDir)\n  return pkg !== null && typeof pkg.name === 'string'\n}\n\n// Returns true when the currently-installed range and the registry-resolved\n// expected range have no intersection — meaning the installed version is\n// incompatible and an upgrade edit should be emitted.\nfunction needsVersionUpgrade(installed: string, expected: string): boolean {\n  return (\n    !semver.satisfies(\n      semver.minVersion(installed)?.version ?? installed,\n      expected,\n    ) && !semver.intersects(installed, expected)\n  )\n}\n\n// ADR-073 §1 — Next.js detection. A package is Next-flavored when it\n// declares `next` as a (dev)dependency AND ships a `next.config.{js,ts,mjs}`\n// at the package root. Both are required: a stray `next` import without the\n// config file isn't a Next app, and a config file without the dep is dead\n// configuration.\nconst NEXT_CONFIG_CANDIDATES = ['next.config.js', 'next.config.ts', 'next.config.mjs']\n\nasync function findNextConfig(serviceDir: string): Promise<string | null> {\n  for (const name of NEXT_CONFIG_CANDIDATES) {\n    const candidate = path.join(serviceDir, name)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\nfunction hasNextDependency(pkg: PackageJsonShape): boolean {\n  return (\n    (pkg.dependencies?.next !== undefined) ||\n    (pkg.devDependencies?.next !== undefined)\n  )\n}\n\n// Read the merged dep + devDep map once per detection step. Framework checks\n// only care about presence, not version.\nfunction allDeps(pkg: PackageJsonShape): Record<string, string> {\n  return { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n}\n\n// Issue #545 — web-framework signals. When a package depends on one of these\n// but the installer couldn't resolve an entry point, it's almost certainly a\n// runnable app whose runtime layer is about to silently fail to engage rather\n// than a true library. The orchestrator uses this to turn a quiet `lib-only N`\n// tally into a loud, actionable line. Presence is enough — version doesn't\n// matter for the warning.\nconst WEB_FRAMEWORK_DEPS = [\n  'express',\n  'fastify',\n  'koa',\n  '@hapi/hapi',\n  'hapi',\n  'restify',\n  'connect',\n  '@nestjs/core',\n  'next',\n  'hono',\n  'elysia',\n  'polka',\n  'micro',\n] as const\n\n// Issue #570 — background-worker / queue-consumer signals. A package that\n// pulls jobs off a queue or consumes a message bus is a runnable process, not\n// a pure library: a lib-only classification on one of these is a missed entry\n// just like a web framework, so it earns the same loud warning instead of a\n// silent `lib-only N`. These sit alongside WEB_FRAMEWORK_DEPS rather than in\n// the registry because they're an app-shape heuristic, not instrumentation\n// coverage — the registry stays the single source of truth for what is/isn't\n// observed (uninstrumentedLibraries below), and these only answer \"is this a\n// runnable app whose entry we failed to find?\".\nconst WORKER_FRAMEWORK_DEPS = [\n  'bullmq',\n  'bull',\n  'bee-queue',\n  'agenda',\n  'kafkajs',\n  'amqplib',\n  'amqp-connection-manager',\n  'nats',\n  'node-resque',\n  'pg-boss',\n  'graphile-worker',\n] as const\n\n// Every dependency family that marks a package as a runnable application\n// (inbound web framework or background worker) rather than a library.\nconst APP_FRAMEWORK_DEPS = [...WEB_FRAMEWORK_DEPS, ...WORKER_FRAMEWORK_DEPS] as const\n\n// The application-framework dependencies a package declares — the names the\n// orchestrator puts in its warning so a lib-only-but-app-shaped package gets a\n// specific recovery line (\"depends on bullmq but neat couldn't resolve an\n// entry\") instead of a silent tally bump.\nexport function appFrameworkDependencies(pkg: PackageJsonShape): string[] {\n  const deps = allDeps(pkg)\n  return APP_FRAMEWORK_DEPS.filter((name) => name in deps)\n}\n\n// Issue #546 — libraries whose calls aren't observed by the default\n// auto-instrumentation set. Resolved through the instrumentation registry (the\n// single source of truth, contract §3) rather than a hardcoded list: a\n// dependency whose registry coverage is `gap` produces no OBSERVED edges out of\n// the box. `sqlite3` / `better-sqlite3` are the motivating cases — in-process\n// drivers that never cross an instrumented wire. Returns the library names so\n// the orchestrator can name them in its guidance line.\nexport function uninstrumentedLibraries(pkg: PackageJsonShape): string[] {\n  const deps = allDeps(pkg)\n  const out: string[] = []\n  for (const [name, version] of Object.entries(deps)) {\n    const entry = resolveRegistry(name, version)\n    if (entry && entry.coverage === 'gap') out.push(name)\n  }\n  return out\n}\n\n// ADR-074 §3 — Remix detection. A package is Remix-flavored when it declares\n// `remix` or any `@remix-run/*` package AND ships an entry-server file at one\n// of the canonical paths (`app/entry.server.{ts,tsx,js,jsx}`).\nconst REMIX_ENTRY_CANDIDATES = [\n  'app/entry.server.ts',\n  'app/entry.server.tsx',\n  'app/entry.server.js',\n  'app/entry.server.jsx',\n]\n\nfunction hasRemixDependency(pkg: PackageJsonShape): boolean {\n  const deps = allDeps(pkg)\n  if ('remix' in deps) return true\n  for (const name of Object.keys(deps)) {\n    if (name.startsWith('@remix-run/')) return true\n  }\n  return false\n}\n\nasync function findRemixEntry(serviceDir: string): Promise<string | null> {\n  for (const rel of REMIX_ENTRY_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\n// ADR-074 §3 — SvelteKit detection. `@sveltejs/kit` dep, plus either an\n// existing `src/hooks.server.{ts,js}` or a top-level `svelte.config.{js,ts}`\n// (the absent-hooks case where the installer creates the hook file).\nconst SVELTEKIT_HOOKS_CANDIDATES = ['src/hooks.server.ts', 'src/hooks.server.js']\nconst SVELTEKIT_CONFIG_CANDIDATES = ['svelte.config.js', 'svelte.config.ts']\n\nfunction hasSvelteKitDependency(pkg: PackageJsonShape): boolean {\n  return '@sveltejs/kit' in allDeps(pkg)\n}\n\nasync function findSvelteKitHooks(serviceDir: string): Promise<string | null> {\n  for (const rel of SVELTEKIT_HOOKS_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\nasync function findSvelteKitConfig(serviceDir: string): Promise<string | null> {\n  for (const rel of SVELTEKIT_CONFIG_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\n// ADR-074 §3 — Nuxt detection. `nuxt` dep + `nuxt.config.{ts,js,mjs}`.\nconst NUXT_CONFIG_CANDIDATES = ['nuxt.config.ts', 'nuxt.config.js', 'nuxt.config.mjs']\n\nfunction hasNuxtDependency(pkg: PackageJsonShape): boolean {\n  return 'nuxt' in allDeps(pkg)\n}\n\nasync function findNuxtConfig(serviceDir: string): Promise<string | null> {\n  for (const name of NUXT_CONFIG_CANDIDATES) {\n    const candidate = path.join(serviceDir, name)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\n// ADR-074 §3 — Astro detection. `astro` dep + `astro.config.{mjs,ts,js}`.\nconst ASTRO_CONFIG_CANDIDATES = ['astro.config.mjs', 'astro.config.ts', 'astro.config.js']\n\nfunction hasAstroDependency(pkg: PackageJsonShape): boolean {\n  return 'astro' in allDeps(pkg)\n}\n\nasync function findAstroConfig(serviceDir: string): Promise<string | null> {\n  for (const name of ASTRO_CONFIG_CANDIDATES) {\n    const candidate = path.join(serviceDir, name)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\n// Parse the leading major version out of a semver range like \"^14.0.3\" or\n// \"~15.0\" or \"15.0.0\". Returns null when the range can't be read (workspace\n// links, git refs, \"*\", etc.).\nexport function parseNextMajor(range: string | undefined): number | null {\n  if (!range) return null\n  const cleaned = range.trim().replace(/^[\\^~>=<\\s]+/, '')\n  const match = cleaned.match(/^(\\d+)/)\n  if (!match) return null\n  const n = Number(match[1])\n  return Number.isFinite(n) ? n : null\n}\n\nasync function isTypeScriptProject(serviceDir: string): Promise<boolean> {\n  return exists(path.join(serviceDir, 'tsconfig.json'))\n}\n\n// ADR-069 §2 + ADR-070 + issue #545 #570 — entry resolution: pkg.main →\n// pkg.bin → scripts.start → scripts.dev → src/index.* →\n// src/{server,main,app,worker}.* → root {server,app,main,worker}.* →\n// root index.*. `pkg.main` is only accepted when\n// the file it names actually exists; a stale `main` (e.g. `dist/index.js` that\n// hasn't been built, or a leftover that was deleted) falls through to the rest\n// of the chain rather than marking the package lib-only. Returns the absolute\n// path to the resolved entry, or null when the package is lib-only (no\n// resolvable entry).\nconst INDEX_EXTENSIONS = ['.ts', '.tsx', '.js', '.mjs', '.cjs']\nconst INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `index${ext}`)\nconst SRC_INDEX_CANDIDATES = INDEX_EXTENSIONS.map((ext) => `src/index${ext}`)\n// `worker` joins the named set (issue #570) — a background-queue worker\n// (bullmq, kafkajs, …) is a runnable process whose entry conventionally lives\n// in `worker.{js,ts}`, never under `index`. Without it the worker fell to\n// lib-only and its runtime layer silently never engaged.\nconst SRC_NAMED_CANDIDATES = ['server', 'main', 'app', 'worker'].flatMap((name) =>\n  INDEX_EXTENSIONS.map((ext) => `src/${name}${ext}`),\n)\n// Issue #545 / #570 — a runnable app commonly keeps its entry at the repo root\n// under a conventional name (`server.js`, `app.js`, `main.js`, or `worker.js`\n// for a queue consumer) with no `scripts.start` and a `pkg.main` that points at\n// a build output that doesn't exist yet. Those shapes resolved to lib-only\n// before — the runtime layer never engaged. Root named candidates sit just\n// before the `index.*` root fallback so they're the last resort after the\n// manifest/script/src signals, but still keep the app from silently dropping\n// out of instrumentation.\nconst ROOT_NAMED_CANDIDATES = ['server', 'app', 'main', 'worker'].flatMap((name) =>\n  INDEX_EXTENSIONS.map((ext) => `${name}${ext}`),\n)\n\n// ADR-070 — script-entry tokeniser. Launchers and similar wrappers we strip\n// before reading the first file-shaped argument. Anything not in this set is\n// treated as a candidate entry if it looks like a relative file path.\nconst SCRIPT_LAUNCHERS = new Set([\n  'node',\n  'ts-node',\n  'tsx',\n  'ts-node-dev',\n  'nodemon',\n  'npx',\n  'pnpm',\n  'yarn',\n  'npm',\n  'cross-env',\n  'dotenv',\n  '--',\n])\n\n// True when the token resembles a path inside the package — contains a `/` or\n// ends in one of the JS/TS extensions we instrument.\nfunction looksLikeEntryPath(token: string): boolean {\n  if (token.length === 0) return false\n  if (token.startsWith('-')) return false\n  if (token.includes('=')) return false // env-var assignments\n  if (token.includes('/')) return true\n  return /\\.(?:m?[jt]sx?|c[jt]s)$/.test(token)\n}\n\n// Bail when the script chains commands or pipes — those scripts mean an\n// orchestrator runs multiple things and our heuristic can't pick safely.\nfunction scriptHasShellChain(script: string): boolean {\n  return /(?:&&|\\|\\||;|\\|(?!\\|))/.test(script)\n}\n\n// Pull the first file-shaped argument out of a script invocation, after\n// stripping recognised launchers and inline env-var assignments. Returns\n// undefined when no candidate surfaces (or when shell chaining bails us out).\nexport function entryFromScript(script: string | undefined): string | undefined {\n  if (!script) return undefined\n  if (scriptHasShellChain(script)) return undefined\n  const tokens = script.split(/\\s+/).filter((t) => t.length > 0)\n  for (const token of tokens) {\n    const lower = token.toLowerCase()\n    if (SCRIPT_LAUNCHERS.has(lower)) continue\n    // Strip a leading `./` so the existence check resolves cleanly.\n    const cleaned = token.startsWith('./') ? token.slice(2) : token\n    if (looksLikeEntryPath(cleaned)) return cleaned\n  }\n  return undefined\n}\n\nexport async function resolveEntry(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n): Promise<string | null> {\n  // 1) pkg.main — but only when it actually exists on disk (ADR-070).\n  if (typeof pkg.main === 'string' && pkg.main.length > 0) {\n    const candidate = path.resolve(serviceDir, pkg.main)\n    if (await exists(candidate)) return candidate\n    // Manifest points main at a missing build output (e.g. dist/index.js\n    // pre-build). Fall through to bin/scripts/src heuristics rather than\n    // marking lib-only.\n  }\n  // 2) pkg.bin (string or pkg.name-keyed map).\n  if (pkg.bin) {\n    let binEntry: string | undefined\n    if (typeof pkg.bin === 'string') {\n      binEntry = pkg.bin\n    } else if (pkg.name && typeof pkg.bin[pkg.name] === 'string') {\n      binEntry = pkg.bin[pkg.name]\n    } else {\n      const first = Object.values(pkg.bin)[0]\n      if (typeof first === 'string') binEntry = first\n    }\n    if (binEntry) {\n      const candidate = path.resolve(serviceDir, binEntry)\n      if (await exists(candidate)) return candidate\n    }\n  }\n  // 3) scripts.start — ADR-070.\n  const startEntry = entryFromScript(pkg.scripts?.start)\n  if (startEntry) {\n    const candidate = path.resolve(serviceDir, startEntry)\n    if (await exists(candidate)) return candidate\n  }\n  // 4) scripts.dev — ADR-070.\n  const devEntry = entryFromScript(pkg.scripts?.dev)\n  if (devEntry) {\n    const candidate = path.resolve(serviceDir, devEntry)\n    if (await exists(candidate)) return candidate\n  }\n  // 5) src/index.* — ADR-070.\n  for (const rel of SRC_INDEX_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  // 6) src/server.*, src/main.*, src/app.*, src/worker.* — ADR-070 + #570.\n  for (const rel of SRC_NAMED_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  // 7) root server.*, app.*, main.*, worker.* — issue #545 / #570. Common for\n  // a runnable app or queue worker whose entry sits at the repo root.\n  for (const rel of ROOT_NAMED_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  // 8) root index.* — original ADR-069 §3 fallback.\n  for (const name of INDEX_CANDIDATES) {\n    const candidate = path.join(serviceDir, name)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\n// ADR-069 §1, §3 — dispatch by entry extension + pkg.type.\ntype EntryFlavor = 'cjs' | 'esm' | 'ts' | 'ts-cjs'\n\nexport function dispatchEntry(entryFile: string, pkg: PackageJsonShape): EntryFlavor {\n  const ext = path.extname(entryFile).toLowerCase()\n  if (ext === '.ts' || ext === '.tsx') return pkg.type === 'module' ? 'ts' : 'ts-cjs'\n  if (ext === '.mjs') return 'esm'\n  if (ext === '.cjs') return 'cjs'\n  // .js — disambiguate on pkg.type. \"module\" → ESM, anything else → CJS.\n  return pkg.type === 'module' ? 'esm' : 'cjs'\n}\n\n// Generated-file basename per flavor.\nfunction otelInitFilename(flavor: EntryFlavor): string {\n  if (flavor === 'ts' || flavor === 'ts-cjs') return 'otel-init.ts'\n  if (flavor === 'esm') return 'otel-init.mjs'\n  return 'otel-init.cjs'\n}\n\nfunction otelInitContents(flavor: EntryFlavor): string {\n  if (flavor === 'ts') return OTEL_INIT_TS\n  if (flavor === 'ts-cjs') return OTEL_INIT_TS_CJS\n  if (flavor === 'esm') return OTEL_INIT_ESM\n  return OTEL_INIT_CJS\n}\n\n// Build the injection line per flavor. The relative path is computed against\n// the entry's directory so the injection works regardless of the entry's\n// depth inside the package.\nexport function injectionLine(\n  flavor: EntryFlavor,\n  entryFile: string,\n  otelInitFile: string,\n): string {\n  let rel = path.relative(path.dirname(entryFile), otelInitFile)\n  if (!rel.startsWith('.')) rel = `./${rel}`\n  // Normalize to forward slashes for cross-platform module specifiers.\n  rel = rel.split(path.sep).join('/')\n  if (flavor === 'cjs') return `require('${rel}')`\n  if (flavor === 'esm') return `import '${rel}'`\n  // TS: drop the .ts extension so the resolver doesn't choke on it under\n  // either tsc-output or runtime-loader pipelines.\n  const tsRel = rel.replace(/\\.ts$/, '')\n  return `import '${tsRel}'`\n}\n\n// Detect whether a given line already matches an injection of our otel-init.\n// Used for the entry-point idempotency check (ADR-069 §6).\nfunction lineIsOtelInjection(line: string): boolean {\n  const trimmed = line.trim()\n  if (trimmed.length === 0) return false\n  // Match require('./otel-init…') and import './otel-init…' shapes.\n  return /(?:require\\(|import\\s+)['\"]\\.\\/otel-init[^'\"]*['\"]/.test(trimmed)\n}\n\n// `create-next-app --src-dir` puts source under `src/` and Next then resolves\n// the instrumentation hook from `src/instrumentation.ts`. Routing the\n// generated files to root in that case means the hook never loads. We detect\n// src-layout by the presence of `src/app/` or `src/pages/` AND the absence of\n// the same at the package root — a project with both is treated as flat, the\n// safer default for monorepos that vendor a `src/` subpackage.\nasync function detectsSrcLayout(serviceDir: string): Promise<boolean> {\n  const [hasSrcApp, hasSrcPages, hasRootApp, hasRootPages] = await Promise.all([\n    exists(path.join(serviceDir, 'src', 'app')),\n    exists(path.join(serviceDir, 'src', 'pages')),\n    exists(path.join(serviceDir, 'app')),\n    exists(path.join(serviceDir, 'pages')),\n  ])\n  return (hasSrcApp || hasSrcPages) && !hasRootApp && !hasRootPages\n}\n\n// ADR-073 §1 / ADR-126 — Next.js apply path. Emits `instrumentation.{ts,js}`,\n// `instrumentation.node.{ts,js}`, and `instrumentation.edge.{ts,js}` at the\n// package root (or under `src/` for `--src-dir` layouts), plus `.env.neat`\n// co-located with them. Skips entry-point injection entirely — Next loads\n// the instrumentation file through its own runtime hook. Queues a\n// next.config edit only when the declared major is < 15 (the flag is\n// on-by-default from Next 15 on).\nasync function planNext(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  nextConfigPath: string,\n  project: string | undefined,\n): Promise<InstallPlan> {\n  const useTs = await isTypeScriptProject(serviceDir)\n  const srcLayout = await detectsSrcLayout(serviceDir)\n  // Co-locate the generated files with where Next looks for the hook. When\n  // src-layout is detected the framework resolves `src/instrumentation.{ts,js}`\n  // and we route the .env.neat alongside so an operator reading the codebase\n  // finds the wiring in one place. The flat layout keeps the existing root\n  // placement.\n  const baseDir = srcLayout ? path.join(serviceDir, 'src') : serviceDir\n  const instrumentationFile = path.join(baseDir, useTs ? 'instrumentation.ts' : 'instrumentation.js')\n  const instrumentationNodeFile = path.join(\n    baseDir,\n    useTs ? 'instrumentation.node.ts' : 'instrumentation.node.js',\n  )\n  const instrumentationEdgeFile = path.join(\n    baseDir,\n    useTs ? 'instrumentation.edge.ts' : 'instrumentation.edge.js',\n  )\n  const envNeatFile = path.join(baseDir, '.env.neat')\n\n  // Dependency edits — `dotenv` is gone repo-wide from v0.4.4 (issue #369),\n  // so SDK_PACKAGES has the three OTel packages the apply phase adds and the\n  // Next branch shares the same loop as every other framework. Issue #376\n  // adds non-bundled instrumentations (Prisma in v0.4.5) — each detected\n  // entry contributes one dep + one registration line into the generated\n  // instrumentation.node file.\n  const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n  const dependencyEdits: DependencyEdit[] = []\n  for (const sdk of SDK_PACKAGES) {\n    if (sdk.name in existingDeps) {\n      if (needsVersionUpgrade(existingDeps[sdk.name]!, sdk.version)) {\n        dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name]! })\n      }\n      continue\n    }\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: sdk.name, version: sdk.version })\n  }\n  // ADR-126 — `@vercel/otel` lands only for the edge file's sake, read from\n  // NEXT_EDGE_PACKAGES rather than SDK_PACKAGES. Same existing-deps / upgrade\n  // check as the loop above so a project that already depends on\n  // `@vercel/otel` (e.g. it already had ambient Vercel tracing) doesn't get a\n  // redundant or downgrading edit.\n  for (const sdk of NEXT_EDGE_PACKAGES) {\n    if (sdk.name in existingDeps) {\n      if (needsVersionUpgrade(existingDeps[sdk.name]!, sdk.version)) {\n        dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name]! })\n      }\n      continue\n    }\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: sdk.name, version: sdk.version })\n  }\n  const nonBundled = detectNonBundledInstrumentations(pkg)\n  for (const inst of nonBundled) {\n    if (inst.pkg in existingDeps) {\n      if (needsVersionUpgrade(existingDeps[inst.pkg]!, inst.version)) {\n        dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg]! })\n      }\n      continue\n    }\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: inst.pkg, version: inst.version })\n  }\n\n  // Generated files — instrumentation pair + .env.neat. Existing files are\n  // preserved (skipIfExists honours user customisations and keeps the apply\n  // phase idempotent per ADR-069 §6). The instrumentation.node template\n  // carries `__SERVICE_NAME__` (the ServiceNode id) and `__PROJECT__` (the\n  // registered project basename — the URL routing key) placeholders we\n  // substitute here so the bundler-survivable `process.env.X ||=` lines land\n  // with both values verbatim.\n  const svcName = serviceNodeName(pkg, serviceDir)\n  const projectName = projectToken(pkg, serviceDir, project)\n  const registrations = nonBundled.map((i) => i.registration)\n  const generatedFiles: GeneratedFile[] = []\n  if (!(await exists(instrumentationFile))) {\n    generatedFiles.push({\n      file: instrumentationFile,\n      contents: useTs ? NEXT_INSTRUMENTATION_TS : NEXT_INSTRUMENTATION_JS,\n      skipIfExists: true,\n    })\n  }\n  if (!(await exists(instrumentationNodeFile))) {\n    generatedFiles.push({\n      file: instrumentationNodeFile,\n      contents: renderNextInstrumentationNode(\n        useTs ? NEXT_INSTRUMENTATION_NODE_TS : NEXT_INSTRUMENTATION_NODE_JS,\n        svcName,\n        projectName,\n        registrations,\n      ),\n      skipIfExists: true,\n    })\n  }\n  // ADR-126 — the edge-runtime file. Same substitution style as the Node\n  // file (renderFrameworkOtelInit does the same __SERVICE_NAME__/__PROJECT__\n  // regex replace renderNextInstrumentationNode does), same skipIfExists\n  // idempotency so a re-run never clobbers a hand-edited registerOTel() call.\n  if (!(await exists(instrumentationEdgeFile))) {\n    generatedFiles.push({\n      file: instrumentationEdgeFile,\n      contents: renderFrameworkOtelInit(\n        useTs ? NEXT_INSTRUMENTATION_EDGE_TS : NEXT_INSTRUMENTATION_EDGE_JS,\n        svcName,\n        projectName,\n      ),\n      skipIfExists: true,\n    })\n  }\n  if (!(await exists(envNeatFile))) {\n    generatedFiles.push({\n      file: envNeatFile,\n      contents: renderEnvNeat(svcName, projectName),\n      skipIfExists: true,\n    })\n  }\n\n  // ADR-073 §1 — `experimental.instrumentationHook: true` is required for\n  // Next 13 / 14 and a no-op on Next 15+. Plan the edit only when the\n  // declared major is < 15 and the flag isn't already present.\n  let nextConfigEdit: InstallPlan['nextConfigEdit']\n  const nextRange = pkg.dependencies?.next ?? pkg.devDependencies?.next\n  const nextMajor = parseNextMajor(nextRange)\n  if (nextMajor !== null && nextMajor < 15) {\n    try {\n      const raw = await fs.readFile(nextConfigPath, 'utf8')\n      if (!raw.includes('instrumentationHook')) {\n        nextConfigEdit = {\n          file: nextConfigPath,\n          reason: `enable experimental.instrumentationHook (Next ${nextMajor} requires the opt-in flag)`,\n        }\n      }\n    } catch {\n      // Config disappeared between detect and plan. Skip the edit.\n    }\n  }\n\n  const empty =\n    dependencyEdits.length === 0 &&\n    generatedFiles.length === 0 &&\n    nextConfigEdit === undefined\n\n  if (empty) {\n    return {\n      language: 'javascript',\n      serviceDir,\n      dependencyEdits: [],\n      entrypointEdits: [],\n      envEdits: [],\n      generatedFiles: [],\n      framework: 'next',\n    }\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits: [],\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n    framework: 'next',\n    ...(nextConfigEdit ? { nextConfigEdit } : {}),\n  }\n}\n\n// ── Meta-framework planners (ADR-074 §3). ───────────────────────────────\n//\n// Each planner mirrors planNext's shape: build dep edits via the same\n// SDK_PACKAGES + existing-deps filter, queue generated files for the\n// framework-canonical hook surface, record `framework: '<name>'`, never\n// inject into pkg.main. Idempotency rides on `skipIfExists` for generated\n// files and on a re-read header-grep for the inject-into-existing case.\n\nfunction buildDependencyEdits(\n  pkg: PackageJsonShape,\n  manifestPath: string,\n): DependencyEdit[] {\n  const existingDeps = allDeps(pkg)\n  const edits: DependencyEdit[] = []\n  for (const sdk of SDK_PACKAGES) {\n    if (sdk.name in existingDeps) continue\n    edits.push({\n      file: manifestPath,\n      kind: 'add',\n      name: sdk.name,\n      version: sdk.version,\n    })\n  }\n  return edits\n}\n\nasync function queueEnvNeat(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  project: string | undefined,\n  generatedFiles: GeneratedFile[],\n): Promise<void> {\n  const envNeatFile = path.join(serviceDir, '.env.neat')\n  if (!(await exists(envNeatFile))) {\n    generatedFiles.push({\n      file: envNeatFile,\n      contents: renderEnvNeat(\n        serviceNodeName(pkg, serviceDir),\n        projectToken(pkg, serviceDir, project),\n      ),\n      skipIfExists: true,\n    })\n  }\n}\n\nfunction renderFrameworkOtelInitForPkg(\n  template: string,\n  pkg: PackageJsonShape,\n  serviceDir: string,\n  project: string | undefined,\n): string {\n  return renderFrameworkOtelInit(\n    template,\n    serviceNodeName(pkg, serviceDir),\n    projectToken(pkg, serviceDir, project),\n  )\n}\n\nfunction fileImportsOtelHook(raw: string, specifiers: readonly string[]): boolean {\n  const lines = raw.split(/\\r?\\n/)\n  for (const line of lines) {\n    const trimmed = line.trim()\n    for (const spec of specifiers) {\n      const escaped = spec.replace(/\\./g, '\\\\.')\n      const pattern = new RegExp(\n        `(?:import\\\\s+['\"]${escaped}['\"]|require\\\\(['\"]${escaped}['\"]\\\\))`,\n      )\n      if (pattern.test(trimmed)) return true\n    }\n  }\n  return false\n}\n\nasync function planRemix(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  entryFile: string,\n  project: string | undefined,\n): Promise<InstallPlan> {\n  const useTs = await isTypeScriptProject(serviceDir)\n  const otelServerFile = path.join(\n    serviceDir,\n    useTs ? 'app/otel.server.ts' : 'app/otel.server.js',\n  )\n\n  const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n  const generatedFiles: GeneratedFile[] = []\n\n  if (!(await exists(otelServerFile))) {\n    generatedFiles.push({\n      file: otelServerFile,\n      contents: renderFrameworkOtelInitForPkg(\n        useTs ? REMIX_OTEL_SERVER_TS : REMIX_OTEL_SERVER_JS,\n        pkg,\n        serviceDir,\n        project,\n      ),\n      skipIfExists: true,\n    })\n  }\n  await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n  const entrypointEdits: EntrypointEdit[] = []\n  try {\n    const raw = await fs.readFile(entryFile, 'utf8')\n    if (!fileImportsOtelHook(raw, ['./otel.server'])) {\n      const lines = raw.split(/\\r?\\n/)\n      const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n      entrypointEdits.push({\n        file: entryFile,\n        before: firstReal,\n        after: \"import './otel.server'\",\n      })\n    }\n  } catch {\n    // Entry file disappeared between detect and plan; fall through.\n  }\n\n  const empty =\n    dependencyEdits.length === 0 &&\n    generatedFiles.length === 0 &&\n    entrypointEdits.length === 0\n\n  if (empty) {\n    return {\n      language: 'javascript',\n      serviceDir,\n      dependencyEdits: [],\n      entrypointEdits: [],\n      envEdits: [],\n      generatedFiles: [],\n      framework: 'remix',\n    }\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits,\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n    framework: 'remix',\n  }\n}\n\nasync function planSvelteKit(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  hooksFile: string | null,\n  project: string | undefined,\n): Promise<InstallPlan> {\n  const useTs = await isTypeScriptProject(serviceDir)\n  const otelInitFile = path.join(\n    serviceDir,\n    useTs ? 'src/otel-init.ts' : 'src/otel-init.js',\n  )\n  const resolvedHooksFile =\n    hooksFile ??\n    path.join(serviceDir, useTs ? 'src/hooks.server.ts' : 'src/hooks.server.js')\n\n  const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n  const generatedFiles: GeneratedFile[] = []\n  const entrypointEdits: EntrypointEdit[] = []\n\n  if (!(await exists(otelInitFile))) {\n    generatedFiles.push({\n      file: otelInitFile,\n      contents: renderFrameworkOtelInitForPkg(\n        useTs ? SVELTEKIT_OTEL_INIT_TS : SVELTEKIT_OTEL_INIT_JS,\n        pkg,\n        serviceDir,\n        project,\n      ),\n      skipIfExists: true,\n    })\n  }\n  await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n  if (hooksFile === null) {\n    generatedFiles.push({\n      file: resolvedHooksFile,\n      contents: useTs ? SVELTEKIT_HOOKS_SERVER_TS : SVELTEKIT_HOOKS_SERVER_JS,\n      skipIfExists: true,\n    })\n  } else {\n    try {\n      const raw = await fs.readFile(hooksFile, 'utf8')\n      if (!fileImportsOtelHook(raw, ['./otel-init'])) {\n        const lines = raw.split(/\\r?\\n/)\n        const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n        entrypointEdits.push({\n          file: hooksFile,\n          before: firstReal,\n          after: \"import './otel-init'\",\n        })\n      }\n    } catch {\n      // Disappeared between detect and plan; fall through.\n    }\n  }\n\n  const empty =\n    dependencyEdits.length === 0 &&\n    generatedFiles.length === 0 &&\n    entrypointEdits.length === 0\n\n  if (empty) {\n    return {\n      language: 'javascript',\n      serviceDir,\n      dependencyEdits: [],\n      entrypointEdits: [],\n      envEdits: [],\n      generatedFiles: [],\n      framework: 'sveltekit',\n    }\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits,\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n    framework: 'sveltekit',\n  }\n}\n\nasync function planNuxt(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  project: string | undefined,\n): Promise<InstallPlan> {\n  const useTs = await isTypeScriptProject(serviceDir)\n  const otelPluginFile = path.join(\n    serviceDir,\n    useTs ? 'server/plugins/otel.ts' : 'server/plugins/otel.js',\n  )\n  const otelInitFile = path.join(\n    serviceDir,\n    useTs ? 'server/plugins/otel-init.ts' : 'server/plugins/otel-init.js',\n  )\n\n  const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n  const generatedFiles: GeneratedFile[] = []\n\n  if (!(await exists(otelInitFile))) {\n    generatedFiles.push({\n      file: otelInitFile,\n      contents: renderFrameworkOtelInitForPkg(\n        useTs ? NUXT_OTEL_INIT_TS : NUXT_OTEL_INIT_JS,\n        pkg,\n        serviceDir,\n        project,\n      ),\n      skipIfExists: true,\n    })\n  }\n  if (!(await exists(otelPluginFile))) {\n    generatedFiles.push({\n      file: otelPluginFile,\n      contents: useTs ? NUXT_OTEL_PLUGIN_TS : NUXT_OTEL_PLUGIN_JS,\n      skipIfExists: true,\n    })\n  }\n  await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n  const empty = dependencyEdits.length === 0 && generatedFiles.length === 0\n\n  if (empty) {\n    return {\n      language: 'javascript',\n      serviceDir,\n      dependencyEdits: [],\n      entrypointEdits: [],\n      envEdits: [],\n      generatedFiles: [],\n      framework: 'nuxt',\n    }\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits: [],\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n    framework: 'nuxt',\n  }\n}\n\nconst ASTRO_MIDDLEWARE_CANDIDATES = ['src/middleware.ts', 'src/middleware.js']\n\nasync function findAstroMiddleware(serviceDir: string): Promise<string | null> {\n  for (const rel of ASTRO_MIDDLEWARE_CANDIDATES) {\n    const candidate = path.join(serviceDir, rel)\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\nasync function planAstro(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  project: string | undefined,\n): Promise<InstallPlan> {\n  const useTs = await isTypeScriptProject(serviceDir)\n  const otelInitFile = path.join(\n    serviceDir,\n    useTs ? 'src/otel-init.ts' : 'src/otel-init.js',\n  )\n  const existingMiddleware = await findAstroMiddleware(serviceDir)\n  const middlewareFile =\n    existingMiddleware ??\n    path.join(serviceDir, useTs ? 'src/middleware.ts' : 'src/middleware.js')\n\n  const dependencyEdits = buildDependencyEdits(pkg, manifestPath)\n  const generatedFiles: GeneratedFile[] = []\n  const entrypointEdits: EntrypointEdit[] = []\n\n  if (!(await exists(otelInitFile))) {\n    generatedFiles.push({\n      file: otelInitFile,\n      contents: renderFrameworkOtelInitForPkg(\n        useTs ? ASTRO_OTEL_INIT_TS : ASTRO_OTEL_INIT_JS,\n        pkg,\n        serviceDir,\n        project,\n      ),\n      skipIfExists: true,\n    })\n  }\n  await queueEnvNeat(serviceDir, pkg, project, generatedFiles)\n\n  if (existingMiddleware === null) {\n    generatedFiles.push({\n      file: middlewareFile,\n      contents: useTs ? ASTRO_MIDDLEWARE_TS : ASTRO_MIDDLEWARE_JS,\n      skipIfExists: true,\n    })\n  } else {\n    try {\n      const raw = await fs.readFile(existingMiddleware, 'utf8')\n      if (!fileImportsOtelHook(raw, ['./otel-init'])) {\n        const lines = raw.split(/\\r?\\n/)\n        const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n        entrypointEdits.push({\n          file: existingMiddleware,\n          before: firstReal,\n          after: \"import './otel-init'\",\n        })\n      }\n    } catch {\n      // Disappeared between detect and plan; fall through.\n    }\n  }\n\n  const empty =\n    dependencyEdits.length === 0 &&\n    generatedFiles.length === 0 &&\n    entrypointEdits.length === 0\n\n  if (empty) {\n    return {\n      language: 'javascript',\n      serviceDir,\n      dependencyEdits: [],\n      entrypointEdits: [],\n      envEdits: [],\n      generatedFiles: [],\n      framework: 'astro',\n    }\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits,\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n    framework: 'astro',\n  }\n}\n\ntype FrameworkDispatch = () => Promise<InstallPlan>\n\n// ADR-073 §1 + ADR-074 §3 — framework signal lookup. Returns a thunk that\n// invokes the framework-specific planner when a match lands, or null when\n// none do. Detection precedence is Next → Remix → SvelteKit → Nuxt → Astro;\n// the chain bails on the first match. Pulled out of `plan()` so issue\n// #375's lib-only check can see the framework signal upfront — a package\n// with no framework hook AND no Node entry buckets as lib-only regardless\n// of stray Vite config or Expo deps.\nasync function findFrameworkDispatch(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  project: string | undefined,\n): Promise<FrameworkDispatch | null> {\n  if (hasNextDependency(pkg)) {\n    const nextConfig = await findNextConfig(serviceDir)\n    if (nextConfig) {\n      return () => planNext(serviceDir, pkg, manifestPath, nextConfig, project)\n    }\n  }\n  if (hasRemixDependency(pkg)) {\n    const remixEntry = await findRemixEntry(serviceDir)\n    if (remixEntry) {\n      return () => planRemix(serviceDir, pkg, manifestPath, remixEntry, project)\n    }\n  }\n  if (hasSvelteKitDependency(pkg)) {\n    const hooks = await findSvelteKitHooks(serviceDir)\n    const config = await findSvelteKitConfig(serviceDir)\n    if (hooks || config) {\n      return () => planSvelteKit(serviceDir, pkg, manifestPath, hooks, project)\n    }\n  }\n  if (hasNuxtDependency(pkg)) {\n    const nuxtConfig = await findNuxtConfig(serviceDir)\n    if (nuxtConfig) {\n      return () => planNuxt(serviceDir, pkg, manifestPath, project)\n    }\n  }\n  if (hasAstroDependency(pkg)) {\n    const astroConfig = await findAstroConfig(serviceDir)\n    if (astroConfig) {\n      return () => planAstro(serviceDir, pkg, manifestPath, project)\n    }\n  }\n  return null\n}\n\n// ADR-232 — the attachment package the user's app loads via NODE_OPTIONS.\n// Adding it as a dependency is the only manifest touch attachment makes. It\n// ships in the release lockstep, so the range is this core's own version: the\n// otel-node that was published alongside it.\nconst ATTACH_PACKAGE_NAME = '@neat.is/otel-node'\n\nexport function attachPackageRange(coreVersion: string = readPackageVersion()): string {\n  return semver.valid(coreVersion) ? `^${coreVersion}` : 'latest'\n}\n\n// Attachment delivery (ADR-232, the default): add `@neat.is/otel-node` and\n// write `.env.neat` with a NODE_OPTIONS `--require`/`--import` line that loads\n// the bootstrap before the app boots. Framework-agnostic — no otel-init, no\n// entry-point edit — so it needs none of the per-framework planners.\nasync function planAttachment(\n  serviceDir: string,\n  pkg: PackageJsonShape,\n  manifestPath: string,\n  project: string | undefined,\n): Promise<InstallPlan> {\n  const svcName = serviceNodeName(pkg, serviceDir)\n  const projectName = projectToken(pkg, serviceDir, project)\n  const envNeatFile = path.join(serviceDir, '.env.neat')\n  // ESM services load the bootstrap with `--import` (the import-in-the-middle\n  // loader-hook path); CJS with `--require` (#1200).\n  const flag = pkg.type === 'module' ? '--import' : '--require'\n  const nodeOptions = `${flag} @neat.is/otel-node/register`\n\n  const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n  const dependencyEdits: DependencyEdit[] = []\n  if (!(ATTACH_PACKAGE_NAME in existingDeps)) {\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: ATTACH_PACKAGE_NAME, version: attachPackageRange() })\n  }\n  // Instrumentations outside the auto bundle (Prisma, Nest 11): the same\n  // dependency edits source-edit makes, named for the preload to load.\n  const nonBundled = detectNonBundledInstrumentations(pkg)\n  for (const inst of nonBundled) {\n    if (inst.pkg in existingDeps) {\n      if (needsVersionUpgrade(existingDeps[inst.pkg]!, inst.version)) {\n        dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg]! })\n      }\n      continue\n    }\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: inst.pkg, version: inst.version })\n  }\n  const extraInstrumentations = nonBundled.map((i) => `${i.pkg}#${i.exportName}`)\n\n  const generatedFiles: GeneratedFile[] = []\n  if (!(await exists(envNeatFile))) {\n    generatedFiles.push({\n      file: envNeatFile,\n      contents: renderEnvNeat(svcName, projectName, nodeOptions, extraInstrumentations),\n      skipIfExists: true,\n    })\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits: [],\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n  }\n}\n\nasync function plan(serviceDir: string, opts?: PlanOptions): Promise<InstallPlan> {\n  const pkg = await readPackageJson(serviceDir)\n  const manifestPath = path.join(serviceDir, 'package.json')\n  const project = opts?.project\n  const empty: InstallPlan = {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits: [],\n    entrypointEdits: [],\n    envEdits: [],\n    generatedFiles: [],\n  }\n  if (!pkg) return empty\n\n  // Issue #375 — classification pipeline order: lib-only → framework →\n  // runtime-kind → emit. A package with no framework hook AND no resolvable\n  // Node entry is lib-only regardless of stray Vite config or Expo deps. The\n  // runtime-kind dispatch only fires for non-framework packages that\n  // actually have an entry to instrument; without this ordering, a UI library\n  // that ships a `vite.config.ts` for its build pipeline would bucket as\n  // browser-bundle and surface in the operator summary as if it were a real\n  // SPA the installer was choosing to skip.\n  const frameworkDispatch = await findFrameworkDispatch(\n    serviceDir,\n    pkg,\n    manifestPath,\n    project,\n  )\n\n  // Resolve the Node entry and runtime kind up front so the skip decisions are\n  // identical in both delivery modes. Frameworks own their boot path, so the\n  // non-framework branch is the only one that needs these signals.\n  let entryFile: string | null = null\n  if (!frameworkDispatch) {\n    entryFile = await resolveEntry(serviceDir, pkg)\n    if (!entryFile) {\n      return { ...empty, libOnly: true }\n    }\n    // Issue #370 — browser bundles (Vite) and React Native / Expo packages\n    // bucket here so the apply phase skips every write and surfaces the package\n    // in the summary instead of instrumenting code that can't run a Node SDK.\n    const runtimeKind = await detectRuntimeKind(serviceDir, pkg)\n    if (runtimeKind !== 'node') {\n      return { ...empty, runtimeKind }\n    }\n  }\n\n  // Instrumentable: a framework service, or a Node service with a resolved\n  // entry. ADR-232 — attachment is the default delivery. It's framework-\n  // agnostic (NODE_OPTIONS loads the bootstrap before any boot path), edits no\n  // source, and needs none of the per-framework planners. Source-edit\n  // injection runs only under --source-edit.\n  if (!opts?.sourceEdit) {\n    return planAttachment(serviceDir, pkg, manifestPath, project)\n  }\n\n  // ── Source-edit delivery (--source-edit) — the pre-ADR-232 path. ──\n  if (frameworkDispatch) {\n    return frameworkDispatch()\n  }\n\n  // Vanilla Node: entryFile is non-null here (lib-only already returned) and\n  // the runtime is Node (checked above). The guard re-narrows it for the type\n  // checker across the delivery-mode branch.\n  if (!entryFile) {\n    return { ...empty, libOnly: true }\n  }\n  const flavor = dispatchEntry(entryFile, pkg)\n  const otelInitFile = path.join(path.dirname(entryFile), otelInitFilename(flavor))\n  const envNeatFile = path.join(serviceDir, '.env.neat')\n\n  // ── Dependency edits (four-deps invariant; ADR-069 §5). ────────────────\n  // Issue #376 — non-bundled instrumentations append additional deps when\n  // the host package declares libraries whose runtime traffic bypasses the\n  // auto-instrumentation set (Prisma's Rust query engine for v0.4.5; the\n  // v0.5.0 registry feeds the same loop with more entries).\n  const existingDeps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }\n  const dependencyEdits: DependencyEdit[] = []\n  for (const sdk of SDK_PACKAGES) {\n    if (sdk.name in existingDeps) {\n      if (needsVersionUpgrade(existingDeps[sdk.name]!, sdk.version)) {\n        dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: sdk.name, version: sdk.version, fromVersion: existingDeps[sdk.name]! })\n      }\n      continue\n    }\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: sdk.name, version: sdk.version })\n  }\n  const nonBundled = detectNonBundledInstrumentations(pkg)\n  for (const inst of nonBundled) {\n    if (inst.pkg in existingDeps) {\n      if (needsVersionUpgrade(existingDeps[inst.pkg]!, inst.version)) {\n        dependencyEdits.push({ file: manifestPath, kind: 'upgrade', name: inst.pkg, version: inst.version, fromVersion: existingDeps[inst.pkg]! })\n      }\n      continue\n    }\n    dependencyEdits.push({ file: manifestPath, kind: 'add', name: inst.pkg, version: inst.version })\n  }\n\n  // ── Entry-point injection edit (ADR-069 §3). ───────────────────────────\n  const entrypointEdits: EntrypointEdit[] = []\n  try {\n    const raw = await fs.readFile(entryFile, 'utf8')\n    const lines = raw.split(/\\r?\\n/)\n    // Preserve a shebang on line 1 and check line 2 (the first non-shebang\n    // line) for an existing injection.\n    const firstReal = lines[0]?.startsWith('#!') ? lines[1] ?? '' : lines[0] ?? ''\n    if (!lineIsOtelInjection(firstReal)) {\n      const inject = injectionLine(flavor, entryFile, otelInitFile)\n      // Use the existing first-real line as the `before` marker so the apply\n      // phase can splice the injection cleanly even if the file shifts.\n      entrypointEdits.push({\n        file: entryFile,\n        before: firstReal,\n        after: inject,\n      })\n    }\n  } catch {\n    // Entry file disappeared between resolve and plan (rare). Treat as\n    // lib-only.\n    return { ...empty, libOnly: true }\n  }\n\n  // ── Generated files (ADR-069 §1, §4). ──────────────────────────────────\n  // v0.4.4 — the otel-init template carries `__SERVICE_NAME__` (the\n  // ServiceNode id) and `__PROJECT__` (the URL routing key) placeholders we\n  // substitute here. The .env.neat shape lands with the same pair so an\n  // operator can grep for both fields in one place.\n  // v0.4.5 — `__INSTRUMENTATION_BLOCK__` substitutes to the registration\n  // snippets for any non-bundled instrumentations detected above (Prisma\n  // for v0.4.5; the v0.5.0 registry will feed more entries through the same\n  // path). Empty list collapses cleanly to nothing.\n  const svcName = serviceNodeName(pkg, serviceDir)\n  const projectName = projectToken(pkg, serviceDir, project)\n  const registrations = nonBundled.map((i) => i.registration)\n  const generatedFiles: GeneratedFile[] = []\n  const otelInitGen = await planOtelInitGeneration(\n    otelInitFile,\n    renderNodeOtelInit(otelInitContents(flavor), svcName, projectName, registrations),\n  )\n  if (otelInitGen) generatedFiles.push(otelInitGen)\n  if (!(await exists(envNeatFile))) {\n    generatedFiles.push({\n      file: envNeatFile,\n      contents: renderEnvNeat(svcName, projectName),\n      skipIfExists: true,\n    })\n  }\n\n  // ── Idempotency check (ADR-069 §6). ────────────────────────────────────\n  // If the package is already instrumented end-to-end — deps present, entry\n  // already injected, generated files already there — return an empty plan.\n  if (\n    dependencyEdits.length === 0 &&\n    entrypointEdits.length === 0 &&\n    generatedFiles.length === 0\n  ) {\n    return empty\n  }\n\n  return {\n    language: 'javascript',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits,\n    envEdits: [OTEL_ENV],\n    generatedFiles,\n    entryFile,\n    libOnly: false,\n  }\n}\n\n// ADR-069 §7 + ADR-073 §1 + ADR-074 §3 — allowed write paths. Anything\n// outside this set inside an installer's apply phase is a contract violation.\nfunction isAllowedWritePath(serviceDir: string, target: string): boolean {\n  const rel = path.relative(serviceDir, target)\n  if (rel.startsWith('..')) return false\n  const base = path.basename(target)\n  if (base === 'package.json') return true\n  if (base === '.env.neat') return true\n  if (/^otel-init\\.(?:js|cjs|mjs|ts)$/.test(base)) return true\n  // ADR-073 §1 / ADR-126 — Next framework files at the package root, or\n  // under src/ when create-next-app's --src-dir layout is in use. The\n  // instrumentation hook resolves from `src/` in that layout; routing files\n  // there is the load-bearing fix for the src-dir shape. `.edge` joins\n  // `.node` as the second runtime-scoped instrumentation file (ADR-126).\n  const relPosix = rel.split(path.sep).join('/')\n  if (/^instrumentation(?:\\.(?:node|edge))?\\.(?:js|cjs|mjs|ts)$/.test(base)) {\n    if (relPosix === base) return true\n    if (relPosix === `src/${base}`) return true\n    return false\n  }\n  if (/^next\\.config\\.(?:js|mjs|ts)$/.test(base)) return true\n  // ADR-074 §3 — meta-framework hook surfaces.\n  if (relPosix === 'app/otel.server.ts' || relPosix === 'app/otel.server.js') return true\n  if (/^app\\/entry\\.server\\.(?:tsx?|jsx?)$/.test(relPosix)) return true\n  if (relPosix === 'src/otel-init.ts' || relPosix === 'src/otel-init.js') return true\n  if (relPosix === 'src/hooks.server.ts' || relPosix === 'src/hooks.server.js') return true\n  if (relPosix === 'server/plugins/otel.ts' || relPosix === 'server/plugins/otel.js') return true\n  if (relPosix === 'server/plugins/otel-init.ts' || relPosix === 'server/plugins/otel-init.js') return true\n  if (relPosix === 'src/middleware.ts' || relPosix === 'src/middleware.js') return true\n  return false\n}\n\nasync function writeAtomic(file: string, contents: string): Promise<void> {\n  // Meta-framework branches write to convention-driven subdirs that the user\n  // may not have scaffolded yet (`server/plugins/`, `src/`, `app/`). Ensure\n  // the parent directory exists before the atomic write; existing parents\n  // are a no-op under `recursive: true`.\n  await fs.mkdir(path.dirname(file), { recursive: true })\n  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`\n  await fs.writeFile(tmp, contents, 'utf8')\n  await fs.rename(tmp, file)\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n  const { serviceDir } = installPlan\n  if (installPlan.libOnly) {\n    return {\n      serviceDir,\n      outcome: 'lib-only',\n      reason: 'no resolvable entry point',\n      writtenFiles: [],\n    }\n  }\n\n  // Issue #370 — non-Node runtimes write nothing. The CLI surfaces the\n  // outcome in the summary so the operator can see which packages were\n  // skipped and why.\n  if (installPlan.runtimeKind === 'browser-bundle') {\n    return {\n      serviceDir,\n      outcome: 'browser-bundle',\n      reason: 'browser bundle; Node OTel SDK cannot run here',\n      writtenFiles: [],\n    }\n  }\n  if (installPlan.runtimeKind === 'react-native') {\n    return {\n      serviceDir,\n      outcome: 'react-native',\n      reason: 'React Native / Expo target; Node OTel SDK cannot run here',\n      writtenFiles: [],\n    }\n  }\n  if (installPlan.runtimeKind === 'bun') {\n    return { serviceDir, outcome: 'bun', reason: 'Bun runtime; use BYO-OTel', writtenFiles: [] }\n  }\n  if (installPlan.runtimeKind === 'deno') {\n    return { serviceDir, outcome: 'deno', reason: 'Deno runtime; use BYO-OTel', writtenFiles: [] }\n  }\n  if (installPlan.runtimeKind === 'cloudflare-workers') {\n    return {\n      serviceDir,\n      outcome: 'cloudflare-workers',\n      reason: 'Cloudflare Workers runtime; use BYO-OTel',\n      writtenFiles: [],\n    }\n  }\n  if (installPlan.runtimeKind === 'electron') {\n    return {\n      serviceDir,\n      outcome: 'electron',\n      reason: 'Electron; use BYO-OTel',\n      writtenFiles: [],\n    }\n  }\n\n  // Already-instrumented check: an empty plan means there's nothing to do.\n  if (\n    installPlan.dependencyEdits.length === 0 &&\n    installPlan.entrypointEdits.length === 0 &&\n    (installPlan.generatedFiles?.length ?? 0) === 0 &&\n    installPlan.nextConfigEdit === undefined\n  ) {\n    return {\n      serviceDir,\n      outcome: 'already-instrumented',\n      writtenFiles: [],\n    }\n  }\n\n  // Validate every target we plan to touch against the allowed-path set.\n  // Bail out before any write if a violation slipped through.\n  const allTargets = new Set<string>()\n  for (const d of installPlan.dependencyEdits) allTargets.add(d.file)\n  for (const e of installPlan.entrypointEdits) allTargets.add(e.file)\n  for (const g of installPlan.generatedFiles ?? []) allTargets.add(g.file)\n  if (installPlan.nextConfigEdit) allTargets.add(installPlan.nextConfigEdit.file)\n  for (const target of allTargets) {\n    // Entry-point edits land in user source files, not the allowed set —\n    // they're explicitly carved out below.\n    const isEntryEdit = installPlan.entrypointEdits.some((e) => e.file === target)\n    if (isEntryEdit) continue\n    if (!isAllowedWritePath(serviceDir, target)) {\n      throw new Error(\n        `javascript installer: refusing to write outside the allowed path set (ADR-069 §7): ${target}`,\n      )\n    }\n  }\n\n  // Snapshot every file we may touch so a partial failure can roll back the\n  // batch (ADR-047 §7). Newly-generated files have no prior contents — they\n  // get tracked separately so rollback unlinks them instead of restoring.\n  const originals = new Map<string, string>()\n  const createdFiles: string[] = []\n  for (const target of allTargets) {\n    if (await exists(target)) {\n      try {\n        originals.set(target, await fs.readFile(target, 'utf8'))\n      } catch {\n        // Best-effort. The mutation loop below will throw if this matters.\n      }\n    }\n  }\n\n  const writtenFiles: string[] = []\n  try {\n    // ── 1. Manifest edits (package.json) ─────────────────────────────────\n    const manifestTargets = installPlan.dependencyEdits\n      .reduce<Set<string>>((acc, e) => {\n        acc.add(e.file)\n        return acc\n      }, new Set())\n    for (const file of manifestTargets) {\n      const raw = originals.get(file)\n      if (raw === undefined) {\n        throw new Error(`javascript installer: cannot read ${file} during apply`)\n      }\n      const pkg = JSON.parse(raw) as PackageJsonShape\n      pkg.dependencies = pkg.dependencies ?? {}\n      for (const dep of installPlan.dependencyEdits) {\n        if (dep.file !== file) continue\n        if (dep.kind === 'add') {\n          if (!(dep.name in (pkg.dependencies ?? {}))) {\n            pkg.dependencies[dep.name] = dep.version\n          }\n        } else if (dep.kind === 'upgrade') {\n          pkg.dependencies[dep.name] = dep.version\n        } else {\n          delete pkg.dependencies[dep.name]\n        }\n      }\n      const newRaw = JSON.stringify(pkg, null, 2) + '\\n'\n      await writeAtomic(file, newRaw)\n      writtenFiles.push(file)\n    }\n\n    // ── 2. Generated files (otel-init, .env.neat) ────────────────────────\n    for (const gen of installPlan.generatedFiles ?? []) {\n      if (gen.skipIfExists && (await exists(gen.file))) {\n        // Skip silently; the contract treats this as part of the\n        // already-instrumented path.\n        continue\n      }\n      await writeAtomic(gen.file, gen.contents)\n      if (!originals.has(gen.file)) createdFiles.push(gen.file)\n      writtenFiles.push(gen.file)\n    }\n\n    // ── 3. Entry-point injection (require/import on first non-shebang line)\n    for (const ep of installPlan.entrypointEdits) {\n      const raw = originals.get(ep.file)\n      if (raw === undefined) {\n        throw new Error(`javascript installer: cannot read entry ${ep.file} during apply`)\n      }\n      const lines = raw.split(/\\r?\\n/)\n      const hasShebang = lines[0]?.startsWith('#!') ?? false\n      const insertAt = hasShebang ? 1 : 0\n      // Idempotency: if the first non-shebang line already matches our\n      // injection pattern, skip — never double-inject.\n      const firstReal = lines[insertAt] ?? ''\n      if (lineIsOtelInjection(firstReal)) continue\n      lines.splice(insertAt, 0, ep.after)\n      const newRaw = lines.join('\\n')\n      await writeAtomic(ep.file, newRaw)\n      writtenFiles.push(ep.file)\n    }\n\n    // ── 4. Next.js config flag (ADR-073 §1) — only present on the Next\n    // path when the declared major is < 15 and the flag isn't already\n    // mentioned in the file. Best-effort regex insertion into the first\n    // config object literal; bails silently when the shape isn't\n    // recognisable so we never corrupt a user-customised config.\n    if (installPlan.nextConfigEdit) {\n      const target = installPlan.nextConfigEdit.file\n      const raw = originals.get(target)\n      if (raw !== undefined && !raw.includes('instrumentationHook')) {\n        const updated = injectInstrumentationHook(raw)\n        if (updated !== null) {\n          await writeAtomic(target, updated)\n          writtenFiles.push(target)\n        }\n      }\n    }\n  } catch (err) {\n    await rollback(installPlan, originals, createdFiles)\n    throw err\n  }\n\n  return {\n    serviceDir,\n    outcome: 'instrumented',\n    writtenFiles,\n  }\n}\n\nasync function rollback(\n  installPlan: InstallPlan,\n  originals: Map<string, string>,\n  createdFiles: string[],\n): Promise<void> {\n  const restored: string[] = []\n  const removed: string[] = []\n  for (const [file, raw] of originals.entries()) {\n    try {\n      await fs.writeFile(file, raw, 'utf8')\n      restored.push(file)\n    } catch {\n      // Best-effort: keep going so we restore as much as we can.\n    }\n  }\n  for (const file of createdFiles) {\n    try {\n      await fs.unlink(file)\n      removed.push(file)\n    } catch {\n      // Best-effort.\n    }\n  }\n  const lines = [\n    '# neat-rollback.patch',\n    '',\n    `# Generated after a partial apply failure in the ${installPlan.language} installer.`,\n    '# Files listed below were restored to their pre-apply contents.',\n    '',\n    ...restored.map((f) => `restored: ${f}`),\n    ...removed.map((f) => `removed:  ${f}`),\n    '',\n  ]\n  const rollbackPath = path.join(installPlan.serviceDir, 'neat-rollback.patch')\n  await fs.writeFile(rollbackPath, lines.join('\\n'), 'utf8')\n}\n\n// ADR-073 §1 — best-effort injection of `experimental.instrumentationHook:\n// true` into a next.config.{js,ts,mjs}. Returns the rewritten contents on\n// success, or null when the config shape isn't recognisable (in which case\n// the apply phase leaves the file alone — partial Next coverage is fine,\n// silent corruption of a user's config is not).\n//\n// Recognised shapes:\n//   - `module.exports = { ... }` (CJS)\n//   - `module.exports = { ... } satisfies NextConfig` (TS-via-CJS)\n//   - `export default { ... }` (ESM / TS)\n//   - `const nextConfig = { ... }; module.exports = nextConfig` (named CJS)\n//   - `const nextConfig: NextConfig = { ... }; export default nextConfig` (TS)\nexport function injectInstrumentationHook(raw: string): string | null {\n  if (raw.includes('instrumentationHook')) return raw\n\n  // Strategy: find the first config object literal whose contents we can\n  // edit, then either merge into an existing `experimental: { ... }` block\n  // or insert a fresh `experimental: { instrumentationHook: true }` entry.\n  //\n  // We look for one of four anchors near a top-level `{` and splice from\n  // there. The regexes capture the `{` so we can splice right after it.\n  const anchors: Array<{ pattern: RegExp; label: string }> = [\n    { pattern: /(module\\.exports\\s*=\\s*\\{)/, label: 'cjs-default' },\n    { pattern: /(export\\s+default\\s*\\{)/, label: 'esm-default' },\n    { pattern: /(?:const|let|var)\\s+\\w+(?:\\s*:\\s*[^=]+)?\\s*=\\s*(\\{)/, label: 'named-config' },\n  ]\n\n  for (const { pattern } of anchors) {\n    const match = pattern.exec(raw)\n    if (!match) continue\n    const insertAfter = match.index + match[0].length\n    const before = raw.slice(0, insertAfter)\n    const after = raw.slice(insertAfter)\n    // Insert a leading newline so the injection sits on its own line and\n    // doesn't fight any existing trailing-comma style. Two-space indent\n    // covers most code-styled configs.\n    const injection = '\\n  experimental: { instrumentationHook: true },'\n    return `${before}${injection}${after}`\n  }\n\n  return null\n}\n\nexport const javascriptInstaller: Installer = {\n  name: 'javascript',\n  detect,\n  plan,\n  apply,\n}\n\n// Re-exports used by the contract test surface.\nexport { NEXT_INSTRUMENTATION_HEADER, OTEL_INIT_HEADER }\n","/**\n * Generated-file templates for the Node SDK installer (ADR-069 §1).\n *\n * Three flavors so the inserted file matches the host package's module\n * system: CJS for `require`-based packages, ESM for `import`-based, TS for\n * TypeScript entries. Env vars are inlined as `process.env.X ||=` defaults\n * rather than loaded from `.env.neat` at runtime — `__dirname` /\n * `import.meta.url` resolve unpredictably once a bundler rewrites the\n * generated file (Brief-smoke evidence, issue #369), so we let the OTel SDK\n * read its config from the same `process.env` either way. Platform env\n * (Vercel / Railway / Fly / etc.) stays authoritative at deploy time;\n * `||=` keeps the local default for laptop dev only.\n */\n\n// Header comment that ships at the top of every generated otel-init. Stable\n// across flavors so a grep for the header line finds every generated file in\n// a target codebase. Used by the idempotency check too (ADR-069 §6).\nexport const OTEL_INIT_HEADER = '// Generated by `neat init --apply` (ADR-069). OpenTelemetry auto-instrumentation hook.'\n\n// Version stamp on the generated otel-init (file-awareness.md §4). A NEAT-owned\n// file carries OTEL_INIT_HEADER; the stamp records which template revision wrote\n// it. On re-run, an existing NEAT-owned file whose stamp is older than the\n// current one is regenerated (a hand-written init — no header — is never\n// touched). Bump the revision whenever the generated body changes shape.\nexport const OTEL_INIT_STAMP =\n  '// neat-template-version: 9 — CommonJS TypeScript uses a synchronous bootstrap (#910); OTel init degrades to no-OBSERVED when dependencies are absent (#820); daemon.json endpoint resolution (ADR-096) + layered file-first capture (ADR-090); spans flushed on exit (#1353).'\n\n// OTLP exporter auth (ADR-073 §3/§4, #410). When the operator runs the\n// instrumented app with `NEAT_OTEL_TOKEN` set — the same secret the daemon's\n// OTLP receiver reads (`NEAT_OTEL_TOKEN ?? NEAT_AUTH_TOKEN`) — the exporter\n// sends `Authorization: Bearer <token>` so a secured daemon accepts the spans.\n// Unset (laptop dev against a loopback daemon with no token) sends no header,\n// matching the daemon's unauthenticated loopback path. The token is the single\n// source: it lives in the environment, never inlined into the generated file.\n// `||=` keeps any platform-set header (Vercel / Railway / Fly) authoritative.\nexport const OTEL_OTLP_HEADERS_JS =\n  \"if (process.env.NEAT_OTEL_TOKEN) process.env.OTEL_EXPORTER_OTLP_HEADERS ||= 'Authorization=Bearer%20' + encodeURIComponent(process.env.NEAT_OTEL_TOKEN)\"\n\n// Export protocol pin (#468). The OTel JS SDK defaults to http/protobuf; NEAT's\n// receiver accepts both, but http/json is the wire format the smoke gates\n// validate hardest, so the generated init pins it. Same `||=` discipline as the\n// other inlined env: an operator who explicitly sets\n// OTEL_EXPORTER_OTLP_PROTOCOL (e.g. to route through a collector that insists\n// on protobuf) stays authoritative.\nexport const OTEL_OTLP_PROTOCOL_JS =\n  \"process.env.OTEL_EXPORTER_OTLP_PROTOCOL ||= 'http/json'\"\n\n// OTLP endpoint resolution (ADR-096 / project-daemon contract, amended #879).\n// Under one-daemon-per-project the daemon allocates its OTLP port once\n// (canonical 4318, stepping to the next free port when a sibling daemon already\n// holds it) and records both that port AND the project name it serves in\n// `<project>/neat-out/daemon.json`. The instrumented app reads THAT record back,\n// or a second project's app — baked to a fixed 4318 — sends its spans to the\n// first project's daemon, which has no slot for them and drops them: the second\n// project's OBSERVED layer goes dark silently. That is exactly the failure this\n// code exists to kill, so the endpoint is resolved at app boot from the daemon's\n// own record rather than hardcoded.\n//\n// Precedence (highest first):\n//   1. An explicit OTEL_EXPORTER_OTLP_TRACES_ENDPOINT / _ENDPOINT env var —\n//      the prod/hosted path where a platform or collector owns the target.\n//   2. `<project>/neat-out/daemon.json` → `ports.otlp` + `project` → the\n//      project-scoped `http://localhost:<otlp>/projects/<project>/v1/traces`\n//      route the per-project daemon serves.\n//   3. The canonical `http://localhost:4318/projects/<project>/v1/traces`\n//      default — the laptop happy path where the daemon took its first-choice\n//      port; the project name is baked in at apply time.\n//\n// This is INJECTED into the user's app, so it is bulletproof: the whole thing\n// is wrapped in try/catch, a missing or malformed daemon.json falls through to\n// the canonical default, and it NEVER throws — a resolution failure must not\n// crash the host app's startup. The daemon.json path is resolved by walking up\n// from the app's runtime cwd looking for `neat-out/daemon.json`, which lands on\n// the project root whether the app boots from the project root (single package)\n// or a package subdirectory (monorepo).\n//\n// The endpoint carries the project scope (#879). The daemon's receiver routes a\n// project-scoped POST by the URL path — a direct slot lookup — instead of\n// guessing the owning project from `service.name` (the legacy bare `/v1/traces`\n// path, fragile under case skew and `deployment.environment` splits, #880). A\n// span aimed at a project a daemon doesn't host gets a loud 404 (#881) rather\n// than a silent drop into the wrong graph. The project name comes from the same\n// daemon.json record as the port, so scope and port always agree.\n\n// CJS flavor — `require('node:fs')` is available in the require-based template.\nexport const OTEL_ENDPOINT_RESOLVER_CJS = `;(function () {\n  try {\n    if (process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return\n    const __neatFs = require('node:fs')\n    const __neatPath = require('node:path')\n    let __neatDir = process.cwd()\n    for (let __i = 0; __i < 8; __i++) {\n      try {\n        const __rec = JSON.parse(__neatFs.readFileSync(__neatPath.join(__neatDir, 'neat-out', 'daemon.json'), 'utf8'))\n        if (__rec && __rec.ports && typeof __rec.ports.otlp === 'number') {\n          const __neatProj = (typeof __rec.project === 'string' && __rec.project) || '__PROJECT__'\n          process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = 'http://localhost:' + __rec.ports.otlp + '/projects/' + __neatProj + '/v1/traces'\n          break\n        }\n      } catch (_e) {}\n      const __parent = __neatPath.dirname(__neatDir)\n      if (__parent === __neatDir) break\n      __neatDir = __parent\n    }\n  } catch (_e) {}\n  process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n})()`\n\n// ESM/TS flavor — `require` is not defined in a pure-ESM module, so the\n// built-in fs/path come in via the hoisted `import` block\n// OTEL_ESM_NODE_IMPORTS adds to the top of the generated ESM/TS file. The\n// resolver references those bindings (`__neatReadFileSync` / `__neatJoin` /\n// `__neatDirname`) directly. ES import bindings are evaluated before this IIFE\n// runs, so they're always present.\nexport const OTEL_ESM_NODE_IMPORTS =\n  \"import { readFileSync as __neatReadFileSync } from 'node:fs'\\n\" +\n  \"import { join as __neatJoin, dirname as __neatDirname } from 'node:path'\"\n\nexport const OTEL_ENDPOINT_RESOLVER_ESM = `;(function () {\n  try {\n    if (process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT || process.env.OTEL_EXPORTER_OTLP_ENDPOINT) return\n    let __neatDir = process.cwd()\n    for (let __i = 0; __i < 8; __i++) {\n      try {\n        const __rec = JSON.parse(__neatReadFileSync(__neatJoin(__neatDir, 'neat-out', 'daemon.json'), 'utf8'))\n        if (__rec && __rec.ports && typeof __rec.ports.otlp === 'number') {\n          const __neatProj = (typeof __rec.project === 'string' && __rec.project) || '__PROJECT__'\n          process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = 'http://localhost:' + __rec.ports.otlp + '/projects/' + __neatProj + '/v1/traces'\n          break\n        }\n      } catch (_e) {}\n      const __parent = __neatDirname(__neatDir)\n      if (__parent === __neatDir) break\n      __neatDir = __parent\n    }\n  } catch (_e) {}\n  process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n})()`\n\n// Inlined layered call-site capture (file-awareness.md §4–6, ADR-090). The\n// whole mechanism is self-contained — NEAT can't import its own package into a\n// user's generated file, so the runtime logic is inlined verbatim. The exact\n// bytes that ship are exercised by the capture spike\n// (test/callsite-processor.test.ts) so a regression here fails CI before it\n// ships. The `ts` flag adds the few type annotations a strict tsconfig needs;\n// the runtime logic is identical across flavors.\n//\n// Three layers land the user's `file:line:function` on every CLIENT / PRODUCER\n// / SERVER span:\n//   1. Synchronous stack walk at span start — covers the sync-wrapper majority.\n//   2. Handler-entry attribution — stamps the framework SERVER span and pushes\n//      the handler frame into the active context so downstream CLIENT/PRODUCER\n//      spans inherit it (the floor).\n//   3. Off-stack facades — undici / built-in `fetch` (diagnostics_channel) and\n//      Prisma (backdated dispatch) push the call-site frame into context for\n//      the inner call; the processor reads it as a fallback.\nfunction neatCaptureSource(ts: boolean): string {\n  const spanT = ts ? ': any' : ''\n  const strOpt = ts ? ': string | undefined' : ''\n  const anyT = ts ? ': any' : ''\n  const fnT = ts ? ': any' : ''\n  const arrAny = ts ? ': any[]' : ''\n  return `// Context key shared by the facade/handler wraps (writers) and the\n// processor fallback (reader). Symbol.for keeps it stable even if the wraps\n// and the processor end up in different module instances.\nconst NEAT_USER_FRAME = Symbol.for('neat.user-frame')\n\nfunction __neatPickUserFrame(stack${strOpt}) {\n  const lines = String(stack || '').split('\\\\n')\n  for (let i = 0; i < lines.length; i++) {\n    const raw = lines[i].trim()\n    if (raw.indexOf('at ') !== 0) continue\n    if (raw.indexOf('node_modules') !== -1) continue\n    if (raw.indexOf('@opentelemetry') !== -1) continue\n    if (raw.indexOf('node:') !== -1) continue\n    if (raw.indexOf('NeatCallSiteSpanProcessor') !== -1) continue\n    // Skip NEAT's own inlined wraps/helpers (all carry the __neat prefix) so a\n    // facade frame never masquerades as the user's call site.\n    if (raw.indexOf('__neat') !== -1) continue\n    const bodyText = raw.slice(3)\n    const loc = bodyText.match(/:(\\\\d+):(\\\\d+)\\\\)?$/)\n    if (!loc) continue\n    const paren = bodyText.lastIndexOf('(')\n    let filepath${strOpt}\n    let fn${strOpt}\n    if (paren !== -1) {\n      fn = bodyText.slice(0, paren).trim()\n      if (fn.indexOf('async ') === 0) fn = fn.slice(6)\n      if (fn.indexOf('new ') === 0) fn = fn.slice(4)\n      filepath = bodyText.slice(paren + 1, bodyText.length - loc[0].length)\n    } else {\n      filepath = bodyText.slice(0, bodyText.length - loc[0].length)\n    }\n    if (filepath.indexOf('file://') === 0) filepath = filepath.slice(7)\n    if (!filepath) continue\n    return { filepath: filepath, lineno: Number(loc[1]), function: fn || undefined }\n  }\n  return null\n}\n\n// Layer 2/3 fallback source: the frame a handler-entry or facade wrap pushed\n// into context. Reads the span's own parent context first, then the active\n// context — the capture spike confirmed both return the value for undici.\nfunction __neatFrameFromContext(parentContext${anyT}) {\n  try {\n    const fromParent =\n      parentContext && typeof parentContext.getValue === 'function'\n        ? parentContext.getValue(NEAT_USER_FRAME)\n        : undefined\n    return fromParent || context.active().getValue(NEAT_USER_FRAME) || null\n  } catch (_e) {\n    return null\n  }\n}\n\nfunction __neatSetCodeAttrs(span${spanT}, frame${anyT}) {\n  span.setAttribute('code.filepath', frame.filepath)\n  if (typeof frame.lineno === 'number') span.setAttribute('code.lineno', frame.lineno)\n  if (frame.function) span.setAttribute('code.function', frame.function)\n}\n\nclass NeatCallSiteSpanProcessor {\n  onStart(span${spanT}, parentContext${anyT}) {\n    if (!span || (span.kind !== 2 && span.kind !== 3)) return\n    // Layer 1 — synchronous stack walk (sync-wrapper instrumentations).\n    let frame = __neatPickUserFrame(new Error().stack)\n    // Layer 2/3 — the handler-entry or off-stack-facade frame from context.\n    if (!frame) frame = __neatFrameFromContext(parentContext)\n    if (!frame) return\n    __neatSetCodeAttrs(span, frame)\n  }\n  onEnd() {}\n  forceFlush() { return Promise.resolve() }\n  shutdown() { return Promise.resolve() }\n}\n\n// Capture the caller's synchronous frame at the wrap point and run \\`fn\\` with\n// that frame pushed into the active context (file-awareness.md §4 layer 3). An\n// off-stack instrumentation that creates its span inside \\`fn\\` inherits the\n// frame; the processor reads it via __neatFrameFromContext.\nfunction __neatRunWithUserFrame(fn${fnT}) {\n  const frame = __neatPickUserFrame(new Error().stack)\n  if (!frame) return fn()\n  return context.with(context.active().setValue(NEAT_USER_FRAME, frame), fn)\n}\n\n// Handler-entry attribution (file-awareness.md §4 layer 2). Stamp the framework\n// SERVER span with the handler frame captured at route registration, and push\n// the same frame into context so downstream CLIENT/PRODUCER spans inherit the\n// handler-file floor when their own stack carries none.\nfunction __neatStampHandler(frame${anyT}, run${fnT}) {\n  try {\n    const active = trace.getActiveSpan()\n    if (active && active.kind === 1 && typeof active.setAttribute === 'function') {\n      __neatSetCodeAttrs(active, frame)\n    }\n  } catch (_e) {}\n  try {\n    return context.with(context.active().setValue(NEAT_USER_FRAME, frame), run)\n  } catch (_e) {\n    return run()\n  }\n}\n\n// require-in-the-middle is a transitive dependency of the OTel instrumentation\n// packages NEAT installs, so it resolves in any instrumented CJS service.\n// Guarded: when it's absent (or the host runs as pure ESM, where require isn't\n// defined) the off-stack/handler wraps degrade to the stack walk + context\n// floor, never to a crash.\nfunction __neatHook(modules${arrAny}, onload${fnT}) {\n  try {\n    const RITM = require('require-in-the-middle')\n    const Hook = RITM && RITM.Hook ? RITM.Hook : RITM\n    new Hook(modules, { internals: false }, onload)\n    return true\n  } catch (_e) {\n    return false\n  }\n}\n\n// Off-stack facade: Node's built-in fetch / undici. The instrumentation creates\n// the CLIENT span inside a diagnostics_channel handler detached from the\n// caller's stack, so wrap the global so the user frame is in context when the\n// span is created. The capture spike (2026-05-28) validated this on real\n// undici. .name is restored to 'fetch' for ecosystem compatibility; the inner\n// __neat name is what the frame skip keys on.\nfunction __neatWrapFetch() {\n  try {\n    const g${anyT} = globalThis\n    if (typeof g.fetch === 'function' && !g.fetch.__neatWrapped) {\n      const realFetch = g.fetch\n      // The wrapper keeps its __neat-prefixed name so the frame skip in\n      // __neatPickUserFrame never mistakes the wrapper's own frame for the\n      // user's call site (renaming it to 'fetch' would defeat the skip).\n      const __neatFetch${anyT} = function (input${anyT}, init${anyT}) {\n        return __neatRunWithUserFrame(function () { return realFetch(input, init) })\n      }\n      __neatFetch.__neatWrapped = true\n      g.fetch = __neatFetch\n    }\n  } catch (_e) {}\n}\n\n// Off-stack facade: @prisma/client. Prisma's query engine backdates its spans\n// from Rust, off the caller's stack. Wrap the model methods on the client\n// prototype so the call-site frame (still synchronous at \\`prisma.user.find\\`)\n// is pushed into context for the engine dispatch.\nfunction __neatWrapPrisma() {\n  __neatHook(['@prisma/client'], function (exports${anyT}) {\n    try {\n      const Client = exports && exports.PrismaClient\n      if (typeof Client === 'function' && !Client.__neatWrapped) {\n        const ops = ['findUnique','findUniqueOrThrow','findFirst','findFirstOrThrow','findMany','create','createMany','update','updateMany','upsert','delete','deleteMany','count','aggregate','groupBy']\n        const __neatPrismaWrapModel = function (model${anyT}) {\n          if (!model || model.__neatWrapped) return model\n          for (let i = 0; i < ops.length; i++) {\n            const op = ops[i]\n            const orig = model[op]\n            if (typeof orig !== 'function') continue\n            model[op] = function __neatPrismaOp(${ts ? '...args: any[]' : '...args'}) {\n              const self = this\n              return __neatRunWithUserFrame(function () { return orig.apply(self, args) })\n            }\n          }\n          model.__neatWrapped = true\n          return model\n        }\n        const proto = Client.prototype\n        const handler = function (model${anyT}) { return __neatPrismaWrapModel(model) }\n        // Model accessors are lazily created getters on the instance; wrap the\n        // \\`$extends\\`-free common path by trapping property access via a proxy\n        // on each constructed client.\n        exports.PrismaClient = new Proxy(Client, {\n          construct(Target${anyT}, argList${anyT}, NewTarget${anyT}) {\n            const instance = Reflect.construct(Target, argList, NewTarget)\n            return new Proxy(instance, {\n              get(target${anyT}, prop${anyT}, receiver${anyT}) {\n                const value = Reflect.get(target, prop, receiver)\n                if (value && typeof value === 'object' && typeof prop === 'string' && prop[0] !== '$' && prop[0] !== '_') {\n                  return handler(value)\n                }\n                return value\n              },\n            })\n          },\n        })\n        exports.PrismaClient.__neatWrapped = true\n        void proto\n      }\n    } catch (_e) {}\n    return exports\n  })\n}\n\n// Handler-entry facades. express / connect share the Layer model (each route\n// handler is a function registered on a Router); the wrap captures the\n// registration frame and stamps + propagates it when the handler runs. The\n// registry is the extensibility seam — koa, fastify (via @fastify/otel),\n// nestjs, restify, and hapi add an entry as their patch surface is wired.\nfunction __neatWrapConnectStyle(mod${anyT}) {\n  try {\n    // express() returns an app whose route verbs live on Router.prototype and\n    // the application proto; connect apps expose \\`use\\`. Wrap the registration\n    // verbs so the user handler is wound with its registration frame.\n    const verbs = ['use','get','post','put','delete','patch','all','options','head']\n    const wrapTarget = function (target${anyT}) {\n      if (!target || target.__neatVerbsWrapped) return\n      for (let i = 0; i < verbs.length; i++) {\n        const verb = verbs[i]\n        const orig = target[verb]\n        if (typeof orig !== 'function') continue\n        target[verb] = function __neatVerb(${ts ? '...args: any[]' : '...args'}) {\n          const frame = __neatPickUserFrame(new Error().stack)\n          if (frame) {\n            for (let a = 0; a < args.length; a++) {\n              const h = args[a]\n              if (typeof h === 'function' && !h.__neatHandlerWrapped && h.length <= 4) {\n                const inner = h\n                const __neatHandler${anyT} = function (${ts ? '...hargs: any[]' : '...hargs'}) {\n                  const self = this\n                  return __neatStampHandler(frame, function () { return inner.apply(self, hargs) })\n                }\n                __neatHandler.__neatHandlerWrapped = true\n                args[a] = __neatHandler\n              }\n            }\n          }\n          return orig.apply(this, args)\n        }\n      }\n      target.__neatVerbsWrapped = true\n    }\n    if (mod && mod.Router && mod.Router.prototype) wrapTarget(mod.Router.prototype)\n    if (mod && mod.application) wrapTarget(mod.application)\n    if (mod && mod.prototype) wrapTarget(mod.prototype)\n  } catch (_e) {}\n}\n\nfunction __neatInstallHandlerEntry() {\n  __neatHook(['express'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })\n  __neatHook(['connect'], function (exports${anyT}) { __neatWrapConnectStyle(exports); return exports })\n}\n\n// Install every off-stack and handler-entry wrap. Called once after sdk.start()\n// — before user code requires the framework / Prisma modules, so the hooks land\n// on first require. Each wrap is independently guarded.\nfunction __neatInstallFacades() {\n  __neatWrapFetch()\n  __neatWrapPrisma()\n  __neatInstallHandlerEntry()\n}`\n}\n\n// The runtime capture source, exported so the capture spike can materialise and\n// exercise the exact bytes that ship in the generated file.\nexport const CALLSITE_PROCESSOR_JS = neatCaptureSource(false)\nexport const CALLSITE_PROCESSOR_TS = neatCaptureSource(true)\n\n// Flush on exit (#1353). The batch processor holds spans for up to its schedule\n// delay, so a process that exits on its own (a script, a CLI, a job, a test run)\n// dropped its last batch. On \\`beforeExit\\` and SIGTERM/SIGINT the SDK is shut\n// down under a bounded wait, so a hung exporter can't hold the process open; a\n// signal is re-raised only when no other handler owns it. Mirrors\n// @neat.is/otel-node's flushOnExit.\nfunction neatFlushOnExitSource(ts: boolean): string {\n  const anyT = ts ? ': any' : ''\n  return `;(function () {\n  let __neatFlushing${anyT}\n  const __neatFlush = () => {\n    if (!__neatFlushing) {\n      __neatFlushing = new Promise((resolve) => {\n        const t${anyT} = setTimeout(() => resolve(true), 2000)\n        if (t && typeof t.unref === 'function') t.unref()\n        Promise.resolve().then(() => sdk.shutdown()).catch(() => {}).then(() => { clearTimeout(t); resolve(false) })\n      })\n    }\n    return __neatFlushing\n  }\n  // Only a flush that timed out forces the exit; otherwise an app's own\n  // beforeExit cleanup still runs.\n  process.once('beforeExit', (code${anyT}) => { __neatFlush().then((timedOut${anyT}) => { if (timedOut) process.exit(process.exitCode ?? code) }) })\n  for (const sig of ['SIGTERM', 'SIGINT']) {\n    process.once(sig${ts ? ' as any' : ''}, () => {\n      const alone = process.listenerCount(sig${ts ? ' as any' : ''}) === 0\n      __neatFlush().then(() => { if (alone) process.kill(process.pid, sig) })\n    })\n  }\n})()`\n}\n\n// Post-`sdk.start()` wiring. NodeSDK keeps its env-configured OTLP exporter\n// (passing `spanProcessors` to the constructor would replace it); we add the\n// call-site processor to the started provider via the public `getDelegate()` +\n// `addSpanProcessor()` surface, then assert it actually attached (file-\n// awareness.md §4 / ADR-090). A wiring regression that would silently drop\n// file-first capture throws loudly at boot instead of shipping service-level-\n// only spans. The facade/handler wraps install last, so a span export path is\n// live before any user module loads.\nfunction neatWireCaptureSource(ts: boolean): string {\n  const providerT = ts ? ': any' : ''\n  return `try {\n  const provider${providerT} = trace.getTracerProvider()\n  const delegate = provider && typeof provider.getDelegate === 'function' ? provider.getDelegate() : provider\n  if (!delegate || typeof delegate.addSpanProcessor !== 'function') {\n    throw new Error('[neat] could not resolve a TracerProvider to attach the call-site processor; file-first OBSERVED capture would be silent (file-awareness.md §4)')\n  }\n  const __neatProcessor = new NeatCallSiteSpanProcessor()\n  delegate.addSpanProcessor(__neatProcessor)\n  // Post-init assertion: confirm attachment on providers that expose their\n  // processor list. An un-introspectable provider is trusted (we just called\n  // its addSpanProcessor); a list that exists and lacks our processor throws.\n  const registered = delegate._registeredSpanProcessors\n  if (Array.isArray(registered) && registered.indexOf(__neatProcessor) === -1) {\n    throw new Error('[neat] call-site processor did not attach to the active TracerProvider (file-awareness.md §4)')\n  }\n} catch (err) {\n  throw err\n}\ntry {\n  __neatInstallFacades()\n} catch (_e) {\n  // Facade install is best-effort: the stack-walk + handler-entry floor still\n  // attribute the sync-wrapper majority even if an off-stack wrap fails.\n}`\n}\n\n// __SERVICE_NAME__ → the ServiceNode id (the package's `pkg.name`, or the\n// directory basename for nameless packages); __PROJECT__ → the registered\n// project basename; __INSTRUMENTATION_BLOCK__ → a (possibly empty) sequence\n// of `instrumentations.push(...)` lines for non-bundled instrumentations\n// (Prisma for v0.4.5; more libraries via the v0.5.0 registry). All three are\n// substituted at apply time via renderNodeOtelInit().\n//\n// v0.4.5 — explicit `NodeSDK` construction replaces the\n// `auto-instrumentations-node/register` shorthand so non-bundled libraries\n// (Prisma's Rust query engine bypasses node-pg; Drizzle, BetterAuth, etc.\n// have their own packages) can compose into the same `instrumentations`\n// array without templating a different file shape per library.\nexport const OTEL_INIT_CJS = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_CJS}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\n// Instrumentation is ambient — it must never break the host app. If the\n// @opentelemetry packages aren't installed (a package-manager install that\n// failed or hasn't run yet), degrade to running WITHOUT OBSERVED rather than\n// crashing the process on a missing module (#820). The require-based flavor can\n// guard this at runtime; do so around the whole SDK setup, not just the\n// requires, so a broken instrumentation registration can't take the app down\n// either.\ntry {\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\nconst { trace, context } = require('@opentelemetry/api')\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatFlushOnExitSource(false)}\n${neatWireCaptureSource(false)}\n} catch (__neatOtelErr) {\n  const __neatMsg = String((__neatOtelErr && __neatOtelErr.message) || __neatOtelErr)\n  if (/Cannot find module|MODULE_NOT_FOUND/.test(__neatMsg)) {\n    console.warn('[neat] OpenTelemetry is not active: its packages are not installed, so this app is running without OBSERVED tracing. Run your package manager install and restart to enable it.')\n  } else {\n    console.warn('[neat] OpenTelemetry failed to start; the app is running without OBSERVED tracing: ' + __neatMsg)\n  }\n}\n`\n\n// TypeScript compiled as CommonJS cannot contain top-level await. Keep the\n// generated file as .ts so tsc copies it beside the compiled entry, while the\n// synchronous require bootstrap preserves initialization ordering.\nexport const OTEL_INIT_TS_CJS = OTEL_INIT_CJS.replace(\n  `${OTEL_INIT_HEADER}\\n${OTEL_INIT_STAMP}`,\n  `${OTEL_INIT_HEADER}\\n${OTEL_INIT_STAMP}\\n// @ts-nocheck — generated CommonJS runtime shim.`,\n)\n\nexport const OTEL_INIT_ESM = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\n${OTEL_ESM_NODE_IMPORTS}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_ESM}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\n// Keep dependency loading inside the guard. Static ESM imports are evaluated\n// before any try/catch and would crash the host app when an install failed.\ntry {\nconst { NodeSDK } = await import('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = await import('@opentelemetry/auto-instrumentations-node')\nconst { trace, context } = await import('@opentelemetry/api')\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatFlushOnExitSource(false)}\n${neatWireCaptureSource(false)}\n} catch (__neatOtelErr) {\n  const __neatMsg = String((__neatOtelErr && __neatOtelErr.message) || __neatOtelErr)\n  if (/Cannot find (?:module|package)|MODULE_NOT_FOUND|ERR_MODULE_NOT_FOUND/.test(__neatMsg)) {\n    console.warn('[neat] OpenTelemetry is not active: its packages are not installed, so this app is running without OBSERVED tracing. Run your package manager install and restart to enable it.')\n  } else {\n    console.warn('[neat] OpenTelemetry failed to start; the app is running without OBSERVED tracing: ' + __neatMsg)\n  }\n}\n`\n\nexport const OTEL_INIT_TS = `${OTEL_INIT_HEADER}\n${OTEL_INIT_STAMP}\n// @ts-nocheck — generated runtime shim. The layered capture mechanism uses\n// dynamic patterns (facade wraps, Proxy traps, a createRequire bridge) that a\n// strict user tsconfig would reject; suppressing type-checking here keeps the\n// generated file from breaking the host project's \\`tsc\\` gate (#427) without\n// constraining the runtime logic. The file is regenerated, never hand-edited.\n${OTEL_ESM_NODE_IMPORTS}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_ESM}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\n// Top-level await preserves the static import's ordering: the host entry does\n// not run until instrumentation has started (or safely degraded).\ntry {\nconst { NodeSDK } = await import('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = await import('@opentelemetry/auto-instrumentations-node')\nconst { trace, context } = await import('@opentelemetry/api')\n\n${CALLSITE_PROCESSOR_TS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatFlushOnExitSource(true)}\n${neatWireCaptureSource(true)}\n} catch (__neatOtelErr) {\n  const __neatMsg = String((__neatOtelErr && __neatOtelErr.message) || __neatOtelErr)\n  if (/Cannot find (?:module|package)|MODULE_NOT_FOUND|ERR_MODULE_NOT_FOUND/.test(__neatMsg)) {\n    console.warn('[neat] OpenTelemetry is not active: its packages are not installed, so this app is running without OBSERVED tracing. Run your package manager install and restart to enable it.')\n  } else {\n    console.warn('[neat] OpenTelemetry failed to start; the app is running without OBSERVED tracing: ' + __neatMsg)\n  }\n}\n`\n\n// Substitute __SERVICE_NAME__, __PROJECT__, and __INSTRUMENTATION_BLOCK__\n// at apply time. The third arg is a list of registration snippets — one per\n// non-bundled instrumentation the installer detected (e.g. Prisma). An empty\n// list collapses the placeholder to nothing so the generated file stays\n// readable on the common \"auto-instrumentations covers everything\" path.\nexport function renderNodeOtelInit(\n  template: string,\n  serviceName: string,\n  projectName: string,\n  registrations: readonly string[] = [],\n): string {\n  const block = registrations.length === 0 ? '' : `\\n${registrations.join('\\n')}\\n`\n  return template\n    .replace(/__SERVICE_NAME__/g, serviceName)\n    .replace(/__PROJECT__/g, projectName)\n    .replace(/__INSTRUMENTATION_BLOCK__\\n?/g, block)\n}\n\n// .env.neat shape (ADR-069 §4, amended v0.4.1 — refs #339, v0.4.4 — refs\n// #367 + #369, v0.4.8 — refs #410, ADR-096). Two keys: OTEL_SERVICE_NAME (the\n// ServiceNode id — the package's own name, scope-preserved, so spans land on\n// per-service nodes inside the project's graph) and\n// OTEL_EXPORTER_OTLP_TRACES_ENDPOINT. Under one-daemon-per-project (ADR-096,\n// amended #879) the daemon serves a project-scoped `/projects/<project>/v1/traces`\n// route and allocates its OTLP port once, recording both the port and the\n// project name in `<project>/neat-out/daemon.json`; the generated `otel-init`\n// reads that record at boot and ignores this file, so the value here is purely\n// the canonical-default advisory the operator sees when grepping for the\n// service.name → endpoint mapping. Both env vars are advisory only — the\n// generated `otel-init` inlines/derives them so bundlers can't lose them. A\n// commented `NEAT_OTEL_TOKEN` hint documents the single source of the OTLP\n// bearer (#410): set it to the secret the daemon's receiver expects and the\n// generated init sends `Authorization: Bearer <token>`.\nexport function renderEnvNeat(\n  serviceName: string,\n  projectName: string,\n  nodeOptions?: string,\n  extraInstrumentations: readonly string[] = [],\n): string {\n  // ADR-232 — attachment delivery. The preload (@neat.is/otel-node) resolves the\n  // project daemon's OTLP endpoint from neat-out/daemon.json itself, and this\n  // file is exported wholesale before the app starts, so it must not pin an\n  // endpoint: an exported fixed 4318 would win over the resolution and send a\n  // second local project's spans to the first project's daemon (#879).\n  if (nodeOptions) {\n    return [\n      '# Generated by `neat init --apply` / `neat <path>` (ADR-069, ADR-232).',\n      '# NEAT attaches its OpenTelemetry bootstrap at process start; no source is edited.',\n      '# NODE_OPTIONS is read once when the process starts, so load this file before',\n      '# your start command:',\n      '#   set -a; . ./.env.neat; set +a; <your start command>',\n      '# or copy these settings into your process manager / platform environment.',\n      `OTEL_SERVICE_NAME=${serviceName}`,\n      '# The preload sends spans to this project\\'s daemon, read from',\n      '# <project>/neat-out/daemon.json; NEAT_PROJECT names the route when no record',\n      '# is found. Set OTEL_EXPORTER_OTLP_ENDPOINT only to send spans elsewhere.',\n      `NEAT_PROJECT=${projectName}`,\n      'OTEL_EXPORTER_OTLP_PROTOCOL=http/json',\n      '# Set NEAT_OTEL_TOKEN to the daemon\\'s OTLP secret to authenticate exported spans (#410).',\n      '# NEAT_OTEL_TOKEN=',\n      ...(extraInstrumentations.length > 0\n        ? [\n            '# Instrumentations outside the auto bundle, loaded by the preload (<package>#<export>).',\n            `NEAT_OTEL_INSTRUMENTATIONS=${extraInstrumentations.join(',')}`,\n          ]\n        : []),\n      `NODE_OPTIONS=\"${nodeOptions}\"`,\n      '',\n    ].join('\\n')\n  }\n  return [\n    '# Generated by `neat init --apply` (ADR-069).',\n    `OTEL_SERVICE_NAME=${serviceName}`,\n    '# Advisory only — the generated otel-init resolves the live endpoint from',\n    '# <project>/neat-out/daemon.json (ports.otlp + project) at boot (ADR-096).',\n    '# This is the canonical default the daemon takes when its first-choice OTLP',\n    '# port is free; the project scope routes the span without service.name guessing (#879).',\n    `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/projects/${projectName}/v1/traces`,\n    'OTEL_EXPORTER_OTLP_PROTOCOL=http/json',\n    '# Set NEAT_OTEL_TOKEN to the daemon\\'s OTLP secret to authenticate exported spans (#410).',\n    '# NEAT_OTEL_TOKEN=',\n    '',\n  ].join('\\n')\n}\n\n// ── Next.js framework-aware templates (ADR-073 §1, ADR-069 §3, ADR-126). ─\n//\n// Next.js owns its own boot — `pkg.main` is unused, and the auto-instrumentation\n// register hook can't run before user code. Next 13+ ships an `instrumentation`\n// file at the project root with an async `register()` export the framework\n// invokes during server start, once per runtime it boots. Browser bundles\n// still never load this file.\n//\n// Three-file shape: `instrumentation.{ts,js}` is the runtime gate, dispatching\n// to `instrumentation.node.{ts,js}` (the Node SDK init) on the nodejs runtime\n// and `instrumentation.edge.{ts,js}` (`@vercel/otel`, ADR-126) on the edge\n// runtime — the standard Node SDK can't execute inside Next's Edge runtime at\n// all, so the edge file leans on a runtime-aware package instead. All three\n// files sit at the project root (or under `src/` for `--src-dir` layouts).\n\nexport const NEXT_INSTRUMENTATION_HEADER =\n  '// Generated by `neat init --apply` (ADR-073). Next.js instrumentation hook.'\n\nexport const NEXT_INSTRUMENTATION_TS = `${NEXT_INSTRUMENTATION_HEADER}\nexport async function register() {\n  if (process.env.NEXT_RUNTIME === 'nodejs') {\n    await import('./instrumentation.node')\n  }\n  if (process.env.NEXT_RUNTIME === 'edge') {\n    await import('./instrumentation.edge')\n  }\n}\n`\n\nexport const NEXT_INSTRUMENTATION_JS = `${NEXT_INSTRUMENTATION_HEADER}\nexport async function register() {\n  if (process.env.NEXT_RUNTIME === 'nodejs') {\n    await import('./instrumentation.node')\n  }\n  if (process.env.NEXT_RUNTIME === 'edge') {\n    await import('./instrumentation.edge')\n  }\n}\n`\n\n// Env vars are inlined as process.env defaults so they survive Turbopack /\n// Webpack bundling — `import.meta.url` resolves to a path under .next/dev/\n// server/chunks/ once Next compiles this file, which would miss .env.neat.\n// `process.env.X ||=` keeps platform env (Vercel / Railway / Fly / etc.)\n// authoritative at deploy time while the local default carries the routing\n// key the daemon needs to map spans back to this project. The endpoint uses\n// the project-scoped URL form so the daemon never has to guess which project\n// owns the span (issue #367); the OTel SDK reads the env vars from\n// process.env directly, so no file-system lookup is required at runtime.\nexport const NEXT_INSTRUMENTATION_NODE_TS = `${NEXT_INSTRUMENTATION_HEADER}\n${OTEL_ESM_NODE_IMPORTS}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_ESM}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nnew NodeSDK({ instrumentations }).start()\n`\n\nexport const NEXT_INSTRUMENTATION_NODE_JS = `${NEXT_INSTRUMENTATION_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_CJS}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nnew NodeSDK({ instrumentations }).start()\n`\n\n// Substitute the placeholders at apply time so the generated file carries the\n// ServiceNode id (`__SERVICE_NAME__`) and the registered project name\n// (`__PROJECT__`) verbatim. The two roles diverged in v0.4.4: the service name\n// names the ServiceNode inside one project's graph, the project basename is\n// the URL routing key. v0.4.5 adds __INSTRUMENTATION_BLOCK__ — a (possibly\n// empty) sequence of `instrumentations.push(...)` calls for non-bundled\n// libraries like Prisma whose query engines bypass the auto-instrumentation\n// set's coverage.\nexport function renderNextInstrumentationNode(\n  template: string,\n  serviceName: string,\n  projectName: string,\n  registrations: readonly string[] = [],\n): string {\n  const block = registrations.length === 0 ? '' : `\\n${registrations.join('\\n')}\\n`\n  return template\n    .replace(/__SERVICE_NAME__/g, serviceName)\n    .replace(/__PROJECT__/g, projectName)\n    .replace(/__INSTRUMENTATION_BLOCK__\\n?/g, block)\n}\n\n// ── Next.js edge-runtime template (ADR-126). ─────────────────────────────\n//\n// `@opentelemetry/sdk-node` cannot run inside Next's Edge runtime — a V8\n// isolate with no Node.js API surface (no `node:fs`, no `node:net`). Next's\n// own build-time analysis rejects an edge bundle that imports `node:fs`, so\n// this file cannot reuse the `OTEL_ENDPOINT_RESOLVER_ESM` daemon.json walk\n// the Node file relies on — that walk is exactly the kind of Node API access\n// the Edge runtime forbids. `@vercel/otel`'s `registerOTel()` is runtime-aware\n// and built on web-standard APIs instead, so one call covers the Edge runtime\n// (and, on Vercel, gets Vercel's own OTel integration for free when present).\n//\n// The endpoint still resolves from the same `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`\n// env var every other generated init reads, defaulting to the same canonical\n// project-scoped `http://localhost:4318/projects/<project>/v1/traces` (#879) —\n// no new env var, no new config surface (framework-installers.md §7, ADR-126).\n// The edge file can't walk daemon.json for the live port (no `node:fs`), so it\n// bakes the project name at apply time and leans on the canonical port; the\n// scope still routes the span by URL instead of by service.name. `registerOTel`\n// reads OTLP endpoint/protocol/headers from `process.env` itself when\n// `traceExporter` is left at its \"auto\" default, so setting the env vars ahead\n// of the call is enough; unlike the Node file there's no filesystem probe first.\nexport const NEXT_INSTRUMENTATION_EDGE_HEADER =\n  '// Generated by `neat init --apply` (ADR-126). Next.js edge-runtime instrumentation via @vercel/otel.'\n\nexport const NEXT_INSTRUMENTATION_EDGE_TS = `${NEXT_INSTRUMENTATION_EDGE_HEADER}\nimport { registerOTel } from '@vercel/otel'\n\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\nprocess.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ||= 'http://localhost:4318/projects/__PROJECT__/v1/traces'\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\nregisterOTel({ serviceName: process.env.OTEL_SERVICE_NAME })\n`\n\n// Edge bundles are ESM-only (Next.js requires `import`/`export` syntax for\n// any file it loads into the Edge runtime), so the JS flavor is identical to\n// the TS flavor byte-for-byte — there's no CJS variant to diverge from, same\n// as the top-level instrumentation.{ts,js} gate above.\nexport const NEXT_INSTRUMENTATION_EDGE_JS = NEXT_INSTRUMENTATION_EDGE_TS\n\n// ── Meta-framework templates (ADR-074 §3). ──────────────────────────────\n//\n// Remix, SvelteKit, Nuxt, and Astro each own their boot path. The installer\n// emits one OTel-init module that loads `.env.neat` and starts the Node SDK,\n// then either creates or injects an import into the framework's canonical\n// hook file. Templates mirror the Next.js pair in shape — one generated init\n// module, one optional framework-hook stub for the absent-file case.\n\nexport const FRAMEWORK_OTEL_INIT_HEADER =\n  '// Generated by `neat init --apply` (ADR-074). OpenTelemetry SDK hook.'\n\n// Same inline-defaults pattern as the plain-Node + Next templates: env vars\n// arrive on `process.env` via the apply-time substitution below so bundler\n// path mangling (issue #369) can't lose them. `__SERVICE_NAME__` /\n// `__PROJECT__` are substituted via renderFrameworkOtelInit().\nconst FRAMEWORK_OTEL_INIT_TS_BODY = `${FRAMEWORK_OTEL_INIT_HEADER}\n${OTEL_ESM_NODE_IMPORTS}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_ESM}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\n\nconst sdk = new NodeSDK({\n  serviceName: process.env.OTEL_SERVICE_NAME,\n  instrumentations: [getNodeAutoInstrumentations()],\n})\nsdk.start()\n${neatFlushOnExitSource(true)}\n`\n\nconst FRAMEWORK_OTEL_INIT_JS_BODY = `${FRAMEWORK_OTEL_INIT_HEADER}\nprocess.env.OTEL_SERVICE_NAME ||= '__SERVICE_NAME__'\n${OTEL_ENDPOINT_RESOLVER_CJS}\n${OTEL_OTLP_PROTOCOL_JS}\n${OTEL_OTLP_HEADERS_JS}\n\nconst { NodeSDK } = require('@opentelemetry/sdk-node')\nconst { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node')\n\nconst sdk = new NodeSDK({\n  serviceName: process.env.OTEL_SERVICE_NAME,\n  instrumentations: [getNodeAutoInstrumentations()],\n})\nsdk.start()\n${neatFlushOnExitSource(false)}\n`\n\nexport function renderFrameworkOtelInit(\n  template: string,\n  serviceName: string,\n  projectName: string,\n): string {\n  return template\n    .replace(/__SERVICE_NAME__/g, serviceName)\n    .replace(/__PROJECT__/g, projectName)\n}\n\n// Remix — `app/otel.server.{ts,js}` carries the SDK bootstrap. The framework\n// loads `entry.server.*` at server-process start, and a top-of-module import\n// of `./otel.server` runs the bootstrap before any request handler imports.\nexport const REMIX_OTEL_SERVER_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const REMIX_OTEL_SERVER_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\n// SvelteKit — `src/otel-init.{ts,js}` carries the SDK bootstrap; the\n// framework's `src/hooks.server.{ts,js}` imports it. When hooks.server is\n// absent, the installer writes the stub below alongside the import.\nexport const SVELTEKIT_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const SVELTEKIT_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const SVELTEKIT_HOOKS_SERVER_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport type { Handle } from '@sveltejs/kit'\n\nexport const handle: Handle = async ({ event, resolve }) => {\n  return resolve(event)\n}\n`\n\nexport const SVELTEKIT_HOOKS_SERVER_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\n/** @type {import('@sveltejs/kit').Handle} */\nexport const handle = async ({ event, resolve }) => {\n  return resolve(event)\n}\n`\n\n// Nuxt — `server/plugins/otel.{ts,js}` is the convention-loaded plugin file;\n// it imports the sibling `otel-init.{ts,js}` which carries the SDK bootstrap.\nexport const NUXT_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const NUXT_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const NUXT_OTEL_PLUGIN_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nexport default defineNitroPlugin(() => {\n  // OTel SDK is initialised at module-load via the side-effect import above.\n})\n`\n\nexport const NUXT_OTEL_PLUGIN_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nrequire('./otel-init')\n\nmodule.exports = defineNitroPlugin(() => {\n  // OTel SDK is initialised at module-load via the side-effect import above.\n})\n`\n\n// Astro — `src/middleware.{ts,js}` runs once at module-load (and then per\n// request via onRequest). The top-of-module import of `./otel-init` boots\n// the SDK before the first request lands.\nexport const ASTRO_OTEL_INIT_TS = FRAMEWORK_OTEL_INIT_TS_BODY\nexport const ASTRO_OTEL_INIT_JS = FRAMEWORK_OTEL_INIT_JS_BODY\n\nexport const ASTRO_MIDDLEWARE_TS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport { defineMiddleware } from 'astro:middleware'\n\nexport const onRequest = defineMiddleware(async (context, next) => {\n  return next()\n})\n`\n\nexport const ASTRO_MIDDLEWARE_JS = `${FRAMEWORK_OTEL_INIT_HEADER}\nimport './otel-init'\n\nimport { defineMiddleware } from 'astro:middleware'\n\nexport const onRequest = defineMiddleware(async (context, next) => {\n  return next()\n})\n`\n","/**\n * Python SDK installer (ADR-047).\n *\n * `detect` matches on the canonical Python project markers — requirements.txt,\n * pyproject.toml, setup.py. `plan` produces dependency edits against the\n * primary manifest and entrypoint edits against a Procfile when one exists.\n *\n * MVP scope:\n *  - requirements.txt is the full-fidelity manifest (read / append).\n *  - pyproject.toml dependencies live inside a TOML `dependencies = [...]`\n *    block; we line-insert into that block when found, otherwise hold off\n *    on rewriting until a successor ADR addresses TOML editing properly.\n *  - Procfile lines starting with `python` get prefixed with\n *    `opentelemetry-instrument`.\n *\n * Lockfiles (poetry.lock, Pipfile.lock) are never touched. After `--apply`,\n * init's summary tells the user to run `pip install -r requirements.txt`\n * (or `poetry lock && poetry install`) so they own the lockfile commit.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n  ApplyResult,\n  DependencyEdit,\n  EntrypointEdit,\n  EnvEdit,\n  GeneratedFile,\n  Installer,\n  InstallPlan,\n  PlanOptions,\n} from './shared.js'\n\nconst SDK_PACKAGES = [\n  { name: 'opentelemetry-distro', version: '>=0.49b0' },\n  { name: 'opentelemetry-exporter-otlp', version: '>=1.28.0' },\n] as const\n\n// ADR-232 — attachment delivery adds the published neat-otel package (the\n// call-site processor + its opentelemetry_post_instrument entry point), loaded\n// with no source edit by running the app under `opentelemetry-instrument`. The\n// source-edit path (--source-edit) instead inlines the processor as neat_otel.py.\nconst NEAT_OTEL_PACKAGE = { name: 'neat-otel', version: '>=0.1.0' } as const\n\nconst OTEL_ENV: EnvEdit = {\n  file: null,\n  key: 'OTEL_EXPORTER_OTLP_ENDPOINT',\n  value: 'http://localhost:4318',\n}\n\nconst NEAT_OTEL_FILENAME = 'neat_otel.py'\nconst NEAT_OTEL_STAMP = 'neat-otel-init v1'\nconst NEAT_IMPORT_LINE = 'import neat_otel  # neat: call-site file attribution'\n\n// The generated Python call-site span processor (ADR-151, file-awareness.md §4)\n// — Python's analog of the Node processor in installers/templates.ts. It stamps\n// the stable OpenTelemetry code attributes (`code.file.path` / `code.line.number`\n// / `code.function.name`, semconv ≥1.33 — the names ingest reads, ADR-152) on\n// CLIENT/PRODUCER/SERVER spans by walking the stack to the first application\n// frame, so NEAT fuses a runtime span onto the source file that issued it.\n// Verified against a live FastAPI + SQLAlchemy app: DB and HTTP-client spans\n// resolve to the caller's file:line even across an `await`; a SERVER span is\n// created before the handler runs, so it stays route/service-grained, honestly.\n// Registration is import-time — under `opentelemetry-instrument` the SDK provider\n// is configured before the app module imports, so `add_span_processor` lands on\n// the real provider. If OpenTelemetry is absent the module degrades to a no-op\n// rather than breaking the host app (the ADR-144 discipline).\nexport function neatOtelPy(): string {\n  return `# ${NEAT_OTEL_STAMP} — generated by NEAT. Safe to re-generate; do not edit.\n# Call-site file attribution (docs/contracts/file-awareness.md section 4). Stamps\n# code.file.path / code.line.number / code.function.name on spans so NEAT fuses\n# runtime spans onto your source files. Import it once at your entry point.\nimport os\nimport sys\n\ntry:\n    from opentelemetry import trace as _neat_trace\n    from opentelemetry.sdk.trace import SpanProcessor as _NeatSpanProcessor\n    from opentelemetry.trace import SpanKind as _NeatSpanKind\n\n    _NEAT_OTEL = True\nexcept Exception:\n    _NEAT_OTEL = False\n\nif _NEAT_OTEL:\n    _NEAT_SELF = os.path.abspath(__file__)\n    _NEAT_PREFIXES = tuple(\n        os.path.abspath(p) + os.sep\n        for p in {sys.prefix, sys.base_prefix, sys.exec_prefix, sys.base_exec_prefix}\n    )\n    _NEAT_KINDS = {_NeatSpanKind.CLIENT, _NeatSpanKind.PRODUCER, _NeatSpanKind.SERVER}\n\n    def _neat_is_user_frame(filename):\n        if not filename:\n            return False\n        if filename.startswith(\"<\") and filename.endswith(\">\"):\n            return False\n        abs_name = os.path.abspath(filename)\n        if abs_name == _NEAT_SELF:\n            return False\n        parts = abs_name.split(os.sep)\n        if \"opentelemetry\" in parts or \"site-packages\" in parts:\n            return False\n        for pref in _NEAT_PREFIXES:\n            if abs_name.startswith(pref):\n                return False\n        return True\n\n    class NeatCallSiteSpanProcessor(_NeatSpanProcessor):\n        def on_start(self, span, parent_context=None):\n            try:\n                if span.kind not in _NEAT_KINDS:\n                    return\n                frame = sys._getframe(1)\n                while frame is not None:\n                    if _neat_is_user_frame(frame.f_code.co_filename):\n                        span.set_attribute(\"code.file.path\", os.path.abspath(frame.f_code.co_filename))\n                        span.set_attribute(\"code.line.number\", frame.f_lineno)\n                        span.set_attribute(\"code.function.name\", frame.f_code.co_name)\n                        return\n                    frame = frame.f_back\n            except Exception:\n                pass  # never break the host application\n\n        def on_end(self, span):\n            pass\n\n        def shutdown(self):\n            pass\n\n        def force_flush(self, timeout_millis=30000):\n            return True\n\n    def _neat_register():\n        try:\n            provider = _neat_trace.get_tracer_provider()\n            add = getattr(provider, \"add_span_processor\", None)\n            if callable(add):\n                add(NeatCallSiteSpanProcessor())\n        except Exception:\n            pass\n\n    if os.environ.get(\"NEAT_CALLSITE_DISABLED\", \"\") != \"1\":\n        _neat_register()\n`\n}\n\nasync function writeFileAtomic(file: string, contents: string): Promise<void> {\n  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`\n  await fs.writeFile(tmp, contents, 'utf8')\n  await fs.rename(tmp, file)\n}\n\n// Resolve the Python entry-point file to inject the neat_otel import into. Reads\n// the Procfile run command (`uvicorn app:app`, `gunicorn app:app`, `python\n// main.py`, `fastapi run app.py`) and resolves the module to a file; falls back\n// to the conventional entry-point names.\nasync function resolvePyEntrypoint(serviceDir: string): Promise<string | null> {\n  const procfile = path.join(serviceDir, 'Procfile')\n  if (await exists(procfile)) {\n    const raw = await fs.readFile(procfile, 'utf8')\n    for (const line of raw.split(/\\r?\\n/)) {\n      const m = line.match(/^[a-zA-Z0-9_-]+:\\s*(.+)$/)\n      if (!m) continue\n      const cmd = m[1]!\n      const asgi = cmd.match(/\\b(?:uvicorn|gunicorn|hypercorn|daphne)\\s+([\\w.]+):/)\n      if (asgi) {\n        const modPath = asgi[1]!.replace(/\\./g, '/')\n        const asFile = path.join(serviceDir, `${modPath}.py`)\n        if (await exists(asFile)) return asFile\n        const asPkg = path.join(serviceDir, modPath, '__init__.py')\n        if (await exists(asPkg)) return asPkg\n      }\n      const runFile = cmd.match(/\\b(?:python3?|fastapi\\s+(?:run|dev))\\s+([\\w./-]+\\.py)\\b/)\n      if (runFile) {\n        const p = path.join(serviceDir, runFile[1]!)\n        if (await exists(p)) return p\n      }\n    }\n  }\n  for (const name of ['main.py', 'app.py', 'asgi.py', 'wsgi.py', 'manage.py', 'server.py']) {\n    const p = path.join(serviceDir, name)\n    if (await exists(p)) return p\n  }\n  return null\n}\n\n// Insert `import neat_otel` at the top of an entry-point's source, after a\n// shebang and any `from __future__` imports (which must stay first, or Python\n// raises a SyntaxError). Idempotent: returns null when the import is already\n// present. A leading module docstring is demoted, which is harmless.\nexport function injectNeatImport(source: string): string | null {\n  if (/^\\s*import\\s+neat_otel\\b/m.test(source)) return null\n  const lines = source.split('\\n')\n  let insertAt = lines[0]?.startsWith('#!') ? 1 : 0\n  for (let i = 0; i < Math.min(lines.length, 15); i++) {\n    if (/^\\s*from\\s+__future__\\s+import\\b/.test(lines[i] ?? '')) insertAt = i + 1\n  }\n  lines.splice(insertAt, 0, NEAT_IMPORT_LINE)\n  return lines.join('\\n')\n}\n\nasync function exists(p: string): Promise<boolean> {\n  try {\n    await fs.stat(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n  const markers = ['requirements.txt', 'pyproject.toml', 'setup.py']\n  for (const m of markers) {\n    if (await exists(path.join(serviceDir, m))) return true\n  }\n  return false\n}\n\n// Strip a requirements.txt line down to its lower-cased package name.\n// `flask==3.0.0` → `flask`, `Flask>=2 ; python_version>\"3.6\"` → `flask`.\nfunction reqPackageName(line: string): string {\n  const stripped = line.split('#')[0]?.trim() ?? ''\n  const head = stripped.split(/[\\s;]/)[0] ?? ''\n  return head.replace(/[<>=!~].*$/, '').toLowerCase()\n}\n\nasync function planRequirementsTxtEdits(\n  serviceDir: string,\n  packages: readonly { name: string; version: string }[] = SDK_PACKAGES,\n): Promise<{ manifest: string; missing: { name: string; version: string }[] } | null> {\n  const file = path.join(serviceDir, 'requirements.txt')\n  if (!(await exists(file))) return null\n  const raw = await fs.readFile(file, 'utf8')\n  const presentNames = new Set(\n    raw\n      .split(/\\r?\\n/)\n      .map(reqPackageName)\n      .filter((n) => n.length > 0),\n  )\n  const missing = packages.filter((p) => !presentNames.has(p.name.toLowerCase()))\n  return { manifest: file, missing: [...missing] }\n}\n\n// Launchers that `opentelemetry-instrument` wraps. Under source-edit the import\n// carries non-`python` launchers, so only `python` is prefixed; under\n// attachment the prefix IS the turn-on, so it covers the common Python web\n// servers too (uvicorn/gunicorn/… for FastAPI/Flask/Django/Celery).\nconst PY_LAUNCHER_PYTHON = /^python3?\\b/\nconst PY_LAUNCHERS_BROAD = /^(python3?|uvicorn|gunicorn|hypercorn|daphne|granian|celery|flask|fastapi)\\b/\n\nasync function planProcfileEdits(serviceDir: string, broad = false): Promise<EntrypointEdit[]> {\n  const procfile = path.join(serviceDir, 'Procfile')\n  if (!(await exists(procfile))) return []\n  const raw = await fs.readFile(procfile, 'utf8')\n  const launcher = broad ? PY_LAUNCHERS_BROAD : PY_LAUNCHER_PYTHON\n  const edits: EntrypointEdit[] = []\n  for (const line of raw.split(/\\r?\\n/)) {\n    if (line.length === 0) continue\n    // Procfile lines look like `<process>: <cmd>`. Prefix the cmd when it\n    // starts with a recognised launcher and isn't already wrapped.\n    const m = line.match(/^([a-zA-Z0-9_-]+):\\s*(.+)$/)\n    if (!m) continue\n    const cmd = m[2]!\n    if (!launcher.test(cmd)) continue\n    if (cmd.startsWith('opentelemetry-instrument ')) continue\n    const after = `${m[1]}: opentelemetry-instrument ${cmd}`\n    edits.push({ file: procfile, before: line, after })\n  }\n  return edits\n}\n\nasync function plan(serviceDir: string, opts?: PlanOptions): Promise<InstallPlan> {\n  const empty: InstallPlan = {\n    language: 'python',\n    serviceDir,\n    dependencyEdits: [],\n    entrypointEdits: [],\n    envEdits: [],\n  }\n\n  // ADR-232 — attachment is the default: add the published neat-otel package\n  // (its post_instrument hook loads under opentelemetry-instrument), edit no\n  // source, generate no neat_otel.py. Source-edit (--source-edit) inlines the\n  // processor and injects the import instead. The Procfile prefix is the\n  // attachment turn-on, so it matches the broad launcher set (uvicorn/gunicorn/…);\n  // the source-edit path keeps the narrow python-only match (the import carries\n  // the rest).\n  if (!opts?.sourceEdit) {\n    const entrypointEdits = await planProcfileEdits(serviceDir, true)\n    const reqs = await planRequirementsTxtEdits(serviceDir, [NEAT_OTEL_PACKAGE, ...SDK_PACKAGES])\n    const dependencyEdits: DependencyEdit[] = reqs\n      ? reqs.missing.map((sdk) => ({\n          file: reqs.manifest,\n          kind: 'add' as const,\n          name: sdk.name,\n          version: sdk.version,\n        }))\n      : []\n    if (dependencyEdits.length === 0 && entrypointEdits.length === 0) return empty\n    return {\n      language: 'python',\n      serviceDir,\n      dependencyEdits,\n      entrypointEdits,\n      envEdits: [OTEL_ENV],\n    }\n  }\n\n  // ── Source-edit delivery (--source-edit) — the pre-ADR-232 path. ──\n  const entrypointEdits = await planProcfileEdits(serviceDir)\n  const dependencyEdits: DependencyEdit[] = []\n  const reqs = await planRequirementsTxtEdits(serviceDir)\n  if (reqs) {\n    for (const sdk of reqs.missing) {\n      dependencyEdits.push({\n        file: reqs.manifest,\n        kind: 'add',\n        name: sdk.name,\n        version: sdk.version,\n      })\n    }\n  }\n  // pyproject.toml / setup.py without requirements.txt: deferred to a\n  // successor ADR. The patch will note it; apply is a no-op for those\n  // manifests in the MVP.\n\n  // The call-site processor gives Python file-grain OBSERVED (ADR-151): a\n  // generated neat_otel.py plus an `import neat_otel` at the resolved entry\n  // point. Only planned when an entry point resolves — a processor module the\n  // app never imports would be dead weight, not instrumentation.\n  const entryFile = await resolvePyEntrypoint(serviceDir)\n  const generatedFiles: GeneratedFile[] = entryFile\n    ? [{ file: path.join(serviceDir, NEAT_OTEL_FILENAME), contents: neatOtelPy() }]\n    : []\n\n  if (dependencyEdits.length === 0 && entrypointEdits.length === 0 && !entryFile) {\n    return empty\n  }\n  return {\n    language: 'python',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits,\n    envEdits: [OTEL_ENV],\n    ...(generatedFiles.length > 0 ? { generatedFiles } : {}),\n    ...(entryFile ? { entryFile } : {}),\n  }\n}\n\nasync function applyRequirementsTxt(\n  manifest: string,\n  edits: DependencyEdit[],\n  original: string,\n): Promise<void> {\n  // Append missing packages on their own lines. Preserve a trailing newline.\n  const newlines = edits\n    .filter((e) => e.kind === 'add')\n    .map((e) => `${e.name}${e.version}`)\n  const trailing = original.endsWith('\\n') ? '' : '\\n'\n  const next = `${original}${trailing}${newlines.join('\\n')}\\n`\n  const tmp = `${manifest}.${process.pid}.${Date.now()}.tmp`\n  await fs.writeFile(tmp, next, 'utf8')\n  await fs.rename(tmp, manifest)\n}\n\nasync function applyProcfile(\n  procfile: string,\n  edits: EntrypointEdit[],\n  original: string,\n): Promise<void> {\n  let next = original\n  for (const e of edits) {\n    if (!next.includes(e.before)) continue\n    next = next.replace(e.before, e.after)\n  }\n  const tmp = `${procfile}.${process.pid}.${Date.now()}.tmp`\n  await fs.writeFile(tmp, next, 'utf8')\n  await fs.rename(tmp, procfile)\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n  const { serviceDir, entryFile } = installPlan\n  const generatedFiles = installPlan.generatedFiles ?? []\n  const touched = new Set<string>()\n  for (const e of installPlan.dependencyEdits) touched.add(e.file)\n  for (const e of installPlan.entrypointEdits) touched.add(e.file)\n  if (entryFile) touched.add(entryFile)\n  if (touched.size === 0 && generatedFiles.length === 0) {\n    return { serviceDir, outcome: 'already-instrumented', writtenFiles: [] }\n  }\n\n  const originals = new Map<string, string>()\n  for (const file of touched) {\n    try {\n      originals.set(file, await fs.readFile(file, 'utf8'))\n    } catch {\n      // Mutation will fail loudly below; rollback covers what did land.\n    }\n  }\n\n  const writtenFiles: string[] = []\n  const createdFiles: string[] = []\n  try {\n    // Generated files first (neat_otel.py). Idempotent: an identical file is\n    // left untouched; a new one is tracked so rollback can delete it.\n    for (const gf of generatedFiles) {\n      const already = await exists(gf.file)\n      if (already) {\n        const cur = await fs.readFile(gf.file, 'utf8').catch(() => null)\n        if (cur === gf.contents) continue\n      }\n      await writeFileAtomic(gf.file, gf.contents)\n      writtenFiles.push(gf.file)\n      if (!already) createdFiles.push(gf.file)\n    }\n\n    for (const file of touched) {\n      const raw = originals.get(file)\n      if (raw === undefined) {\n        throw new Error(`python installer: cannot read ${file} during apply`)\n      }\n      const base = path.basename(file)\n      if (base === 'requirements.txt') {\n        const edits = installPlan.dependencyEdits.filter((e) => e.file === file)\n        if (edits.length > 0) {\n          await applyRequirementsTxt(file, edits, raw)\n          writtenFiles.push(file)\n        }\n      } else if (base === 'Procfile') {\n        const edits = installPlan.entrypointEdits.filter((e) => e.file === file)\n        if (edits.length > 0) {\n          await applyProcfile(file, edits, raw)\n          writtenFiles.push(file)\n        }\n      } else if (file === entryFile) {\n        // Inject `import neat_otel` so the call-site processor registers at\n        // startup. Idempotent — a re-run leaves an already-injected entry alone.\n        const injected = injectNeatImport(raw)\n        if (injected !== null) {\n          await writeFileAtomic(file, injected)\n          writtenFiles.push(file)\n        }\n      }\n      // pyproject.toml / setup.py: MVP no-op as planned above.\n    }\n  } catch (err) {\n    await rollback(installPlan, originals, createdFiles)\n    throw err\n  }\n\n  const outcome = writtenFiles.length > 0 ? 'instrumented' : 'already-instrumented'\n  return { serviceDir, outcome, writtenFiles }\n}\n\nasync function rollback(\n  installPlan: InstallPlan,\n  originals: Map<string, string>,\n  createdFiles: string[] = [],\n): Promise<void> {\n  const restored: string[] = []\n  for (const [file, raw] of originals.entries()) {\n    try {\n      await fs.writeFile(file, raw, 'utf8')\n      restored.push(file)\n    } catch {\n      // Best-effort.\n    }\n  }\n  const removed: string[] = []\n  for (const file of createdFiles) {\n    try {\n      await fs.rm(file, { force: true })\n      removed.push(file)\n    } catch {\n      // Best-effort.\n    }\n  }\n  const lines = [\n    '# neat-rollback.patch',\n    '',\n    `# Generated after a partial apply failure in the ${installPlan.language} installer.`,\n    '# Files listed below were restored to their pre-apply contents.',\n    '',\n    ...restored.map((f) => `restored: ${f}`),\n    ...removed.map((f) => `removed: ${f}`),\n    '',\n  ]\n  const rollbackPath = path.join(installPlan.serviceDir, 'neat-rollback.patch')\n  await fs.writeFile(rollbackPath, lines.join('\\n'), 'utf8')\n}\n\nexport const pythonInstaller: Installer = {\n  name: 'python',\n  detect,\n  plan,\n  apply,\n}\n","import { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type { ApplyResult, DependencyEdit, Installer, InstallPlan } from './shared.js'\n\nconst GO_DEPS = [\n  { name: 'go.opentelemetry.io/otel', version: 'v1.38.0' },\n  { name: 'go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp', version: 'v1.38.0' },\n  { name: 'go.opentelemetry.io/otel/sdk', version: 'v1.38.0' },\n] as const\n\n// Bump whenever the generated body changes shape. A generated file carrying an\n// older version (its header's `v<N>`) is rewritten on the next apply; a\n// hand-written file — one without the header — is never touched.\nexport const NEAT_OTEL_GO_VERSION = 2\n\nasync function exists(file: string): Promise<boolean> {\n  return fs.stat(file).then(() => true, () => false)\n}\n\n// Whether an existing neat_otel.go should be rewritten. A file without the\n// `// neat-otel-init v<N>` header is hand-written and never touched; one with an\n// older version is regenerated so an existing install picks up a fix (#1367).\nasync function generatedIsStale(file: string): Promise<boolean> {\n  const existing = await fs.readFile(file, 'utf8').catch(() => undefined)\n  if (existing === undefined) return false\n  const version = existing.match(/^\\/\\/ neat-otel-init v(\\d+)\\b/)\n  return version ? Number(version[1]) < NEAT_OTEL_GO_VERSION : false\n}\n\nasync function findMain(serviceDir: string): Promise<string | null> {\n  const root = path.join(serviceDir, 'main.go')\n  if (await exists(root)) return root\n  const cmd = path.join(serviceDir, 'cmd')\n  const entries = await fs.readdir(cmd, { withFileTypes: true }).catch(() => [])\n  for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n    if (!entry.isDirectory()) continue\n    const candidate = path.join(cmd, entry.name, 'main.go')\n    if (await exists(candidate)) return candidate\n  }\n  return null\n}\n\nexport function neatOtelGo(packageName = 'main'): string {\n  return `// neat-otel-init v${NEAT_OTEL_GO_VERSION} — generated by NEAT. Safe to re-generate; do not edit.\npackage ${packageName}\n\nimport (\n  \"context\"\n  \"os\"\n  \"os/signal\"\n  \"path/filepath\"\n  \"runtime\"\n  \"strings\"\n  \"syscall\"\n  \"time\"\n\n  \"go.opentelemetry.io/otel\"\n  \"go.opentelemetry.io/otel/attribute\"\n  \"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp\"\n  sdktrace \"go.opentelemetry.io/otel/sdk/trace\"\n  \"go.opentelemetry.io/otel/trace\"\n)\n\ntype neatCallSiteSpanProcessor struct { root string }\n\nfunc (p neatCallSiteSpanProcessor) OnStart(_ context.Context, span sdktrace.ReadWriteSpan) {\n  if span.SpanKind() != trace.SpanKindClient && span.SpanKind() != trace.SpanKindProducer { return }\n  pcs := make([]uintptr, 32)\n  n := runtime.Callers(2, pcs)\n  frames := runtime.CallersFrames(pcs[:n])\n  for {\n    frame, more := frames.Next()\n    clean := filepath.Clean(frame.File)\n    slash := filepath.ToSlash(clean)\n    if clean != \"\" && strings.HasPrefix(clean, p.root+string(os.PathSeparator)) && !strings.Contains(slash, \"/vendor/\") && !strings.HasSuffix(slash, \"/neat_otel.go\") {\n      span.SetAttributes(\n        attribute.String(\"code.file.path\", clean),\n        attribute.Int(\"code.line.number\", frame.Line),\n        attribute.String(\"code.function.name\", frame.Function),\n      )\n      return\n    }\n    if !more { return }\n  }\n}\nfunc (neatCallSiteSpanProcessor) OnEnd(sdktrace.ReadOnlySpan) {}\nfunc (neatCallSiteSpanProcessor) Shutdown(context.Context) error { return nil }\nfunc (neatCallSiteSpanProcessor) ForceFlush(context.Context) error { return nil }\n\n// neatFlushOnSignal exports whatever the batch processor still holds when the\n// service is signalled to stop (#1367). SIGTERM (Cloud Run, Kubernetes) and\n// SIGINT (Ctrl-C) otherwise drop the last batch. Go has no atexit, so a file\n// generated beside main can only cover signal termination; a CLI that returns\n// from main on its own still needs its own shutdown. The flush is bounded so a\n// stuck exporter can't hold the process open, then the signal is re-raised so\n// the default behaviour (and any handler the app installs) still ends it.\nfunc neatFlushOnSignal(provider *sdktrace.TracerProvider) {\n  ch := make(chan os.Signal, 1)\n  signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)\n  go func() {\n    sig := <-ch\n    ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)\n    _ = provider.Shutdown(ctx)\n    cancel()\n    signal.Stop(ch)\n    if self, err := os.FindProcess(os.Getpid()); err == nil { _ = self.Signal(sig) }\n  }()\n}\n\nfunc init() {\n  root := os.Getenv(\"NEAT_SERVICE_ROOT\")\n  if root == \"\" {\n    _, self, _, ok := runtime.Caller(0)\n    if !ok { return }\n    root = filepath.Dir(self)\n    for {\n      if _, err := os.Stat(filepath.Join(root, \"go.mod\")); err == nil { break }\n      parent := filepath.Dir(root)\n      if parent == root { return }\n      root = parent\n    }\n  }\n  root, _ = filepath.Abs(root)\n  if canonical, err := filepath.EvalSymlinks(root); err == nil { root = canonical }\n  exporter, err := otlptracehttp.New(context.Background())\n  if err != nil { return }\n  provider := sdktrace.NewTracerProvider(\n    sdktrace.WithBatcher(exporter),\n    sdktrace.WithSpanProcessor(neatCallSiteSpanProcessor{root: filepath.Clean(root)}),\n  )\n  otel.SetTracerProvider(provider)\n  neatFlushOnSignal(provider)\n}\n`\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n  return exists(path.join(serviceDir, 'go.mod'))\n}\n\nasync function plan(serviceDir: string): Promise<InstallPlan> {\n  const manifest = path.join(serviceDir, 'go.mod')\n  const raw = await fs.readFile(manifest, 'utf8')\n  const main = await findMain(serviceDir)\n  const dependencyEdits: DependencyEdit[] = GO_DEPS\n    .filter((dep) => !raw.includes(dep.name))\n    .map((dep) => ({ file: manifest, kind: 'add', ...dep }))\n  if (!main) return { language: 'go', serviceDir, dependencyEdits: [], entrypointEdits: [], envEdits: [], libOnly: true }\n  const source = await fs.readFile(main, 'utf8')\n  const packageName = source.match(/^\\s*package\\s+(\\w+)\\s*$/m)?.[1] ?? 'main'\n  const generated = path.join(path.dirname(main), 'neat_otel.go')\n  const write = !(await exists(generated)) || (await generatedIsStale(generated))\n  const generatedFiles = write ? [{ file: generated, contents: neatOtelGo(packageName) }] : []\n  return { language: 'go', serviceDir, dependencyEdits, entrypointEdits: [], envEdits: [], generatedFiles, entryFile: main }\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n  if (installPlan.libOnly) return { serviceDir: installPlan.serviceDir, outcome: 'lib-only', writtenFiles: [] }\n  const writtenFiles: string[] = []\n  const byManifest = new Map<string, DependencyEdit[]>()\n  for (const edit of installPlan.dependencyEdits) byManifest.set(edit.file, [...(byManifest.get(edit.file) ?? []), edit])\n  for (const [manifest, edits] of byManifest) {\n    const raw = await fs.readFile(manifest, 'utf8')\n    const suffix = raw.endsWith('\\n') ? '' : '\\n'\n    await fs.writeFile(manifest, `${raw}${suffix}${edits.map((e) => `require ${e.name} ${e.version}`).join('\\n')}\\n`, 'utf8')\n    writtenFiles.push(manifest)\n  }\n  for (const generated of installPlan.generatedFiles ?? []) {\n    // Write a new file or regenerate a stale generated one; never clobber a\n    // hand-written neat_otel.go (plan already excludes it; re-checked here).\n    if ((await exists(generated.file)) && !(await generatedIsStale(generated.file))) continue\n    await fs.writeFile(generated.file, generated.contents, 'utf8')\n    writtenFiles.push(generated.file)\n  }\n  // When go.mod changed, the operator resolves the new requires with the Go\n  // toolchain — NEAT instructs rather than spawning the JS PM (ADR-186). Before\n  // this, a go.mod edit spuriously scheduled an `npm install` in the Go service.\n  const wroteManifest = writtenFiles.some((f) => f.split(/[\\\\/]/).pop() === 'go.mod')\n  return {\n    serviceDir: installPlan.serviceDir,\n    outcome: writtenFiles.length ? 'instrumented' : 'already-instrumented',\n    writtenFiles,\n    ...(wroteManifest ? { followUpInstall: 'go mod download' } : {}),\n  }\n}\n\nexport const goInstaller: Installer = { name: 'go', detect, plan, apply }\n","/**\n * Ruby SDK installer (ADR-186).\n *\n * `detect` matches on a Gemfile (a Rails or plain-Ruby service). `plan` adds\n * the OpenTelemetry gems to the Gemfile and — for a Rails app — generates a\n * `config/initializers/neat_otel.rb` that Rails auto-loads at boot. The\n * initializer configures the OTLP exporter at NEAT's project-scoped path,\n * enables the Ruby auto-instrumentation set (`use_all`), and installs a\n * call-site span processor that stamps the stable `code.*` attributes on\n * CLIENT/PRODUCER spans so a runtime span fuses onto the source file that\n * issued it (docs/contracts/file-awareness.md).\n *\n * The initializer is convention-loaded — Rails requires everything under\n * `config/initializers/` at startup — so there is no entry-point injection to\n * do, the same shape the Go installer's same-package `init()` and the Nuxt\n * `server/plugins/` convention take. Bundler's `Gemfile.lock` is never written\n * (it is a lockfile, ADR-046 §4); after `--apply` the user runs\n * `bundle install` so bundler resolves the lockfile itself.\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n  ApplyResult,\n  DependencyEdit,\n  EnvEdit,\n  GeneratedFile,\n  Installer,\n  InstallPlan,\n  PlanOptions,\n} from './shared.js'\n\n// Marker basenames. Kept as bare string literals on their own lines so the\n// lockfile-reference audit (contracts.test.ts, ADR-046 §4) reads the only\n// 'Gemfile.lock' occurrence as a set entry, never a write target — the manifest\n// we edit is the Gemfile, the lock is detect-only.\nconst RUBY_MARKERS = [\n  'Gemfile',\n  'Gemfile.lock',\n] as const\n\n// Gems added to the Gemfile. The SDK + OTLP exporter mirror Python's\n// distro/exporter pair; `opentelemetry-instrumentation-all` is the meta-gem\n// that pulls Rails, ActiveRecord, Net::HTTP, PG, and the rest of the\n// auto-instrumentation set, so a Rails app gets route + DB spans without\n// naming each instrumentation gem individually.\nconst RUBY_GEMS = [\n  { name: 'opentelemetry-sdk', version: '~> 1.5' },\n  { name: 'opentelemetry-exporter-otlp', version: '~> 0.29' },\n  { name: 'opentelemetry-instrumentation-all', version: '~> 0.62' },\n] as const\n\nconst NEAT_OTEL_STAMP = 'neat-otel-init v1'\nconst INITIALIZER_REL = path.join('config', 'initializers', 'neat_otel.rb')\n\n// The generated Rails initializer. `project` bakes the OTLP scope + service\n// name (ADR-183 — hooks export to the project-scoped path, not the bare one);\n// both stay overridable through the standard OTel env vars so an operator can\n// point the app at a different daemon without regenerating the file.\nexport function neatOtelRb(opts: { project?: string } = {}): string {\n  const service = opts.project ?? 'ruby-service'\n  const endpoint = opts.project\n    ? `http://localhost:4318/projects/${opts.project}/v1/traces`\n    : 'http://localhost:4318/v1/traces'\n  return `# ${NEAT_OTEL_STAMP} — generated by NEAT. Safe to re-generate; do not edit.\n# Rails auto-loads this at boot (config/initializers/*). It points the\n# OpenTelemetry SDK at your NEAT daemon, enables the Ruby auto-instrumentation\n# set, and installs a span processor that stamps code.file.path /\n# code.line.number / code.function.name on the CLIENT/PRODUCER spans your app\n# issues, so NEAT fuses each runtime span onto the source file that made the\n# call (docs/contracts/file-awareness.md). Absolute paths are emitted here;\n# ingest anchors them against the service root. If the OpenTelemetry gems are\n# not installed this file degrades to a no-op rather than breaking boot.\n\nbegin\n  require 'opentelemetry/sdk'\n  require 'opentelemetry/exporter/otlp'\n  require 'opentelemetry/instrumentation/all'\n  _neat_otel_loaded = true\nrescue LoadError\n  _neat_otel_loaded = false\nend\n\nif _neat_otel_loaded && ENV['NEAT_CALLSITE_DISABLED'] != '1'\n  # Walk the Ruby call stack to the first application frame and stamp the stable\n  # OTel source attributes on CLIENT/PRODUCER spans. SERVER spans are created\n  # before the handler runs, so they stay route/service-grained, honestly.\n  class NeatCallSiteSpanProcessor\n    def initialize(root)\n      @root = root.to_s.end_with?(File::SEPARATOR) ? root.to_s : root.to_s + File::SEPARATOR\n    end\n\n    def on_start(span, _parent_context)\n      kind = span.kind\n      return unless kind == OpenTelemetry::Trace::SpanKind::CLIENT ||\n                    kind == OpenTelemetry::Trace::SpanKind::PRODUCER\n      caller_locations(1).each do |loc|\n        file = loc.absolute_path || loc.path\n        next if file.nil?\n        next unless file.start_with?(@root)\n        next if file.include?('/vendor/') || file.include?('/.bundle/')\n        next if file.end_with?('neat_otel.rb')\n        span.set_attribute('code.file.path', file)\n        span.set_attribute('code.line.number', loc.lineno)\n        span.set_attribute('code.function.name', loc.label.to_s)\n        break\n      end\n    rescue StandardError\n      # never break the host application\n    end\n\n    def on_finish(_span); end\n\n    def force_flush(timeout: nil)\n      OpenTelemetry::SDK::Trace::Export::SUCCESS\n    end\n\n    def shutdown(timeout: nil)\n      OpenTelemetry::SDK::Trace::Export::SUCCESS\n    end\n  end\n\n  _neat_root = defined?(Rails) ? Rails.root.to_s : Dir.pwd\n  _neat_service = ENV.fetch('OTEL_SERVICE_NAME', '${service}')\n  _neat_endpoint = ENV.fetch('OTEL_EXPORTER_OTLP_TRACES_ENDPOINT', '${endpoint}')\n\n  OpenTelemetry::SDK.configure do |c|\n    c.service_name = _neat_service\n    c.use_all\n    c.add_span_processor(\n      OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(\n        OpenTelemetry::Exporter::OTLP::Exporter.new(endpoint: _neat_endpoint)\n      )\n    )\n    c.add_span_processor(NeatCallSiteSpanProcessor.new(_neat_root))\n  end\nend\n`\n}\n\nasync function exists(p: string): Promise<boolean> {\n  try {\n    await fs.stat(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n  for (const marker of RUBY_MARKERS) {\n    if (await exists(path.join(serviceDir, marker))) return true\n  }\n  return false\n}\n\n// A Rails app carries a `rails` gem or the conventional Rails layout. Only a\n// Rails app gets the convention-loaded initializer; a plain-Ruby service still\n// gets the gems but leaves boot-time wiring to the operator (there is no\n// universal auto-load point outside Rails).\nasync function isRailsApp(serviceDir: string, gemfile: string | null): Promise<boolean> {\n  if (gemfile && /^\\s*gem\\s+['\"]rails['\"]/m.test(gemfile)) return true\n  for (const marker of ['config/application.rb', 'config/environment.rb', 'bin/rails']) {\n    if (await exists(path.join(serviceDir, marker))) return true\n  }\n  return false\n}\n\n// True when the Gemfile already declares `gem '<name>'` at any version.\nfunction gemPresent(gemfile: string, name: string): boolean {\n  const escaped = name.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n  return new RegExp(`^\\\\s*gem\\\\s+['\"]${escaped}['\"]`, 'm').test(gemfile)\n}\n\nasync function readGemfile(serviceDir: string): Promise<{ file: string; body: string } | null> {\n  const file = path.join(serviceDir, 'Gemfile')\n  if (!(await exists(file))) return null\n  return { file, body: await fs.readFile(file, 'utf8') }\n}\n\nasync function plan(serviceDir: string, opts?: PlanOptions): Promise<InstallPlan> {\n  const empty: InstallPlan = {\n    language: 'ruby',\n    serviceDir,\n    dependencyEdits: [],\n    entrypointEdits: [],\n    envEdits: [],\n  }\n\n  const gemfile = await readGemfile(serviceDir)\n\n  // Manifest edits only when a real Gemfile is on disk. A directory that carries\n  // only Gemfile.lock has no manifest we may safely write, so we add nothing —\n  // and never reference the lockfile.\n  const dependencyEdits: DependencyEdit[] = []\n  if (gemfile) {\n    for (const gem of RUBY_GEMS) {\n      if (!gemPresent(gemfile.body, gem.name)) {\n        dependencyEdits.push({ file: gemfile.file, kind: 'add', name: gem.name, version: gem.version })\n      }\n    }\n  }\n\n  const rails = await isRailsApp(serviceDir, gemfile?.body ?? null)\n  const initializer = path.join(serviceDir, INITIALIZER_REL)\n  const generatedFiles: GeneratedFile[] = []\n  if (rails && !(await exists(initializer))) {\n    generatedFiles.push({\n      file: initializer,\n      contents: neatOtelRb({ project: opts?.project }),\n      skipIfExists: true,\n    })\n  }\n\n  if (dependencyEdits.length === 0 && generatedFiles.length === 0) {\n    return empty\n  }\n\n  const envEdits: EnvEdit[] = [\n    { file: null, key: 'OTEL_EXPORTER_OTLP_ENDPOINT', value: 'http://localhost:4318' },\n  ]\n\n  return {\n    language: 'ruby',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits: [],\n    envEdits,\n    ...(generatedFiles.length > 0 ? { generatedFiles } : {}),\n  }\n}\n\nasync function writeFileAtomic(file: string, contents: string): Promise<void> {\n  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`\n  await fs.writeFile(tmp, contents, 'utf8')\n  await fs.rename(tmp, file)\n}\n\n// Append the missing gems to the Gemfile, preserving everything already there\n// (merge, never clobber). A trailing newline is kept so the file stays clean.\nasync function applyGemfile(file: string, edits: DependencyEdit[], original: string): Promise<void> {\n  const lines = edits.filter((e) => e.kind === 'add').map((e) => `gem '${e.name}', '${e.version}'`)\n  const banner = `\\n# ${NEAT_OTEL_STAMP} — OpenTelemetry gems added by NEAT\\n`\n  const trailing = original.endsWith('\\n') ? '' : '\\n'\n  await writeFileAtomic(file, `${original}${trailing}${banner}${lines.join('\\n')}\\n`)\n}\n\nasync function rollback(\n  serviceDir: string,\n  language: string,\n  originals: Map<string, string>,\n  created: string[],\n): Promise<void> {\n  const restored: string[] = []\n  for (const [file, raw] of originals.entries()) {\n    try {\n      await fs.writeFile(file, raw, 'utf8')\n      restored.push(file)\n    } catch {\n      // best-effort\n    }\n  }\n  const removed: string[] = []\n  for (const file of created) {\n    try {\n      await fs.rm(file, { force: true })\n      removed.push(file)\n    } catch {\n      // best-effort\n    }\n  }\n  const body = [\n    '# neat-rollback.patch',\n    '',\n    `# Generated after a partial apply failure in the ${language} installer.`,\n    '# Files listed below were restored to their pre-apply contents.',\n    '',\n    ...restored.map((f) => `restored: ${f}`),\n    ...removed.map((f) => `removed: ${f}`),\n    '',\n  ]\n  await fs.writeFile(path.join(serviceDir, 'neat-rollback.patch'), body.join('\\n'), 'utf8')\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n  const { serviceDir } = installPlan\n  const generatedFiles = installPlan.generatedFiles ?? []\n  const manifests = new Set(installPlan.dependencyEdits.map((e) => e.file))\n\n  if (manifests.size === 0 && generatedFiles.length === 0) {\n    return { serviceDir, outcome: 'already-instrumented', writtenFiles: [] }\n  }\n\n  const originals = new Map<string, string>()\n  for (const file of manifests) {\n    try {\n      originals.set(file, await fs.readFile(file, 'utf8'))\n    } catch {\n      // Mutation fails loudly below; rollback covers what did land.\n    }\n  }\n\n  const writtenFiles: string[] = []\n  const created: string[] = []\n  try {\n    // Generated initializer first (createOnly, ADR-069 §6): an existing file is\n    // preserved untouched; a new one is tracked so rollback can delete it.\n    for (const gf of generatedFiles) {\n      if (await exists(gf.file)) continue\n      await fs.mkdir(path.dirname(gf.file), { recursive: true })\n      await writeFileAtomic(gf.file, gf.contents)\n      writtenFiles.push(gf.file)\n      created.push(gf.file)\n    }\n\n    for (const file of manifests) {\n      const raw = originals.get(file)\n      if (raw === undefined) throw new Error(`ruby installer: cannot read ${file} during apply`)\n      const edits = installPlan.dependencyEdits.filter((e) => e.file === file)\n      if (edits.length > 0) {\n        await applyGemfile(file, edits, raw)\n        writtenFiles.push(file)\n      }\n    }\n  } catch (err) {\n    await rollback(serviceDir, installPlan.language, originals, created)\n    throw err\n  }\n\n  // When the Gemfile changed, the operator resolves the new gems with bundler —\n  // NEAT doesn't run it (it can't guarantee bundler is on PATH), it instructs\n  // (ADR-186). The orchestrator surfaces this instead of spawning the JS PM.\n  const wroteManifest = writtenFiles.some((f) => path.basename(f) === 'Gemfile')\n\n  return {\n    serviceDir,\n    outcome: writtenFiles.length > 0 ? 'instrumented' : 'already-instrumented',\n    writtenFiles,\n    ...(wroteManifest ? { followUpInstall: 'bundle install' } : {}),\n  }\n}\n\nexport const rubyInstaller: Installer = { name: 'ruby', detect, plan, apply }\n","/**\n * PHP SDK installer (ADR-186).\n *\n * `detect` matches on a composer.json (a Laravel or plain-PHP service). `plan`\n * adds the OpenTelemetry Composer packages to the `require` map and generates a\n * `neat_otel.php` bootstrap that points the OTLP exporter at NEAT's\n * project-scoped path and turns on the zero-code SDK autoloader. For a Laravel\n * app it also adds `open-telemetry/opentelemetry-auto-laravel`, whose hooks give\n * route, DB (Eloquent), cache, and queue spans that fuse onto the extracted\n * Laravel routes and Eloquent tables.\n *\n * HONESTY — the PECL extension NEAT cannot install:\n *   PHP OpenTelemetry auto-instrumentation is driven by the `opentelemetry`\n *   PECL extension, a system-level install (`pecl install opentelemetry`) that\n *   composer cannot provide. Without it the auto-instrumentation hooks never\n *   fire and no spans are produced. This installer PLANS the requirement — the\n *   generated file header, the recommended env, and the apply result all name\n *   it as a required user step — but it does not and cannot pretend composer\n *   alone instruments PHP.\n *\n * FILE-GRAIN — deferred (ADR-186). Ruby and Go stamp `code.file.path` from a\n * call-site span processor; the PHP equivalent would register a custom span\n * processor into the zero-code autoloaded SDK, a hook that can't be verified\n * without a live PHP + PECL runtime. Rather than ship an unverified\n * registration that may silently never fire, PHP lands route/table/service\n * grain now and file-grain is a tracked follow-up. composer.lock is never\n * written (it is a lockfile, ADR-046 §4).\n */\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport type {\n  ApplyResult,\n  DependencyEdit,\n  EnvEdit,\n  GeneratedFile,\n  Installer,\n  InstallPlan,\n  PlanOptions,\n} from './shared.js'\n\n// Marker basenames, kept as bare string literals on their own lines to stay\n// clear of the lockfile-reference audit (ADR-046 §4). composer.lock is\n// detect-only; the manifest we edit is composer.json.\nconst PHP_MARKERS = [\n  'composer.json',\n  'composer.lock',\n] as const\n\nconst NEAT_OTEL_FILENAME = 'neat_otel.php'\nconst NEAT_OTEL_STAMP = 'neat-otel-init v1'\nconst LARAVEL_PACKAGE = 'open-telemetry/opentelemetry-auto-laravel'\n\n// Composer packages. The SDK + OTLP exporter are the base; the guzzle7 adapter\n// gives the exporter a PSR-18 HTTP client via discovery (Laravel already ships\n// Guzzle); the auto-laravel package is added only for a Laravel app.\nconst PHP_PACKAGES = [\n  { name: 'open-telemetry/sdk', version: '^1.0' },\n  { name: 'open-telemetry/exporter-otlp', version: '^1.0' },\n  { name: 'php-http/guzzle7-adapter', version: '^1.0' },\n  { name: LARAVEL_PACKAGE, version: '^0.1' },\n] as const\n\n// Surfaced everywhere the user might look: the generated file header, the\n// recommended env, and the apply result reason.\nconst PHP_PECL_CAVEAT =\n  'PHP auto-instrumentation requires the `opentelemetry` PECL extension ' +\n  '(`pecl install opentelemetry`, then `extension=opentelemetry.so` in php.ini). ' +\n  'NEAT cannot install a PECL extension via composer — until it is loaded no ' +\n  'spans are produced. See neat_otel.php and ADR-186.'\n\n// The generated bootstrap. `project` bakes the OTLP scope + service name\n// (ADR-183 — hooks export to the project-scoped path); both stay overridable\n// through the standard OTel env vars.\nexport function neatOtelPhp(opts: { project?: string } = {}): string {\n  const service = opts.project ?? 'php-service'\n  const endpoint = opts.project\n    ? `http://localhost:4318/projects/${opts.project}/v1/traces`\n    : 'http://localhost:4318/v1/traces'\n  return `<?php\n// ${NEAT_OTEL_STAMP} — generated by NEAT. Safe to re-generate; do not edit.\n//\n// REQUIRED SYSTEM STEP — NEAT CANNOT DO THIS FOR YOU:\n//   PHP OpenTelemetry auto-instrumentation needs the \\`opentelemetry\\` PECL\n//   extension, a system-level install composer cannot provide:\n//       pecl install opentelemetry\n//   then enable it in your php.ini:\n//       extension=opentelemetry.so\n//   Verify with \\`php -m | grep opentelemetry\\`. Until the extension is loaded\n//   the Laravel auto-instrumentation hooks never fire and no spans are emitted.\n//\n// Wire this file so it runs before the framework boots — either set\n//   auto_prepend_file = /absolute/path/to/neat_otel.php\n// in php.ini / .user.ini, or require it at the very top of public/index.php and\n// artisan. It points the exporter at your NEAT daemon and turns on the SDK\n// autoloader; the auto-laravel instrumentation then produces route, DB, cache,\n// and queue spans that fuse onto your extracted routes and Eloquent tables.\n//\n// FILE-GRAIN (code.file.path call-site attribution) is a documented follow-up\n// for PHP — see ADR-186. Route, table, and service grain land now.\n\ndeclare(strict_types=1);\n\n// Degrade to a no-op when the extension isn't present, so a bare app still\n// boots (never break the host application).\nif (!extension_loaded('opentelemetry')) {\n    return;\n}\n\n// Point the exporter at NEAT unless the operator already set these. The\n// endpoint is NEAT's project-scoped traces path (ADR-183).\n$neat_defaults = [\n    'OTEL_PHP_AUTOLOAD_ENABLED' => 'true',\n    'OTEL_SERVICE_NAME' => '${service}',\n    'OTEL_TRACES_EXPORTER' => 'otlp',\n    'OTEL_EXPORTER_OTLP_PROTOCOL' => 'http/json',\n    'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' => '${endpoint}',\n    'OTEL_PROPAGATORS' => 'baggage,tracecontext',\n];\nforeach ($neat_defaults as $neat_key => $neat_value) {\n    if (getenv($neat_key) === false && !isset($_SERVER[$neat_key]) && !isset($_ENV[$neat_key])) {\n        putenv($neat_key . '=' . $neat_value);\n        $_SERVER[$neat_key] = $neat_value;\n        $_ENV[$neat_key] = $neat_value;\n    }\n}\n`\n}\n\nasync function exists(p: string): Promise<boolean> {\n  try {\n    await fs.stat(p)\n    return true\n  } catch {\n    return false\n  }\n}\n\nasync function detect(serviceDir: string): Promise<boolean> {\n  for (const marker of PHP_MARKERS) {\n    if (await exists(path.join(serviceDir, marker))) return true\n  }\n  return false\n}\n\ninterface ComposerManifest {\n  require: Record<string, unknown>\n  requireDev: Record<string, unknown>\n}\n\nfunction readComposerObject(body: string): ComposerManifest {\n  let parsed: unknown = null\n  try {\n    parsed = JSON.parse(body)\n  } catch {\n    parsed = null\n  }\n  const obj = parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? (parsed as Record<string, unknown>) : {}\n  const require = obj.require && typeof obj.require === 'object' && !Array.isArray(obj.require)\n    ? (obj.require as Record<string, unknown>)\n    : {}\n  const requireDev = obj['require-dev'] && typeof obj['require-dev'] === 'object' && !Array.isArray(obj['require-dev'])\n    ? (obj['require-dev'] as Record<string, unknown>)\n    : {}\n  return { require, requireDev }\n}\n\nasync function plan(serviceDir: string, opts?: PlanOptions): Promise<InstallPlan> {\n  const empty: InstallPlan = {\n    language: 'php',\n    serviceDir,\n    dependencyEdits: [],\n    entrypointEdits: [],\n    envEdits: [],\n  }\n\n  const composerPath = path.join(serviceDir, 'composer.json')\n  const hasComposer = await exists(composerPath)\n\n  const dependencyEdits: DependencyEdit[] = []\n  if (hasComposer) {\n    const body = await fs.readFile(composerPath, 'utf8')\n    const { require, requireDev } = readComposerObject(body)\n    const laravel =\n      'laravel/framework' in require ||\n      'laravel/framework' in requireDev ||\n      (await exists(path.join(serviceDir, 'artisan')))\n    const wanted = laravel ? PHP_PACKAGES : PHP_PACKAGES.filter((p) => p.name !== LARAVEL_PACKAGE)\n    for (const pkg of wanted) {\n      if (!(pkg.name in require)) {\n        dependencyEdits.push({ file: composerPath, kind: 'add', name: pkg.name, version: pkg.version })\n      }\n    }\n  }\n\n  // The bootstrap is generated whenever a composer.json is present; createOnly\n  // preserves any existing file (ADR-069 §6).\n  const bootstrap = path.join(serviceDir, NEAT_OTEL_FILENAME)\n  const generatedFiles: GeneratedFile[] = []\n  if (hasComposer && !(await exists(bootstrap))) {\n    generatedFiles.push({ file: bootstrap, contents: neatOtelPhp({ project: opts?.project }), skipIfExists: true })\n  }\n\n  if (dependencyEdits.length === 0 && generatedFiles.length === 0) {\n    return empty\n  }\n\n  const envEdits: EnvEdit[] = [\n    { file: null, key: 'OTEL_PHP_AUTOLOAD_ENABLED', value: 'true' },\n    { file: null, key: 'OTEL_EXPORTER_OTLP_ENDPOINT', value: 'http://localhost:4318' },\n  ]\n\n  return {\n    language: 'php',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits: [],\n    envEdits,\n    ...(generatedFiles.length > 0 ? { generatedFiles } : {}),\n  }\n}\n\nasync function writeFileAtomic(file: string, contents: string): Promise<void> {\n  const tmp = `${file}.${process.pid}.${Date.now()}.tmp`\n  await fs.writeFile(tmp, contents, 'utf8')\n  await fs.rename(tmp, file)\n}\n\n// Merge the missing packages into composer.json's `require`, preserving every\n// other key (merge, never clobber). composer.json is strict JSON, so the safe\n// edit is parse → add missing keys → re-serialize; existing require entries and\n// all sibling keys (name, type, require-dev, autoload, …) are kept.\nasync function applyComposerJson(file: string, edits: DependencyEdit[], original: string): Promise<void> {\n  let parsed: unknown\n  try {\n    parsed = JSON.parse(original)\n  } catch {\n    throw new Error(`php installer: composer.json at ${file} is not valid JSON`)\n  }\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n    throw new Error(`php installer: composer.json at ${file} is not a JSON object`)\n  }\n  const obj = parsed as Record<string, unknown>\n  const require = obj.require && typeof obj.require === 'object' && !Array.isArray(obj.require)\n    ? (obj.require as Record<string, string>)\n    : {}\n  for (const e of edits) {\n    if (e.kind !== 'add') continue\n    if (!(e.name in require)) require[e.name] = e.version\n  }\n  obj.require = require\n  await writeFileAtomic(file, JSON.stringify(obj, null, 2) + '\\n')\n}\n\nasync function rollback(\n  serviceDir: string,\n  language: string,\n  originals: Map<string, string>,\n  created: string[],\n): Promise<void> {\n  const restored: string[] = []\n  for (const [file, raw] of originals.entries()) {\n    try {\n      await fs.writeFile(file, raw, 'utf8')\n      restored.push(file)\n    } catch {\n      // best-effort\n    }\n  }\n  const removed: string[] = []\n  for (const file of created) {\n    try {\n      await fs.rm(file, { force: true })\n      removed.push(file)\n    } catch {\n      // best-effort\n    }\n  }\n  const body = [\n    '# neat-rollback.patch',\n    '',\n    `# Generated after a partial apply failure in the ${language} installer.`,\n    '# Files listed below were restored to their pre-apply contents.',\n    '',\n    ...restored.map((f) => `restored: ${f}`),\n    ...removed.map((f) => `removed: ${f}`),\n    '',\n  ]\n  await fs.writeFile(path.join(serviceDir, 'neat-rollback.patch'), body.join('\\n'), 'utf8')\n}\n\nasync function apply(installPlan: InstallPlan): Promise<ApplyResult> {\n  const { serviceDir } = installPlan\n  const generatedFiles = installPlan.generatedFiles ?? []\n  const manifests = new Set(installPlan.dependencyEdits.map((e) => e.file))\n\n  if (manifests.size === 0 && generatedFiles.length === 0) {\n    return { serviceDir, outcome: 'already-instrumented', writtenFiles: [], reason: PHP_PECL_CAVEAT }\n  }\n\n  const originals = new Map<string, string>()\n  for (const file of manifests) {\n    try {\n      originals.set(file, await fs.readFile(file, 'utf8'))\n    } catch {\n      // Mutation fails loudly below; rollback covers what did land.\n    }\n  }\n\n  const writtenFiles: string[] = []\n  const created: string[] = []\n  try {\n    for (const gf of generatedFiles) {\n      if (await exists(gf.file)) continue\n      await fs.mkdir(path.dirname(gf.file), { recursive: true })\n      await writeFileAtomic(gf.file, gf.contents)\n      writtenFiles.push(gf.file)\n      created.push(gf.file)\n    }\n\n    for (const file of manifests) {\n      const raw = originals.get(file)\n      if (raw === undefined) throw new Error(`php installer: cannot read ${file} during apply`)\n      const edits = installPlan.dependencyEdits.filter((e) => e.file === file)\n      if (edits.length > 0) {\n        await applyComposerJson(file, edits, raw)\n        writtenFiles.push(file)\n      }\n    }\n  } catch (err) {\n    await rollback(serviceDir, installPlan.language, originals, created)\n    throw err\n  }\n\n  // Surface the PECL requirement loudly at apply time — it is the step that\n  // makes or breaks whether PHP produces any spans at all.\n  if (writtenFiles.length > 0) {\n    console.warn(`neat: PHP instrumentation staged in ${path.basename(serviceDir)}, but a system step remains:\\n  ${PHP_PECL_CAVEAT}`)\n  }\n\n  // When composer.json changed, the operator resolves the new packages with\n  // composer — NEAT instructs rather than spawning the JS PM (ADR-186).\n  const wroteManifest = writtenFiles.some((f) => path.basename(f) === 'composer.json')\n\n  return {\n    serviceDir,\n    outcome: writtenFiles.length > 0 ? 'instrumented' : 'already-instrumented',\n    writtenFiles,\n    reason: PHP_PECL_CAVEAT,\n    ...(wroteManifest ? { followUpInstall: 'composer install' } : {}),\n  }\n}\n\nexport const phpInstaller: Installer = { name: 'php', detect, plan, apply }\n","/**\n * Shared types for SDK installer modules (ADR-047).\n *\n * Each language has its own installer at `installers/<language>.ts` exporting\n * a `detect / plan / apply` triple. Plans are pure data — no fs side effects\n * during planning — so `init --dry-run` can render a patch without ever\n * touching the project. `apply` runs the codemod in place.\n *\n * Step 2 (this PR) ships the interface and an empty registry. Step 3 (Node\n * installer) and step 4 (Python installer) populate it.\n */\n\n// Field names match ADR-047's documented patch shape exactly: `file`, `kind`,\n// `name`, `version`. Patches will be reviewed by humans and matched in tests\n// by name; renaming for clarity would have cost more than it bought.\n\nexport interface DependencyEdit {\n  file: string\n  kind: 'add' | 'remove' | 'upgrade'\n  name: string\n  version: string\n  fromVersion?: string\n}\n\nexport interface EntrypointEdit {\n  file: string\n  before: string\n  after: string\n}\n\nexport interface EnvEdit {\n  // `null` denotes a recommendation only — the user will set the env var in\n  // their orchestration layer, NEAT does not write a `.env` file.\n  file: string | null\n  key: string\n  value: string\n}\n\n// Files the installer generates from scratch (ADR-069 §1). The generated\n// `otel-init.{js,ts}` for the Node installer rides here, along with the\n// per-package `.env.neat` (ADR-069 §4). Treated as additive writes — the\n// apply phase skips any file already present (ADR-069 §6).\nexport interface GeneratedFile {\n  file: string\n  contents: string\n  // When true, write only if the file does not already exist. The apply\n  // phase logs an `already instrumented` / `already present` notice instead\n  // of overwriting (ADR-069 §6).\n  skipIfExists?: boolean\n}\n\nexport interface InstallPlan {\n  // Free-form language tag matching the service node's language: `'javascript'`,\n  // `'python'`, …\n  language: string\n  // Service directory the plan targets. Absolute path.\n  serviceDir: string\n  dependencyEdits: DependencyEdit[]\n  entrypointEdits: EntrypointEdit[]\n  envEdits: EnvEdit[]\n  // ADR-069 §1, §4 — generated files (otel-init, .env.neat). Optional so\n  // installers that don't generate files (the Python installer at MVP) can\n  // omit it.\n  generatedFiles?: GeneratedFile[]\n  // ADR-069 §2 — flagged when entry-point resolution found nothing.\n  // The apply phase records this in the summary and skips all file writes\n  // for the package.\n  libOnly?: boolean\n  // ADR-069 §2 — resolved entry-point path (absolute). Present when the\n  // installer is going to inject the require/import. Absent for libOnly\n  // packages and for the Python installer.\n  entryFile?: string\n  // ADR-073 §1 + ADR-074 §3 — when a framework owns its own boot, the\n  // installer skips `pkg.main` injection and emits framework-native\n  // instrumentation files instead. Five values today: Next.js from v0.3.8,\n  // then Remix / SvelteKit / Nuxt / Astro from v0.3.9.\n  framework?: 'next' | 'remix' | 'sveltekit' | 'nuxt' | 'astro'\n  // v0.4.4 / issue #370 — when a JavaScript package isn't a Node service\n  // (browser bundle, React Native), the installer records the runtime here\n  // and writes nothing. Absent → vanilla Node default (the existing apply\n  // path). Browser-side OTel support (`@opentelemetry/sdk-trace-web`) lands\n  // in a future release.\n  runtimeKind?: 'browser-bundle' | 'react-native' | 'bun' | 'deno' | 'cloudflare-workers' | 'electron'\n  // ADR-073 §1 — Next.js' `next.config.{js,ts,mjs}` may need the\n  // `experimental.instrumentationHook: true` flag set when the major\n  // version is < 15. The apply phase mutates the file in place when this\n  // field is set. Absent → no config mutation planned.\n  nextConfigEdit?: {\n    file: string\n    // Reason this edit is queued — surfaces in the dry-run patch and the\n    // apply summary so the operator knows why their next.config moved.\n    reason: string\n  }\n}\n\n// ADR-069 §9 — apply outcome per service. The CLI surfaces these counts\n// at the end of `neat init --apply`. v0.4.4 / issue #370 — two new buckets\n// for non-Node JavaScript runtimes: `browser-bundle` (Vite, esbuild-shipped\n// SPAs) and `react-native` (Expo / RN bare). The Node SDK can't run in\n// either; both buckets skip every write and surface the package in the\n// summary so the operator knows the frontend wasn't instrumented.\nexport type ApplyOutcome =\n  | 'instrumented'\n  | 'already-instrumented'\n  | 'lib-only'\n  | 'failed'\n  | 'browser-bundle'\n  | 'react-native'\n  | 'bun'\n  | 'deno'\n  | 'cloudflare-workers'\n  | 'electron'\n\nexport interface ApplyResult {\n  serviceDir: string\n  outcome: ApplyOutcome\n  // Free-form reason string for `lib-only` / `failed` outcomes. Surfaced\n  // in the CLI summary so the user knows why a package was skipped.\n  reason?: string\n  // Absolute paths the apply phase actually wrote to. Used by the contract\n  // test that asserts the allowed-path-set restriction (ADR-069 §7).\n  writtenFiles: string[]\n  // Native dependency-install command the operator must run to resolve the\n  // manifest edits this apply staged — `bundle install` (Ruby), `composer\n  // install` (PHP), `go mod download` (Go). NEAT does not drive those\n  // ecosystems' package managers, so it instructs rather than spawns; the\n  // orchestrator surfaces this in the apply summary instead of running the JS\n  // package manager. Unset for JavaScript, whose package manager the\n  // orchestrator runs itself off a `package.json` edit (ADR-186).\n  followUpInstall?: string\n}\n\n// Plan-time inputs the orchestrator threads through (v0.4.1 — refs #339).\n// `project` is the registered project name — the routing key the daemon\n// owns. When present the installer writes it as `OTEL_SERVICE_NAME` so the\n// OTLP wire and the registry agree end-to-end. Absent → installers fall\n// back to a package-local default for ad-hoc / test usage.\nexport interface PlanOptions {\n  project?: string\n  // ADR-232 — delivery mode. Default (false/undefined) is runtime attachment:\n  // the installer adds a dependency + `NODE_OPTIONS`/env and edits no source.\n  // `true` selects the legacy source-edit injection (generated otel-init +\n  // entry-point require/import), reached only via an explicit `--source-edit`,\n  // never automatically and never from the front-door run. Per-installer\n  // branches on this flag land the behaviour; the flag is threaded here first.\n  sourceEdit?: boolean\n}\n\nexport interface Installer {\n  // Free-form module name. Used for the patch header and for diagnostics.\n  name: string\n  // Returns true if the installer thinks `serviceDir` is shaped like a project\n  // it can instrument. Cheap; no fs writes.\n  detect(serviceDir: string): boolean | Promise<boolean>\n  // Builds an `InstallPlan` describing the edits the installer would make.\n  // Pure data; no fs writes. An empty plan (every edits array empty) means\n  // the SDK is already installed and there is nothing to do.\n  plan(serviceDir: string, opts?: PlanOptions): InstallPlan | Promise<InstallPlan>\n  // Apply a previously-produced plan. Mutates files in place. On failure,\n  // produces `<serviceDir>/neat-rollback.patch` per ADR-047 #7. Returns a\n  // structured outcome so the CLI can surface coverage (ADR-069 §9).\n  apply(plan: InstallPlan): Promise<ApplyResult>\n}\n\nexport function isEmptyPlan(plan: InstallPlan): boolean {\n  return (\n    plan.dependencyEdits.length === 0 &&\n    plan.entrypointEdits.length === 0 &&\n    plan.envEdits.length === 0 &&\n    (plan.generatedFiles?.length ?? 0) === 0 &&\n    plan.nextConfigEdit === undefined\n  )\n}\n","/**\n * One-command orchestrator (ADR-073 §1).\n *\n * Bare `neat <path>` dispatches here when the first positional argument\n * resolves to a directory and doesn't match a registered verb. Six steps,\n * in order:\n *\n *   1. Discovery + extraction (per static-extraction contract).\n *   2. `.gitignore` automation (ADR-073 §6) + project registration.\n *   3. SDK install by attachment (ADR-232) — adds the register dependency and\n *      writes `.env.neat` (with `NODE_OPTIONS` for Node), editing no source.\n *      Default yes; `--no-instrument` opts out; `--source-edit` selects the\n *      legacy injection.\n *   4. Daemon spawn — `neatd start --detach` if no daemon is running.\n *      Polls `/health` up to 15s for readiness.\n *   5. Browser open against the web UI on port 6328 (T9 NEAT) — opt-in\n *      only. `--open` launches it; the default (and `--no-open`, and\n *      headless runs) stays in the terminal. Local NEAT is CLI-first.\n *   6. Summary block — value-forward findings + OTel env-vars block.\n *\n * `neat init` retains its patch-by-default contract (ADR-046 §5). The\n * orchestrator instruments unconditionally because the bare-`<path>` shape's\n * intent is \"make this work end-to-end\" — by attachment (ADR-232), editing no\n * source. Source-edit injection is a strictly-gated `--source-edit` fallback\n * the front-door run can never reach.\n */\n\nimport { promises as fs } from 'node:fs'\nimport http from 'node:http'\nimport net from 'node:net'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { spawn } from 'node:child_process'\nimport readline from 'node:readline'\nimport type { GraphEdge, GraphNode } from '@neat.is/types'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport { discoverServices } from './extract/services.js'\nimport { ensureNeatOutIgnored } from './gitignore.js'\nimport { saveGraphToDisk } from './persist.js'\nimport { pathsForProject } from './projects.js'\nimport { addProject, ProjectNameCollisionError } from './registry.js'\nimport { readDaemonRecord, resolveHost, type DaemonPorts } from './daemon.js'\nimport { printBanner, commandPrefix } from './banner.js'\nimport {\n  isEmptyPlan,\n  pickInstaller,\n  type InstallPlan,\n} from './installers/index.js'\nimport { appFrameworkDependencies, uninstrumentedLibraries } from './installers/javascript.js'\nimport {\n  detectPackageManager,\n  runPackageManagerInstall,\n  type PackageManager,\n  type PackageManagerInvocation,\n} from './installers/package-manager.js'\n\nexport interface OrchestratorOptions {\n  scanPath: string\n  // Project name resolution mirrors `neat init` — basename of the scan\n  // path unless overridden via --project.\n  project: string\n  projectExplicit: boolean\n  // Skip step 3 (SDK install apply).\n  noInstrument: boolean\n  // ADR-232 — opt into source-edit injection instead of attachment. Never set\n  // on the front-door path.\n  sourceEdit?: boolean\n  // Opt in to step 5 (browser open). The dashboard is NOT auto-opened —\n  // local NEAT is CLI-first — so a bare run stays in the terminal unless\n  // the caller passes `--open`.\n  open?: boolean\n  // Force step 5 skipped even when `open` is set. Kept so `--no-open`\n  // still reads as an explicit \"don't launch a browser\".\n  noOpen: boolean\n  // Skip the interactive prompt (CI invocation flag — implied when\n  // stdin/stdout aren't a TTY).\n  yes: boolean\n  // Dashboard URL — defaults to http://localhost:6328 (T9 NEAT, ADR-059).\n  dashboardUrl?: string\n  // Health-check timeout in ms. Default 15s.\n  daemonReadyTimeoutMs?: number\n  // Something upstream already introduced the product — the front door prints\n  // the wordmark and version — so the banner here would be a second header.\n  skipBanner?: boolean\n}\n\nexport interface OrchestratorResult {\n  exitCode: number\n  // High-level step-by-step status for the test surface.\n  steps: {\n    discovery: { services: number; languages: string[] }\n    extraction: { nodesAdded: number; edgesAdded: number }\n    gitignore: 'added' | 'created' | 'unchanged'\n    apply: {\n      instrumented: number\n      alreadyInstrumented: number\n      libOnly: number\n      skipped: boolean\n      bun?: number\n      deno?: number\n      cloudflareWorkers?: number\n      electron?: number\n      // Issue #381 — package-manager invocations the orchestrator ran\n      // after apply() mutated package.json. Absent for `--no-instrument`\n      // runs and runs where every plan was empty.\n      packageManagerInstalls?: PackageManagerInvocation[]\n      // ADR-232 — true when services were instrumented by attachment, which\n      // only takes effect when the app starts with the preload loaded.\n      attached?: boolean\n    }\n    daemon: 'spawned' | 'already-running' | 'timed-out' | 'skipped'\n    browser: 'opened' | 'skipped' | 'failed'\n  }\n}\n\n// Shared sub-pipeline `neat sync` re-uses (ADR-074 §1). Discovery + extract\n// + snapshot write. Distinct from the first-run-only steps (registry add,\n// daemon spawn, browser open, summary block) that the orchestrator owns\n// directly.\nexport interface ExtractAndPersistOptions {\n  scanPath: string\n  project: string\n  projectExplicit: boolean\n  // When true, skip persisting to disk — for `neat sync --dry-run`.\n  dryRun?: boolean\n}\n\nexport interface ExtractAndPersistResult {\n  graph: ReturnType<typeof getGraph>\n  graphKey: string\n  services: Awaited<ReturnType<typeof discoverServices>>\n  languages: string[]\n  nodesAdded: number\n  edgesAdded: number\n  snapshotPath: string\n  errorsPath: string\n}\n\n/**\n * Extraction finished; writing the snapshot didn't.\n *\n * Carries what the operator needs to decide what to do — the directory that was\n * scanned and how big the graph got — so the caller can say it plainly instead\n * of surfacing a serializer stack (#1254).\n */\nexport class SnapshotWriteError extends Error {\n  constructor(\n    readonly scanPath: string,\n    readonly nodeCount: number,\n    readonly edgeCount: number,\n    override readonly cause: Error,\n  ) {\n    super(`could not write the snapshot for ${scanPath}: ${cause.message}`)\n    this.name = 'SnapshotWriteError'\n  }\n}\n\nexport async function extractAndPersist(\n  opts: ExtractAndPersistOptions,\n): Promise<ExtractAndPersistResult> {\n  const services = await discoverServices(opts.scanPath)\n  const languages = [...new Set(services.map((s) => s.node.language))].sort()\n\n  const graphKey = opts.projectExplicit ? opts.project : DEFAULT_PROJECT\n  resetGraph(graphKey)\n  const graph = getGraph(graphKey)\n  const projectPaths = pathsForProject(graphKey, path.join(opts.scanPath, 'neat-out'))\n  const extraction = await extractFromDirectory(graph, opts.scanPath, {\n    errorsPath: projectPaths.errorsPath,\n  })\n  if (!opts.dryRun) {\n    try {\n      await saveGraphToDisk(graph, projectPaths.snapshotPath)\n    } catch (err) {\n      // Extraction worked and only the write failed. The user has already sat\n      // through the scan, so say what happened in their terms — the directory,\n      // how big the graph got — instead of handing them the serializer's stack\n      // (#1254). The caller turns this into a message and a non-zero exit.\n      throw new SnapshotWriteError(opts.scanPath, graph.order, graph.size, err as Error)\n    }\n  }\n  return {\n    graph,\n    graphKey,\n    services,\n    languages,\n    nodesAdded: extraction.nodesAdded,\n    edgesAdded: extraction.edgesAdded,\n    snapshotPath: projectPaths.snapshotPath,\n    errorsPath: projectPaths.errorsPath,\n  }\n}\n\n// SDK-install apply over a discovered service list. Returns the same shape\n// the orchestrator's result.steps.apply uses so callers (orchestrator + sync)\n// share the rollup logic. v0.4.1 / refs #339 — `project` is threaded through\n// to the installer so the per-package `.env.neat` carries\n// `OTEL_SERVICE_NAME=<project>`, matching the daemon's routing key.\nexport interface ApplyInstallersTally {\n  instrumented: number\n  alreadyInstrumented: number\n  libOnly: number\n  browserBundle: number\n  reactNative: number\n  // Issues #389 #390 — BYO-OTel out-of-scope runtime counters.\n  bun: number\n  deno: number\n  cloudflareWorkers: number\n  electron: number\n  // Issue #381 — package-manager invocations the orchestrator ran after\n  // apply() mutated package.json. One entry per distinct lockfile-owning\n  // directory (monorepos share a single install run regardless of how\n  // many sub-packages got instrumented). Empty when nothing was added to\n  // any package.json.\n  packageManagerInstalls: PackageManagerInvocation[]\n  // ADR-186 — native dependency-install commands the operator must run for\n  // non-JS services (Ruby → `bundle install`, PHP → `composer install`,\n  // Go → `go mod download`). One entry per service dir whose manifest edits\n  // NEAT staged but does not resolve itself: the JS package manager only runs\n  // for a `package.json` edit, so a Gemfile / composer.json / go.mod edit\n  // surfaces the native command here instead of spawning npm. Empty on a\n  // JS-only run.\n  dependencyInstructions: Array<{ dir: string; command: string }>\n}\n\n// Knobs the test surface uses to swap the real spawn for a no-op. Default\n// uses the real installer; the contract suite passes a stub so the wiring\n// can be asserted without spawning npm against an unreliable registry.\nexport interface ApplyInstallersOptions {\n  runInstall?: (cmd: { pm: PackageManager; cwd: string; args: string[] }) => Promise<PackageManagerInvocation>\n  resolveManager?: (serviceDir: string) => Promise<{ pm: PackageManager; cwd: string; args: string[] }>\n  // ADR-232 — pass through to each installer's plan; `true` selects source-edit\n  // injection, default is attachment.\n  sourceEdit?: boolean\n}\n\nexport async function applyInstallersOver(\n  services: Awaited<ReturnType<typeof discoverServices>>,\n  project: string,\n  options: ApplyInstallersOptions = {},\n): Promise<ApplyInstallersTally> {\n  const resolveManager = options.resolveManager ?? detectPackageManager\n  const runInstall = options.runInstall ?? runPackageManagerInstall\n  let instrumented = 0\n  let already = 0\n  let libOnly = 0\n  let browserBundle = 0\n  let reactNative = 0\n  let bun = 0\n  let deno = 0\n  let cloudflareWorkers = 0\n  let electron = 0\n  // Distinct install commands keyed by `<pm>:<cwd>` so a monorepo with\n  // multiple instrumented sub-packages still runs install exactly once at\n  // its workspace root. The first plan that landed a dep edit for a given\n  // root wins; later sub-packages skip the re-run.\n  const installPlans = new Map<string, { pm: PackageManager; cwd: string; args: string[] }>()\n  // ADR-186 — native install commands to surface for non-JS services, keyed by\n  // service dir so a re-detected service doesn't print twice.\n  const dependencyInstructions = new Map<string, string>()\n  for (const svc of services) {\n    const installer = await pickInstaller(svc.dir)\n    if (!installer) continue\n    const plan: InstallPlan = await installer.plan(svc.dir, { project, sourceEdit: options.sourceEdit })\n    if (isEmptyPlan(plan) && !plan.libOnly && plan.runtimeKind === undefined) {\n      already++\n      continue\n    }\n    const outcome = await installer.apply(plan)\n    if (outcome.outcome === 'instrumented') {\n      instrumented++\n      // Schedule an install whenever apply() actually added deps. The\n      // generated otel-init file lives under the service dir but the\n      // packages the user must resolve at runtime (`@opentelemetry/sdk-node`,\n      // `@prisma/instrumentation`) live in package.json — without the\n      // install, the next `npm run dev` throws `Cannot find module ...`\n      // before any of NEAT's code even loads.\n      if (plan.dependencyEdits.length > 0) {\n        // Language-aware dispatch (ADR-186). Only a package.json edit gets the\n        // JS package manager. A Gemfile / composer.json / go.mod edit belongs to\n        // an ecosystem NEAT doesn't drive — running npm there would install the\n        // wrong deps (npm walks up to any ancestor package.json) and leave the\n        // real Gemfile/composer/go deps unresolved. Surface the native command\n        // the installer reported instead of spawning anything.\n        const manifest = path.basename(plan.dependencyEdits[0]!.file)\n        if (manifest === 'package.json') {\n          const cmd = await resolveManager(svc.dir)\n          const key = `${cmd.pm}:${cmd.cwd}`\n          if (!installPlans.has(key)) installPlans.set(key, cmd)\n        } else if (outcome.followUpInstall) {\n          dependencyInstructions.set(svc.dir, outcome.followUpInstall)\n        }\n      }\n    } else if (outcome.outcome === 'already-instrumented') already++\n    else if (outcome.outcome === 'lib-only') {\n      libOnly++\n      // Issue #545 / #570 — a lib-only package that carries a web-framework or\n      // background-worker dependency is almost certainly a runnable app whose\n      // entry the installer couldn't find, not a true library. Left in the\n      // `lib-only N` tally it's silent; the runtime layer never engages and the\n      // user has no idea why. Name the dependency we found and the recovery path\n      // loudly. A genuine library with no app signal stays quiet — there's\n      // nothing for its runtime layer to engage.\n      const appDeps = svc.pkg ? appFrameworkDependencies(svc.pkg) : []\n      if (appDeps.length > 0) {\n        const svcName = path.basename(svc.dir)\n        const list = appDeps.join(', ')\n        console.warn(\n          `neat: runtime layer won't engage for ${svcName}: no entry point found.\\n` +\n            `  ${svc.dir} depends on ${list} — a runnable app — but neat couldn't resolve an entry to instrument.\\n` +\n            `  Add a \"start\" script to package.json, or point neat at the entry file directly.`,\n        )\n      }\n    }\n    else if (outcome.outcome === 'browser-bundle') {\n      browserBundle++\n      console.log(`skipping ${svc.dir}: browser bundle; browser-OTel support lands in a future release.`)\n    } else if (outcome.outcome === 'react-native') {\n      reactNative++\n      const svcName = path.basename(svc.dir)\n      console.log(\n        `neat: ${svc.dir} detected as React Native / Expo\\n` +\n          `  The installer doesn't cover this runtime deterministically.\\n` +\n          `  Configure your OTel binding to send spans to:\\n` +\n          `    http://localhost:4318/projects/${project}/v1/traces\\n` +\n          `  Set OTEL_SERVICE_NAME=${svcName}\\n` +\n          `  See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n      )\n    } else if (outcome.outcome === 'bun') {\n      bun++\n      const svcName = path.basename(svc.dir)\n      console.log(\n        `neat: ${svc.dir} detected as Bun\\n` +\n          `  The installer doesn't cover this runtime deterministically.\\n` +\n          `  Configure your OTel binding to send spans to:\\n` +\n          `    http://localhost:4318/projects/${project}/v1/traces\\n` +\n          `  Set OTEL_SERVICE_NAME=${svcName}\\n` +\n          `  See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n      )\n    } else if (outcome.outcome === 'deno') {\n      deno++\n      const svcName = path.basename(svc.dir)\n      console.log(\n        `neat: ${svc.dir} detected as Deno\\n` +\n          `  The installer doesn't cover this runtime deterministically.\\n` +\n          `  Configure your OTel binding to send spans to:\\n` +\n          `    http://localhost:4318/projects/${project}/v1/traces\\n` +\n          `  Set OTEL_SERVICE_NAME=${svcName}\\n` +\n          `  See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n      )\n    } else if (outcome.outcome === 'cloudflare-workers') {\n      cloudflareWorkers++\n      const svcName = path.basename(svc.dir)\n      console.log(\n        `neat: ${svc.dir} detected as Cloudflare Workers\\n` +\n          `  The installer doesn't cover this runtime deterministically.\\n` +\n          `  Configure your OTel binding to send spans to:\\n` +\n          `    http://localhost:4318/projects/${project}/v1/traces\\n` +\n          `  Set OTEL_SERVICE_NAME=${svcName}\\n` +\n          `  See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n      )\n    } else if (outcome.outcome === 'electron') {\n      electron++\n      const svcName = path.basename(svc.dir)\n      console.log(\n        `neat: ${svc.dir} detected as Electron\\n` +\n          `  The installer doesn't cover this runtime deterministically.\\n` +\n          `  Configure your OTel binding to send spans to:\\n` +\n          `    http://localhost:4318/projects/${project}/v1/traces\\n` +\n          `  Set OTEL_SERVICE_NAME=${svcName}\\n` +\n          `  See docs/installer-scope.md → \"Manual setup for out-of-scope runtimes\"`,\n      )\n    }\n\n    // Issue #546 — a service can be fully instrumented and still produce an\n    // empty OBSERVED layer when it leans on a library the default\n    // auto-instrumentation set doesn't cover (sqlite3 is the motivating case:\n    // an in-process driver whose calls never cross an instrumented wire). The\n    // differentiator goes silently empty. Name the libraries and point at the\n    // extend path so the user knows why and what to do. Skip the lib-only and\n    // out-of-scope buckets — there's no OBSERVED layer for them to be missing\n    // from yet.\n    if (svc.pkg && (outcome.outcome === 'instrumented' || outcome.outcome === 'already-instrumented')) {\n      const gaps = uninstrumentedLibraries(svc.pkg)\n      if (gaps.length > 0) {\n        const svcName = path.basename(svc.dir)\n        const list = gaps.join(', ')\n        const subject = gaps.length === 1 ? 'this library' : 'these libraries'\n        const aux = gaps.length === 1 ? \"isn't\" : \"aren't\"\n        console.warn(\n          `neat: calls to ${list} won't be observed by default in ${svcName}.\\n` +\n            `  ${subject} ${aux} in the default instrumentation set, so they produce no OBSERVED edges.\\n` +\n            `  Run \\`neat list-uninstrumented\\` to review them, then \\`neat extend\\` to capture them.`,\n        )\n      }\n    }\n  }\n\n  // Run each distinct install command serially. Parallelism would race the\n  // lockfile in the rare monorepo-of-monorepos case and most package\n  // managers serialise themselves internally anyway — the time saving is\n  // tiny next to the operator-trust cost of a corrupted lockfile.\n  const packageManagerInstalls: PackageManagerInvocation[] = []\n  for (const cmd of installPlans.values()) {\n    console.log(`running \\`${cmd.pm} ${cmd.args.join(' ')}\\` in ${cmd.cwd}`)\n    const result = await runInstall(cmd)\n    packageManagerInstalls.push(result)\n    if (result.exitCode !== 0) {\n      console.error(\n        `neat: ${cmd.pm} install failed in ${cmd.cwd} (exit ${result.exitCode}); run it manually to surface the error.`,\n      )\n      if (result.stderr.length > 0) {\n        for (const line of result.stderr.split(/\\r?\\n/).slice(0, 20)) {\n          console.error(`  ${line}`)\n        }\n      }\n    }\n  }\n\n  // Surface the native install command for each non-JS service. NEAT stages the\n  // manifest edit but does not run bundler / composer / the Go toolchain — it\n  // can't guarantee they're on PATH, and running the wrong package manager is\n  // worse than instructing the operator (ADR-186).\n  for (const [dir, command] of dependencyInstructions) {\n    console.log(\n      `neat: dependencies staged in ${dir}; run \\`${command}\\` to install them — NEAT does not run it for you.`,\n    )\n  }\n\n  return {\n    instrumented,\n    alreadyInstrumented: already,\n    libOnly,\n    browserBundle,\n    reactNative,\n    bun,\n    deno,\n    cloudflareWorkers,\n    electron,\n    packageManagerInstalls,\n    dependencyInstructions: [...dependencyInstructions].map(([dir, command]) => ({ dir, command })),\n  }\n}\n\nasync function promptYesNo(question: string): Promise<boolean> {\n  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })\n  return new Promise((resolve) => {\n    rl.question(`${question} [Y/n] `, (answer) => {\n      rl.close()\n      const trimmed = answer.trim().toLowerCase()\n      resolve(trimmed === '' || trimmed === 'y' || trimmed === 'yes')\n    })\n  })\n}\n\n// 60s covers boot + per-project graph load across a registry with several\n// sibling projects. Issue #340 — `app.listen()` now returns the moment the\n// socket binds, so the steady-state happy path lands well inside the first\n// second; the longer ceiling is the cold-clone window where multi-project\n// bootstraps run in the background after listen.\nexport const DEFAULT_DAEMON_READY_TIMEOUT_MS = 60_000\n\n// 500ms poll cadence — responsive enough that the operator sees a fresh\n// status line on every transition without spamming the daemon.\nconst PROBE_INTERVAL_MS = 500\n\ninterface DaemonHealthResponse {\n  ok?: boolean\n  uptimeMs?: number\n  projects?: Array<{\n    name: string\n    status?: 'bootstrapping' | 'active' | 'broken'\n    elapsedMs?: number\n  }>\n}\n\nasync function fetchDaemonHealth(restPort: number): Promise<DaemonHealthResponse | null> {\n  return new Promise((resolve) => {\n    const req = http.get(`http://127.0.0.1:${restPort}/health`, (res) => {\n      const ok = res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300\n      if (!ok) {\n        res.resume()\n        resolve(null)\n        return\n      }\n      let body = ''\n      res.setEncoding('utf8')\n      res.on('data', (chunk: string) => { body += chunk })\n      res.on('end', () => {\n        try {\n          resolve(JSON.parse(body) as DaemonHealthResponse)\n        } catch {\n          resolve({ ok: true })\n        }\n      })\n    })\n    req.on('error', () => resolve(null))\n    req.setTimeout(1000, () => {\n      req.destroy()\n      resolve(null)\n    })\n  })\n}\n\n\nasync function probeProjectHealth(\n  restPort: number,\n  name: string,\n): Promise<'bootstrapping' | 'active' | 'broken'> {\n  return new Promise((resolve) => {\n    const req = http.get(\n      `http://127.0.0.1:${restPort}/projects/${encodeURIComponent(name)}/health`,\n      (res) => {\n        const code = res.statusCode ?? 0\n        res.resume()\n        if (code >= 200 && code < 300) resolve('active')\n        else resolve('bootstrapping')\n      },\n    )\n    req.on('error', () => resolve('bootstrapping'))\n    req.setTimeout(1000, () => {\n      req.destroy()\n      resolve('bootstrapping')\n    })\n  })\n}\n\n// Resolve the status of the one project this run just started — and only that\n// project (ADR-096: the orchestrator spawns a daemon scoped to a single\n// project, so readiness is a single-project question). A broken or stale\n// sibling sitting in the machine registry must never gate this run; it\n// belongs to a different daemon and would otherwise poison an otherwise-healthy\n// start. Prefers the daemon-wide /health entry for the project when one is\n// carried (the legacy multi-project shape); otherwise probes that project's\n// per-project /health directly. The registry is not consulted — siblings are\n// out of scope by construction.\nasync function snapshotProjectStatus(\n  restPort: number,\n  project: string,\n  body: DaemonHealthResponse,\n): Promise<Array<{ name: string; status: 'bootstrapping' | 'active' | 'broken' }>> {\n  if (body.projects && body.projects.length > 0) {\n    const mine = body.projects.filter((p) => p.name === project)\n    if (mine.length > 0) {\n      return mine.map((p) => ({ name: p.name, status: p.status ?? 'active' }))\n    }\n  }\n  return [{ name: project, status: await probeProjectHealth(restPort, project) }]\n}\n\ninterface DaemonReadyResult {\n  ready: boolean\n  brokenProjects: string[]\n  stillBootstrapping: string[]\n}\n\n// What is happening while a project's daemon comes up. `starting` fires once,\n// when the process is spawned; `waiting` fires every STILL_WAITING_INTERVAL_MS\n// after that for as long as it hasn't answered ready.\nexport type DaemonProgress = { kind: 'starting' } | { kind: 'waiting'; elapsedMs: number }\n\n// A daemon usually answers inside a second or two, so the first reminder that\n// it hasn't is held back long enough not to appear on an ordinary start.\nconst STILL_WAITING_INTERVAL_MS = 10_000\n\n// The words for a progress event, without a prefix — the bare run says them as\n// `neat: …` and `neat up` as `neat up: …`, so the two paths read alike (#1273).\nexport function daemonProgressLine(project: string, event: DaemonProgress): string {\n  if (event.kind === 'starting') return `starting the daemon for ${project}…`\n  return `still waiting for ${project}'s daemon (${Math.round(event.elapsedMs / 1000)}s)`\n}\n\nasync function waitForDaemonReady(\n  restPort: number,\n  project: string,\n  timeoutMs: number,\n  onProgress?: (event: DaemonProgress) => void,\n  reminderIntervalMs: number = STILL_WAITING_INTERVAL_MS,\n): Promise<DaemonReadyResult> {\n  const startedAt = Date.now()\n  const deadline = startedAt + timeoutMs\n  let nextReminderAt = startedAt + reminderIntervalMs\n  while (Date.now() < deadline) {\n    const body = await fetchDaemonHealth(restPort)\n    if (body !== null) {\n      const projects = await snapshotProjectStatus(restPort, project, body)\n      const bootstrapping = projects\n        .filter((p) => p.status === 'bootstrapping')\n        .map((p) => p.name)\n      const broken = projects.filter((p) => p.status === 'broken').map((p) => p.name)\n      if (bootstrapping.length === 0) {\n        return { ready: true, brokenProjects: broken, stillBootstrapping: [] }\n      }\n    }\n    // Not up yet — whether it hasn't bound its port or is still loading the\n    // graph, the person is waiting on the same thing, so it is said one way.\n    if (Date.now() >= nextReminderAt) {\n      onProgress?.({ kind: 'waiting', elapsedMs: Date.now() - startedAt })\n      nextReminderAt += reminderIntervalMs\n    }\n    await new Promise((r) => setTimeout(r, PROBE_INTERVAL_MS))\n  }\n  const final = await fetchDaemonHealth(restPort)\n  const projects = final ? await snapshotProjectStatus(restPort, project, final) : []\n  return {\n    ready: false,\n    brokenProjects: projects.filter((p) => p.status === 'broken').map((p) => p.name),\n    stillBootstrapping: projects\n      .filter((p) => p.status === 'bootstrapping')\n      .map((p) => p.name),\n  }\n}\n\n// Port-availability probe (#377 / ADR-079 §2).\n//\n// The orchestrator's daemon-spawn step assumes `:8080` (REST), `:4318` (OTLP\n// HTTP), and `:6328` (web UI) are free. When a sibling daemon from another\n// terminal session — or any unrelated listener — is holding one of them, the\n// spawn exits 1 with no actionable message. The probe runs before\n// `spawnDaemonDetached()` and surfaces the named port plus recovery commands\n// on collision, exiting with code 3 (environmental) per the CLI exit-code\n// surface.\nexport const NEAT_PORTS = [8080, 4318, 6328] as const\n\n// Probe `host` so the availability answer reflects the interface the daemon\n// will actually bind. The daemon binds 0.0.0.0 on the authenticated path\n// (resolveHost) and 127.0.0.1 otherwise; probing loopback while the daemon\n// binds the wildcard reads a wildcard-held port as free, hands it to the\n// spawn, and the daemon dies on EADDRINUSE before it can write daemon.json —\n// the silent \"daemon.json timeout\" (#574). Check host must equal bind host.\n//\n// #580 — and the answer must span both IP families. A daemon binds one host,\n// but clients reach it through `localhost`, which resolves `::1` ahead of\n// `127.0.0.1` on macOS and other dual-stack systems. A foreign listener on the\n// IPv6 side of a port we bind only on IPv4 swallows every `localhost` query\n// while a pure-IPv4 probe still reads the port as free, so allocation hands\n// over a port that's already shadowed. We probe the bind host's family AND its\n// cross-family loopback/wildcard sibling, and call the port taken if a holder\n// sits on either. A family the machine genuinely lacks (no IPv6 stack →\n// EADDRNOTAVAIL / EAFNOSUPPORT on the sibling) is not a holder and doesn't\n// block allocation; only an EADDRINUSE on the sibling does.\ntype ProbeOutcome = 'free' | 'in-use' | 'unavailable'\n\nfunction probeBind(port: number, host: string): Promise<ProbeOutcome> {\n  return new Promise((resolve) => {\n    const server = net.createServer()\n    server.once('error', (err) => {\n      resolve((err as NodeJS.ErrnoException).code === 'EADDRINUSE' ? 'in-use' : 'unavailable')\n    })\n    server.once('listening', () => server.close(() => resolve('free')))\n    server.listen(port, host)\n  })\n}\n\n// The cross-family sibling to also probe for a shadowing holder. Loopback and\n// wildcard are the only hosts that have a meaningful sibling; a specific IP is\n// probed on its own.\nfunction crossFamilyHost(host: string): string | null {\n  switch (host) {\n    case '127.0.0.1':\n    case 'localhost':\n      return '::1'\n    case '::1':\n      return '127.0.0.1'\n    case '0.0.0.0':\n      return '::'\n    case '::':\n      return '0.0.0.0'\n    default:\n      return null\n  }\n}\n\nexport async function isPortFree(port: number, host = '127.0.0.1'): Promise<boolean> {\n  // Primary interface: any failure (in-use or otherwise) means we can't bind\n  // it, so the port isn't usable — preserve the pre-#580 \"any error → false\".\n  if ((await probeBind(port, host)) !== 'free') return false\n  // Cross-family sibling: only a live holder (EADDRINUSE) counts. A missing\n  // family answers 'unavailable' and is not a shadow.\n  const sibling = crossFamilyHost(host)\n  if (sibling && (await probeBind(port, sibling)) === 'in-use') return false\n  return true\n}\n\nexport async function probePortsFree(): Promise<\n  { free: true } | { free: false; held: number }\n> {\n  for (const port of NEAT_PORTS) {\n    if (!(await isPortFree(port))) return { free: false, held: port }\n  }\n  return { free: true }\n}\n\nexport function formatPortCollisionMessage(port: number): string[] {\n  return [\n    `neat: port ${port} is in use; the NEAT daemon needs it.`,\n    `      run \\`neatd stop\\` to release the previous daemon, or`,\n    `      \\`lsof -i :${port}\\` to find the holding process.`,\n  ]\n}\n\n// ── Per-project port allocation (ADR-096 §3 / project-daemon contract) ──────\n//\n// One daemon per project means a second project's daemon must coexist with the\n// first rather than fight for one binding. The canonical triple\n// (8080/4318/6328) stays the first choice; when any of it is taken, allocation\n// steps to the next free triple. Each project's ports are persisted (in its\n// daemon.json, written by the daemon) and reused across restarts, so the\n// instrumented app's endpoint stays constant — critical, because the generated\n// otel-init reads `ports.otlp` back and a drifting port would silently dark the\n// OBSERVED layer (§1).\n\n// How far to step before giving up. 8 triples (8080→8101 etc.) is far more\n// concurrent projects than a laptop ever runs; past it the environment is\n// genuinely saturated and the operator wants the collision message, not an\n// ever-climbing search.\nconst PORT_ALLOCATION_ATTEMPTS = 8\n// Stride between candidate triples. Keeping rest/otlp/web on the same offset\n// keeps each project's three ports visually grouped (8080/4318/6328 →\n// 8081/4319/6329 …) so `neat ps` output reads cleanly.\nconst PORT_STRIDE = 1\n\nexport interface AllocatedPorts extends DaemonPorts {}\n\n// True when all three ports of a candidate triple are free on `host` — the\n// interface the daemon will bind (see isPortFree).\nasync function tripleFree(ports: AllocatedPorts, host = '127.0.0.1'): Promise<boolean> {\n  for (const p of [ports.rest, ports.otlp, ports.web]) {\n    if (!(await isPortFree(p, host))) return false\n  }\n  return true\n}\n\n// Allocate a free port triple, canonical 8080/4318/6328 first, stepping by\n// PORT_STRIDE to the next free triple when the canonical set is taken (a\n// sibling project's daemon already holds it). Returns null when nothing in the\n// search window is free — a genuinely saturated environment. Reuse of a\n// project's persisted ports is the caller's decision (it has the /health\n// identity result); this only finds fresh free ports.\nexport async function allocatePorts(host = '127.0.0.1'): Promise<AllocatedPorts | null> {\n  const [baseRest, baseOtlp, baseWeb] = NEAT_PORTS\n  for (let i = 0; i < PORT_ALLOCATION_ATTEMPTS; i++) {\n    const candidate: AllocatedPorts = {\n      rest: baseRest + i * PORT_STRIDE,\n      otlp: baseOtlp + i * PORT_STRIDE,\n      web: baseWeb + i * PORT_STRIDE,\n    }\n    if (await tripleFree(candidate, host)) return candidate\n  }\n  return null\n}\n\n// Read this project's persisted ports from its daemon.json, if any. Returns\n// null when the project has never run a daemon (fresh install) or the record\n// is malformed — the caller falls back to fresh allocation.\nexport async function persistedPortsFor(scanPath: string): Promise<AllocatedPorts | null> {\n  const record = await readDaemonRecord(scanPath)\n  if (!record) return null\n  return { rest: record.ports.rest, otlp: record.ports.otlp, web: record.ports.web }\n}\n\n// Project-local concurrent-spawn guard (contract §1 \"exactly one daemon\").\n// Two `neat init` on the same project in the same instant would each find no\n// healthy daemon, allocate the same canonical triple, and the second daemon's\n// bind would crash on the conflict. A best-effort lockfile under the project's\n// own neat-out/ serialises them: the loser waits for the winner's daemon to\n// answer /health rather than racing it to the bind. It's project-local — no\n// machine-wide lock — so two DIFFERENT projects never contend here.\nasync function acquireSpawnLock(scanPath: string): Promise<(() => Promise<void>) | null> {\n  const lockPath = path.join(scanPath, 'neat-out', 'daemon.spawn.lock')\n  await fs.mkdir(path.dirname(lockPath), { recursive: true })\n  const STALE_LOCK_MS = 60_000\n  try {\n    const fd = await fs.open(lockPath, 'wx')\n    await fd.writeFile(`${process.pid}\\n`, 'utf8')\n    await fd.close()\n    return async () => {\n      await fs.unlink(lockPath).catch(() => {})\n    }\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code !== 'EEXIST') return null\n    // A lock exists. If it's stale (a crashed prior spawn), reclaim it.\n    try {\n      const stat = await fs.stat(lockPath)\n      if (Date.now() - stat.mtimeMs > STALE_LOCK_MS) {\n        await fs.unlink(lockPath).catch(() => {})\n        return acquireSpawnLock(scanPath)\n      }\n    } catch {\n      // stat raced with the holder's unlink — treat as not-held and retry once.\n      return acquireSpawnLock(scanPath)\n    }\n    return null\n  }\n}\n\n// Wait (briefly) for another concurrent spawn to bring up a daemon that answers\n// /health for this project. Used by the loser of the spawn-lock race so it\n// reuses the winner's daemon instead of erroring.\nasync function waitForPeerDaemon(\n  restPort: number,\n  project: string,\n  timeoutMs: number,\n): Promise<boolean> {\n  const deadline = Date.now() + timeoutMs\n  while (Date.now() < deadline) {\n    if (await healthIsForProject(restPort, project)) return true\n    await new Promise((r) => setTimeout(r, PROBE_INTERVAL_MS))\n  }\n  return healthIsForProject(restPort, project)\n}\n\n// The spawn-vs-reuse identity check (contract §7). A daemon found answering\n// /health on a candidate REST port is reused only when it reports THIS project;\n// a different project's daemon on a reused port answers with its own name and\n// is correctly treated as not-mine. Returns true only on a confirmed match.\nasync function healthIsForProject(restPort: number, project: string): Promise<boolean> {\n  const body = await fetchDaemonHealth(restPort)\n  if (body === null) return false\n  // Single-project daemons stamp a top-level `project`; be tolerant of the\n  // legacy daemon-wide shape that lists projects in an array, so a transitional\n  // daemon still matches by name.\n  const named = (body as { project?: string }).project\n  if (typeof named === 'string') return named === project\n  if (Array.isArray(body.projects)) {\n    return body.projects.some((p) => p.name === project)\n  }\n  return false\n}\n\n// Test seam for the spawn-reuse identity check (project-daemon contract §7).\n// Production callers go through the spawn flow; the integration suite asserts\n// the matching-vs-not-mine decision directly.\nexport function healthIsForProjectForTest(restPort: number, project: string): Promise<boolean> {\n  return healthIsForProject(restPort, project)\n}\n\n// Test seam for the readiness wait (one-command-cli contract §1 / ADR-096).\n// The integration suite drives a fake single-project daemon against this to\n// prove the gate scopes to the just-started project and never blocks on a\n// broken sibling sitting in the registry.\nexport function waitForDaemonReadyForTest(\n  restPort: number,\n  project: string,\n  timeoutMs: number,\n  onProgress?: (event: DaemonProgress) => void,\n  reminderIntervalMs?: number,\n): Promise<DaemonReadyResult> {\n  return waitForDaemonReady(restPort, project, timeoutMs, onProgress, reminderIntervalMs)\n}\n\n// Where a project's daemon writes its stdout/stderr. Lives beside the\n// snapshot under the project's own `neat-out/` so the operator finds it next\n// to everything else NEAT wrote for that project.\nexport function daemonLogPath(projectPath: string): string {\n  return path.join(projectPath, 'neat-out', 'daemon.log')\n}\n\n// How much of the log to show when the daemon never came up. Enough for a\n// multi-line diagnostic — the web-standalone-missing message runs to three —\n// without pasting a whole boot sequence into the terminal.\nconst DAEMON_LOG_TAIL_LINES = 12\n\n/**\n * The last few meaningful lines of a project's `daemon.log`.\n *\n * The daemon writes the real reason it couldn't start, in plain English, to a\n * file a first-timer has no reason to know exists (#1238). Sixty seconds of\n * silence and then a timeout with no cause in it is the worst version of that,\n * so the caller prints this under the timeout.\n *\n * Returns an empty array rather than throwing when the log is missing, empty or\n * unreadable: this runs on a path that has already failed, and it must not turn\n * a bad message into a crash.\n */\nexport async function readDaemonLogTail(\n  projectPath: string,\n  maxLines: number = DAEMON_LOG_TAIL_LINES,\n): Promise<string[]> {\n  try {\n    const raw = await fs.readFile(daemonLogPath(projectPath), 'utf8')\n    const lines = raw\n      .split(/\\r?\\n/)\n      .map((l: string) => l.trimEnd())\n      .filter((l: string) => l.trim().length > 0)\n    return lines.slice(-maxLines)\n  } catch {\n    return []\n  }\n}\n\n// Spawn the daemon as a fully detached background process and hand the terminal\n// back. `detached: true` puts it in its own session and `unref()` lets the\n// orchestrator exit cleanly the moment its own work is done — the one-command\n// flow prints its summary and returns the prompt (#639/#529). The daemon's\n// stdout and stderr go to `<project>/neat-out/daemon.log`, never the caller's\n// fds: an inherited stderr keeps the shell attached and streams the daemon's\n// ongoing logs into the operator's terminal indefinitely. Startup faults (a\n// `BindAuthorityError`, a bind collision) land in that log; the caller's\n// `/health` readiness poll is what tells the operator a start failed, and\n// points them at the log for the detail.\n//\n// ADR-096 — when `spec` is given the daemon is spawned scoped to that one\n// project on the allocated ports (passed through the env neatd + startDaemon\n// read). The legacy no-arg form spawns the multi-project daemon on the\n// canonical ports; it stays so callers we haven't migrated keep working.\nexport interface DaemonSpawnSpec {\n  project: string\n  projectPath: string\n  ports: AllocatedPorts\n}\n\nfunction spawnDaemonDetached(\n  spec?: DaemonSpawnSpec,\n): import('node:child_process').ChildProcess {\n  // Resolve the neatd entry inside the @neat.is/core dist next to this\n  // file. `import.meta.url` is post-bundling — at runtime, this resolves\n  // to `<core>/dist/neatd.{js,cjs}`. We pick the .cjs because tsup ships\n  // it in both forms and node tolerates either. `fileURLToPath` (not\n  // `URL().pathname`) so the Windows drive-letter path resolves to\n  // `C:\\…\\neatd.cjs`, not the invalid `/C:/…` a raw URL pathname yields.\n  const here = path.dirname(fileURLToPath(import.meta.url))\n  const candidates = [\n    path.join(here, 'neatd.cjs'),\n    path.join(here, 'neatd.js'),\n  ]\n  let entry: string | null = null\n  // eslint-disable-next-line @typescript-eslint/no-require-imports\n  const fsSync = require('node:fs') as typeof import('node:fs')\n  for (const c of candidates) {\n    try {\n      fsSync.accessSync(c)\n      entry = c\n      break\n    } catch {\n      // try next\n    }\n  }\n  if (!entry) {\n    throw new Error(`orchestrator: cannot locate neatd entry in ${here}`)\n  }\n\n  // ADR-073 §3 + issue #341 — first-touch path is loopback-only. When the\n  // operator hasn't set `NEAT_AUTH_TOKEN` the orchestrator hard-pins\n  // HOST=127.0.0.1 in the child env so `assertBindAuthority` lets the bind\n  // through. Public-bind is opt-in via the token (and an explicit\n  // `HOST=0.0.0.0` if the operator wants the literal). The parent's HOST is\n  // preserved untouched when the token is set — that's the deploy path,\n  // where the platform owns the bind decision.\n  const env = { ...process.env }\n  const hasToken = typeof env.NEAT_AUTH_TOKEN === 'string' && env.NEAT_AUTH_TOKEN.length > 0\n  if (!hasToken && (!env.HOST || env.HOST.length === 0)) {\n    env.HOST = '127.0.0.1'\n  }\n\n  // ADR-096 — scope the spawned daemon to one project on the allocated ports.\n  // neatd reads NEAT_PROJECT/NEAT_PROJECT_PATH and PORT/OTEL_PORT/NEAT_WEB_PORT\n  // and threads them into startDaemon, which serves only this project and\n  // writes its daemon.json self-description with these ports.\n  if (spec) {\n    env.NEAT_PROJECT = spec.project\n    env.NEAT_PROJECT_PATH = spec.projectPath\n    env.PORT = String(spec.ports.rest)\n    env.OTEL_PORT = String(spec.ports.otlp)\n    env.NEAT_WEB_PORT = String(spec.ports.web)\n  }\n\n  // Redirect the daemon's output to a log file rather than inheriting the\n  // caller's fds (#639/#529). Inherited stderr keeps the shell attached — the\n  // prompt never returns and the daemon's ongoing warnings spill into the\n  // operator's terminal. A per-project `neat-out/daemon.log` keeps the output\n  // reachable without holding the terminal. We open once and hand the same fd\n  // to stdout and stderr; the OS dups it into the child at spawn, so the parent\n  // closes its copy right after. With no spec (legacy multi-project form) there\n  // is no project dir to write into, so output is discarded.\n  let logFd: number | null = null\n  if (spec) {\n    const logPath = daemonLogPath(spec.projectPath)\n    fsSync.mkdirSync(path.dirname(logPath), { recursive: true })\n    logFd = fsSync.openSync(logPath, 'a')\n  }\n  const child = spawn(process.execPath, [entry, 'start'], {\n    detached: true,\n    stdio: ['ignore', logFd ?? 'ignore', logFd ?? 'ignore'],\n    env,\n  })\n  child.unref()\n  if (logFd !== null) fsSync.closeSync(logFd)\n  return child\n}\n\n// What bringing a project's daemon up came to. Shared by the bare run, which starts\n// one as its fourth step, and `neat up`, which does only this.\nexport type EnsureDaemonOutcome =\n  | { status: 'already-running'; ports: AllocatedPorts }\n  | { status: 'spawned'; ports: AllocatedPorts; brokenProjects: string[] }\n  | { status: 'timed-out'; ports: AllocatedPorts; stillBootstrapping: string[]; brokenProjects: string[] }\n  | { status: 'no-ports' }\n  | { status: 'peer-timeout' }\n  | { status: 'spawn-failed'; message: string }\n\nexport interface EnsureDaemonOptions {\n  project: string\n  projectPath: string\n  timeoutMs?: number\n  // Told when a daemon is spawned and, if it is slow, that it is still coming\n  // up. Not called when a live daemon is simply reused.\n  onProgress?: (event: DaemonProgress) => void\n}\n\n// Make sure this project has a live daemon (ADR-096 per-project daemon).\n//\n// One daemon per project: this project either has a live daemon to reuse,\n// or we allocate ports and spawn one scoped to it. The spawn-vs-reuse\n// decision turns on the /health identity check — a daemon answering on a\n// port must report THIS project to count as ours (a sibling project's\n// daemon on a port we'd otherwise reuse is correctly seen as not-mine).\n//\n// Prints nothing; the caller owns the words, and hears about a slow start\n// through `onProgress`.\nexport async function ensureProjectDaemon(opts: EnsureDaemonOptions): Promise<EnsureDaemonOutcome> {\n  const timeoutMs = opts.timeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS\n  // The interface the spawned daemon will bind — 0.0.0.0 on the authenticated\n  // path, 127.0.0.1 otherwise. resolveHost is the single source of that\n  // decision (the daemon calls it too), so the free-port probe below checks the\n  // exact interface the bind will use; a wildcard-held port must read as taken\n  // on the token path or the spawn collides on EADDRINUSE (#574).\n  const bindHost = resolveHost(\n    {},\n    typeof process.env.NEAT_AUTH_TOKEN === 'string' && process.env.NEAT_AUTH_TOKEN.length > 0,\n  )\n  // Ports the project used last time (its daemon.json), if any — reuse keeps\n  // the instrumented app's exporter endpoint stable across restarts (§3).\n  const persistedPorts = await persistedPortsFor(opts.projectPath)\n\n  // Already running? A daemon answering /health on the persisted REST port and\n  // reporting this project is reused outright.\n  if (persistedPorts && (await healthIsForProject(persistedPorts.rest, opts.project))) {\n    return { status: 'already-running', ports: persistedPorts }\n  }\n\n  // Decide the ports to bind. Reuse the persisted triple when its REST port\n  // is free (the prior daemon is gone, so we take its ports back and the\n  // app's endpoint stays put); otherwise allocate a fresh free triple,\n  // stepping past the canonical set when a sibling project holds it.\n  let allocated: AllocatedPorts | null\n  if (\n    persistedPorts &&\n    (await isPortFree(persistedPorts.rest, bindHost)) &&\n    (await tripleFree(persistedPorts, bindHost))\n  ) {\n    allocated = persistedPorts\n  } else {\n    allocated = await allocatePorts(bindHost)\n  }\n  if (!allocated) return { status: 'no-ports' }\n\n  // Concurrent-spawn guard (§1). The winner spawns; a loser that couldn't\n  // take the lock waits for the winner's daemon to answer /health and reuses\n  // it rather than racing it into a bind conflict.\n  const release = await acquireSpawnLock(opts.projectPath)\n  if (!release) {\n    const reused = await waitForPeerDaemon(allocated.rest, opts.project, timeoutMs)\n    return reused ? { status: 'already-running', ports: allocated } : { status: 'peer-timeout' }\n  }\n  try {\n    // Re-check under the lock: a daemon the winner brought up between our\n    // first probe and acquiring the lock is reused instead of double-spawned.\n    if (await healthIsForProject(allocated.rest, opts.project)) {\n      return { status: 'already-running', ports: allocated }\n    }\n    spawnDaemonDetached({\n      project: opts.project,\n      projectPath: opts.projectPath,\n      ports: allocated,\n    })\n    opts.onProgress?.({ kind: 'starting' })\n    const ready = await waitForDaemonReady(allocated.rest, opts.project, timeoutMs, opts.onProgress)\n    if (!ready.ready) {\n      return {\n        status: 'timed-out',\n        ports: allocated,\n        stillBootstrapping: ready.stillBootstrapping,\n        brokenProjects: ready.brokenProjects,\n      }\n    }\n    return { status: 'spawned', ports: allocated, brokenProjects: ready.brokenProjects }\n  } catch (err) {\n    return { status: 'spawn-failed', message: (err as Error).message }\n  } finally {\n    await release()\n  }\n}\n\n// The lines that explain a daemon that never came up, cause included.\nexport async function describeDaemonTimeout(\n  outcome: Extract<EnsureDaemonOutcome, { status: 'timed-out' }>,\n  projectPath: string,\n  timeoutMs: number,\n): Promise<string[]> {\n  const lines = [`neat: daemon did not become ready within ${timeoutMs}ms`]\n  if (outcome.stillBootstrapping.length > 0) {\n    lines.push(`neat: still bootstrapping: ${outcome.stillBootstrapping.join(', ')}`)\n  }\n  if (outcome.brokenProjects.length > 0) {\n    lines.push(`neat: broken projects: ${outcome.brokenProjects.join(', ')}`)\n  }\n  // The daemon already wrote why, in plain English, to a file the\n  // user has no reason to know about (#1238). Show it rather than\n  // making sixty seconds of silence end in a sentence with no cause.\n  const logPath = daemonLogPath(projectPath)\n  const tail = await readDaemonLogTail(projectPath)\n  if (tail.length > 0) {\n    lines.push('')\n    lines.push(`neat: the daemon's last words (${path.relative(projectPath, logPath)}):`)\n    for (const line of tail) lines.push(`  ${line}`)\n  } else {\n    // Nothing readable — name the file anyway, so there is somewhere\n    // to look. This is the minimum the issue asks for.\n    lines.push(`neat: see ${logPath}`)\n  }\n  return lines\n}\n\nfunction openBrowser(url: string): 'opened' | 'failed' {\n  // Skip when running headlessly; we don't want CI invocations to fail\n  // because xdg-open isn't installed.\n  if (!process.stdout.isTTY) return 'failed'\n  const platform = process.platform\n  const cmd =\n    platform === 'darwin' ? 'open' :\n    platform === 'win32' ? 'cmd' :\n    'xdg-open'\n  const args = platform === 'win32' ? ['/c', 'start', '', url] : [url]\n  try {\n    const child = spawn(cmd, args, { detached: true, stdio: 'ignore' })\n    child.on('error', () => {})\n    child.unref()\n    return 'opened'\n  } catch {\n    return 'failed'\n  }\n}\n\nexport async function runOrchestrator(opts: OrchestratorOptions): Promise<OrchestratorResult> {\n  const result: OrchestratorResult = {\n    exitCode: 0,\n    steps: {\n      discovery: { services: 0, languages: [] },\n      extraction: { nodesAdded: 0, edgesAdded: 0 },\n      gitignore: 'unchanged',\n      apply: { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, skipped: false },\n      daemon: 'skipped',\n      browser: 'skipped',\n    },\n  }\n\n  // ── Path validation ───────────────────────────────────────────────────\n  const stat = await fs.stat(opts.scanPath).catch(() => null)\n  if (!stat || !stat.isDirectory()) {\n    console.error(`neat: ${opts.scanPath} is not a directory`)\n    result.exitCode = 2\n    return result\n  }\n\n  // ASCII banner up front — this is the one-command zero-to-graph path's\n  // first impression (issue #483). Same artwork `neat init` prints, shared\n  // through banner.ts so it's never duplicated. Skipped when the front door\n  // has already put a header on this run (#1242).\n  if (!opts.skipBanner) printBanner()\n  console.log(`neat: ${opts.scanPath}`)\n  console.log('')\n\n  // ── Step 1: discovery, Step 2: extraction + snapshot ─────────────────\n  // Shared with `neat sync` (ADR-074 §1) via extractAndPersist.\n  let persisted: ExtractAndPersistResult\n  try {\n    persisted = await extractAndPersist({\n      scanPath: opts.scanPath,\n      project: opts.project,\n      projectExplicit: opts.projectExplicit,\n    })\n  } catch (err) {\n    if (!(err instanceof SnapshotWriteError)) throw err\n    // The scan worked and the write didn't, which on a very large tree means\n    // the snapshot outgrew what can be held as a single string. Say what was\n    // scanned, how big it got, and the one thing that actually helps — a\n    // narrower root — rather than printing the serializer's stack (#1254).\n    console.error(`neat: extracted ${opts.scanPath}, but could not write the snapshot.`)\n    console.error(`neat: the graph came to ${err.nodeCount} nodes and ${err.edgeCount} edges — too large to save.`)\n    console.error(`neat: point neat at one project instead of a tree that holds many:`)\n    console.error(`neat:   npx neat.is <path-to-one-project>`)\n    console.error(`neat: cause: ${err.cause.message}`)\n    result.exitCode = 1\n    return result\n  }\n  const { graph, services, languages } = persisted\n  result.steps.discovery = { services: services.length, languages }\n  console.log(`discovered ${services.length} service(s) across ${languages.length} language(s)`)\n\n  // No services means nothing to instrument and no graph worth spawning a\n  // daemon for. Bail with a clear pointer instead of standing up an empty\n  // daemon (issue #483) — most often the operator ran from outside their\n  // project root.\n  if (services.length === 0) {\n    console.error(\n      `neat: no services found in ${opts.scanPath} — run from inside your project root, or \\`npx neat.is <path>\\``,\n    )\n    result.exitCode = 2\n    return result\n  }\n\n  // ── Confirmation prompt (default yes; --no-instrument or no-TTY skip)\n  let runApply = !opts.noInstrument\n  if (runApply && !opts.yes && process.stdout.isTTY && process.stdin.isTTY) {\n    runApply = await promptYesNo('instrument your services?')\n  }\n\n  result.steps.extraction = {\n    nodesAdded: persisted.nodesAdded,\n    edgesAdded: persisted.edgesAdded,\n  }\n\n  const gi = await ensureNeatOutIgnored(opts.scanPath)\n  result.steps.gitignore = gi.action\n  if (gi.action !== 'unchanged') {\n    console.log(`${gi.action} .gitignore (neat-out/)`)\n  }\n\n  let currentProjectName = opts.project\n  try {\n    const entry = await addProject({\n      name: opts.project,\n      path: opts.scanPath,\n      languages,\n      status: 'active',\n    })\n    currentProjectName = entry.name\n  } catch (err) {\n    if (!(err instanceof ProjectNameCollisionError)) throw err\n    // Same path, same name → re-init. Different path → bail with a clear\n    // message so the operator can pass --project <other-name>.\n    // Non-interactive: there is nobody to ask, so this stays an error — but it has to\n    // name a command that can actually be run. The old text said \"pass --project\" to\n    // someone who may have reached this from a bare `neat` with no argv to add it to.\n    console.error(`neat: ${err.message}`)\n    console.error(`neat: run \\`neat <path> --project <other-name>\\` to register it under a different name,`)\n    console.error(`neat: or \\`neat uninstall ${opts.project}\\` if the old registration is stale.`)\n    result.exitCode = 1\n    return result\n  }\n\n  // Registering this project leaves every other project as it was (ADR-231).\n  // Each project has its own daemon on its own ports, so a second one starts\n  // beside the first rather than in place of it.\n\n  // ── Step 3: SDK install apply (default yes; --no-instrument skips) ───\n  if (!runApply) {\n    result.steps.apply.skipped = true\n    console.log('skipped instrumentation (--no-instrument)')\n  } else {\n    const tally = await applyInstallersOver(services, opts.project, { sourceEdit: opts.sourceEdit })\n    result.steps.apply = {\n      ...tally,\n      skipped: false,\n      ...(!opts.sourceEdit && tally.instrumented > 0 ? { attached: true } : {}),\n    }\n    console.log(\n      `instrumented ${tally.instrumented}, already ${tally.alreadyInstrumented}, lib-only ${tally.libOnly}`,\n    )\n    const failedInstalls = tally.packageManagerInstalls.filter((i) => i.exitCode !== 0)\n    if (failedInstalls.length > 0) {\n      result.exitCode = 1\n    }\n  }\n\n  // ── Step 4: daemon spawn + health poll (ADR-096 per-project daemon) ──\n  const timeoutMs = opts.daemonReadyTimeoutMs ?? DEFAULT_DAEMON_READY_TIMEOUT_MS\n  const outcome = await ensureProjectDaemon({\n    project: currentProjectName,\n    projectPath: opts.scanPath,\n    timeoutMs,\n    onProgress: (event) => console.log(`neat: ${daemonProgressLine(currentProjectName, event)}`),\n  })\n  const allocated: AllocatedPorts | null = 'ports' in outcome ? outcome.ports : null\n  switch (outcome.status) {\n    case 'already-running':\n      result.steps.daemon = 'already-running'\n      break\n    case 'spawned':\n      result.steps.daemon = 'spawned'\n      if (outcome.brokenProjects.length > 0) {\n        console.warn(\n          `neat: ${outcome.brokenProjects.length} project(s) reported broken: ${outcome.brokenProjects.join(', ')}`,\n        )\n      }\n      break\n    case 'no-ports':\n      // The search window is saturated — surface the canonical REST port as the\n      // representative collision so the operator gets the recovery hints.\n      for (const line of formatPortCollisionMessage(NEAT_PORTS[0])) {\n        console.error(line)\n      }\n      result.exitCode = 3\n      return result\n    case 'timed-out':\n      result.steps.daemon = 'timed-out'\n      for (const line of await describeDaemonTimeout(outcome, opts.scanPath, timeoutMs)) {\n        console.error(line)\n      }\n      result.exitCode = 1\n      return result\n    case 'peer-timeout':\n      console.error('neat: another `neat` is spawning this project but its daemon did not come up in time')\n      result.exitCode = 1\n      return result\n    case 'spawn-failed':\n      console.error(`neat: daemon spawn failed — ${outcome.message}`)\n      result.exitCode = 1\n      return result\n  }\n\n  // ── Step 5: browser open (opt-in) ────────────────────────────────────\n  // The local dashboard is NOT auto-opened. A bare `neat <path>` / `npx\n  // neat.is` stays in the terminal: local NEAT is CLI-first, and the visual\n  // dashboard is the hosted experience. The web listener still binds — it's\n  // reachable by choice — but we only launch a browser into it when the\n  // caller explicitly passes `--open` (and never with `--no-open` or on a\n  // headless run). The dashboard lives on the daemon's allocated web port,\n  // not a fixed 6328 — a second project's daemon serves its one port over.\n  const webPort = allocated?.web ?? NEAT_PORTS[2]\n  const dashboardUrl = opts.dashboardUrl ?? `http://localhost:${webPort}`\n  if (opts.open === true && !opts.noOpen && process.stdout.isTTY) {\n    result.steps.browser = openBrowser(dashboardUrl)\n  } else {\n    result.steps.browser = 'skipped'\n  }\n\n  // ── Step 6: summary + onboarding signpost ────────────────────────────\n  // The daemon runs in the background writing to its own log; point the\n  // operator at it and at the honest next step (run their own app/tests).\n  const daemonRunning =\n    result.steps.daemon === 'spawned' || result.steps.daemon === 'already-running'\n  // Show the log path relative to the project root — the summary already\n  // printed the project path up top, so `neat-out/daemon.log` reads cleanly\n  // and matches what the operator sees on disk.\n  const daemonLog = daemonRunning\n    ? path.relative(opts.scanPath, daemonLogPath(opts.scanPath))\n    : null\n  printSummary(result, graph, daemonLog)\n\n  return result\n}\n\nexport function printSummary(\n  result: OrchestratorResult,\n  graph: ReturnType<typeof getGraph>,\n  daemonLog: string | null,\n): void {\n  const nodes: GraphNode[] = []\n  graph.forEachNode((_id, attrs) => nodes.push(attrs))\n  const edges: GraphEdge[] = []\n  graph.forEachEdge((_id, attrs) => edges.push(attrs))\n\n  const byNode = new Map<string, number>()\n  for (const n of nodes) byNode.set(n.type, (byNode.get(n.type) ?? 0) + 1)\n  const byEdge = new Map<string, number>()\n  for (const e of edges) byEdge.set(e.type, (byEdge.get(e.type) ?? 0) + 1)\n\n  console.log('')\n  console.log('=== summary ===')\n  console.log(`graph: ${graph.order} nodes, ${graph.size} edges`)\n  for (const [t, c] of [...byNode.entries()].sort()) console.log(`  ${t}: ${c}`)\n  for (const [t, c] of [...byEdge.entries()].sort()) console.log(`  ${t}: ${c}`)\n  console.log('')\n  // The graph is the product, and the way to read it is from your coding agent\n  // over MCP — or from this CLI. That is the primary next step, so it leads the\n  // closing guidance: put the graph in front of the agent that will use it.\n  const neat = commandPrefix()\n  console.log('query the graph from your coding agent — NEAT runs as an MCP server, so')\n  console.log('Claude Code, Cursor, and the rest read it directly:')\n  console.log(`      ${neat} skill --apply    put NEAT in front of Claude Code`)\n  console.log(`      (\\`${neat} --help\\` lists Cursor, Codex, Gemini, and the other clients)`)\n  console.log('or ask it straight from this terminal:')\n  console.log(`      ${neat} ask \"how does checkout work?\"`)\n\n  // Local NEAT is CLI-first. The visual dashboard is the hosted experience, so\n  // GUI-seekers get a single pointer there rather than a local web URL.\n  console.log('')\n  console.log(`want a visual dashboard? log in to hosted NEAT — \\`${neat} login\\``)\n\n  // Be honest about the auth posture (issue #483). The bare first-touch path\n  // pins the daemon to loopback with no token (see spawnDaemonDetached), so\n  // there's nothing to log in with. When the operator has set NEAT_AUTH_TOKEN,\n  // the daemon enforces it and the user needs it to reach the daemon — the CLI\n  // and the MCP server both query it — and to route OTel, so we print the real\n  // value rather than fabricating one the daemon wouldn't accept.\n  const token = process.env.NEAT_AUTH_TOKEN\n  console.log('')\n  if (typeof token === 'string' && token.length > 0) {\n    console.log(`auth token (needed to reach the daemon and route OTel): ${token}`)\n  } else {\n    console.log('running locally — no auth token needed')\n  }\n\n  // Onboarding signpost — the one-command flow returns here, so the last thing\n  // the operator reads has to tell them the daemon is up (and where its log is)\n  // and what to do next. The honest next step is to run their own app or test\n  // suite: the graph fills its OBSERVED layer as their code executes, and\n  // divergences surface where code and runtime disagree. Never suggest\n  // synthetic traffic — the point is what their real system does.\n  //\n  // Issue #831 — but only when the dependency install actually completed. If a\n  // `<pm> install` exited non-zero the OTel SDK never landed, so the manifests\n  // are patched but instrumentation is inert: telling the operator to \"run your\n  // app, OBSERVED edges fill in\" would be a lie, because nothing would fill in.\n  // In that case we say so plainly and hand back the exact install command to\n  // finish, and we withhold the clean next-step line until deps are in place.\n  const failedInstalls = (result.steps.apply.packageManagerInstalls ?? []).filter(\n    (i) => i.exitCode !== 0,\n  )\n\n  if (daemonLog !== null) {\n    console.log('')\n    console.log(`daemon running in the background (logs: ${daemonLog})`)\n  }\n\n  if (failedInstalls.length > 0) {\n    if (daemonLog === null) console.log('')\n    console.log(\n      'instrumentation is wired into your manifests, but it is NOT yet active:',\n    )\n    console.log(\n      'the dependency install did not complete, so the OTel SDK never landed and',\n    )\n    console.log('OBSERVED edges will stay empty until you finish the install. Fix it:')\n    for (const i of failedInstalls) {\n      console.log(`      run \\`${i.pm} install\\` in ${i.cwd}`)\n    }\n  } else if (daemonLog !== null && result.steps.apply.attached === true) {\n    // ADR-232 — attachment edits no source, so a plain start command runs\n    // uninstrumented. The next step has to name how to start with it.\n    console.log('next: start your app with NEAT attached — OBSERVED edges fill in as it runs,')\n    console.log('      and divergences surface where code and runtime disagree.')\n    console.log('      Node: in the service directory, `set -a; . ./.env.neat; set +a`, then your')\n    console.log('            usual start command (or put its NODE_OPTIONS in your process manager).')\n    console.log('      Python: run your start command under `opentelemetry-instrument`.')\n  } else if (daemonLog !== null) {\n    console.log(\n      'next: run your app or your test suite — OBSERVED edges fill in as it executes,',\n    )\n    console.log('      and divergences surface where code and runtime disagree.')\n  }\n}\n","// `neat connector add/list/remove/test` — the write side of the ADR-130\n// on-ramp (docs/contracts/connector-config.md §3). The daemon-read chain\n// (#730) already turns a `~/.neat/connectors.json` entry into a running poll\n// loop; this is the command a human actually touches to put an entry there.\n//\n// Everything provider-specific is dispatched through the registry table\n// (connectors/registry.ts §5) — the required-field schema this prompts for and\n// the auth round-trip `add`/`test` run both come from the entry, so no per-\n// provider branch lives here. The two security non-negotiables the contract\n// names ride through this module: validate-on-add by default (the credential\n// is proven against the provider before it's written), and env-ref-by-default /\n// `0600` / never-a-resolved-secret-on-screen (the write helpers in\n// connectors-config.ts own the file mode; this module only ever prints the\n// redacted pointer, never a resolved value).\n//\n// Handlers take their filesystem home, environment, `fetch`, prompt, and output\n// streams as injected deps so the whole surface is testable against a temp home\n// and a stubbed provider — no live account, no real `~/.neat`.\n\nimport readline from 'node:readline'\nimport {\n  autoSlugConnectorId,\n  describeCredential,\n  isEnvRef,\n  readConnectorsConfig,\n  removeConnectorEntry,\n  upsertConnectorEntry,\n  type ConnectorEntry,\n  type CredentialRef,\n} from './connectors-config.js'\nimport {\n  deprovisionConnector,\n  getProviderFieldSchema,\n  isPushProvider,\n  knownProviderNames,\n  provisionConnector,\n  validateConnectorEntry,\n  type ProviderFieldSchema,\n  type ValidateOutcome,\n} from './connectors/registry.js'\n\n// ── deps / injection ──────────────────────────────────────────────────────\n\nexport interface ConnectorCliDeps {\n  // NEAT_HOME override. Undefined uses connectors-config.ts's own env-based\n  // resolution (the real CLI); tests pass a temp home.\n  home?: string\n  env?: NodeJS.ProcessEnv\n  // Test seam for the provider auth round-trip (contract §4). Undefined → the\n  // junction's real `fetch`.\n  fetchImpl?: typeof fetch\n  // Interactive prompt. Undefined → a readline prompt that returns '' when\n  // stdin isn't a TTY, so CI never hangs waiting on input.\n  prompt?: (question: string) => Promise<string>\n  // Whether to prompt at all for missing fields. Undefined → `process.stdin`\n  // is a TTY. Non-interactive runs require every field as a flag.\n  interactive?: boolean\n  out?: (line: string) => void\n  err?: (line: string) => void\n}\n\ninterface ResolvedDeps {\n  home: string | undefined\n  env: NodeJS.ProcessEnv\n  fetchImpl?: typeof fetch\n  prompt: (question: string) => Promise<string>\n  interactive: boolean\n  out: (line: string) => void\n  err: (line: string) => void\n}\n\nasync function defaultPrompt(question: string): Promise<string> {\n  if (!process.stdin.isTTY) return ''\n  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })\n  try {\n    return await new Promise<string>((resolve) => rl.question(`${question} `, resolve))\n  } finally {\n    rl.close()\n  }\n}\n\nfunction resolveDeps(deps: ConnectorCliDeps): ResolvedDeps {\n  return {\n    home: deps.home,\n    env: deps.env ?? process.env,\n    ...(deps.fetchImpl ? { fetchImpl: deps.fetchImpl } : {}),\n    prompt: deps.prompt ?? defaultPrompt,\n    interactive: deps.interactive ?? Boolean(process.stdin.isTTY),\n    out: deps.out ?? ((l) => console.log(l)),\n    err: deps.err ?? ((l) => console.error(l)),\n  }\n}\n\n// ── argument parsing ──────────────────────────────────────────────────────\n\nexport interface ConnectorArgs {\n  subcommand: string\n  positional: string[]\n  project?: string\n  // Single-field credential from --credential / --token (an env-ref or a\n  // literal). Multi-field providers read their fields from `fields` instead.\n  credential?: string\n  id?: string\n  skipValidate: boolean\n  plaintext: boolean\n  // `--help`/`-h` anywhere prints usage and exits 0; `--json` asks a read\n  // subcommand (list) for machine-readable output. Both are valueless flags —\n  // the parser recognizes them so they never trip the \"flag requires a value\"\n  // path (a papercut the first blind run hit: `neat connector --help` erroring).\n  help: boolean\n  json: boolean\n  // Provider-specific option/credential fields, camelCased from their kebab\n  // flag (`--account-id` → accountId). Object-valued flags (`--workers '{…}'`)\n  // are JSON-parsed; `*Ms` flags are numbered; everything else stays a string.\n  fields: Record<string, unknown>\n}\n\nfunction kebabToCamel(name: string): string {\n  return name.replace(/-([a-z0-9])/g, (_, c: string) => c.toUpperCase())\n}\n\nfunction coerceFieldValue(name: string, raw: string): unknown {\n  const t = raw.trim()\n  if (t.startsWith('{') || t.startsWith('[')) {\n    try {\n      return JSON.parse(t)\n    } catch {\n      return raw\n    }\n  }\n  // Only numeric-shaped option names become numbers, so string ids that happen\n  // to be all-digits (rare, but possible) are never silently retyped.\n  if (/Ms$/.test(name) && /^\\d+$/.test(t)) return Number(t)\n  return raw\n}\n\nexport function parseConnectorArgs(\n  args: string[],\n): { ok: true; value: ConnectorArgs } | { ok: false; error: string } {\n  const out: ConnectorArgs = {\n    subcommand: '',\n    positional: [],\n    skipValidate: false,\n    plaintext: false,\n    help: false,\n    json: false,\n    fields: {},\n  }\n  const positional: string[] = []\n  for (let i = 0; i < args.length; i++) {\n    const arg = args[i] as string\n    if (arg === '--skip-validate') {\n      out.skipValidate = true\n      continue\n    }\n    if (arg === '--plaintext') {\n      out.plaintext = true\n      continue\n    }\n    // Valueless flags — recognized here so they never reach the \"flag requires\n    // a value\" branch below (which assumes every `--flag` takes an argument).\n    if (arg === '--help' || arg === '-h') {\n      out.help = true\n      continue\n    }\n    if (arg === '--json') {\n      out.json = true\n      continue\n    }\n    if (arg.startsWith('--')) {\n      let flag = arg\n      let value: string | undefined\n      const eq = arg.indexOf('=')\n      if (eq >= 0) {\n        flag = arg.slice(0, eq)\n        value = arg.slice(eq + 1)\n      } else {\n        const next = args[i + 1]\n        if (next === undefined || next.startsWith('--')) {\n          return { ok: false, error: `${flag} requires a value` }\n        }\n        value = next\n        i++\n      }\n      const name = flag.slice(2)\n      if (name === 'project') {\n        out.project = value\n        continue\n      }\n      if (name === 'credential' || name === 'token') {\n        out.credential = value\n        continue\n      }\n      if (name === 'id') {\n        out.id = value\n        continue\n      }\n      const field = kebabToCamel(name)\n      out.fields[field] = coerceFieldValue(field, value)\n      continue\n    }\n    positional.push(arg)\n  }\n  out.subcommand = positional[0] ?? ''\n  out.positional = positional.slice(1)\n  return { ok: true, value: out }\n}\n\n// ── credential assembly ───────────────────────────────────────────────────\n\n// Build the credential ref from flags + prompts. A single-field provider takes\n// one ref (--credential/--token or its primary key flag); a multi-field\n// provider (Firebase carries projectId + accessToken) takes one ref per\n// required field. Values are stored verbatim: a leading `$` is an env-ref\n// pointer, anything else is a literal — the exact rule the daemon resolves by,\n// so no transformation happens here.\nasync function buildCredentialRef(\n  dispatch: ProviderFieldSchema,\n  args: ConnectorArgs,\n  deps: ResolvedDeps,\n): Promise<CredentialRef> {\n  const hint = 'an env-var reference like $PROVIDER_TOKEN is recommended (stored as a pointer, not the secret); a literal value is stored as-is'\n  if (dispatch.requiredCredentialFields.length <= 1) {\n    const key = dispatch.primaryCredentialKey\n    let value = args.credential\n    if (value === undefined && typeof args.fields[key] === 'string') {\n      value = args.fields[key] as string\n    }\n    if (value === undefined && deps.interactive) {\n      value = await deps.prompt(`Credential for ${dispatch.provider} (${hint}):`)\n    }\n    return (value ?? '').trim()\n  }\n  const out: Record<string, string> = {}\n  for (const f of dispatch.requiredCredentialFields) {\n    let value: string | undefined\n    if (typeof args.fields[f] === 'string') value = args.fields[f] as string\n    else if (f === dispatch.primaryCredentialKey && args.credential !== undefined) value = args.credential\n    if (value === undefined && deps.interactive) {\n      value = await deps.prompt(`Credential field \"${f}\" for ${dispatch.provider} (${hint}):`)\n    }\n    out[f] = (value ?? '').trim()\n  }\n  return out\n}\n\n// Whether every required credential field carries a non-empty value.\nfunction credentialComplete(dispatch: ProviderFieldSchema, ref: CredentialRef): string[] {\n  if (typeof ref === 'string') {\n    return ref.length > 0 ? [] : [dispatch.primaryCredentialKey]\n  }\n  return dispatch.requiredCredentialFields.filter((f) => !ref[f] || ref[f].length === 0)\n}\n\n// The plaintext (non-env-ref) fields in a credential — the ones that put a\n// secret at rest and so warrant the opt-in warning.\nfunction plaintextFields(ref: CredentialRef): string[] {\n  if (typeof ref === 'string') return isEnvRef(ref) ? [] : ['credential']\n  return Object.entries(ref)\n    .filter(([, v]) => !isEnvRef(v))\n    .map(([k]) => k)\n}\n\n// ── `add` ─────────────────────────────────────────────────────────────────\n\nasync function connectorAdd(args: ConnectorArgs, deps: ResolvedDeps): Promise<number> {\n  // Provider — positional or prompt. Must be a known, built provider.\n  let provider = args.positional[0]\n  if (!provider && deps.interactive) {\n    provider = (await deps.prompt(`Provider (${knownProviderNames().join(', ')}):`)).trim()\n  }\n  if (!provider) {\n    deps.err('neat connector add: a provider is required (e.g. `neat connector add supabase`)')\n    return 2\n  }\n  // Field schema from either table — pull or push (a Vercel drain, ADR-146) —\n  // so the credential/option parsing below is identical for both shapes.\n  const dispatch = getProviderFieldSchema(provider)\n  if (!dispatch) {\n    deps.err(\n      `neat connector add: unknown provider \"${provider}\". known providers: ${knownProviderNames().join(', ')}`,\n    )\n    return 2\n  }\n  const push = isPushProvider(provider)\n\n  // Project — optional; blank binds to whatever project the daemon bootstraps.\n  let project = args.project\n  if (project === undefined && deps.interactive) {\n    const answer = (await deps.prompt('Project (blank = the project the daemon is bootstrapping):')).trim()\n    if (answer.length > 0) project = answer\n  }\n\n  // Credential + non-secret options.\n  const credential = await buildCredentialRef(dispatch, args, deps)\n  const options: Record<string, unknown> = { ...args.fields }\n  // The credential fields aren't options — strip any that arrived via a\n  // generic flag so they don't double-write into `options`.\n  for (const k of dispatch.requiredCredentialFields) delete options[k]\n\n  // Prompt for any still-missing required option field (interactive only).\n  for (const field of dispatch.requiredOptionFields) {\n    if (field in options) continue\n    if (!deps.interactive) continue\n    const answer = (await deps.prompt(`Option \"${field}\" for ${provider}:`)).trim()\n    if (answer.length > 0) options[field] = coerceFieldValue(field, answer)\n  }\n\n  // Structural completeness — caught before any write, even under\n  // --skip-validate, so an entry that can never run isn't silently stored.\n  const missingCred = credentialComplete(dispatch, credential)\n  if (missingCred.length > 0) {\n    deps.err(\n      `neat connector add: credential is incomplete — missing ${missingCred.join(', ')}. ` +\n        'Pass it as a flag (e.g. `--token $PROVIDER_TOKEN`) or run interactively.',\n    )\n    return 2\n  }\n  const missingOpts = dispatch.requiredOptionFields.filter((f) => !(f in options))\n  if (missingOpts.length > 0) {\n    deps.err(\n      `neat connector add: missing required option(s) for ${provider}: ${missingOpts.join(', ')}. ` +\n        `Pass e.g. \\`--${missingOpts[0].replace(/([A-Z])/g, '-$1').toLowerCase()} <value>\\`.`,\n    )\n    return 2\n  }\n\n  // Assemble the entry — auto-slug the id unless one was given.\n  const existing = await readConnectorsConfig(deps.home)\n  const existingIds = new Set(existing.connectors.map((c) => c.id))\n  const id = args.id ?? autoSlugConnectorId(provider, project, existingIds)\n  const entry: ConnectorEntry = {\n    id,\n    provider,\n    ...(project ? { project } : {}),\n    credential,\n    ...(Object.keys(options).length > 0 ? { options } : {}),\n  }\n\n  // Validate-on-add by default (contract §4) — a wrong credential fails fast\n  // here rather than quietly at the first poll. An unset env-ref is its own\n  // distinct outcome, never conflated with a rejected token. A push provider\n  // skips this pre-check: its provision step (below) creates the drain, and\n  // creating a drain against a custom endpoint validates reachability on\n  // Vercel's side already, so a separate round-trip would only double the work.\n  if (!push && !args.skipValidate) {\n    const outcome = await validateConnectorEntry(entry, deps.env, deps.fetchImpl)\n    const code = reportPreWriteValidation(outcome, deps)\n    if (code !== 0) return code\n  }\n\n  // Plaintext is the explicit opt-in; surface it so a secret never lands at\n  // rest by accident (contract §2).\n  const plaintext = plaintextFields(credential)\n  if (plaintext.length > 0 && !args.plaintext) {\n    deps.err(\n      `neat connector add: storing a literal secret at rest for ${plaintext.join(', ')} — ` +\n        'prefer an env-var reference like `$PROVIDER_TOKEN` (pass --plaintext to silence this).',\n    )\n  }\n\n  // Push providers (ADR-146): `add` doesn't just record the entry, it\n  // provisions the provider-side resource (the drain) — before the entry is\n  // written, so a failed provision leaves nothing behind — and folds the\n  // returned handle (drainId) into the entry so `remove` can tear it down.\n  if (push) {\n    if (args.skipValidate) {\n      deps.out('note: --skip-validate has no effect for a push provider — provisioning the drain is the add.')\n    }\n    const outcome = await provisionConnector(entry, deps.env, deps.fetchImpl)\n    if (outcome.status !== 'ok') {\n      deps.err(\n        `neat connector add: could not provision the ${provider} connector — ${outcome.reason}. Nothing was written.`,\n      )\n      return 1\n    }\n    if (outcome.options) entry.options = { ...(entry.options ?? {}), ...outcome.options }\n    if (outcome.note) deps.out(`note: ${outcome.note}`)\n  }\n\n  const { replaced } = await upsertConnectorEntry(entry, deps.home)\n  const verb = replaced ? 'updated' : 'added'\n  const where = project ? `project \"${project}\"` : 'every project (no --project set)'\n  deps.out(`${verb} connector \"${id}\" (${provider}) for ${where}.`)\n  if (push) {\n    deps.out(\"The drain is live — traces arrive at the daemon's OTLP receiver. No poll or restart needed.\")\n  } else {\n    if (args.skipValidate) {\n      deps.out('skipped validation (--skip-validate) — the credential is checked at the next daemon poll.')\n    }\n    deps.out(\"Restart the project's daemon (or start it) to begin polling this connector.\")\n  }\n  return 0\n}\n\n// Turn a pre-write validation outcome into an exit code, printing the distinct\n// message each case warrants. 0 means proceed to write.\nfunction reportPreWriteValidation(outcome: ValidateOutcome, deps: ResolvedDeps): number {\n  switch (outcome.status) {\n    case 'ok':\n      deps.out('credential validated against the provider.')\n      return 0\n    case 'unset-env':\n      deps.err(\n        `neat connector add: ${outcome.reason}. Export the variable before adding, ` +\n          'or pass --skip-validate to add now and set it before the daemon runs.',\n      )\n      return 1\n    case 'rejected':\n      deps.err(\n        `neat connector add: the provider rejected the credential — ${outcome.reason}. ` +\n          'Nothing was written. Fix the credential, or pass --skip-validate to store it anyway.',\n      )\n      return 1\n    case 'missing-field':\n      deps.err(`neat connector add: ${outcome.reason}.`)\n      return 2\n    case 'unknown-provider':\n      deps.err(`neat connector add: ${outcome.reason}.`)\n      return 2\n  }\n}\n\n// ── `list` ────────────────────────────────────────────────────────────────\n\nasync function connectorList(deps: ResolvedDeps, filterProject?: string, json = false): Promise<number> {\n  const config = await readConnectorsConfig(deps.home)\n  let entries = config.connectors\n  if (filterProject) entries = entries.filter((e) => e.project === filterProject)\n\n  // Machine-readable listing (--json). Credentials stay redacted here exactly\n  // as in the human table — the pointer/`****`, never a resolved secret (§6).\n  // `options` is safe to emit verbatim: by contract it never holds a secret.\n  if (json) {\n    const rows = entries.map((e) => ({\n      id: e.id,\n      provider: e.provider,\n      project: e.project ?? null,\n      kind: isPushProvider(e.provider) ? 'push' : 'pull',\n      credential: describeCredential(e.credential, deps.env).map((c) => ({\n        ...(c.field ? { field: c.field } : {}),\n        ref: c.display,\n        ...(c.status ? { status: c.status } : { kind: c.kind }),\n      })),\n      ...(e.options ? { options: e.options } : {}),\n    }))\n    deps.out(JSON.stringify(rows, null, 2))\n    return 0\n  }\n\n  if (entries.length === 0) {\n    deps.out(\n      filterProject\n        ? `no connectors configured for project \"${filterProject}\".`\n        : 'no connectors configured. run `neat connector add <provider>` to add one.',\n    )\n    return 0\n  }\n  deps.out('id\\tprovider\\tproject\\tcredential')\n  for (const e of entries) {\n    const project = e.project ?? '(every project)'\n    const credential = describeCredential(e.credential, deps.env)\n      .map((c) => {\n        const status = c.status ? ` (${c.status})` : c.kind === 'plaintext' ? ' (plaintext)' : ''\n        return c.field ? `${c.field}=${c.display}${status}` : `${c.display}${status}`\n      })\n      .join(', ')\n    deps.out(`${e.id}\\t${e.provider}\\t${project}\\t${credential}`)\n  }\n  return 0\n}\n\n// ── `remove` ──────────────────────────────────────────────────────────────\n\nasync function connectorRemove(deps: ResolvedDeps, id: string | undefined): Promise<number> {\n  if (!id) {\n    deps.err('neat connector remove: missing <id>. run `neat connector list` to see configured ids.')\n    return 2\n  }\n  // Read first: a push provider's drain must be torn down before the entry is\n  // dropped, so a live drain is never orphaned from its config (connectors.md\n  // §9). deprovision is idempotent, so retrying after a partial failure is safe.\n  const config = await readConnectorsConfig(deps.home)\n  const entry = config.connectors.find((c) => c.id === id)\n  if (!entry) {\n    deps.err(`neat connector remove: no connector with id \"${id}\". run \\`neat connector list\\` to see configured ids.`)\n    return 1\n  }\n  if (isPushProvider(entry.provider)) {\n    const outcome = await deprovisionConnector(entry, deps.env, deps.fetchImpl)\n    if (outcome.status !== 'ok') {\n      deps.err(\n        `neat connector remove: could not delete the ${entry.provider} drain — ${outcome.reason}. ` +\n          'The entry was kept so you can retry (or delete the drain in the Vercel dashboard, then re-run).',\n      )\n      return 1\n    }\n    if (outcome.note) deps.out(`note: ${outcome.note}`)\n  }\n\n  const removed = await removeConnectorEntry(id, deps.home)\n  if (!removed) {\n    deps.err(`neat connector remove: no connector with id \"${id}\". run \\`neat connector list\\` to see configured ids.`)\n    return 1\n  }\n  deps.out(`removed connector \"${id}\" (${removed.provider}).`)\n  return 0\n}\n\n// ── `test` ────────────────────────────────────────────────────────────────\n\nasync function connectorTest(deps: ResolvedDeps, id: string | undefined): Promise<number> {\n  if (!id) {\n    deps.err('neat connector test: missing <id>. run `neat connector list` to see configured ids.')\n    return 2\n  }\n  const config = await readConnectorsConfig(deps.home)\n  const entry = config.connectors.find((c) => c.id === id)\n  if (!entry) {\n    deps.err(`neat connector test: no connector with id \"${id}\". run \\`neat connector list\\` to see configured ids.`)\n    return 1\n  }\n  const outcome = await validateConnectorEntry(entry, deps.env, deps.fetchImpl)\n  switch (outcome.status) {\n    case 'ok':\n      deps.out(`ok: \"${id}\" (${entry.provider}) authenticated against the provider.`)\n      return 0\n    case 'unset-env':\n      deps.err(`unset: \"${id}\" (${entry.provider}) — ${outcome.reason}. Export the variable so the daemon can resolve it.`)\n      return 1\n    case 'rejected':\n      deps.err(`rejected: \"${id}\" (${entry.provider}) — ${outcome.reason}.`)\n      return 1\n    case 'missing-field':\n      deps.err(`incomplete: \"${id}\" (${entry.provider}) — ${outcome.reason}.`)\n      return 2\n    case 'unknown-provider':\n      deps.err(`unknown provider: \"${id}\" — ${outcome.reason}.`)\n      return 2\n  }\n}\n\n// ── dispatch ──────────────────────────────────────────────────────────────\n\nexport function printConnectorUsage(write: (line: string) => void): void {\n  write('usage: neat connector <add|list|remove|test> [args]')\n  write(`  providers:        ${knownProviderNames().join(', ')}`)\n  write('                    pull (polled): supabase, railway, firebase, cloudflare, neon')\n  write('                    push (drains): vercel — provisions a Vercel trace Drain that forwards')\n  write(\"                                   traces to the daemon's OTLP receiver; no app instrumentation\")\n  write('  add <provider>    add a connector; validates the credential first (--skip-validate to skip)')\n  write('                    flags: --project <name>  --credential/--token <$VAR|value>  --id <id>')\n  write('                           --<option> <value> (provider-specific)  --plaintext  --skip-validate')\n  write('                    vercel: neat connector add vercel --token $VERCEL_TOKEN \\\\')\n  write('                              --otel-token $NEAT_OTEL_TOKEN --team-id <teamId> \\\\')\n  write('                              --endpoint https://<public-host>/v1/traces [--project-ids <id,id>]')\n  write('                    neon: neat connector add neon --credential $NEON_OBSERVER_URL \\\\')\n  write('                            --project-id <projectId> --service-name <serviceName>')\n  write('  list              list configured connectors (credentials shown redacted)')\n  write('                    flags: --project <name>')\n  write('  remove <id>       remove a connector by id (a push provider also has its drain deleted)')\n  write('  test <id>         re-run validation for an existing connector (a push provider re-tests its drain)')\n}\n\n/**\n * Entry point the CLI wires `neat connector …` to. `rawArgs` is argv past the\n * `connector` token. Returns a process exit code; never calls `process.exit`\n * itself so the caller (and tests) own control flow.\n */\nexport async function runConnectorCommand(\n  rawArgs: string[],\n  deps: ConnectorCliDeps = {},\n): Promise<number> {\n  const resolved = resolveDeps(deps)\n  const parsed = parseConnectorArgs(rawArgs)\n  if (!parsed.ok) {\n    resolved.err(`neat connector: ${parsed.error}`)\n    return 2\n  }\n  const a = parsed.value\n  // `--help`/`-h` anywhere (with or without a subcommand) prints usage on\n  // stdout and exits 0 — the instinctive `neat connector [add] --help` path.\n  if (a.help) {\n    printConnectorUsage(resolved.out)\n    return 0\n  }\n  switch (a.subcommand) {\n    case 'add':\n      return connectorAdd(a, resolved)\n    case 'list':\n      return connectorList(resolved, a.project, a.json)\n    case 'remove':\n      return connectorRemove(resolved, a.positional[0])\n    case 'test':\n      return connectorTest(resolved, a.positional[0])\n    case '':\n      resolved.err('neat connector: missing subcommand.')\n      printConnectorUsage(resolved.err)\n      return 2\n    default:\n      resolved.err(`neat connector: unknown subcommand \"${a.subcommand}\".`)\n      printConnectorUsage(resolved.err)\n      return 2\n  }\n}\n","// `neat connect <provider>` — connect a provider to your HOSTED NEAT project over OAuth: the CLI equivalent\n// of the console's \"Connect\" button. It asks the hosted control plane for the provider's consent URL, opens\n// the browser, and polls until the connection lands.\n//\n// This is distinct from `neat connector add`, which configures a connector for a LOCAL/self-hosted daemon by\n// credential. `connect` talks to the control plane, not a daemon, so it needs the hosted CP URL + a NEAT API\n// key + the hosted project id. Those come from the environment (NEAT_CP_URL / NEAT_API_KEY /\n// NEAT_CP_PROJECT_ID) today, and from the active profile once `neat login` persists them. Every side effect\n// (fetch, the browser opener, the clock) is injected so the whole flow is testable with no network.\n\nimport { spawn } from 'node:child_process'\nimport { resolveCpUrl } from './login-sso.js'\n\nexport interface HostedConnectDeps {\n  env?: NodeJS.ProcessEnv\n  fetchImpl?: typeof fetch\n  openBrowser?: (url: string) => boolean\n  out?: (line: string) => void\n  err?: (line: string) => void\n  /** Poll cadence and ceiling (tests shrink them). */\n  pollMs?: number\n  timeoutMs?: number\n  sleepImpl?: (ms: number) => Promise<void>\n}\n\nfunction defaultOpenBrowser(url: string): boolean {\n  const platform = process.platform\n  const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open'\n  const args = platform === 'win32' ? ['/c', 'start', '', url] : [url]\n  try {\n    const child = spawn(cmd, args, { detached: true, stdio: 'ignore' })\n    child.on('error', () => {})\n    child.unref()\n    return true\n  } catch {\n    return false\n  }\n}\n\ninterface HostedCreds {\n  cpUrl: string\n  apiKey: string\n  projectId: string\n}\n\nfunction resolveCreds(env: NodeJS.ProcessEnv): HostedCreds | { error: string } {\n  const apiKey = env.NEAT_API_KEY\n  const projectId = env.NEAT_CP_PROJECT_ID\n  if (!apiKey) return { error: 'not logged in — run `neat login`, or set NEAT_API_KEY (a neat_pat_… key)' }\n  if (!projectId) return { error: 'no hosted project — run `neat login`, or set NEAT_CP_PROJECT_ID' }\n  return { cpUrl: resolveCpUrl(env).replace(/\\/+$/, ''), apiKey, projectId }\n}\n\ninterface ConnectionListItem {\n  provider?: string\n  status?: string\n}\n\n/**\n * `neat connect …` entry point. `rawArgs` is argv past the `connect` token. Returns a process exit code and\n * never calls `process.exit` itself, so the caller (and tests) own control flow.\n */\nexport async function runConnectCommand(rawArgs: string[], deps: HostedConnectDeps = {}): Promise<number> {\n  const env = deps.env ?? process.env\n  const out = deps.out ?? ((l) => console.log(l))\n  const err = deps.err ?? ((l) => console.error(l))\n  const fetchImpl = deps.fetchImpl ?? fetch\n  const open = deps.openBrowser ?? defaultOpenBrowser\n  const pollMs = deps.pollMs ?? 2000\n  const timeoutMs = deps.timeoutMs ?? 180_000\n  const sleep = deps.sleepImpl ?? ((ms: number) => new Promise<void>((r) => setTimeout(r, ms)))\n\n  const provider = rawArgs.find((a) => !a.startsWith('-'))\n  if (!provider || rawArgs.includes('-h') || rawArgs.includes('--help')) {\n    out('usage: neat connect <provider>   connect a provider to your hosted NEAT project over OAuth')\n    out(\"  Opens the provider's consent screen in your browser and waits for the connection to land.\")\n    out('  Needs a hosted login (`neat login`) or NEAT_CP_URL + NEAT_API_KEY + NEAT_CP_PROJECT_ID.')\n    out('  For a local/self-hosted daemon, use `neat connector add` instead.')\n    return provider ? 0 : 2\n  }\n\n  const creds = resolveCreds(env)\n  if ('error' in creds) {\n    err(`neat connect: ${creds.error}`)\n    return 2\n  }\n\n  const connectionsUrl = `${creds.cpUrl}/me/projects/${encodeURIComponent(creds.projectId)}/connections`\n\n  // Leg 1 — ask the control plane for the provider's OAuth consent URL.\n  let authorizeUrl: string\n  try {\n    const res = await fetchImpl(`${connectionsUrl}/${encodeURIComponent(provider)}/authorize`, {\n      method: 'POST',\n      headers: { authorization: `Bearer ${creds.apiKey}` },\n    })\n    if (res.status === 401) {\n      err('neat connect: not authorized — run `neat login` (or check NEAT_API_KEY).')\n      return 1\n    }\n    if (res.status === 404 || res.status === 501) {\n      err(`neat connect: ${provider} isn't available to connect over OAuth yet.`)\n      return 1\n    }\n    if (!res.ok) {\n      err(`neat connect: couldn't start connecting ${provider} (HTTP ${res.status}).`)\n      return 1\n    }\n    const body = (await res.json().catch(() => ({}))) as { authorizeUrl?: string }\n    if (!body.authorizeUrl) {\n      err(`neat connect: the control plane returned no authorize URL for ${provider}.`)\n      return 1\n    }\n    authorizeUrl = body.authorizeUrl\n  } catch (e) {\n    err(`neat connect: couldn't reach the control plane at ${creds.cpUrl} — ${(e as Error).message}`)\n    return 1\n  }\n\n  out(`Opening ${provider}'s consent screen in your browser…`)\n  if (!open(authorizeUrl)) out('Could not open a browser automatically — open this URL to authorize:')\n  out(`  ${authorizeUrl}`)\n  out('Waiting for you to authorize…')\n\n  // Poll the control plane until the provider connection lands (the callback seals it server-side).\n  const deadline = Date.now() + timeoutMs\n  while (Date.now() < deadline) {\n    await sleep(pollMs)\n    try {\n      const res = await fetchImpl(connectionsUrl, { headers: { authorization: `Bearer ${creds.apiKey}` } })\n      if (res.ok) {\n        const conns = (await res.json().catch(() => [])) as ConnectionListItem[]\n        const hit = Array.isArray(conns) ? conns.find((c) => c.provider === provider) : undefined\n        if (hit) {\n          out(`✓ ${provider} connected${hit.status ? ` (${hit.status})` : ''}.`)\n          return 0\n        }\n      }\n    } catch {\n      // Transient reachability blip — keep polling until the deadline.\n    }\n  }\n  err(\n    `neat connect: timed out waiting for ${provider}. If you authorized, run \\`neat connect ${provider}\\` ` +\n      'again to re-check — the connection may still land.',\n  )\n  return 1\n}\n","// The browser / access-token side of `neat login` — the hosted \"I have a NEAT\n// account\" path (client-profiles.md; the control-plane spec in neat-infra #19).\n//\n// Given the hosted control plane's base URL and the user's short-lived Supabase\n// access token — obtained via a browser loopback (Method 1) or pasted directly\n// (Method 2 / `--sso-token`, also the smoke path) — this reads the account's\n// projects from GET /me, resolves the chosen project's per-project daemon\n// credential from GET /me/projects/:id/cli-credential, writes the profile, and\n// surfaces the OTLP instrumentation block.\n//\n// The access token is transient: it authenticates the user just long enough to\n// fetch the daemon token, and is never written to disk. Only the long-lived\n// daemon token lands in ~/.neat/profiles.json (client-profiles.md §6). The OTel\n// token is app-paste creds, printed for the user, never persisted either.\n\nimport { createServer } from 'node:http'\nimport { spawn } from 'node:child_process'\nimport { randomBytes } from 'node:crypto'\nimport { upsertProfile } from './profiles.js'\nimport { probeDaemon } from './daemon-probe.js'\nimport { commandPrefix } from './banner.js'\nimport {\n  runPostLoginConnect,\n  waitForFirstProject,\n  onboardingUrl,\n  type MeAccount,\n  type ConnectDeps,\n} from './login-connect.js'\nimport { otlpBearerHeader } from './otlp-headers.js'\n\n// api.neat.is is the control plane's home and now resolves with a valid cert, so\n// it is the default — the raw Cloud Run URL carries the project number and can\n// change under us. NEAT_CP_URL (or --cp-url) overrides it, which is how a staging\n// control plane gets used. app.neat.is is the GUI, not the CP — the browser bridge\n// page that hands the access token back lives on the GUI (NEAT_WEB_URL / --web-url).\nconst DEFAULT_CP_URL = 'https://api.neat.is'\nconst DEFAULT_WEB_URL = 'https://app.neat.is'\nconst CALLBACK_TIMEOUT_MS = 5 * 60_000\n\nexport function resolveCpUrl(env: NodeJS.ProcessEnv = process.env, override?: string): string {\n  const v = override ?? env.NEAT_CP_URL\n  return (v && v.length > 0 ? v : DEFAULT_CP_URL).replace(/\\/+$/, '')\n}\n\nexport function resolveWebUrl(env: NodeJS.ProcessEnv = process.env, override?: string): string {\n  const v = override ?? env.NEAT_WEB_URL\n  return (v && v.length > 0 ? v : DEFAULT_WEB_URL).replace(/\\/+$/, '')\n}\n\n// GET /me → { user, org, projects } (control-plane spec). A project is usable\n// only when status === \"running\" (it then carries restUrl and cli-credential\n// returns 200); any other status is not yet provisioned.\ntype ProjectStatus = 'created' | 'provisioning' | 'running' | 'stopped' | 'failed'\ninterface CpProject {\n  id: string\n  name: string\n  status: ProjectStatus\n  restUrl?: string\n}\ninterface CliCredential {\n  endpoint: string\n  authToken: string\n  ingestEndpoint?: string\n  otelToken?: string\n}\n\nexport interface SsoDeps {\n  fetchImpl?: typeof fetch\n  out?: (line: string) => void\n  err?: (line: string) => void\n  // Open a URL in the browser; returns whether it launched. Injected for tests.\n  openBrowser?: (url: string) => boolean\n  // `~/.neat` override, for tests.\n  home?: string\n  // Read a line the user types — the post-login offer. Undefined → non-interactive,\n  // which prints the routes without asking.\n  readLine?: (prompt: string) => Promise<string | undefined>\n  // Test seams for the health probe's cold-start retry and the onboarding wait.\n  sleep?: (ms: number) => Promise<void>\n  now?: () => number\n  // Ends the onboarding wait on Ctrl-C.\n  signal?: AbortSignal\n  // Seams for the post-login repo step (repo detection, local-snapshot check, cwd).\n  connect?: ConnectDeps\n}\n\n// An error carries the CLI exit code to surface (1 rejected/needs-action, 2\n// misuse, 3 unreachable), matching the rest of `neat login`.\ninterface SsoError {\n  code: number\n  message: string\n  /**\n   * Set when the account simply has no running project yet. The caller offers the\n   * console-first onboarding wait for this one case; every other error stays\n   * terminal. A discriminator rather than a string match, so the message can be\n   * reworded without quietly turning the wait off.\n   */\n  kind?: 'no-project'\n}\n\n// ── the /me → cli-credential exchange ─────────────────────────────────────────\n\nfunction pickProject(\n  projects: CpProject[],\n  want: string | undefined,\n): { project: CpProject } | { error: SsoError } {\n  if (want) {\n    const p = projects.find((x) => x.id === want || x.name === want)\n    if (!p) return { error: { code: 1, message: `no project named or id'd \"${want}\" on this account` } }\n    return { project: p }\n  }\n  const running = projects.filter((p) => p.status === 'running')\n  if (running.length === 1) return { project: running[0]! }\n  if (running.length === 0) {\n    const listed = projects.length\n      ? ` (have: ${projects.map((p) => `${p.name} [${p.status}]`).join(', ')})`\n      : ''\n    return {\n      error: {\n        code: 1,\n        kind: 'no-project',\n        message: `no running project to connect to — create + provision one in the console first${listed}`,\n      },\n    }\n  }\n  return {\n    error: {\n      code: 2,\n      message: `several running projects — pass --project <name>: ${running.map((p) => p.name).join(', ')}`,\n    },\n  }\n}\n\n/**\n * Exchange a Supabase access token for a project's daemon credential:\n * GET /me → pick a running project → GET /me/projects/:id/cli-credential.\n * Returns the chosen project + its `{ endpoint, authToken, ingestEndpoint?,\n * otelToken? }`, or an error carrying the exit code to surface.\n */\nexport async function exchangeCredential(\n  cpUrl: string,\n  accessToken: string,\n  opts: { project?: string },\n  deps: SsoDeps,\n): Promise<{ project: CpProject; cred: CliCredential; me: MeAccount } | { error: SsoError }> {\n  const fetchImpl = deps.fetchImpl ?? fetch\n  const auth = { authorization: `Bearer ${accessToken}` }\n\n  let meRes: Response\n  try {\n    meRes = await fetchImpl(`${cpUrl}/me`, { headers: auth })\n  } catch (e) {\n    return { error: { code: 3, message: `can't reach the control plane at ${cpUrl} — ${(e as Error).message}` } }\n  }\n  if (meRes.status === 401) return { error: { code: 1, message: 'your session is expired or invalid — log in again' } }\n  if (!meRes.ok) return { error: { code: 1, message: `the control plane returned HTTP ${meRes.status} on /me` } }\n  const me = (await meRes.json().catch(() => ({}))) as MeAccount & { projects?: unknown }\n  const projects = (Array.isArray(me.projects) ? me.projects : []) as CpProject[]\n\n  const picked = pickProject(projects, opts.project)\n  if ('error' in picked) return picked\n  const project = picked.project\n\n  let credRes: Response\n  try {\n    credRes = await fetchImpl(`${cpUrl}/me/projects/${encodeURIComponent(project.id)}/cli-credential`, {\n      headers: auth,\n    })\n  } catch (e) {\n    return { error: { code: 3, message: `can't reach the control plane — ${(e as Error).message}` } }\n  }\n  if (credRes.status === 409) {\n    return {\n      error: {\n        code: 1,\n        message: `project \"${project.name}\" isn't provisioned yet (status: ${project.status}) — provision it first`,\n      },\n    }\n  }\n  if (credRes.status === 404) return { error: { code: 1, message: `project \"${project.name}\" was not found, or isn't yours` } }\n  if (credRes.status === 401) return { error: { code: 1, message: 'your session is expired or invalid — log in again' } }\n  if (!credRes.ok) return { error: { code: 1, message: `the control plane returned HTTP ${credRes.status} for the credential` } }\n\n  const cred = (await credRes.json().catch(() => ({}))) as CliCredential\n  if (!cred.endpoint || !cred.authToken) {\n    return { error: { code: 1, message: 'the credential response was missing endpoint/authToken' } }\n  }\n  return { project, cred, me }\n}\n\n// ── the browser loopback (Method 1) ───────────────────────────────────────────\n\nfunction defaultOpenBrowser(url: string): boolean {\n  const platform = process.platform\n  const cmd = platform === 'darwin' ? 'open' : platform === 'win32' ? 'cmd' : 'xdg-open'\n  const args = platform === 'win32' ? ['/c', 'start', '', url] : [url]\n  try {\n    const child = spawn(cmd, args, { detached: true, stdio: 'ignore' })\n    child.on('error', () => {})\n    child.unref()\n    return true\n  } catch {\n    return false\n  }\n}\n\n/**\n * Start a one-shot loopback listener on 127.0.0.1, open the browser to the GUI's\n * bridge page (`<webUrl>/cli/auth?callback=…&state=…`), and resolve with the\n * Supabase access token the page forwards to `…/callback?token=…&state=…`. The\n * `state` nonce is validated so only this CLI's own launch is accepted.\n */\nexport async function loopbackReceiveToken(\n  webUrl: string,\n  deps: SsoDeps,\n  opts: { timeoutMs?: number } = {},\n): Promise<{ token: string } | { error: SsoError }> {\n  const out = deps.out ?? (() => {})\n  const openFn = deps.openBrowser ?? defaultOpenBrowser\n  const state = randomBytes(16).toString('hex')\n\n  return new Promise((resolve) => {\n    let settled = false\n    let timer: ReturnType<typeof setTimeout>\n    const done = (r: { token: string } | { error: SsoError }): void => {\n      if (settled) return\n      settled = true\n      clearTimeout(timer)\n      try {\n        server.close()\n      } catch {\n        // already closing\n      }\n      resolve(r)\n    }\n\n    const server = createServer((req, res) => {\n      const reqUrl = new URL(req.url ?? '/', 'http://127.0.0.1')\n      if (reqUrl.pathname !== '/callback') {\n        res.writeHead(404)\n        res.end()\n        return\n      }\n      const token = reqUrl.searchParams.get('token')\n      const gotState = reqUrl.searchParams.get('state')\n      if (!token || gotState !== state) {\n        res.writeHead(400, { 'content-type': 'text/html' })\n        res.end('<h1>NEAT login failed</h1><p>Invalid or mismatched token. You can close this tab.</p>')\n        done({ error: { code: 1, message: 'the browser returned an invalid or mismatched token' } })\n        return\n      }\n      res.writeHead(200, { 'content-type': 'text/html' })\n      res.end(\"<h1>You're logged in to NEAT.</h1><p>You can close this tab and return to the terminal.</p>\")\n      done({ token })\n    })\n\n    server.on('error', (e) => done({ error: { code: 3, message: `couldn't start the local login listener — ${e.message}` } }))\n    timer = setTimeout(\n      () => done({ error: { code: 1, message: 'timed out waiting for the browser login' } }),\n      opts.timeoutMs ?? CALLBACK_TIMEOUT_MS,\n    )\n\n    server.listen(0, '127.0.0.1', () => {\n      const addr = server.address()\n      const port = typeof addr === 'object' && addr ? addr.port : 0\n      const callback = `http://127.0.0.1:${port}/callback`\n      const authUrl = `${webUrl}/cli/auth?callback=${encodeURIComponent(callback)}&state=${state}`\n      out('Opening your browser to log in to NEAT…')\n      out(`If it doesn't open, visit:\\n  ${authUrl}`)\n      openFn(authUrl)\n    })\n  })\n}\n\n// ── orchestration ─────────────────────────────────────────────────────────────\n\nexport interface SsoLoginOptions {\n  cpUrl: string\n  webUrl: string\n  // A pasted/piped Supabase access token (Method 2 / smoke). When absent, the\n  // browser loopback (Method 1) obtains one.\n  ssoToken?: string\n  name: string\n  project?: string\n  json: boolean\n  timeoutMs?: number\n}\n\n/**\n * Run the hosted login: obtain the access token (pasted or via the browser),\n * exchange it for the project's daemon credential, write the profile + set it\n * active, and surface the OTLP block. Returns a CLI exit code.\n */\nexport async function runSsoLogin(opts: SsoLoginOptions, deps: SsoDeps): Promise<number> {\n  const out = deps.out ?? ((l: string) => console.log(l))\n  const err = deps.err ?? ((l: string) => console.error(l))\n\n  let accessToken = opts.ssoToken\n  if (!accessToken) {\n    const lb = await loopbackReceiveToken(opts.webUrl, deps, { timeoutMs: opts.timeoutMs ?? CALLBACK_TIMEOUT_MS })\n    if ('error' in lb) {\n      err(`neat login: ${lb.error.message}`)\n      return lb.error.code\n    }\n    accessToken = lb.token\n  }\n\n  const fetchImpl = deps.fetchImpl ?? fetch\n  const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)))\n  const now = deps.now ?? Date.now\n\n  let ex = await exchangeCredential(opts.cpUrl, accessToken, { project: opts.project }, deps)\n\n  // A fresh account has an org and no projects, so the first thing the front door\n  // does would otherwise be to fail. The console knows how to route someone to\n  // their first project — including whether they may have one — so point at it\n  // and wait, rather than modelling provisioning here. Scripts (`--json`) keep\n  // the old terminal error instead of blocking for ten minutes.\n  if ('error' in ex && ex.error.kind === 'no-project' && !opts.json) {\n    const url = onboardingUrl(opts.webUrl)\n    out('')\n    out(\"You don't have a project yet — let's make one.\")\n    const opened = (deps.openBrowser ?? defaultOpenBrowser)(url)\n    out(opened ? `Opened ${url}` : `Open this to create your first project:\\n  ${url}`)\n    out('Waiting for it to come up — Ctrl-C to stop and finish later.')\n    const waited = await waitForFirstProject(fetchImpl, opts.cpUrl, accessToken, {\n      sleep,\n      now,\n      ...(deps.signal ? { signal: deps.signal } : {}),\n    })\n    if (waited.kind === 'aborted') {\n      out(`Stopped. Run \\`${commandPrefix()} login\\` again once your project is up.`)\n      return 130\n    }\n    if (waited.kind === 'timeout') {\n      err('neat login: no project came up while waiting — run `neat login` again once it does')\n      return 1\n    }\n    out(`${waited.project.name} is up.`)\n    ex = await exchangeCredential(opts.cpUrl, accessToken, { project: opts.project }, deps)\n  }\n\n  if ('error' in ex) {\n    err(`neat login: ${ex.error.message}`)\n    return ex.error.code\n  }\n  const { project, cred, me } = ex\n\n  // Confirm the daemon actually answers before claiming success. A project's\n  // status is set once at provision and never revisited from tenant health, so\n  // `running` does not mean `answering` — without this the CLI writes a profile,\n  // prints \"Logged in\", and the next command fails against a daemon that isn't\n  // there. The probe tolerates a cold start, so a merely-sleeping tenant still\n  // passes. Nothing is written when it fails, matching the pasted-endpoint path.\n  const probe = await probeDaemon(fetchImpl, cred.endpoint, cred.authToken, {\n    sleep,\n    now,\n    onWaiting: () => err('Waking the hosted daemon — a cold instance can take up to a minute…'),\n  })\n  if (probe.kind !== 'ok') {\n    const why =\n      probe.kind === 'unreachable'\n        ? probe.detail\n        : probe.kind === 'unauthorized'\n          ? `it rejected the credential (HTTP ${probe.status})`\n          : `it answered HTTP ${probe.status} and doesn't look like NEAT`\n    err(`neat login: \"${project.name}\" is provisioned, but its daemon isn't answering — ${why}.`)\n    err(`Nothing was changed. Check the project at ${opts.webUrl} and run \\`neat login\\` again.`)\n    return probe.kind === 'unreachable' ? 3 : 1\n  }\n\n  await upsertProfile(\n    { name: opts.name, endpoint: cred.endpoint, authToken: cred.authToken },\n    { makeActive: true, ...(deps.home ? { home: deps.home } : {}) },\n  )\n\n  if (opts.json) {\n    out(\n      JSON.stringify(\n        {\n          status: 'logged-in',\n          profile: opts.name,\n          project: project.name,\n          endpoint: cred.endpoint,\n          ...(cred.ingestEndpoint ? { ingestEndpoint: cred.ingestEndpoint } : {}),\n        },\n        null,\n        2,\n      ),\n    )\n  } else {\n    out(`Logged in — profile \"${opts.name}\" → ${project.name} (${cred.endpoint})`)\n    out('The neat CLI and the MCP server now read this hosted graph by default.')\n    if (cred.ingestEndpoint && cred.otelToken) {\n      out('')\n      out('To fill the OBSERVED layer, instrument your app to send OpenTelemetry to the hosted daemon:')\n      out(`  OTEL_EXPORTER_OTLP_ENDPOINT=${cred.ingestEndpoint}`)\n      out(`  OTEL_EXPORTER_OTLP_HEADERS=${otlpBearerHeader(cred.otelToken)}`)\n    }\n    // Logging in connects an account, not a directory. Say where this repo stands\n    // against the project and offer the two routes that put it in the graph (#1234).\n    await runPostLoginConnect({\n      cpUrl: opts.cpUrl,\n      webUrl: opts.webUrl,\n      accessToken,\n      project: { id: project.id, name: project.name },\n      // What a push actually needs: `sync --to` takes the daemon's URL, and its\n      // token comes from the flag rather than the profile (#1302).\n      endpoint: cred.endpoint,\n      pushToken: cred.authToken,\n      me,\n      deps: {\n        fetchImpl,\n        out,\n        ...(deps.readLine ? { readLine: deps.readLine } : {}),\n        ...(deps.openBrowser ? { openBrowser: deps.openBrowser } : { openBrowser: defaultOpenBrowser }),\n        ...(deps.connect ?? {}),\n      },\n    })\n    out('')\n    out(`Run \\`${commandPrefix()} logout\\` to switch back to your local daemon.`)\n  }\n  return 0\n}\n","// The client profile store — `~/.neat/profiles.json`, the per-user address book\n// of the remote NEATs this machine talks to (client-profiles.md §4, ADR-102).\n//\n// A profile is exactly `{ name, endpoint, authToken? }`: the daemon's REST root\n// and an optional bearer. It is how every NEAT client — the `neat` CLI, the\n// `neat-mcp` server — answers \"which NEAT am I talking to,\" the same code path\n// whether the daemon is a local loopback one (endpoint, no token) or a hosted\n// one (endpoint + token). This module owns the file; resolution precedence\n// (§3) lives in the clients that consume it.\n//\n// This is a CLIENT config, not a daemon registry (§4): daemons never read it,\n// never coordinate through it, and losing it costs convenience, not\n// correctness. It is a per-user `~/.neat` store, sibling to the others, and\n// follows the same discipline — atomic tmp+fsync+rename writes under an\n// exclusive-create lock, mode 0600 because `authToken` is a secret at rest.\n//\n// The `authToken` a hosted profile carries is the per-project daemon token\n// (what the control plane's provision/rotate return): long-lived until rotated\n// and accepted as `Authorization: Bearer <token>` on the daemon's REST root.\n// The short-lived control-plane session token used during login is never\n// persisted here — it authenticates the user just long enough to fetch the\n// daemon token, then is discarded.\n\nimport { promises as fs } from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nexport const PROFILES_CONFIG_VERSION = 1\n\n// One remote NEAT this machine talks to. `endpoint` is a daemon REST root\n// (ADR-096 — the project is the daemon; the name is only this profile's label).\nexport interface Profile {\n  name: string\n  endpoint: string\n  authToken?: string\n}\n\n// The file shape. `active` names the profile a client uses when nothing more\n// explicit is selected — the persisted counterpart of `--profile` / NEAT_PROFILE\n// (§3 level 1). It is a pointer by name, so removing a profile clears it.\nexport interface ProfilesConfig {\n  version: number\n  active?: string\n  profiles: Profile[]\n}\n\n// Resolve `~/.neat/` the same way the sibling stores do — per call, honoring a\n// NEAT_HOME override — so a test setting NEAT_HOME (or HOME) before a run lands\n// here too, and module-load order never matters.\nfunction neatHome(): string {\n  const override = process.env.NEAT_HOME\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(os.homedir(), '.neat')\n}\n\nexport function profilesConfigPath(home: string = neatHome()): string {\n  return path.join(home, 'profiles.json')\n}\n\nexport function profilesConfigLockPath(home: string = neatHome()): string {\n  return path.join(home, 'profiles.json.lock')\n}\n\n// Owner-read/write only. A file with group or other bits set is looser than the\n// 0600 an at-rest bearer calls for — warn, but read it anyway: a\n// mis-permissioned file is a hygiene problem, not a reason to lock a user out\n// of their own hosted graph.\nconst MODE_MASK_LOOSER_THAN_0600 = 0o077\n\nasync function warnIfModeLooserThan0600(file: string): Promise<void> {\n  // The POSIX bits are meaningless on Windows; skip rather than warn on reads.\n  if (process.platform === 'win32') return\n  try {\n    const stat = await fs.stat(file)\n    if ((stat.mode & MODE_MASK_LOOSER_THAN_0600) !== 0) {\n      const mode = (stat.mode & 0o777).toString(8).padStart(3, '0')\n      console.warn(\n        `[neat] ${file} is mode 0${mode}, looser than the 0600 this file's token calls for — run \\`chmod 600 ${file}\\``,\n      )\n    }\n  } catch {\n    // Racing a delete between read and stat is harmless — the read already\n    // succeeded; skip the warning rather than crash on it.\n  }\n}\n\n/**\n * Read and validate `~/.neat/profiles.json`.\n *\n * - A missing file is the common, un-configured case → an empty profile list,\n *   never an error. A machine that has never logged into a hosted NEAT simply\n *   has no named profiles and falls through to local daemon discovery.\n * - A malformed file throws a clear error naming what's wrong, so a hand-edit\n *   typo is legible rather than a silent empty list.\n * - A file looser than 0600 is read but warns.\n */\nexport async function readProfilesConfig(home: string = neatHome()): Promise<ProfilesConfig> {\n  const file = profilesConfigPath(home)\n  let raw: string\n  try {\n    raw = await fs.readFile(file, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n      return { version: PROFILES_CONFIG_VERSION, profiles: [] }\n    }\n    throw err\n  }\n  await warnIfModeLooserThan0600(file)\n\n  let parsed: unknown\n  try {\n    parsed = JSON.parse(raw)\n  } catch (err) {\n    throw new Error(`${file} is not valid JSON: ${(err as Error).message}`)\n  }\n  return validateConfig(parsed, file)\n}\n\nfunction validateConfig(parsed: unknown, file: string): ProfilesConfig {\n  if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {\n    throw new Error(`${file} must be a JSON object with a \"profiles\" array`)\n  }\n  const obj = parsed as Record<string, unknown>\n\n  const version = obj.version === undefined ? PROFILES_CONFIG_VERSION : obj.version\n  if (typeof version !== 'number' || !Number.isInteger(version)) {\n    throw new Error(`${file}: \"version\" must be an integer`)\n  }\n\n  const rawProfiles = obj.profiles\n  if (!Array.isArray(rawProfiles)) {\n    throw new Error(`${file}: \"profiles\" must be an array`)\n  }\n  const profiles = rawProfiles.map((entry, i) => validateEntry(entry, i, file))\n\n  // Reject a duplicate name up front: names are the address a client selects by,\n  // so two entries sharing one make selection ambiguous.\n  const seen = new Set<string>()\n  for (const p of profiles) {\n    if (seen.has(p.name)) throw new Error(`${file}: duplicate profile name \"${p.name}\"`)\n    seen.add(p.name)\n  }\n\n  let active: string | undefined\n  if (obj.active !== undefined) {\n    if (typeof obj.active !== 'string' || obj.active.length === 0) {\n      throw new Error(`${file}: \"active\" must be a non-empty string when present`)\n    }\n    // A dangling `active` (points at a profile that isn't there) is treated as\n    // unset rather than an error — the same graceful-skip the sibling stores use.\n    active = seen.has(obj.active) ? obj.active : undefined\n  }\n\n  return { version, ...(active ? { active } : {}), profiles }\n}\n\nfunction validateEntry(entry: unknown, index: number, file: string): Profile {\n  const where = `${file}: profiles[${index}]`\n  if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {\n    throw new Error(`${where} must be an object`)\n  }\n  const e = entry as Record<string, unknown>\n\n  const name = e.name\n  if (typeof name !== 'string' || name.length === 0) {\n    throw new Error(`${where}.name must be a non-empty string`)\n  }\n\n  const endpoint = e.endpoint\n  if (typeof endpoint !== 'string' || endpoint.length === 0) {\n    throw new Error(`${where}.endpoint must be a non-empty string`)\n  }\n  // A profile endpoint is a daemon REST root — a real absolute URL. Catch the\n  // common paste-mistakes (a bare host, a trailing path) at write/read time\n  // rather than as an opaque fetch failure later.\n  let parsedUrl: URL\n  try {\n    parsedUrl = new URL(endpoint)\n  } catch {\n    throw new Error(`${where}.endpoint must be an absolute URL (got \"${endpoint}\")`)\n  }\n  if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {\n    throw new Error(`${where}.endpoint must be an http(s) URL (got \"${parsedUrl.protocol}\")`)\n  }\n\n  if (e.authToken !== undefined && (typeof e.authToken !== 'string' || e.authToken.length === 0)) {\n    throw new Error(`${where}.authToken must be a non-empty string when present`)\n  }\n\n  return {\n    name,\n    endpoint,\n    ...(typeof e.authToken === 'string' ? { authToken: e.authToken } : {}),\n  }\n}\n\n/**\n * The named profile, or undefined if there is none by that name. This is the\n * primitive the client precedence chain (§3 level 1) calls once it has a name\n * from `--profile` / NEAT_PROFILE / the persisted `active` pointer.\n */\nexport async function resolveProfile(\n  name: string,\n  home: string = neatHome(),\n): Promise<Profile | undefined> {\n  const { profiles } = await readProfilesConfig(home)\n  return profiles.find((p) => p.name === name)\n}\n\n/**\n * The active profile — the persisted default a bare client uses when nothing\n * more explicit is selected — or undefined when none is set. Returns undefined\n * (never throws) on a missing file so a client falls cleanly through to local\n * daemon discovery.\n */\nexport async function getActiveProfile(home: string = neatHome()): Promise<Profile | undefined> {\n  const { active, profiles } = await readProfilesConfig(home)\n  if (!active) return undefined\n  return profiles.find((p) => p.name === active)\n}\n\n// Serialize a config to the on-disk shape, dropping an `active` that no longer\n// points at a real profile so the file never carries a dangling pointer.\nfunction serialize(config: ProfilesConfig): string {\n  const names = new Set(config.profiles.map((p) => p.name))\n  const active = config.active && names.has(config.active) ? config.active : undefined\n  const out: ProfilesConfig = {\n    version: config.version ?? PROFILES_CONFIG_VERSION,\n    ...(active ? { active } : {}),\n    profiles: config.profiles,\n  }\n  return `${JSON.stringify(out, null, 2)}\\n`\n}\n\n/**\n * Write `~/.neat/profiles.json` atomically: a tmp file created mode 0600 (so the\n * token bytes are never briefly world-readable), fsync'd, then renamed over the\n * target — atomic on POSIX, and the rename carries the tmp inode's mode with it.\n * Callers should hold the lock (see `withProfilesLock`) so a read-modify-write\n * can't race another client.\n */\nasync function writeConfigAtomic(config: ProfilesConfig, home: string): Promise<void> {\n  const file = profilesConfigPath(home)\n  await fs.mkdir(path.dirname(file), { recursive: true })\n  const tmp = `${file}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`\n  const fd = await fs.open(tmp, 'w', 0o600)\n  try {\n    await fd.writeFile(serialize(config), 'utf8')\n    await fd.sync()\n  } finally {\n    await fd.close()\n  }\n  await fs.rename(tmp, file)\n}\n\n// Exclusive-create lock — the same cross-platform flock stand-in the sibling\n// stores use. `wx` fails if the lock file already exists; we retry briefly, then\n// give up rather than hang a CLI forever behind a stale lock.\nconst LOCK_RETRY_MS = 50\nconst LOCK_TIMEOUT_MS = 5_000\n\nasync function acquireLock(lockPath: string): Promise<void> {\n  await fs.mkdir(path.dirname(lockPath), { recursive: true })\n  const deadline = Date.now() + LOCK_TIMEOUT_MS\n  for (;;) {\n    try {\n      const fd = await fs.open(lockPath, 'wx')\n      await fd.writeFile(`${process.pid}\\n`, 'utf8')\n      await fd.close()\n      return\n    } catch (err) {\n      if ((err as NodeJS.ErrnoException).code !== 'EEXIST') throw err\n      if (Date.now() >= deadline) {\n        throw new Error(\n          `timed out acquiring ${lockPath} after ${LOCK_TIMEOUT_MS}ms — ` +\n            `if no other neat process is running, remove the stale lock file`,\n        )\n      }\n      await new Promise((resolve) => setTimeout(resolve, LOCK_RETRY_MS))\n    }\n  }\n}\n\nasync function releaseLock(lockPath: string): Promise<void> {\n  await fs.rm(lockPath, { force: true })\n}\n\nasync function withProfilesLock<T>(home: string, fn: () => Promise<T>): Promise<T> {\n  const lockPath = profilesConfigLockPath(home)\n  await acquireLock(lockPath)\n  try {\n    return await fn()\n  } finally {\n    await releaseLock(lockPath)\n  }\n}\n\n/**\n * Add or replace a profile by name, under the lock. When `makeActive` is set (or\n * this is the first profile written), the new profile also becomes active — the\n * common case for `neat login`, where connecting a machine to a hosted NEAT\n * should also point the local clients at it.\n */\nexport async function upsertProfile(\n  profile: Profile,\n  opts: { makeActive?: boolean; home?: string } = {},\n): Promise<void> {\n  const home = opts.home ?? neatHome()\n  // Validate the caller's profile through the same gate a hand-edited file goes\n  // through, so a bad endpoint is rejected before it reaches disk.\n  const validated = validateEntry(profile, 0, profilesConfigPath(home))\n  await withProfilesLock(home, async () => {\n    const config = await readProfilesConfig(home)\n    const others = config.profiles.filter((p) => p.name !== validated.name)\n    const profiles = [...others, validated]\n    const makeActive = opts.makeActive ?? config.profiles.length === 0\n    const active = makeActive ? validated.name : config.active\n    await writeConfigAtomic({ version: config.version, ...(active ? { active } : {}), profiles }, home)\n  })\n}\n\n/**\n * Remove a profile by name, under the lock. Returns whether one was removed. A\n * removed profile that was active clears the active pointer (serialize drops a\n * dangling one) — a client then falls back to local discovery, never to a\n * silently different endpoint.\n */\nexport async function removeProfile(name: string, home: string = neatHome()): Promise<boolean> {\n  return withProfilesLock(home, async () => {\n    const config = await readProfilesConfig(home)\n    const profiles = config.profiles.filter((p) => p.name !== name)\n    if (profiles.length === config.profiles.length) return false\n    const active = config.active === name ? undefined : config.active\n    await writeConfigAtomic({ version: config.version, ...(active ? { active } : {}), profiles }, home)\n    return true\n  })\n}\n\n/**\n * Clear the active pointer, leaving the profiles in place, under the lock —\n * a client then falls back to local discovery (`neat logout`). Returns whether\n * an active pointer was actually cleared, so the caller can tell \"logged out\"\n * from \"wasn't logged in\".\n */\nexport async function clearActiveProfile(home: string = neatHome()): Promise<boolean> {\n  return withProfilesLock(home, async () => {\n    const config = await readProfilesConfig(home)\n    if (!config.active) return false\n    await writeConfigAtomic({ version: config.version, profiles: config.profiles }, home)\n    return true\n  })\n}\n\n/**\n * Point the active pointer at an existing profile, under the lock. Throws if no\n * profile by that name exists — selecting a non-existent endpoint should fail\n * loudly, not silently set a dangling pointer.\n */\nexport async function setActiveProfile(name: string, home: string = neatHome()): Promise<void> {\n  await withProfilesLock(home, async () => {\n    const config = await readProfilesConfig(home)\n    if (!config.profiles.some((p) => p.name === name)) {\n      throw new Error(`no profile named \"${name}\" — run \\`neat login\\` or add it first`)\n    }\n    await writeConfigAtomic({ version: config.version, active: name, profiles: config.profiles }, home)\n  })\n}\n","// Is this endpoint a reachable NEAT daemon that accepts this token?\n//\n// The `/health` round-trip `neat doctor` and both halves of `neat login` share.\n// It lived in login-cli.ts while the pasted-endpoint path was its only caller;\n// the browser path needs the identical check before it reports success, and\n// login-cli.ts already imports login-sso.ts, so the probe moved here rather than\n// being duplicated or imported backwards.\n//\n// The cold-start budget is the load-bearing part. A hosted tenant on Cloud Run\n// scales to zero, so a *healthy* daemon can stall the first request for tens of\n// seconds. A flat timeout reports that daemon as unreachable, which is how a\n// sleeping project comes to look like a broken one.\n\nconst PROBE_ATTEMPT_TIMEOUT_MS = 30_000\nconst PROBE_TOTAL_BUDGET_MS = 120_000\nconst PROBE_RETRY_PAUSE_MS = 2_000\n\nexport type Probe =\n  | { kind: 'ok' }\n  | { kind: 'unauthorized'; status: number }\n  | { kind: 'not-neat'; status: number }\n  | { kind: 'unreachable'; detail: string }\n\n// True when the error is our own request timeout (AbortSignal.timeout) rather\n// than a connection/DNS failure. A cold hosted daemon stalls the first request\n// for tens of seconds, so a timeout is worth retrying — a refused connection or\n// an unknown host is not.\nfunction isTimeoutError(err: unknown): boolean {\n  const name = (err as { name?: string })?.name\n  return name === 'TimeoutError' || name === 'AbortError'\n}\n\n// One `/health` round-trip. Returns a terminal Probe, or 'timeout' to tell the\n// caller it may retry (a possible cold start).\nasync function probeOnce(\n  fetchImpl: typeof fetch,\n  root: string,\n  token: string,\n  timeoutMs: number,\n): Promise<Probe | { kind: 'timeout' }> {\n  let res: Response\n  try {\n    res = await fetchImpl(`${root}/health`, {\n      headers: { authorization: `Bearer ${token}` },\n      signal: AbortSignal.timeout(timeoutMs),\n    })\n  } catch (err) {\n    if (isTimeoutError(err)) return { kind: 'timeout' }\n    return { kind: 'unreachable', detail: (err as Error).message }\n  }\n  if (res.status === 401 || res.status === 403) return { kind: 'unauthorized', status: res.status }\n  if (!res.ok) return { kind: 'not-neat', status: res.status }\n  const contentType = res.headers.get('content-type') ?? ''\n  // A NEAT /health returns JSON; a random 200 from a foreign server does not.\n  if (!contentType.includes('json')) return { kind: 'not-neat', status: res.status }\n  return { kind: 'ok' }\n}\n\n/**\n * Confirm the endpoint is a reachable NEAT daemon that accepts the token, the\n * same `/health` probe `neat doctor` uses: a secured daemon answers 401/403 to a\n * bad bearer, so a wrong token fails here rather than being stored and failing on\n * the first read. A fast connection/DNS error fails immediately (a wrong URL),\n * but a request timeout is retried within a longer budget — a hosted daemon\n * scaled to zero cold-starts in tens of seconds, and the old flat cap reported\n * that valid daemon as unreachable.\n */\nexport async function probeDaemon(\n  fetchImpl: typeof fetch,\n  endpoint: string,\n  token: string,\n  hooks: { sleep: (ms: number) => Promise<void>; now: () => number; onWaiting: () => void },\n): Promise<Probe> {\n  const root = endpoint.replace(/\\/$/, '')\n  const deadline = hooks.now() + PROBE_TOTAL_BUDGET_MS\n  let warned = false\n  for (;;) {\n    const result = await probeOnce(fetchImpl, root, token, PROBE_ATTEMPT_TIMEOUT_MS)\n    if (result.kind !== 'timeout') return result\n    // A timeout, not a refused connection — treat it as a possible cold start\n    // and keep waiting within the budget, telling the user why once.\n    if (!warned) {\n      hooks.onWaiting()\n      warned = true\n    }\n    if (hooks.now() >= deadline) {\n      return { kind: 'unreachable', detail: `no response after ${Math.round(PROBE_TOTAL_BUDGET_MS / 1000)}s` }\n    }\n    await hooks.sleep(PROBE_RETRY_PAUSE_MS)\n  }\n}\n","// What happens after `neat login` succeeds — connecting the repo the user is\n// standing in to the hosted project they just connected their account to.\n//\n// Logging in connects an *account*: it reads /me, resolves a running project's\n// daemon credential, and writes a profile. It never looks at the working\n// directory. Someone who arrived from the front door is standing in a repo they\n// expect to see in the graph, so the run ends by telling them where that repo\n// stands and offering the two routes that put it in (#1234):\n//\n//   bind   — the hosted daemon clones and extracts the repo itself, through the\n//            GitHub App. Durable: it re-syncs on its own.\n//   sync   — push the local EXTRACTED snapshot with `neat sync --to`. Immediate\n//            and needs no GitHub App, but it is a snapshot, not a subscription.\n//\n// Before either, there is a question this step used to answer by itself: which\n// project the repo belongs to. It assumed the one the login connected to, which\n// is a real choice made silently — a second repo in a project is not free today\n// (#1294), and a repo can have a project of its own instead. So it asks, every\n// time, with no default and no recommendation (#1272).\n//\n// That makes one call here a write: creating a project is a POST, and so is\n// provisioning it. Everything else still reads, prints, or at most opens a\n// browser tab, so a control plane that is down or an older CP that doesn't serve\n// these fields degrades to saying less rather than failing. The write happens\n// only on an explicit keypress, and it reports each of its three outcomes\n// separately — created and running, created but unprovisioned, or not created —\n// because \"your project exists but has no daemon\" is a state the user has to be\n// able to act on.\n\nimport { execFile } from 'node:child_process'\nimport { promisify } from 'node:util'\nimport { promises as fs } from 'node:fs'\nimport { commandPrefix } from './banner.js'\nimport path from 'node:path'\n\nconst execFileAsync = promisify(execFile)\n\n/**\n * Is there an extracted snapshot here to push? `neat sync --to` pushes an\n * existing `neat-out/graph.json`; in a repo NEAT has never run on there is\n * nothing to send, and offering the push without saying so sends the user at a\n * command that exits on a missing file.\n */\nexport async function hasLocalSnapshot(cwd: string): Promise<boolean> {\n  try {\n    await fs.access(path.join(cwd, 'neat-out', 'graph.json'))\n    return true\n  } catch {\n    return false\n  }\n}\n\nconst POLL_INTERVAL_MS = 3_000\nconst POLL_BUDGET_MS = 10 * 60_000\nconst CP_TIMEOUT_MS = 10_000\n\n/** The slice of GET /me this step reads. `github` is absent on an older control plane. */\nexport interface MeAccount {\n  projects?: Array<{ id: string; name: string; status: string }>\n  github?: { installed?: boolean }\n}\n\n/** A repo bound to a hosted project (GET /me/projects/:id/repos). */\nexport interface BoundRepo {\n  owner: string\n  name: string\n  syncStatus?: string\n  detail?: string\n  lastSyncAt?: string\n}\n\nexport interface RepoRef {\n  owner: string\n  name: string\n}\n\nexport interface ConnectDeps {\n  fetchImpl?: typeof fetch\n  out?: (line: string) => void\n  readLine?: (prompt: string) => Promise<string | undefined>\n  openBrowser?: (url: string) => boolean\n  /** Resolve the current directory's GitHub repo; injected so tests never shell out. */\n  detectRepo?: (cwd: string) => Promise<RepoRef | null>\n  /** Does a local EXTRACTED snapshot exist to push? Injected for tests. */\n  hasLocalGraph?: (cwd: string) => Promise<boolean>\n  cwd?: string\n  sleep?: (ms: number) => Promise<void>\n  now?: () => number\n  /** Aborts the zero-project wait (Ctrl-C). */\n  signal?: AbortSignal\n  /**\n   * Run the local zero-to-graph orchestrator — the same one the door's local\n   * path runs, through the same overrides seam. Absent in a non-interactive or\n   * test context, in which case the step prints the commands instead of running\n   * anything.\n   */\n  orchestrator?: (\n    cwd: string,\n    opts?: { project?: string; noInstrument?: boolean; yes?: boolean; headerShown?: boolean },\n  ) => Promise<number>\n}\n\n/**\n * The GitHub repo this directory belongs to, or null when there isn't one.\n *\n * Reads `git remote get-url origin` and falls back to the first remote, so a\n * clone whose remote is named something else still resolves. Both URL forms are\n * accepted (`https://github.com/o/n.git`, `git@github.com:o/n.git`). Anything\n * that isn't GitHub returns null — the bind route only exists for GitHub, and\n * guessing an owner/name we can't bind would make the offer a lie.\n */\nexport async function detectGitHubRepo(cwd: string): Promise<RepoRef | null> {\n  const read = async (args: string[]): Promise<string | null> => {\n    try {\n      const { stdout } = await execFileAsync('git', args, { cwd, timeout: 5_000 })\n      return stdout.trim()\n    } catch {\n      return null\n    }\n  }\n  let url = await read(['remote', 'get-url', 'origin'])\n  if (!url) {\n    const names = await read(['remote'])\n    const first = names?.split(/\\r?\\n/).find((l) => l.trim().length > 0)?.trim()\n    if (!first) return null\n    url = await read(['remote', 'get-url', first])\n  }\n  if (!url) return null\n  return parseGitHubRemote(url)\n}\n\n/** github.com owner/name out of an https or ssh remote URL; null for anything else. */\nexport function parseGitHubRemote(url: string): RepoRef | null {\n  const trimmed = url.trim().replace(/\\.git$/, '')\n  const m =\n    trimmed.match(/^https?:\\/\\/(?:[^@/]+@)?github\\.com\\/([^/]+)\\/([^/]+)$/) ??\n    trimmed.match(/^git@github\\.com:([^/]+)\\/([^/]+)$/) ??\n    trimmed.match(/^ssh:\\/\\/git@github\\.com\\/([^/]+)\\/([^/]+)$/)\n  if (!m) return null\n  const owner = m[1]!\n  const name = m[2]!\n  if (!owner || !name) return null\n  return { owner, name }\n}\n\nasync function cpGetJson<T>(\n  fetchImpl: typeof fetch,\n  cpUrl: string,\n  path: string,\n  accessToken: string,\n): Promise<{ ok: true; body: T } | { ok: false }> {\n  try {\n    const res = await fetchImpl(`${cpUrl}${path}`, {\n      headers: { authorization: `Bearer ${accessToken}`, accept: 'application/json' },\n      signal: AbortSignal.timeout(CP_TIMEOUT_MS),\n    })\n    // 501 is an honest \"the GitHub App isn't configured here\"; treat every\n    // non-2xx the same way — we simply know less, and say less.\n    if (!res.ok) return { ok: false }\n    return { ok: true, body: (await res.json()) as T }\n  } catch {\n    return { ok: false }\n  }\n}\n\n/** Repos bound to this project, or null when the control plane can't say. */\nexport async function listBoundRepos(\n  fetchImpl: typeof fetch,\n  cpUrl: string,\n  accessToken: string,\n  projectId: string,\n): Promise<BoundRepo[] | null> {\n  const res = await cpGetJson<BoundRepo[]>(\n    fetchImpl,\n    cpUrl,\n    `/me/projects/${encodeURIComponent(projectId)}/repos`,\n    accessToken,\n  )\n  if (!res.ok || !Array.isArray(res.body)) return null\n  return res.body\n}\n\nexport type WaitResult =\n  | { kind: 'project'; project: { id: string; name: string; status: string } }\n  | { kind: 'aborted' }\n  | { kind: 'timeout' }\n\n/**\n * Send a fresh account to the console to create its first project, then wait for\n * one to come up.\n *\n * The console routes an account from `/onboarding` to wherever it needs to go, so\n * the CLI points at one URL and polls `/me` rather than modelling that flow\n * itself — no control-plane change, and nothing here decides who may provision.\n * Ctrl-C is a clean exit, not a crash: the signal ends the wait and the caller\n * returns 130.\n */\nexport async function waitForFirstProject(\n  fetchImpl: typeof fetch,\n  cpUrl: string,\n  accessToken: string,\n  deps: {\n    sleep: (ms: number) => Promise<void>\n    now: () => number\n    signal?: AbortSignal\n    pollMs?: number\n    budgetMs?: number\n  },\n): Promise<WaitResult> {\n  const pollMs = deps.pollMs ?? POLL_INTERVAL_MS\n  const deadline = deps.now() + (deps.budgetMs ?? POLL_BUDGET_MS)\n  for (;;) {\n    if (deps.signal?.aborted) return { kind: 'aborted' }\n    const me = await cpGetJson<MeAccount>(fetchImpl, cpUrl, '/me', accessToken)\n    if (me.ok) {\n      const running = (me.body.projects ?? []).find((p) => p.status === 'running')\n      if (running) return { kind: 'project', project: running }\n    }\n    if (deps.now() >= deadline) return { kind: 'timeout' }\n    await deps.sleep(pollMs)\n    if (deps.signal?.aborted) return { kind: 'aborted' }\n  }\n}\n\n/** `app.neat.is/config/repos?project=<id>` — the console's bind screen for one project. */\n/** A project the control plane named back to us. */\nexport interface NamedProject {\n  id: string\n  name: string\n}\n\n/**\n * What happened when we tried to give this repo a project of its own.\n *\n * Four outcomes rather than ok/error, because creating and provisioning are two\n * calls and the middle state is real: `POST /me/projects` always succeeds for a\n * signed-in account, and `POST /me/projects/:id/provision` is where the\n * subscription gate answers 402. A user who is told \"that didn't work\" after the\n * first call succeeded will make a second project the next time they try.\n */\nexport type CreateProjectOutcome =\n  /** Created, and a daemon is coming up. */\n  | { ok: true; project: NamedProject }\n  /** The project exists; provisioning it needs a plan. */\n  | { ok: false; reason: 'needs-plan'; project: NamedProject; detail?: string }\n  /** The project exists; provisioning failed for some other reason. */\n  | { ok: false; reason: 'not-provisioned'; project: NamedProject; detail: string }\n  /** Nothing was created. */\n  | { ok: false; reason: 'not-created'; detail: string }\n\n/**\n * A project name for a repo, as a DNS label.\n *\n * The control plane takes `[a-z0-9-]+` only, and repo names are freer than that\n * (`My.App_v2`), so this derives rather than passes through. A name that strips\n * to nothing still has to be a legal label.\n */\nexport function projectNameForRepo(repo: RepoRef): string {\n  const slug = repo.name\n    .toLowerCase()\n    .replace(/[^a-z0-9-]/g, '-')\n    .replace(/-+/g, '-')\n    .replace(/^-+|-+$/g, '')\n  return slug || 'repo'\n}\n\nasync function detailOf(res: Response): Promise<string> {\n  const body = await res.text().catch(() => '')\n  try {\n    const parsed = JSON.parse(body) as { error?: string }\n    if (parsed.error) return parsed.error\n  } catch {\n    // Not JSON — fall through to the raw body.\n  }\n  return body.trim() || `HTTP ${res.status}`\n}\n\n/**\n * Create a project for this repo and provision its daemon.\n *\n * The only write in this module, and it runs only on an explicit choice. Both\n * calls are reported separately: a 402 on provision leaves a real project with\n * no daemon behind, and saying so is the difference between the user paying and\n * carrying on, or making a duplicate project tomorrow.\n */\nexport async function createProjectForRepo(\n  fetchImpl: typeof fetch,\n  cpUrl: string,\n  accessToken: string,\n  name: string,\n): Promise<CreateProjectOutcome> {\n  const headers = { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' }\n  let project: NamedProject\n  try {\n    const res = await fetchImpl(`${cpUrl}/me/projects`, {\n      method: 'POST',\n      headers,\n      body: JSON.stringify({ name }),\n      signal: AbortSignal.timeout(CP_TIMEOUT_MS),\n    })\n    if (!res.ok) return { ok: false, reason: 'not-created', detail: await detailOf(res) }\n    project = (await res.json()) as NamedProject\n  } catch (err) {\n    return { ok: false, reason: 'not-created', detail: err instanceof Error ? err.message : String(err) }\n  }\n\n  try {\n    const res = await fetchImpl(`${cpUrl}/me/projects/${encodeURIComponent(project.id)}/provision`, {\n      method: 'POST',\n      headers,\n      signal: AbortSignal.timeout(CP_TIMEOUT_MS),\n    })\n    if (res.status === 402) return { ok: false, reason: 'needs-plan', project, detail: await detailOf(res) }\n    if (!res.ok) return { ok: false, reason: 'not-provisioned', project, detail: await detailOf(res) }\n  } catch (err) {\n    return {\n      ok: false,\n      reason: 'not-provisioned',\n      project,\n      detail: err instanceof Error ? err.message : String(err),\n    }\n  }\n  return { ok: true, project }\n}\n\nexport function bindUrl(webUrl: string, projectId: string): string {\n  return `${webUrl}/config/repos?project=${encodeURIComponent(projectId)}`\n}\n\nexport function onboardingUrl(webUrl: string): string {\n  return `${webUrl}/onboarding`\n}\n\n/**\n * Offer to build the local graph now, and run it if they say yes.\n *\n * The door's own local path runs this same orchestrator, through the same\n * overrides seam — so the instrument question is asked exactly once and the\n * answer reaches the run as the flag it stands for. Returns whether a graph now\n * exists, so the caller can say \"now push it\" rather than \"build it, then push\n * it\".\n *\n * No reader (non-interactive) means no offer: printing the two commands is the\n * honest fallback, not running an extraction nobody asked for.\n */\nasync function offerLocalExtraction(\n  input: { project: { name: string } },\n  d: ConnectDeps,\n  out: (line: string) => void,\n  readLine: ((prompt: string) => Promise<string | undefined>) | undefined,\n): Promise<boolean> {\n  const run = d.orchestrator\n  if (!run || !readLine) return false\n  const answer = (await readLine('Build it now? [Y/n] '))?.trim().toLowerCase()\n  if (answer === 'n' || answer === 'no') return false\n  out('')\n  const code = await run(d.cwd ?? process.cwd(), {})\n  return code === 0\n}\n\n/**\n * Tell the user where this directory stands against the project they just\n * connected, and offer the two routes that put it in the graph.\n *\n * Read-only and best-effort by design. Not a git repo, not a GitHub remote, or a\n * control plane that won't answer all leave the user with an accurate short\n * message instead of a wrong offer.\n */\nexport async function runPostLoginConnect(input: {\n  cpUrl: string\n  webUrl: string\n  accessToken: string\n  project: { id: string; name: string }\n  /**\n   * The hosted daemon's base URL and push token (#1302).\n   *\n   * `neat sync --to` takes a URL, not a project name, and reads its token from\n   * `--token`/`NEAT_REMOTE_TOKEN` and never from the profile — so the project\n   * name this step used to print was not a command anyone could run. Both values\n   * are in hand at the call site. Absent, the push route is left unsaid rather\n   * than printed wrong.\n   */\n  endpoint?: string\n  pushToken?: string\n  me?: MeAccount\n  deps: ConnectDeps\n}): Promise<void> {\n  const d = input.deps\n  const out = d.out ?? ((line: string) => console.log(line))\n  const fetchImpl = d.fetchImpl ?? fetch\n  const cwd = d.cwd ?? process.cwd()\n  const detect = d.detectRepo ?? detectGitHubRepo\n  const readLine = d.readLine\n\n  const repo = await detect(cwd)\n  out('')\n\n  const cmd = commandPrefix()\n  // `--to` is a base URL and the token comes from the flag, never the profile\n  // (#1302). Printing the project name here produced a command that fails on\n  // `Failed to parse URL`. Without an endpoint there is no runnable push line to\n  // print, so the step says where to find one instead of inventing it.\n  const pushCmd = input.endpoint\n    ? `${cmd} sync --to ${input.endpoint}${input.pushToken ? ` --token ${input.pushToken}` : ''}`\n    : null\n  const pushInto = (label: string): string[] =>\n    pushCmd ? [`  ${pushCmd}`] : [`  Its daemon URL and token are on ${label} in the console: ${input.webUrl}`]\n\n  if (!repo) {\n    // No GitHub remote to bind, so pushing the local graph is the only route.\n    // The door only opens on a directory NEAT has never extracted, which makes\n    // \"no snapshot\" the common case here rather than the edge one — offering\n    // `sync --to` on its own sends the user at a command with nothing to push\n    // (#1272).\n    out(\"This directory has no GitHub remote, so it can't be bound to the project.\")\n    const hasGraph = await (d.hasLocalGraph ?? hasLocalSnapshot)(cwd)\n    if (!hasGraph) {\n      out(`A graph of this directory has to be built first, then pushed to ${input.project.name}.`)\n      const built = await offerLocalExtraction(input, d, out, readLine)\n      out('')\n      if (built) {\n        out(`Now push it to ${input.project.name}:`)\n        for (const line of pushInto(input.project.name)) out(line)\n      } else {\n        out(`When you're ready, build it and push it to ${input.project.name}:`)\n        out(`  ${cmd}`)\n        for (const line of pushInto(input.project.name)) out(line)\n      }\n      out(`  Manage projects and repos:   ${input.webUrl}`)\n      return\n    }\n    out(`  Push its graph to ${input.project.name}:`)\n    for (const line of pushInto(input.project.name)) out(line)\n    out(`  Manage projects and repos:   ${input.webUrl}`)\n    return\n  }\n\n  const slug = `${repo.owner}/${repo.name}`\n  const bound = await listBoundRepos(fetchImpl, input.cpUrl, input.accessToken, input.project.id)\n  const match = bound?.find((r) => r.owner === repo.owner && r.name === repo.name)\n\n  if (match) {\n    const state = match.syncStatus ? ` (${match.syncStatus})` : ''\n    out(`${slug} is bound to ${input.project.name}${state} — hosted NEAT extracts it for you.`)\n    out(`  See the graph:  ${input.webUrl}`)\n    return\n  }\n\n  out(`${slug} isn't in ${input.project.name} — logging in connected your account, not this repo.`)\n  out('')\n\n  // Which project the repo belongs to was being decided for the user, silently,\n  // in favour of the one the login happened to connect to. Ask it (#1272). No\n  // default and no recommendation: a project each costs a daemon each, and a\n  // shared project costs the collision below, and which of those is worse\n  // depends on things the CLI can't see.\n  const suggested = projectNameForRepo(repo)\n  out('Where should this repo go?')\n  out('')\n  out(`1) A project of its own, called ${suggested}`)\n  out(`2) ${input.project.name} — the project this login connected to`)\n  for (const line of sharedProjectCaveat(bound)) out(`   ${line}`)\n  out('3) Neither, for now')\n  out('')\n\n  const answer = readLine ? (await readLine('Choose 1, 2 or 3 (Enter skips): '))?.trim() : undefined\n\n  if (answer === '1') {\n    out('')\n    const outcome = await createProjectForRepo(fetchImpl, input.cpUrl, input.accessToken, suggested)\n    reportCreate(outcome, input.webUrl, cmd, input.project.name, out)\n    return\n  }\n\n  // Both remaining routes point at a project; 2 is the one just connected to,\n  // and anything else (including Enter) is the no-op.\n  if (answer === '2') {\n    out('')\n    out(`Two ways into ${input.project.name} — either is fine, and you can do both:`)\n    out('')\n    // `github.installed` is absent on a control plane that predates it; when we\n    // don't know, describe the destination rather than asserting a state.\n    const installed = input.me?.github?.installed\n    out(\n      installed === false\n        ? '  Bind it (install the GitHub App first) — hosted NEAT keeps it in sync:'\n        : installed === true\n          ? '  Bind it — hosted NEAT clones and extracts it, and keeps it in sync:'\n          : '  Bind it through the console — hosted NEAT keeps it in sync:',\n    )\n    out(`    ${bindUrl(input.webUrl, input.project.id)}`)\n    out('')\n    const hasGraph = await (d.hasLocalGraph ?? hasLocalSnapshot)(cwd)\n    if (hasGraph) {\n      out('  Or push the graph on this machine now — a snapshot, not a subscription:')\n      for (const line of pushInto(input.project.name)) out(`  ${line}`)\n    } else {\n      // `sync --to` pushes an existing snapshot; there's nothing to push in a\n      // repo NEAT has never extracted, so name the step that comes first.\n      out('  Or build a graph here and push it — a snapshot, not a subscription:')\n      out(`    ${cmd}`)\n      for (const line of pushInto(input.project.name)) out(`  ${line}`)\n    }\n    return\n  }\n\n  out('')\n  out('No problem — when you want this repo in the graph:')\n  out(`  Its own project:   ${input.webUrl}`)\n  out(`  Or into ${input.project.name}: ${bindUrl(input.webUrl, input.project.id)}`)\n}\n\n/**\n * What to say about putting a second repo in a project someone else's files\n * already live in.\n *\n * Two repos in one project mint the same FileNode ids for the same relative\n * paths, so each sync's retire sweep can drop the other's files (#1294). That is\n * a real cost of choosing the shared project today, so it is stated on the\n * option rather than left for the user to discover in a graph that quietly\n * shrank. `null` means the control plane didn't answer — say the general thing\n * rather than a count we don't have.\n */\nfunction sharedProjectCaveat(bound: BoundRepo[] | null): string[] {\n  const hazard = \"Two repos in one project can currently retire each other's files (#1294),\"\n  if (!bound) return [hazard, 'so a graph there may end up short of code until that is fixed.']\n  if (bound.length === 0) return ['Nothing else is bound there yet.', `Adding a second repo later would hit #1294 — ${hazard.toLowerCase()}`]\n  const names = bound.map((r) => `${r.owner}/${r.name}`).join(', ')\n  return [\n    `${bound.length} already there: ${names}.`,\n    hazard,\n    'so both graphs may end up short of code until that is fixed.',\n  ]\n}\n\n/**\n * Report a project creation, telling the three end states apart.\n *\n * \"Created and running\", \"created but needs a plan\", and \"nothing was created\"\n * lead to different next actions, and conflating them costs the user either a\n * duplicate project or a wait for a daemon that was never asked for.\n */\nfunction reportCreate(\n  outcome: CreateProjectOutcome,\n  webUrl: string,\n  cmd: string,\n  connectedTo: string,\n  out: (line: string) => void,\n): void {\n  if (outcome.ok) {\n    out(`Created ${outcome.project.name} and started its daemon.`)\n    out('')\n    // The profile this login wrote still points at the old project. Saying so\n    // beats letting the next `neat` command read a graph they didn't mean.\n    out(`This CLI is still pointed at ${connectedTo}. Switch it to the new project with:`)\n    out(`  ${cmd} login --project ${outcome.project.name}`)\n    out('')\n    // That login prints the new daemon's URL and token, which is what a push\n    // needs — this step can't print a `sync --to` line for a project whose\n    // daemon it has never seen (#1302).\n    out('Then bind this repo to it:')\n    out(`  ${bindUrl(webUrl, outcome.project.id)}`)\n    return\n  }\n\n  if (outcome.reason === 'needs-plan') {\n    out(`Created ${outcome.project.name}, but starting a daemon for it needs a plan.`)\n    out(`  Choose one:  ${webUrl}/checkout`)\n    out('')\n    out(\"The project is made and keeps its name, so there's nothing to redo here afterwards.\")\n    return\n  }\n\n  if (outcome.reason === 'not-provisioned') {\n    out(`Created ${outcome.project.name}, but its daemon didn't start: ${outcome.detail}`)\n    out('')\n    out('The project exists — start it from the console rather than making a second one:')\n    out(`  ${webUrl}`)\n    return\n  }\n\n  out(`Couldn't create the project: ${outcome.detail}`)\n  out(`Nothing was made, so this is safe to retry, or do it in the console: ${webUrl}`)\n}\n","// `neat doctor` — a read-only preflight that answers \"why isn't this working?\"\n// in one command. Getting to a live graph takes a few separate things — the\n// right Node, a project set up in this directory, the daemon actually up — and\n// when one is missing nothing points at which. Doctor probes each and prints a\n// line per check, with a fix on the ones that failed.\n//\n// It's a diagnostic command alongside the `connector` family (cli-surface.md),\n// not one of the locked query verbs. Two properties set it apart from the query\n// verbs and from `neat ps`: it is the command you reach for *because* something\n// is down, so it must run even when the daemon is unreachable and never throw\n// on the way; and it does a real HTTP `/health` round-trip rather than reading\n// a pid, so it catches a daemon whose process is alive but whose REST surface\n// isn't answering.\n//\n// Exit code is its own thing (cli-surface.md §neat doctor): 0 when every check\n// passes, 1 when any check fails. It deliberately never exits 3 — a daemon\n// being down is a normal finding doctor reports, not a fatal error that aborts\n// the run.\n//\n// v1 checks the daemon path only: Node runtime, project-in-this-directory, and\n// daemon reachability. The dashboard/web-port probe and an index-readiness line\n// are held back for later (the readiness signal rides with the empty-result\n// work). Handlers take their cwd, environment, `fetch`, and record reader as\n// injected deps so the whole surface is testable without a live daemon.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport { readDaemonRecord, type DaemonRecord } from './daemon.js'\nimport { resolveAuthToken } from './cli-client.js'\nimport * as style from './style.js'\n\n// ── deps / injection ─────────────────────────────────────────────────────────\n\nexport interface DoctorCliDeps {\n  cwd?: string\n  env?: NodeJS.ProcessEnv\n  // The running Node version. Defaults to this process's; a test overrides it to\n  // exercise the below-floor branch without a second Node.\n  nodeVersion?: string\n  // Test seam for the daemon `/health` probe. Undefined → the platform `fetch`.\n  fetchImpl?: typeof fetch\n  // Test seam for the per-directory daemon record read. Undefined → the real\n  // `neat-out/daemon.json` reader.\n  readRecord?: (scanPath: string) => Promise<DaemonRecord | null>\n  out?: (line: string) => void\n}\n\ninterface ResolvedDeps {\n  cwd: string\n  env: NodeJS.ProcessEnv\n  nodeVersion: string\n  fetchImpl: typeof fetch\n  readRecord: (scanPath: string) => Promise<DaemonRecord | null>\n  out: (line: string) => void\n}\n\nfunction resolveDeps(deps: DoctorCliDeps): ResolvedDeps {\n  return {\n    cwd: deps.cwd ?? process.cwd(),\n    env: deps.env ?? process.env,\n    nodeVersion: deps.nodeVersion ?? process.versions.node,\n    fetchImpl: deps.fetchImpl ?? fetch,\n    readRecord: deps.readRecord ?? readDaemonRecord,\n    out: deps.out ?? ((line: string) => console.log(line)),\n  }\n}\n\n// ── check result shape ───────────────────────────────────────────────────────\n\nexport interface DoctorCheck {\n  name: string\n  ok: boolean\n  detail: string\n  // A one-line remediation, present only when the check failed.\n  fix?: string\n}\n\nconst NODE_FLOOR = 20\nconst HEALTH_TIMEOUT_MS = 3000\n\n// ── individual checks ────────────────────────────────────────────────────────\n\nfunction checkNode(nodeVersion: string): DoctorCheck {\n  const major = Number.parseInt(nodeVersion.split('.')[0] ?? '', 10)\n  const ok = Number.isFinite(major) && major >= NODE_FLOOR\n  return ok\n    ? { name: 'node', ok, detail: `v${nodeVersion} (>= ${NODE_FLOOR} required)` }\n    : {\n        name: 'node',\n        ok,\n        detail: `v${nodeVersion} — NEAT needs Node ${NODE_FLOOR} or newer`,\n        fix: `install Node ${NODE_FLOOR}.x (e.g. \\`nvm install ${NODE_FLOOR}\\`) and re-run`,\n      }\n}\n\n// Does `<cwd>/neat-out/` exist? First run writes it and it survives across\n// restarts, so it's the honest \"is this a NEAT project\" signal — independent of\n// whether a daemon happens to be running right now.\nasync function neatOutExists(cwd: string): Promise<boolean> {\n  try {\n    const st = await fs.stat(path.join(cwd, 'neat-out'))\n    return st.isDirectory()\n  } catch {\n    return false\n  }\n}\n\nasync function checkProject(\n  cwd: string,\n  record: DaemonRecord | null,\n): Promise<DoctorCheck> {\n  if (record) {\n    return {\n      name: 'project',\n      ok: true,\n      detail: `\"${record.project}\" — set up in this directory (daemon record on REST ${record.ports.rest})`,\n    }\n  }\n  // No daemon.json (a stopped daemon clears its own on graceful exit), so lean\n  // on neat-out/ to tell \"set up but not running\" from \"not a project here\".\n  if (await neatOutExists(cwd)) {\n    return {\n      name: 'project',\n      ok: true,\n      detail: 'set up in this directory (no live daemon record — it may be stopped)',\n    }\n  }\n  return {\n    name: 'project',\n    ok: false,\n    detail: 'no NEAT project in this directory',\n    fix: 'set one up: `neat .`',\n  }\n}\n\n// The daemon URL doctor probes. Resolution mirrors the query verbs' precedence\n// without importing them (which would cycle through cli.ts): an explicit env\n// pin wins, then the directory's own recorded REST port, then the loopback\n// default.\nfunction resolveHealthUrl(env: NodeJS.ProcessEnv, record: DaemonRecord | null): string {\n  const explicit = env.NEAT_API_URL ?? env.NEAT_CORE_URL\n  if (explicit && explicit.length > 0) return explicit.replace(/\\/$/, '')\n  if (record) return `http://localhost:${record.ports.rest}`\n  return 'http://localhost:8080'\n}\n\ninterface HealthBody {\n  ok?: boolean\n  project?: string\n  projects?: Array<{ name?: string; nodeCount?: number; edgeCount?: number }>\n}\n\nfunction summariseHealth(url: string, body: HealthBody): string {\n  const projects = body.projects ?? []\n  const nodes = projects.reduce((n, p) => n + (p.nodeCount ?? 0), 0)\n  const edges = projects.reduce((n, p) => n + (p.edgeCount ?? 0), 0)\n  const proj = body.project ?? projects[0]?.name\n  const graph = projects.length > 0 ? ` — ${nodes} nodes / ${edges} edges` : ''\n  return `up at ${url}${proj ? ` (project \"${proj}\"${graph})` : ''}`\n}\n\nasync function checkDaemon(deps: ResolvedDeps, record: DaemonRecord | null): Promise<DoctorCheck> {\n  const url = resolveHealthUrl(deps.env, record)\n  const token = resolveAuthToken(deps.env)\n  const headers: Record<string, string> = token ? { authorization: `Bearer ${token}` } : {}\n  try {\n    const res = await deps.fetchImpl(`${url}/health`, {\n      headers,\n      signal: AbortSignal.timeout(HEALTH_TIMEOUT_MS),\n    })\n    if (res.status === 401 || res.status === 403) {\n      return {\n        name: 'daemon',\n        ok: false,\n        detail: `up at ${url}, but rejected the request (${res.status})`,\n        fix: 'set NEAT_AUTH_TOKEN to the daemon\\'s token',\n      }\n    }\n    if (!res.ok) {\n      return {\n        name: 'daemon',\n        ok: false,\n        detail: `reachable at ${url} but /health returned ${res.status}`,\n        fix: 'check the daemon logs',\n      }\n    }\n    const body = (await res.json().catch(() => ({}))) as HealthBody\n    return { name: 'daemon', ok: true, detail: summariseHealth(url, body) }\n  } catch {\n    // Connection refused, DNS, or the 3s timeout — the daemon isn't answering.\n    // This is a finding, not a crash: report it and keep going.\n    return {\n      name: 'daemon',\n      ok: false,\n      detail: `down — nothing answering at ${url}`,\n      fix: 'start it: `neat .`  (or `neat watch`)',\n    }\n  }\n}\n\n// ── run + render ─────────────────────────────────────────────────────────────\n\nexport async function runDoctorChecks(deps: DoctorCliDeps = {}): Promise<DoctorCheck[]> {\n  const d = resolveDeps(deps)\n  const record = await d.readRecord(d.cwd).catch(() => null)\n  return [checkNode(d.nodeVersion), await checkProject(d.cwd, record), await checkDaemon(d, record)]\n}\n\n// Longest check name, for aligning the human table.\nconst NAME_COL = 'project'.length\n\nfunction renderHuman(checks: DoctorCheck[], out: (line: string) => void): void {\n  out(style.heading('neat doctor') + style.dim(\" — checking this project's setup\"))\n  out('')\n  for (const c of checks) {\n    const mark = c.ok ? style.ok(style.sym.ok) : style.error(style.sym.fail)\n    out(`  ${mark}  ${style.dim(c.name.padEnd(NAME_COL))}  ${c.detail}`)\n    if (!c.ok && c.fix) out(`  ${' '.repeat(NAME_COL + 3)}${style.dim('fix:')} ${style.warn(c.fix)}`)\n  }\n  out('')\n  const failed = checks.filter((c) => !c.ok).length\n  out(failed === 0 ? style.ok('all good.') : style.warn(`${failed} check${failed === 1 ? '' : 's'} failed.`))\n}\n\n// The whole command: parse `--json`, run the checks, print, return the exit\n// code (0 = all pass, 1 = any fail). Unknown flags are a misuse — exit 2,\n// matching the rest of the CLI — handled before any probe runs.\nexport async function runDoctorCommand(argv: string[], deps: DoctorCliDeps = {}): Promise<number> {\n  const out = deps.out ?? ((line: string) => console.log(line))\n  let json = false\n  for (const arg of argv) {\n    if (arg === '--json') json = true\n    else if (arg === '-h' || arg === '--help') {\n      out('usage: neat doctor [--json]')\n      out('  Probe this directory\\'s NEAT setup: Node version, project, daemon.')\n      out('  Exit 0 when every check passes, 1 when any fails.')\n      return 0\n    } else {\n      out(`neat doctor: unknown argument \"${arg}\"`)\n      return 2\n    }\n  }\n\n  const checks = await runDoctorChecks(deps)\n  if (json) out(JSON.stringify({ ok: checks.every((c) => c.ok), checks }, null, 2))\n  else renderHuman(checks, out)\n\n  return checks.every((c) => c.ok) ? 0 : 1\n}\n","// REST helper + CLI verb implementations for `neat <verb>` (ADR-050).\n//\n// The HttpClient and its createHttpClient factory are the \"shared REST helper\n// module\" the contract calls for — one endpoint surface, two consumers\n// (`packages/mcp/src/client.ts` re-exports from here, the CLI dispatcher\n// imports it directly).\n//\n// Verb handlers live alongside the client because they're tightly coupled:\n// each verb maps 1:1 to an MCP tool from ADR-039, but produces the structured\n// `{ summary, block, confidence, provenance }` shape (ADR-050 #3) in pure\n// data form. cli.ts formats that shape into either human-readable text or\n// `--json` output.\n\nimport type {\n  AskResult,\n  BlastRadiusAffectedNode,\n  BlastRadiusResult,\n  Divergence,\n  DivergenceResult,\n  DivergenceType,\n  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  HypotheticalAction,\n  ObservedDependenciesResult,\n  PolicyViolation,\n  ProjectListEntry,\n  RootCauseResult,\n  TransitiveDependenciesResult,\n} from '@neat.is/types'\nimport { Provenance } from '@neat.is/types'\nimport * as style from './style.js'\nimport { deployContextsFor, deployHintLines, flagMismatchPhrase } from './incidents-render.js'\n\n// ──────────────────────────────────────────────────────────────────────────\n// REST client\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface HttpClient {\n  get<T>(path: string): Promise<T>\n  post?<T>(path: string, body: unknown): Promise<T>\n}\n\nexport class HttpError extends Error {\n  constructor(\n    public readonly status: number,\n    message: string,\n    public readonly responseBody: string = '',\n  ) {\n    super(message)\n    this.name = 'HttpError'\n  }\n}\n\n// Network-level failures (ECONNREFUSED, ETIMEDOUT, DNS) — distinct from\n// HttpError so the CLI can map them to exit code 3 (daemon-down) without\n// parsing error strings.\nexport class TransportError extends Error {\n  constructor(message: string) {\n    super(message)\n    this.name = 'TransportError'\n  }\n}\n\n// Single-source the bearer for every first-party read (ADR-073 §3). The CLI\n// query verbs, `neat sync`, the MCP server, and the snapshot push all read the\n// token from here so a new read site can't quietly skip auth. Returns\n// undefined when the env var is unset or empty — a loopback dev daemon stays\n// reachable without a token.\nexport function resolveAuthToken(env: NodeJS.ProcessEnv = process.env): string | undefined {\n  const t = env.NEAT_AUTH_TOKEN\n  return t && t.length > 0 ? t : undefined\n}\n\nexport function createHttpClient(\n  baseUrl: string,\n  bearerToken?: string,\n  // Tests inject a fetch stub the way the login-sso path does; production\n  // leaves it unset and the module-global fetch is used.\n  fetchImpl: typeof fetch = fetch,\n): HttpClient {\n  const root = baseUrl.replace(/\\/$/, '')\n  const authHeader: Record<string, string> = bearerToken && bearerToken.length > 0\n    ? { authorization: `Bearer ${bearerToken}` }\n    : {}\n  return {\n    async get<T>(path: string): Promise<T> {\n      let res: Response\n      try {\n        res = await fetchImpl(`${root}${path}`, {\n          headers: { ...authHeader },\n        })\n      } catch (err) {\n        throw new TransportError(\n          `cannot reach neat-core at ${root}: ${(err as Error).message}`,\n        )\n      }\n      if (!res.ok) {\n        const body = await res.text().catch(() => '')\n        throw new HttpError(\n          res.status,\n          `${res.status} ${res.statusText} on GET ${path}: ${body}`,\n          body,\n        )\n      }\n      return (await res.json()) as T\n    },\n    async post<T>(path: string, body: unknown): Promise<T> {\n      let res: Response\n      try {\n        res = await fetchImpl(`${root}${path}`, {\n          method: 'POST',\n          headers: { 'content-type': 'application/json', ...authHeader },\n          body: JSON.stringify(body),\n        })\n      } catch (err) {\n        throw new TransportError(\n          `cannot reach neat-core at ${root}: ${(err as Error).message}`,\n        )\n      }\n      if (!res.ok) {\n        const text = await res.text().catch(() => '')\n        throw new HttpError(\n          res.status,\n          `${res.status} ${res.statusText} on POST ${path}: ${text}`,\n          text,\n        )\n      }\n      return (await res.json()) as T\n    },\n  }\n}\n\n// Project routing per ADR-050 #2: `--project <name>` (handled in cli.ts) →\n// `NEAT_PROJECT` env → `default`. The default routes hit the legacy\n// unprefixed URLs which the core resolves to project=`default`.\nfunction projectPath(project: string | undefined, suffix: string): string {\n  if (!project) return suffix\n  return `/projects/${encodeURIComponent(project)}${suffix}`\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Verb result shape (ADR-050 #3)\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface VerbResult {\n  // NL paragraph. What was found and why it matters.\n  summary: string\n  // Structured payload — usually a bulleted list. Empty when the summary\n  // already conveys everything.\n  block?: string\n  // Per-result confidence in [0, 1]. Undefined → footer reads \"n/a\".\n  confidence?: number\n  // Per-result provenance. String, array (mixed paths), or undefined.\n  provenance?: string | string[]\n}\n\n// Common shape the nine verbs produce. cli.ts renders this to text or JSON.\n\n// ──────────────────────────────────────────────────────────────────────────\n// Verbs\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface RootCauseInput {\n  errorNode: string\n  errorId?: string\n  project?: string\n}\n\nexport async function runRootCause(\n  client: HttpClient,\n  input: RootCauseInput,\n): Promise<VerbResult> {\n  const qs = input.errorId ? `?errorId=${encodeURIComponent(input.errorId)}` : ''\n  const path = projectPath(\n    input.project,\n    `/graph/root-cause/${encodeURIComponent(input.errorNode)}${qs}`,\n  )\n  try {\n    const result = await client.get<RootCauseResult>(path)\n    const arrowPath = result.traversalPath.join(' ← ')\n    const provenances = result.edgeProvenances.length\n      ? result.edgeProvenances.join(', ')\n      : '(direct, no edges traversed)'\n    const summary =\n      `Root cause for ${input.errorNode} is ${result.rootCauseNode}. ` +\n      result.rootCauseReason +\n      (result.fixRecommendation ? ` Recommended fix: ${result.fixRecommendation}.` : '')\n    const blockLines = [\n      `Traversal path: ${arrowPath}`,\n      `Edge provenances: ${provenances}`,\n    ]\n    if (result.fixRecommendation) blockLines.push(`Recommended fix: ${result.fixRecommendation}`)\n    return {\n      summary,\n      block: blockLines.join('\\n'),\n      confidence: result.confidence,\n      provenance: result.edgeProvenances.length ? result.edgeProvenances : undefined,\n    }\n  } catch (err) {\n    if (err instanceof HttpError && err.status === 404) {\n      return {\n        summary: `No root cause found for ${input.errorNode}. The node may be healthy, or it may not exist in the graph.`,\n      }\n    }\n    throw err\n  }\n}\n\nexport interface BlastRadiusInput {\n  nodeId: string\n  depth?: number\n  project?: string\n}\n\nexport async function runBlastRadius(\n  client: HttpClient,\n  input: BlastRadiusInput,\n): Promise<VerbResult> {\n  const qs = input.depth !== undefined ? `?depth=${input.depth}` : ''\n  const path = projectPath(\n    input.project,\n    `/graph/blast-radius/${encodeURIComponent(input.nodeId)}${qs}`,\n  )\n  try {\n    const result = await client.get<BlastRadiusResult>(path)\n    if (result.totalAffected === 0) {\n      return {\n        summary: `${result.origin} has no dependents. Nothing else would break if it failed.`,\n      }\n    }\n    const sorted = [...result.affectedNodes].sort(\n      (a, b) => a.distance - b.distance || a.nodeId.localeCompare(b.nodeId),\n    )\n    const blockLines = sorted.map(formatBlastEntry)\n    const minConfidence = sorted.reduce(\n      (m, n) => Math.min(m, n.confidence),\n      Number.POSITIVE_INFINITY,\n    )\n    const provenances = [...new Set(sorted.map((n) => n.edgeProvenance))]\n    return {\n      summary: `Blast radius for ${result.origin}: ${result.totalAffected} dependent node${result.totalAffected === 1 ? '' : 's'} would break if it changed.`,\n      block: blockLines.join('\\n'),\n      confidence: Number.isFinite(minConfidence) ? minConfidence : undefined,\n      provenance: provenances.length ? provenances : undefined,\n    }\n  } catch (err) {\n    if (err instanceof HttpError && err.status === 404) {\n      return { summary: `Node ${input.nodeId} not found in the graph.` }\n    }\n    throw err\n  }\n}\n\nfunction formatBlastEntry(n: BlastRadiusAffectedNode): string {\n  const tag = n.edgeProvenance === Provenance.STALE ? ' [STALE — last seen too long ago]' : ''\n  return `  • ${n.nodeId} (distance ${n.distance}, ${n.edgeProvenance})${tag}`\n}\n\nexport interface DependenciesInput {\n  nodeId: string\n  depth?: number\n  project?: string\n}\n\nexport async function runDependencies(\n  client: HttpClient,\n  input: DependenciesInput,\n): Promise<VerbResult> {\n  const depth = input.depth ?? 3\n  const path = projectPath(\n    input.project,\n    `/graph/dependencies/${encodeURIComponent(input.nodeId)}?depth=${depth}`,\n  )\n  try {\n    const result = await client.get<TransitiveDependenciesResult>(path)\n    if (result.total === 0) {\n      return {\n        summary:\n          depth === 1\n            ? `${input.nodeId} has no direct dependencies in the graph.`\n            : `${input.nodeId} has no dependencies (BFS to depth ${depth}).`,\n      }\n    }\n    const byDistance = new Map<number, typeof result.dependencies>()\n    for (const dep of result.dependencies) {\n      const ring = byDistance.get(dep.distance) ?? []\n      ring.push(dep)\n      byDistance.set(dep.distance, ring)\n    }\n    const blockLines: string[] = []\n    for (const distance of [...byDistance.keys()].sort((a, b) => a - b)) {\n      const label = distance === 1 ? 'Direct (distance 1)' : `Distance ${distance}`\n      blockLines.push(`${label}:`)\n      for (const dep of byDistance.get(distance)!) {\n        blockLines.push(`  • ${dep.nodeId} — ${dep.edgeType} (${dep.provenance})`)\n      }\n    }\n    const provenances = [...new Set(result.dependencies.map((d) => d.provenance))]\n    const directCount = byDistance.get(1)?.length ?? 0\n    const summary =\n      depth === 1\n        ? `${input.nodeId} has ${directCount} direct dependenc${directCount === 1 ? 'y' : 'ies'}.`\n        : `${input.nodeId} has ${result.total} dependenc${result.total === 1 ? 'y' : 'ies'} reachable to depth ${depth} (${directCount} direct).`\n    return { summary, block: blockLines.join('\\n'), provenance: provenances }\n  } catch (err) {\n    if (err instanceof HttpError && err.status === 404) {\n      return { summary: `Node ${input.nodeId} not found in the graph.` }\n    }\n    throw err\n  }\n}\n\n// Render one OBSERVED dependency. The edge is file-grained, so when its source\n// isn't the node we asked about (a service's owned file made the call) name the\n// originating file — that's the file-first answer, not a service rollup.\nfunction observedDepLine(nodeId: string, e: GraphEdge): string {\n  const via = e.source !== nodeId ? ` (via ${e.source})` : ''\n  return `  • ${e.target} — ${e.type}${via}${edgeMeta(e)}`\n}\n\nexport async function runObservedDependencies(\n  client: HttpClient,\n  input: DependenciesInput,\n): Promise<VerbResult> {\n  try {\n    const result = await client.get<ObservedDependenciesResult>(\n      projectPath(\n        input.project,\n        `/graph/observed-dependencies/${encodeURIComponent(input.nodeId)}`,\n      ),\n    )\n    if (result.dependencies.length === 0) {\n      // A pure receiver — hit at runtime but calling nothing downstream — is\n      // fully observed, so don't imply OTel is down. That note is honest only\n      // when nothing has been observed and static deps exist.\n      if (result.observed) {\n        return {\n          summary:\n            `${input.nodeId} makes no outbound runtime calls, but OTel has observed it ` +\n            `receiving traffic on ${result.inboundObservedCount} inbound call ` +\n            `path${result.inboundObservedCount === 1 ? '' : 's'} — it's a pure receiver.`,\n          provenance: Provenance.OBSERVED,\n        }\n      }\n      const note = result.hasExtractedOutbound\n        ? ' Static (EXTRACTED) dependencies exist but no runtime traffic has been seen — is OTel running?'\n        : ''\n      return { summary: `No OBSERVED dependencies for ${input.nodeId}.${note}` }\n    }\n    const blockLines = result.dependencies.map((e) => observedDepLine(input.nodeId, e))\n    return {\n      summary: `${input.nodeId} has ${result.dependencies.length} runtime dependenc${result.dependencies.length === 1 ? 'y' : 'ies'} confirmed by OTel.`,\n      block: blockLines.join('\\n'),\n      provenance: Provenance.OBSERVED,\n    }\n  } catch (err) {\n    if (err instanceof HttpError && err.status === 404) {\n      return { summary: `Node ${input.nodeId} not found in the graph.` }\n    }\n    throw err\n  }\n}\n\nfunction edgeMeta(e: GraphEdge): string {\n  const bits: string[] = []\n  if (e.signal) {\n    bits.push(`spans=${e.signal.spanCount}`)\n    if (e.signal.errorCount > 0) bits.push(`errors=${e.signal.errorCount}`)\n    if (e.signal.lastObservedAgeMs !== undefined) {\n      bits.push(`age=${formatDuration(e.signal.lastObservedAgeMs)}`)\n    }\n  } else if (e.callCount !== undefined) {\n    bits.push(`callCount=${e.callCount}`)\n  }\n  if (e.lastObserved) bits.push(`lastObserved=${e.lastObserved}`)\n  if (e.confidence !== undefined) bits.push(`confidence=${e.confidence}`)\n  return bits.length ? ` [${bits.join(', ')}]` : ''\n}\n\nfunction formatDuration(ms: number): string {\n  if (ms < 1000) return `${Math.round(ms)}ms`\n  const s = Math.round(ms / 1000)\n  if (s < 60) return `${s}s`\n  const m = Math.round(s / 60)\n  if (m < 60) return `${m}m`\n  const h = Math.round(m / 60)\n  if (h < 48) return `${h}h`\n  return `${Math.round(h / 24)}d`\n}\n\nexport interface IncidentsInput {\n  nodeId?: string\n  limit?: number\n  project?: string\n}\n\n// `neat incidents` shape: with a node id, returns that node's incidents.\n// Without one, returns the global recent log.\nexport async function runIncidents(\n  client: HttpClient,\n  input: IncidentsInput,\n): Promise<VerbResult> {\n  const path = input.nodeId\n    ? projectPath(input.project, `/incidents/${encodeURIComponent(input.nodeId)}`)\n    : projectPath(input.project, '/incidents')\n  try {\n    const body = await client.get<{ count: number; total: number; events: ErrorEvent[] }>(path)\n    const events = body.events\n    if (events.length === 0) {\n      return {\n        summary: input.nodeId\n          ? `No incidents recorded against ${input.nodeId}.`\n          : 'No incidents recorded.',\n      }\n    }\n    const ordered = [...events].reverse().slice(0, input.limit ?? 20)\n    const contexts = await deployContextsFor(ordered, (nodeId) =>\n      client\n        .get<{ node?: { observedDeployContext?: unknown } }>(\n          projectPath(input.project, `/graph/node/${encodeURIComponent(nodeId)}`),\n        )\n        .then((r) => r.node))\n    const blockLines: string[] = []\n    for (const ev of ordered) {\n      blockLines.push(`  ${ev.timestamp} — ${ev.service}: ${ev.errorMessage}`)\n      if (ev.exceptionType) blockLines.push(`    exception: ${ev.exceptionType}`)\n      for (const l of deployHintLines(contexts.get(ev.id))) blockLines.push(`    ${l}`)\n      blockLines.push(`    trace=${ev.traceId} span=${ev.spanId}`)\n    }\n    const target = input.nodeId ?? 'the project'\n    return {\n      summary: `${target} has ${body.total} recorded incident${body.total === 1 ? '' : 's'}; showing the ${ordered.length} most recent.`,\n      block: blockLines.join('\\n'),\n      provenance: Provenance.OBSERVED,\n    }\n  } catch (err) {\n    if (err instanceof HttpError && err.status === 404) {\n      return { summary: `Node ${input.nodeId ?? ''} not found in the graph.` }\n    }\n    throw err\n  }\n}\n\nexport interface SearchInput {\n  query: string\n  project?: string\n}\n\ninterface SearchResponse {\n  query: string\n  provider?: 'ollama' | 'transformers' | 'substring'\n  matches: (GraphNode & { score?: number })[]\n}\n\nexport async function runSearch(\n  client: HttpClient,\n  input: SearchInput,\n): Promise<VerbResult> {\n  const result = await client.get<SearchResponse>(\n    projectPath(input.project, `/search?q=${encodeURIComponent(input.query)}`),\n  )\n  if (result.matches.length === 0) {\n    return { summary: `No matches for \"${input.query}\".` }\n  }\n  const provider = result.provider ?? 'substring'\n  const blockLines: string[] = []\n  let topScore: number | undefined\n  for (const n of result.matches) {\n    const score = provider !== 'substring' && typeof n.score === 'number' ? n.score : undefined\n    const scoreBit = score !== undefined ? ` [score=${score.toFixed(2)}]` : ''\n    if (score !== undefined && (topScore === undefined || score > topScore)) topScore = score\n    blockLines.push(\n      `  • ${n.id} (${n.type}) — ${(n as { name?: string }).name ?? n.id}${scoreBit}`,\n    )\n  }\n  return {\n    summary: `Found ${result.matches.length} match${result.matches.length === 1 ? '' : 'es'} for \"${input.query}\" via ${provider} provider.`,\n    block: blockLines.join('\\n'),\n    confidence: topScore,\n  }\n}\n\nexport interface DiffInput {\n  againstSnapshot: string\n  project?: string\n}\n\ninterface GraphDiffResponse {\n  base: { exportedAt?: string }\n  current: { exportedAt: string }\n  added: { nodes: GraphNode[]; edges: GraphEdge[] }\n  removed: { nodes: GraphNode[]; edges: GraphEdge[] }\n  changed: {\n    nodes: { id: string; before: GraphNode; after: GraphNode }[]\n    edges: { id: string; before: GraphEdge; after: GraphEdge }[]\n  }\n}\n\nexport async function runDiff(client: HttpClient, input: DiffInput): Promise<VerbResult> {\n  const result = await client.get<GraphDiffResponse>(\n    projectPath(\n      input.project,\n      `/graph/diff?against=${encodeURIComponent(input.againstSnapshot)}`,\n    ),\n  )\n  const total =\n    result.added.nodes.length +\n    result.added.edges.length +\n    result.removed.nodes.length +\n    result.removed.edges.length +\n    result.changed.nodes.length +\n    result.changed.edges.length\n  const baseLabel = result.base.exportedAt ?? 'unknown'\n  if (total === 0) {\n    return {\n      summary: `No differences between the current graph and ${input.againstSnapshot} (base exportedAt=${baseLabel}).`,\n    }\n  }\n  const blockLines: string[] = [\n    `  base exportedAt:    ${baseLabel}`,\n    `  current exportedAt: ${result.current.exportedAt}`,\n    '',\n  ]\n  if (result.added.nodes.length || result.added.edges.length) {\n    blockLines.push('Added:')\n    for (const n of result.added.nodes) blockLines.push(`  + node ${n.id} (${n.type})`)\n    for (const e of result.added.edges)\n      blockLines.push(`  + edge ${e.id} — ${e.source} -> ${e.target} (${e.type}, ${e.provenance})`)\n    blockLines.push('')\n  }\n  if (result.removed.nodes.length || result.removed.edges.length) {\n    blockLines.push('Removed:')\n    for (const n of result.removed.nodes) blockLines.push(`  - node ${n.id} (${n.type})`)\n    for (const e of result.removed.edges)\n      blockLines.push(`  - edge ${e.id} — ${e.source} -> ${e.target} (${e.type}, ${e.provenance})`)\n    blockLines.push('')\n  }\n  if (result.changed.nodes.length || result.changed.edges.length) {\n    blockLines.push('Changed:')\n    for (const c of result.changed.nodes) {\n      blockLines.push(`  ~ node ${c.id} — ${summariseAttrDiff(c.before, c.after)}`)\n    }\n    for (const c of result.changed.edges) {\n      const provBit =\n        c.before.provenance !== c.after.provenance\n          ? `provenance ${c.before.provenance} → ${c.after.provenance}`\n          : summariseAttrDiff(c.before, c.after)\n      blockLines.push(`  ~ edge ${c.id} — ${provBit}`)\n    }\n  }\n  return {\n    summary: `Diff against ${input.againstSnapshot}: ${total} change${total === 1 ? '' : 's'} between the snapshot and the live graph.`,\n    block: blockLines.join('\\n').trimEnd(),\n  }\n}\n\nfunction summariseAttrDiff(\n  before: Record<string, unknown>,\n  after: Record<string, unknown>,\n): string {\n  const keys = new Set([...Object.keys(before), ...Object.keys(after)])\n  const changed: string[] = []\n  for (const k of keys) {\n    if (JSON.stringify(before[k]) !== JSON.stringify(after[k])) changed.push(k)\n  }\n  return changed.length === 0 ? 'attributes differ' : `fields changed: ${changed.sort().join(', ')}`\n}\n\nexport interface StaleEdgesInput {\n  limit?: number\n  edgeType?: string\n  project?: string\n}\n\ninterface StaleEventResponse {\n  edgeId: string\n  source: string\n  target: string\n  edgeType: string\n  thresholdMs: number\n  ageMs: number\n  lastObserved: string\n  transitionedAt: string\n}\n\nexport async function runStaleEdges(\n  client: HttpClient,\n  input: StaleEdgesInput,\n): Promise<VerbResult> {\n  const params = new URLSearchParams()\n  if (input.limit !== undefined) params.set('limit', String(input.limit))\n  if (input.edgeType) params.set('edgeType', input.edgeType)\n  const qs = params.size > 0 ? `?${params.toString()}` : ''\n  const body = await client.get<{ count: number; total: number; events: StaleEventResponse[] }>(\n    projectPath(input.project, `/stale-events${qs}`),\n  )\n  const events = body.events\n  if (events.length === 0) {\n    return {\n      summary: input.edgeType\n        ? `No stale ${input.edgeType} edges recorded.`\n        : 'No stale-edge transitions recorded yet.',\n    }\n  }\n  const blockLines = events.map(\n    (e) =>\n      `  ${e.transitionedAt} — ${e.source} -[${e.edgeType}]-> ${e.target}` +\n      ` (last seen ${e.lastObserved}, threshold ${formatDuration(e.thresholdMs)})`,\n  )\n  return {\n    summary: `${events.length} stale-edge transition${events.length === 1 ? '' : 's'} recorded${input.edgeType ? ` for ${input.edgeType}` : ''}.`,\n    block: blockLines.join('\\n'),\n    provenance: Provenance.STALE,\n  }\n}\n\nexport interface PoliciesInput {\n  nodeId?: string\n  policyId?: string\n  hypotheticalAction?: HypotheticalAction\n  project?: string\n}\n\ninterface PoliciesCheckResponse {\n  allowed: boolean\n  hypotheticalAction?: HypotheticalAction\n  violations: PolicyViolation[]\n}\n\nexport async function runPolicies(\n  client: HttpClient,\n  input: PoliciesInput,\n): Promise<VerbResult> {\n  let violations: PolicyViolation[]\n  let allowed = true\n  let hypothetical: HypotheticalAction | undefined\n\n  if (input.hypotheticalAction) {\n    if (typeof client.post !== 'function') {\n      throw new Error('HttpClient does not support POST — required for policies dry-run')\n    }\n    const body = await client.post<PoliciesCheckResponse>(\n      projectPath(input.project, '/policies/check'),\n      { hypotheticalAction: input.hypotheticalAction },\n    )\n    violations = body.violations\n    allowed = body.allowed\n    hypothetical = body.hypotheticalAction\n  } else {\n    const params = new URLSearchParams()\n    if (input.policyId) params.set('policyId', input.policyId)\n    const qs = params.size > 0 ? `?${params.toString()}` : ''\n    const body = await client.get<{ violations: PolicyViolation[] }>(\n      projectPath(input.project, `/policies/violations${qs}`),\n    )\n    violations = body.violations\n    allowed = violations.every((v) => v.onViolation !== 'block')\n  }\n\n  // Optional --node filter is applied here against the returned set; the\n  // server-side endpoint doesn't take a node-id query yet.\n  if (input.nodeId) {\n    violations = violations.filter(\n      (v) => v.subject.nodeId === input.nodeId || v.subject.path?.includes(input.nodeId!),\n    )\n  }\n\n  if (violations.length === 0) {\n    return {\n      summary: hypothetical\n        ? `No violations would result from the hypothetical action (${hypothetical.kind}).`\n        : 'No policy violations recorded.',\n    }\n  }\n\n  const blockCount = violations.filter((v) => v.onViolation === 'block').length\n  const summaryParts: string[] = []\n  if (hypothetical) {\n    summaryParts.push(\n      `Hypothetical ${hypothetical.kind} would surface ${violations.length} violation${violations.length === 1 ? '' : 's'}`,\n    )\n  } else {\n    summaryParts.push(\n      `${violations.length} policy violation${violations.length === 1 ? '' : 's'} currently recorded`,\n    )\n  }\n  if (blockCount > 0) summaryParts.push(`${blockCount} of which block`)\n  if (!allowed && hypothetical) summaryParts.push('action denied')\n  const summary = summaryParts.join('; ') + '.'\n\n  const blockLines = violations.map((v) => {\n    const subject = v.subject.nodeId ?? v.subject.edgeId ?? v.subject.path?.[0] ?? '(global)'\n    return `  • [${v.severity}/${v.onViolation}] ${v.policyName}: ${v.message} — ${subject}`\n  })\n  const severities = [...new Set(violations.map((v) => v.severity))]\n  return {\n    summary,\n    block: blockLines.join('\\n'),\n    confidence: hypothetical ? 0.7 : 1,\n    provenance: severities.join(' '),\n  }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// divergences (ADR-060) — the tenth verb. Amends ADR-050's nine-verb\n// allowlist; the verb mirrors the get_divergences MCP tool.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface DivergencesInput {\n  type?: ReadonlyArray<DivergenceType>\n  minConfidence?: number\n  node?: string\n  project?: string\n}\n\nfunction formatDivergenceLine(d: Divergence): string {\n  switch (d.type) {\n    case 'missing-observed':\n    case 'missing-extracted':\n      // Column locus (ADR-157 §4) — a column-grain drift on one `sql-table` node,\n      // no edge. Edge locus — the declared/observed edge triple.\n      if (d.column) {\n        return `  • [${d.type}] ${d.table ?? d.source} column ${d.column} — confidence ${d.confidence.toFixed(2)}`\n      }\n      return `  • [${d.type}] ${d.source} → ${d.target} (${d.edgeType}) — confidence ${d.confidence.toFixed(2)}`\n    case 'version-mismatch':\n      return `  • [${d.type}] ${d.source} → ${d.target} — declared ${d.extractedVersion}, observed engine ${d.observedVersion} (${d.compatibility})`\n    case 'host-mismatch':\n      return `  • [${d.type}] ${d.source} → ${d.target} — declared host ${d.extractedHost}, observed host ${d.observedHost}`\n    case 'compat-violation':\n      return `  • [${d.type}] ${d.source} → ${d.target} — ${d.rule.kind}${d.rule.package ? ` (${d.rule.package})` : ''}`\n    case 'observed-symbol-mismatch': {\n      // Symbol/field-grain (ADR-215) — the code declares access to a member the\n      // runtime object lacks. source == target (the code node), so name the\n      // member and the declaring file:line instead of an edge.\n      const at = d.location ? ` at ${d.location}` : ''\n      const member = d.symbol ? ` ${d.symbol}` : ''\n      return `  • [${d.type}] ${d.source}${member}${at} (${d.mismatchKind}) — confidence ${d.confidence.toFixed(2)}`\n    }\n    case 'observed-failing': {\n      // Behavioral-failure (ADR-220). Edge locus — a declared+observed dependency\n      // edge whose calls predominantly fail; name the edge + error rate. Incident\n      // locus — source == target (the declaring code node); name the file:line.\n      if (d.edgeType) {\n        const rate = d.errorRate !== undefined ? ` ${Math.round(d.errorRate * 100)}% errors` : ''\n        return `  • [${d.type}] ${d.source} → ${d.target} (${d.edgeType}) —${rate} (${d.failureKind}) — confidence ${d.confidence.toFixed(2)}`\n      }\n      const at = d.location ? ` at ${d.location}` : ''\n      return `  • [${d.type}] ${d.source}${at} (${d.failureKind}) — confidence ${d.confidence.toFixed(2)}`\n    }\n    case 'deploy-mismatch': {\n      // Deploy divergence (ADR-225) — declared manifest vs observed cluster on\n      // one service node; source == target. The stuck rollout: declared image ≠\n      // running image, no incident.\n      if (d.kind === 'image') {\n        return `  • [${d.type}] ${d.source} — declared image ${d.declaredImage ?? '?'}, running ${d.observedImage ?? '?'} — confidence ${d.confidence.toFixed(2)}`\n      }\n      return `  • [${d.type}] ${d.source} — declared ${d.declaredReplicas ?? '?'} replicas, ${d.observedReplicas ?? '?'} ready — confidence ${d.confidence.toFixed(2)}`\n    }\n    case 'flag-mismatch':\n      // Flag grain (ADR-242): the reading service against the flag store.\n      return `  • [${d.type}] ${d.source} — ${flagMismatchPhrase(d)} — confidence ${d.confidence.toFixed(2)}`\n  }\n}\n\nexport async function runDivergences(\n  client: HttpClient,\n  input: DivergencesInput,\n): Promise<VerbResult> {\n  const params = new URLSearchParams()\n  if (input.type && input.type.length > 0) params.set('type', input.type.join(','))\n  if (input.minConfidence !== undefined) {\n    params.set('minConfidence', String(input.minConfidence))\n  }\n  if (input.node) params.set('node', input.node)\n  const qs = params.size > 0 ? `?${params.toString()}` : ''\n  const result = await client.get<DivergenceResult>(\n    projectPath(input.project, `/graph/divergences${qs}`),\n  )\n  if (result.totalAffected === 0) {\n    return {\n      summary:\n        'No divergences found between the declared (EXTRACTED) and observed (OBSERVED) views of the graph.',\n    }\n  }\n  const headline = result.divergences[0]!\n  const summary =\n    `Found ${result.totalAffected} divergence${result.totalAffected === 1 ? '' : 's'} between code and production. ` +\n    `Highest-confidence: ${headline.type} on ${headline.source} → ${headline.target}. ${headline.reason}`\n  const blockLines: string[] = []\n  for (const d of result.divergences) {\n    blockLines.push(formatDivergenceLine(d))\n    blockLines.push(`    reason: ${d.reason}`)\n    blockLines.push(`    recommendation: ${d.recommendation}`)\n  }\n  const maxConfidence = result.divergences.reduce(\n    (m, d) => Math.max(m, d.confidence),\n    0,\n  )\n  return {\n    summary,\n    block: blockLines.join('\\n'),\n    confidence: maxConfidence,\n    provenance: 'composite (EXTRACTED + OBSERVED)',\n  }\n}\n\n// ask — the plain-language door (ADR-198). One natural-language question →\n// GET /graph/ask?q=… → the composed, provenance-tagged answer. The verb renders\n// the AskResult's compact `answer` as the summary and its sections as the block;\n// the footer carries the aggregate confidence + provenance.\nexport interface AskInput {\n  question: string\n  project?: string\n}\n\nexport async function runAsk(client: HttpClient, input: AskInput): Promise<VerbResult> {\n  const result = await client.get<AskResult>(\n    projectPath(input.project, `/graph/ask?q=${encodeURIComponent(input.question)}`),\n  )\n  const blockLines: string[] = []\n  if (result.matched.length > 0) {\n    blockLines.push(\n      `Matched: ${result.matched.map((m) => `${m.nodeId} [${m.via} ${m.score.toFixed(2)}]`).join(', ')}`,\n    )\n    blockLines.push(`Intent: ${result.intent}`)\n  } else if (result.scope === 'global') {\n    // A graph-wide answer to an entity-less question — no node was named.\n    blockLines.push(`Graph-wide answer (${result.intent}) — no entity named.`)\n  }\n  for (const section of result.sections) {\n    blockLines.push('', section.heading + ':')\n    for (const fact of section.facts) {\n      const tag = fact.provenance\n        ? ` [${fact.provenance}${fact.confidence !== undefined ? ` ${fact.confidence.toFixed(2)}` : ''}]`\n        : fact.confidence !== undefined\n          ? ` [confidence ${fact.confidence.toFixed(2)}]`\n          : ''\n      blockLines.push(`  • ${fact.text}${tag}`)\n    }\n  }\n  return {\n    summary: result.answer,\n    block: blockLines.join('\\n').trim(),\n    ...(result.confidence !== undefined ? { confidence: result.confidence } : {}),\n    ...(result.provenance.length > 0 ? { provenance: result.provenance } : {}),\n  }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Output formatting (ADR-050 #3)\n// ──────────────────────────────────────────────────────────────────────────\n\nfunction formatFooter(\n  confidence: number | undefined,\n  provenance: string | string[] | undefined,\n): string {\n  const c = confidence === undefined ? 'n/a' : confidence.toFixed(2)\n  const p =\n    provenance === undefined\n      ? 'n/a'\n      : Array.isArray(provenance)\n        ? [...new Set(provenance)].join(', ')\n        : provenance\n  return style.footer(c, p)\n}\n\n// Default human output (NL summary + table-shaped block + footer). Mirrors\n// the three-part MCP response from ADR-039 in plain text.\nexport function formatHuman(result: VerbResult): string {\n  const sections: string[] = [result.summary.trim()]\n  if (result.block && result.block.trim().length > 0) sections.push(style.styleBlock(result.block.trimEnd()))\n  sections.push(formatFooter(result.confidence, result.provenance))\n  return sections.join('\\n\\n')\n}\n\n// `--json` output. Same three sections as named fields per ADR-050 #3.\nexport function formatJson(result: VerbResult): string {\n  return JSON.stringify(\n    {\n      summary: result.summary,\n      block: result.block ?? '',\n      confidence: result.confidence ?? null,\n      provenance: result.provenance ?? null,\n    },\n    null,\n    2,\n  )\n}\n\n// Exit-code mapping for thrown errors (ADR-050 #4):\n//   0 — success (handled at the call site, never via throw)\n//   1 — server error (HttpError)\n//   2 — misuse (handled in cli.ts before any network call)\n//   3 — daemon unreachable (TransportError)\nexport function exitCodeForError(err: unknown): number {\n  if (err instanceof TransportError) return 3\n  if (err instanceof HttpError) return 1\n  return 1\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Snapshot push (ADR-074 §1)\n//\n// `neat sync` (local + --to <url>) feeds the freshly extracted snapshot into\n// either the local daemon or a remote one. The endpoint is dual-mounted via\n// registerRoutes — default project lands at /snapshot, named projects at\n// /projects/:project/snapshot. The helper goes through the shared\n// HttpClient so the verb stays on the same network path as every query verb.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface PushSnapshotInput {\n  baseUrl: string\n  token: string | undefined\n  project: string\n  snapshot: unknown\n}\n\nexport interface PushSnapshotResult {\n  project: string\n  nodesAdded: number\n  edgesAdded: number\n  nodeCount: number\n  edgeCount: number\n}\n\nexport function createSnapshotPushClient(\n  baseUrl: string,\n  token: string | undefined,\n  fetchImpl?: typeof fetch,\n): HttpClient {\n  return createHttpClient(baseUrl, token && token.length > 0 ? token : undefined, fetchImpl)\n}\n\n// A hosted tenant daemon serves exactly one project, named by the control plane\n// (the provisioner sets NEAT_PROJECT), and marks it `hostedHere: true` in\n// GET /projects. `neat sync --to <url>` must push under THAT name — not the\n// local directory-derived project name — or the snapshot 404s when a user's\n// repo isn't named the same as their hosted project.\n//\n// The resolution is deliberately conservative so local and self-host sync never\n// regress: if GET /projects can't be reached or reports no `hostedHere` entry,\n// fall back to the caller's local project name and let the push proceed exactly\n// as before. A genuinely unreachable daemon still surfaces on the push that\n// follows this call.\nexport async function resolveRemoteProjectName(\n  input: {\n    baseUrl: string\n    token: string | undefined\n    fallback: string\n  },\n  fetchImpl?: typeof fetch,\n): Promise<string> {\n  const client = createSnapshotPushClient(input.baseUrl, input.token, fetchImpl)\n  try {\n    const projects = await client.get<ProjectListEntry[]>('/projects')\n    const hosted = Array.isArray(projects)\n      ? projects.find((p) => p?.hostedHere)\n      : undefined\n    return hosted?.name ?? input.fallback\n  } catch {\n    return input.fallback\n  }\n}\n\nexport async function pushSnapshotToRemote(\n  input: PushSnapshotInput,\n): Promise<PushSnapshotResult> {\n  const client = createSnapshotPushClient(input.baseUrl, input.token)\n  if (typeof client.post !== 'function') {\n    throw new Error('HttpClient does not support POST — required for snapshot push')\n  }\n  return client.post<PushSnapshotResult>(\n    `/projects/${encodeURIComponent(input.project)}/snapshot`,\n    { snapshot: input.snapshot },\n  )\n}\n","// `neat up` — start or recover the daemon for the project you're standing in.\n//\n// A query verb that can't reach its daemon exits 3 and starts nothing: reads stay\n// reads (#1250). This is the command that message points at. It does the one\n// thing the bare run does as its fourth step — make sure this project has a live\n// daemon — without extracting, instrumenting, or registering anything, and says\n// what it found: already running, started, or why it would not come up.\n//\n// A config-style command alongside `doctor` (cli-surface.md §neat up), not one of\n// the locked query verbs. Loopback only: a daemon this machine doesn't run isn't\n// ours to start. Its collaborators are injected so the surface is testable\n// without spawning a process.\n\nimport path from 'node:path'\nimport type { RegistryEntry } from '@neat.is/types'\nimport { findProjectByPath, getProject } from './registry.js'\nimport {\n  DEFAULT_DAEMON_READY_TIMEOUT_MS,\n  NEAT_PORTS,\n  daemonLogPath,\n  daemonProgressLine,\n  describeDaemonTimeout,\n  ensureProjectDaemon,\n  formatPortCollisionMessage,\n  type EnsureDaemonOptions,\n  type EnsureDaemonOutcome,\n} from './orchestrator.js'\n\n// Where a query verb run from here would go. `local` is false when that is a\n// daemon on another machine — a hosted profile, a remote pin.\nexport interface UpTarget {\n  endpoint: string\n  local: boolean\n  // What chose the endpoint, in words — for the message.\n  via: string\n}\n\nexport interface UpCliDeps {\n  cwd?: string\n  env?: NodeJS.ProcessEnv\n  resolveTarget: (opts: { project?: string; profile?: string }) => Promise<UpTarget>\n  ensureDaemon?: (opts: EnsureDaemonOptions) => Promise<EnsureDaemonOutcome>\n  out?: (line: string) => void\n  err?: (line: string) => void\n}\n\ninterface UpArgs {\n  project?: string\n  profile?: string\n  json: boolean\n  help: boolean\n  unknown?: string\n}\n\nfunction parseUpArgs(argv: string[], env: NodeJS.ProcessEnv): UpArgs {\n  const args: UpArgs = { json: false, help: false }\n  for (let i = 0; i < argv.length; i++) {\n    const a = argv[i]!\n    if (a === '--json') args.json = true\n    else if (a === '-h' || a === '--help') args.help = true\n    else if (a === '--project') args.project = argv[++i]\n    else if (a.startsWith('--project=')) args.project = a.slice('--project='.length)\n    else if (a === '--profile') args.profile = argv[++i]\n    else if (a.startsWith('--profile=')) args.profile = a.slice('--profile='.length)\n    else if (args.unknown === undefined) args.unknown = a\n  }\n  if (!args.project && env.NEAT_PROJECT && env.NEAT_PROJECT.length > 0) args.project = env.NEAT_PROJECT\n  return args\n}\n\nconst USAGE = [\n  'usage: neat up [--project <name>] [--json]',\n  '',\n  \"Start this project's daemon, or recover it if it died. Does nothing when it is\",\n  'already running. Extracts and instruments nothing — run `neat` for that.',\n]\n\nexport async function runUpCommand(argv: string[], deps: UpCliDeps): Promise<number> {\n  const cwd = deps.cwd ?? process.cwd()\n  const env = deps.env ?? process.env\n  const out = deps.out ?? ((line: string) => console.log(line))\n  const err = deps.err ?? ((line: string) => console.error(line))\n  const ensure = deps.ensureDaemon ?? ensureProjectDaemon\n\n  const args = parseUpArgs(argv, env)\n  if (args.help) {\n    for (const line of USAGE) out(line)\n    return 0\n  }\n  if (args.unknown !== undefined) {\n    err(`neat up: unexpected argument \\`${args.unknown}\\``)\n    for (const line of USAGE) err(line)\n    return 2\n  }\n\n  // Which project. The name wins when given; otherwise the one this directory\n  // belongs to. A registry that can't be read is no project, not a crash.\n  let entry: RegistryEntry | undefined\n  try {\n    entry = args.project ? await getProject(args.project) : await findProjectByPath(cwd)\n  } catch {\n    entry = undefined\n  }\n  if (!entry) {\n    err(\n      args.project\n        ? `neat up: no project named \"${args.project}\" is registered on this machine — \\`neat list\\` shows what is.`\n        : \"neat up: This directory isn't a NEAT project yet — run `npx neat.is` here first, or pass --project <name>.\",\n    )\n    return 2\n  }\n\n  // Where queries from here go. If that's a daemon on another machine, starting a\n  // local one would leave every query still pointed somewhere else.\n  let target: UpTarget\n  try {\n    target = await deps.resolveTarget({ project: entry.name, profile: args.profile })\n  } catch (e) {\n    err(`neat up: ${(e as Error).message}`)\n    return 2\n  }\n  if (!target.local) {\n    err(`neat up: queries from here go to ${target.endpoint}, through ${target.via}.`)\n    err(\"neat up: that daemon doesn't run on this machine, so it isn't yours to start.\")\n    return 2\n  }\n\n  const project = entry.name\n  const outcome = await ensure({\n    project,\n    projectPath: entry.path,\n    // `--json` prints one object and nothing else, so progress stays quiet there.\n    ...(args.json\n      ? {}\n      : { onProgress: (event) => out(`neat up: ${daemonProgressLine(project, event)}`) }),\n  })\n  const log = daemonLogPath(entry.path)\n\n  if (args.json) {\n    const ports = 'ports' in outcome ? outcome.ports : undefined\n    out(\n      JSON.stringify({\n        project: entry.name,\n        path: entry.path,\n        status: outcome.status,\n        ...(ports ? { endpoint: `http://localhost:${ports.rest}`, ports } : {}),\n        ...(outcome.status === 'spawn-failed' ? { error: outcome.message } : {}),\n        log,\n      }),\n    )\n  }\n\n  switch (outcome.status) {\n    case 'already-running':\n      if (!args.json) {\n        out(`neat up: ${entry.name} is already running — http://localhost:${outcome.ports.rest}`)\n      }\n      return 0\n    case 'spawned':\n      if (!args.json) {\n        out(`neat up: started ${entry.name} — http://localhost:${outcome.ports.rest}`)\n        out(`neat up: traces on :${outcome.ports.otlp}, log at ${path.relative(cwd, log) || log}`)\n      }\n      return 0\n    case 'timed-out':\n      if (!args.json) {\n        for (const line of await describeDaemonTimeout(outcome, entry.path, DEFAULT_DAEMON_READY_TIMEOUT_MS)) err(line)\n      }\n      return 1\n    case 'peer-timeout':\n      if (!args.json) {\n        err('neat up: another `neat` is starting this project, and its daemon did not come up in time.')\n        err(`neat up: see ${log}`)\n      }\n      return 1\n    case 'spawn-failed':\n      if (!args.json) err(`neat up: could not start the daemon — ${outcome.message}`)\n      return 1\n    case 'no-ports':\n      if (!args.json) for (const line of formatPortCollisionMessage(NEAT_PORTS[0])) err(line)\n      return 3\n  }\n}\n","// `neat login` / `neat logout` — connect this machine to a hosted NEAT by\n// writing a client profile (client-profiles.md §4) and setting it active, so the\n// CLI and the MCP server both resolve there (§3). A config command family, not a\n// query verb: it parses its own argv and keeps its own exit codes (0 done, 1 the\n// endpoint or token was rejected, 2 misuse, 3 the endpoint was unreachable).\n//\n// v1 is the paste flow: the user gives the hosted daemon's endpoint and token —\n// the same pair the hosted console surfaces as \"point your CLI at this daemon\".\n// The browser loopback flow writes the same profile once the control plane's\n// credential exchange is live, and will reuse `runLoginCommand`'s core.\n\nimport readline from 'node:readline/promises'\nimport {\n  upsertProfile,\n  getActiveProfile,\n  removeProfile,\n  clearActiveProfile,\n} from './profiles.js'\nimport { runSsoLogin, resolveCpUrl, resolveWebUrl } from './login-sso.js'\nimport { probeDaemon } from './daemon-probe.js'\nimport type { ConnectDeps } from './login-connect.js'\n\nexport interface LoginCliDeps {\n  env?: NodeJS.ProcessEnv\n  fetchImpl?: typeof fetch\n  out?: (line: string) => void\n  err?: (line: string) => void\n  // Read a line the user types (the endpoint). Undefined → non-interactive; the\n  // default reads from the terminal only when stdin is a TTY.\n  readLine?: (prompt: string) => Promise<string | undefined>\n  // Read a secret without echoing it (the token). Undefined → non-interactive.\n  readSecret?: (prompt: string) => Promise<string | undefined>\n  // `~/.neat` override, for tests. Undefined → the real per-user store.\n  home?: string\n  // Test seams for the endpoint probe's cold-start retry.\n  sleep?: (ms: number) => Promise<void>\n  now?: () => number\n  // Open a URL in the browser (the Method 1 loopback); injected for tests.\n  openBrowser?: (url: string) => boolean\n  // Ends the zero-project onboarding wait on Ctrl-C.\n  signal?: AbortSignal\n  // Seams for the post-login repo step (repo detection, local-snapshot check, cwd).\n  connect?: ConnectDeps\n}\n\nconst DEFAULT_PROFILE_NAME = 'hosted'\n\n// ── login ────────────────────────────────────────────────────────────────────\n\ninterface ParsedLoginArgs {\n  endpoint?: string\n  token?: string\n  name: string\n  json: boolean\n  help: boolean\n  error?: string\n  // Hosted SSO path: --browser (Method 1 loopback) or --sso-token (Method 2 /\n  // scripts). --cp-url / --web-url override the hosted endpoints; --project picks\n  // among several running projects.\n  browser: boolean\n  ssoToken?: string\n  cpUrl?: string\n  webUrl?: string\n  project?: string\n}\n\n// Reads a `--flag value` or `--flag=value` string flag; returns the value and\n// the index to continue from (past a consumed separate token).\nfunction readFlagValue(argv: string[], i: number): { value: string | undefined; next: number } {\n  const arg = argv[i]!\n  const eq = arg.indexOf('=')\n  if (eq !== -1) return { value: arg.slice(eq + 1), next: i }\n  return { value: argv[i + 1], next: i + 1 }\n}\n\nfunction parseLoginArgs(argv: string[]): ParsedLoginArgs {\n  const parsed: ParsedLoginArgs = { name: DEFAULT_PROFILE_NAME, json: false, help: false, browser: false }\n  for (let i = 0; i < argv.length; i++) {\n    const arg = argv[i]!\n    if (arg === '-h' || arg === '--help') parsed.help = true\n    else if (arg === '--json') parsed.json = true\n    else if (arg === '--browser') parsed.browser = true\n    else if (arg === '--endpoint' || arg.startsWith('--endpoint=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.endpoint = value\n      i = next\n    } else if (arg === '--token' || arg.startsWith('--token=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.token = value\n      i = next\n    } else if (arg === '--sso-token' || arg.startsWith('--sso-token=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.ssoToken = value\n      i = next\n    } else if (arg === '--cp-url' || arg.startsWith('--cp-url=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.cpUrl = value\n      i = next\n    } else if (arg === '--web-url' || arg.startsWith('--web-url=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.webUrl = value\n      i = next\n    } else if (arg === '--project' || arg.startsWith('--project=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.project = value\n      i = next\n    } else if (arg === '--name' || arg.startsWith('--name=')) {\n      const { value, next } = readFlagValue(argv, i)\n      if (value && value.length > 0) parsed.name = value\n      i = next\n    } else {\n      parsed.error = `unknown argument \"${arg}\"`\n      break\n    }\n  }\n  return parsed\n}\n\nfunction printLoginHelp(out: (line: string) => void): void {\n  out('usage: neat login [--browser | --endpoint <url> --token <token>] [--name <name>] [--json]')\n  out('  Connect this machine to a hosted NEAT and make it the default for the')\n  out('  neat CLI and the MCP server. Methods:')\n  out('    --browser            log in through your browser, then connect the')\n  out('                         account\\'s running project (Method 1)')\n  out('    --sso-token <jwt>    exchange a pasted session token (headless / scripts)')\n  out('    --endpoint <url> --token <token>')\n  out('                         paste a daemon endpoint + token directly, or omit')\n  out('                         both to be prompted (the token is read without echo)')\n  out('  --project <name|id> picks among several running projects. --cp-url / --web-url')\n  out('  (or NEAT_CP_URL / NEAT_WEB_URL) override the hosted endpoints; --name labels')\n  out('  the profile (default \"hosted\"); the paste token can also come from NEAT_LOGIN_TOKEN.')\n  out('  Exit 0 on success, 1 rejected/needs-action, 2 misuse, 3 unreachable.')\n}\n\nexport async function runLoginCommand(argv: string[], deps: LoginCliDeps = {}): Promise<number> {\n  const out = deps.out ?? ((line: string) => console.log(line))\n  const err = deps.err ?? ((line: string) => console.error(line))\n  const env = deps.env ?? process.env\n  const fetchImpl = deps.fetchImpl ?? fetch\n  const readLine = deps.readLine ?? defaultReadLine\n  const readSecret = deps.readSecret ?? defaultReadSecret\n  const sleep = deps.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)))\n  const now = deps.now ?? Date.now\n\n  const args = parseLoginArgs(argv)\n  if (args.help) {\n    printLoginHelp(out)\n    return 0\n  }\n  if (args.error) {\n    err(`neat login: ${args.error}`)\n    return 2\n  }\n\n  // Hosted \"I have a NEAT account\" path: --browser (Method 1 loopback) or a\n  // pasted access token (--sso-token, Method 2 / scripts). Both exchange the\n  // Supabase token for the project's daemon credential and write the profile\n  // (login-sso.ts); the access token itself is never persisted.\n  if (args.browser || args.ssoToken) {\n    return runSsoLogin(\n      {\n        cpUrl: resolveCpUrl(env, args.cpUrl),\n        webUrl: resolveWebUrl(env, args.webUrl),\n        ssoToken: args.ssoToken,\n        name: args.name,\n        project: args.project,\n        json: args.json,\n      },\n      {\n        fetchImpl,\n        out,\n        err,\n        readLine,\n        sleep,\n        now,\n        ...(deps.openBrowser ? { openBrowser: deps.openBrowser } : {}),\n        ...(deps.home ? { home: deps.home } : {}),\n        ...(deps.signal ? { signal: deps.signal } : {}),\n        ...(deps.connect ? { connect: deps.connect } : {}),\n      },\n    )\n  }\n\n  let endpoint = args.endpoint\n  if (!endpoint) endpoint = (await readLine('Hosted NEAT endpoint (https://…): '))?.trim()\n  if (!endpoint) {\n    err('neat login: an endpoint is required — pass --endpoint <url> or run interactively')\n    return 2\n  }\n\n  let url: URL\n  try {\n    url = new URL(endpoint)\n  } catch {\n    err(`neat login: --endpoint must be an absolute URL (got \"${endpoint}\")`)\n    return 2\n  }\n  if (url.protocol !== 'http:' && url.protocol !== 'https:') {\n    err(`neat login: --endpoint must be an http(s) URL (got \"${url.protocol}\")`)\n    return 2\n  }\n\n  const envToken = env.NEAT_LOGIN_TOKEN\n  let token = args.token ?? (envToken && envToken.length > 0 ? envToken : undefined)\n  if (!token) token = (await readSecret('Daemon token: '))?.trim()\n  if (!token) {\n    err('neat login: a token is required — pass --token, set NEAT_LOGIN_TOKEN, or run interactively')\n    return 2\n  }\n\n  const probe = await probeDaemon(fetchImpl, endpoint, token, {\n    sleep,\n    now,\n    onWaiting: () => err('Waking the hosted daemon — a cold instance can take up to a minute…'),\n  })\n  if (probe.kind === 'unreachable') {\n    err(`neat login: can't reach ${endpoint} — ${probe.detail}`)\n    return 3\n  }\n  if (probe.kind === 'unauthorized') {\n    err(`neat login: ${endpoint} rejected the token (HTTP ${probe.status}). Check the token and try again.`)\n    return 1\n  }\n  if (probe.kind === 'not-neat') {\n    err(`neat login: ${endpoint} answered but does not look like a NEAT daemon (HTTP ${probe.status}).`)\n    return 1\n  }\n\n  await upsertProfile(\n    { name: args.name, endpoint, authToken: token },\n    { makeActive: true, ...(deps.home ? { home: deps.home } : {}) },\n  )\n\n  if (args.json) {\n    out(JSON.stringify({ status: 'logged-in', profile: args.name, endpoint }, null, 2))\n  } else {\n    out(`Logged in — profile \"${args.name}\" → ${endpoint}`)\n    out('The neat CLI and the MCP server now read this hosted graph by default.')\n    out('Run `neat logout` to switch back to your local daemon.')\n  }\n  return 0\n}\n\n// ── logout ───────────────────────────────────────────────────────────────────\n\ninterface ParsedLogoutArgs {\n  name?: string\n  help: boolean\n  error?: string\n}\n\nfunction parseLogoutArgs(argv: string[]): ParsedLogoutArgs {\n  const parsed: ParsedLogoutArgs = { help: false }\n  for (let i = 0; i < argv.length; i++) {\n    const arg = argv[i]!\n    if (arg === '-h' || arg === '--help') parsed.help = true\n    else if (arg === '--name' || arg.startsWith('--name=')) {\n      const { value, next } = readFlagValue(argv, i)\n      parsed.name = value\n      i = next\n    } else {\n      parsed.error = `unknown argument \"${arg}\"`\n      break\n    }\n  }\n  return parsed\n}\n\nexport async function runLogoutCommand(argv: string[], deps: LoginCliDeps = {}): Promise<number> {\n  const out = deps.out ?? ((line: string) => console.log(line))\n  const err = deps.err ?? ((line: string) => console.error(line))\n  const home = deps.home\n\n  const args = parseLogoutArgs(argv)\n  if (args.help) {\n    out('usage: neat logout [--name <name>]')\n    out('  With no argument, clears the active hosted profile so the CLI and MCP')\n    out('  server go back to your local daemon (the stored profile is kept).')\n    out('  --name <name> removes that profile from ~/.neat/profiles.json entirely.')\n    return 0\n  }\n  if (args.error) {\n    err(`neat logout: ${args.error}`)\n    return 2\n  }\n\n  // `--name` removes a specific profile outright.\n  if (args.name !== undefined) {\n    if (args.name.length === 0) {\n      err('neat logout: --name needs a profile name')\n      return 2\n    }\n    const removed = await removeProfile(args.name, home ?? undefined)\n    if (!removed) {\n      err(`neat logout: no profile named \"${args.name}\"`)\n      return 1\n    }\n    out(`Removed profile \"${args.name}\".`)\n    return 0\n  }\n\n  const active = await getActiveProfile(home ?? undefined)\n  if (!active) {\n    out('Not logged in to a hosted NEAT — the CLI is already using your local daemon.')\n    return 0\n  }\n  await clearActiveProfile(home ?? undefined)\n  out(`Logged out of \"${active.name}\" (${active.endpoint}). The CLI is back on your local daemon.`)\n  return 0\n}\n\n// ── default interactive readers (used when deps don't override) ────────────────\n\n// Prompt for a line, echoed, from the terminal. Returns undefined when stdin is\n// not a TTY so a scripted `neat login` fails with the \"pass --endpoint\" hint\n// rather than hanging on a prompt nobody can answer.\nasync function defaultReadLine(prompt: string): Promise<string | undefined> {\n  if (!process.stdin.isTTY) return undefined\n  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })\n  try {\n    return await rl.question(prompt)\n  } finally {\n    rl.close()\n  }\n}\n\n// Prompt for a secret WITHOUT echoing it — the token must not land in the\n// terminal scrollback. Returns undefined when stdin is not a TTY. Control keys\n// are matched by code point so no literal control bytes sit in this source.\nasync function defaultReadSecret(prompt: string): Promise<string | undefined> {\n  const stdin = process.stdin\n  if (!stdin.isTTY) return undefined\n  process.stdout.write(prompt)\n  return new Promise<string>((resolve) => {\n    const chars: string[] = []\n    stdin.setRawMode(true)\n    stdin.resume()\n    stdin.setEncoding('utf8')\n    const cleanup = (): void => {\n      stdin.setRawMode(false)\n      stdin.pause()\n      stdin.off('data', onData)\n    }\n    const onData = (ch: string): void => {\n      const code = ch.charCodeAt(0)\n      if (ch === '\\n' || ch === '\\r' || code === 4) {\n        // Enter or Ctrl-D — done.\n        cleanup()\n        process.stdout.write('\\n')\n        resolve(chars.join(''))\n      } else if (code === 3) {\n        // Ctrl-C — abort the login without writing anything.\n        cleanup()\n        process.stdout.write('\\n')\n        process.exit(130)\n      } else if (code === 127 || ch === '\\b') {\n        // Backspace / delete.\n        chars.pop()\n      } else {\n        chars.push(ch)\n      }\n    }\n    stdin.on('data', onData)\n  })\n}\n","// The first-run \"front door\" for the `neat` CLI (published as `npx neat.is`).\n//\n// A bare `npx neat.is` with no command runs the local zero-to-graph\n// orchestrator on the cwd. That is the right thing for a returning user, but a\n// first-timer lands in the middle of an extraction with no idea whether they\n// wanted the local path or their hosted account. `runWelcome` prints the wordmark\n// and asks: log into hosted NEAT, or set it up locally — then hands off to the\n// flow they chose.\n//\n// It opens when this DIRECTORY is not yet a NEAT project, in an interactive\n// terminal (see `shouldShowWelcome`) — not once per machine. Every other\n// invocation keeps the exact behaviour it had before.\n//\n// Dependencies are injected (the login fn, the orchestrator fn, an output sink, a\n// line reader, a key reader, and the cursor move the menu repaints with) the same\n// way `login-cli.ts` injects its readers, so the whole flow — arrow menu included\n// — is unit-testable without a real TTY.\n\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\nimport readline from 'node:readline/promises'\nimport { readPackageVersion } from './banner.js'\nimport { AGENT_DIRECTIVE } from './agent-directive.generated.js'\nimport { findDaemonByProject, readRegistry as readRegistryFile } from './registry.js'\n\n// The NEAT block-letter wordmark. Hand-written box-drawing glyphs — no external\n// font, no dependency — matching the artwork the orchestrator's banner prints\n// so the brand reads the same in both places.\nconst WORDMARK: readonly string[] = [\n  '███╗   ██╗███████╗ █████╗ ████████╗',\n  '████╗  ██║██╔════╝██╔══██╗╚══██╔══╝',\n  '██╔██╗ ██║█████╗  ███████║   ██║   ',\n  '██║╚██╗██║██╔══╝  ██╔══██║   ██║   ',\n  '██║ ╚████║███████╗██║  ██║   ██║   ',\n  '╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝   ╚═╝   ',\n]\n\n/** The local door's prompt is rendered after the orchestrator, using its actual project and daemon. */\nexport function renderAgentSetupPrompt(project: string, restPort?: number): string {\n  const endpoint =\n    restPort === undefined\n      ? 'The daemon endpoint is unavailable; run `npx neat.is up` to start it.'\n      : `The local daemon is serving it at http://127.0.0.1:${restPort}.`\n  return `NEAT is set up for project \"${project}\". ${endpoint}\n\nNEAT does the investigation for this system, so you can spend your effort on the\ncode. When something fails, query the incident — get_incident_history and\nget_root_cause on the failing service, file or symbol, then expand/relate to\nconfirm the cause. get_incident_card composes those into one work order (where\nthe failure is, the cause chain with provenance on every hop, what a fix reaches,\nthe policies that govern the code, and where code and runtime disagree) — the same\ncard NEAT hands you when it detects a failure. For anything else about how the\nsystem works, ask. NEAT answers from a live graph that fuses the code with what\nactually ran; a path it hasn't seen run is not proof the path never runs.\n\n1. Wire NEAT's MCP server into this agent session:\n     npx neat.is skill --apply\n   For Codex: npx neat.is codex --apply\n   For Cursor or Gemini, use the corresponding cursor or gemini subcommand.\n2. Verify the MCP \\`ask\\` tool answers:\n     ask \"what services are in this project and what do they talk to?\"\n   If the daemon is unreachable, run \\`npx neat.is up\\`.\n\n${AGENT_DIRECTIVE}\nRuntime evidence arrives once the app runs with NEAT attached: for Node, load\n.env.neat first (\\`set -a; . ./.env.neat; set +a\\`); for Python, start under\n\\`opentelemetry-instrument\\`. Daemon log: neat-out/daemon.log. Reopen this\ndoor with \\`npx neat.is welcome\\`.`\n}\n\nexport interface WelcomeDeps {\n  // Where lines are written. Defaults to stdout via console.log.\n  out?: (line: string) => void\n  // Read a line the user types (a menu choice, a yes/no). Undefined → no\n  // terminal to read from; the default reads only when stdin is a TTY. Injected\n  // for tests so no real TTY is needed.\n  readLine?: (prompt: string) => Promise<string | undefined>\n  // Read one normalised keypress, for the navigable menu. Undefined → the\n  // default raw-mode reader is used, and when the terminal cannot do raw mode the\n  // menu falls back to `readLine`'s numbered prompt. Injected for tests so the\n  // arrow menu needs no TTY.\n  readKey?: () => Promise<MenuKey | undefined>\n  // Move the terminal cursor up `rows` lines so the menu repaints in place.\n  // Defaults to an ANSI write on stdout; a no-op in tests, which assert the\n  // rendered rows rather than the escape codes.\n  moveCursorUp?: (rows: number) => void\n  // Run the hosted-login flow (menu option 1). Given the argv to pass through —\n  // the welcome menu picks the browser method by default. Defaults are wired in\n  // cli.ts to `runLoginCommand`.\n  login?: (argv: string[]) => Promise<number>\n  // Run the local zero-to-graph orchestrator on `cwd` (menu option 2b). Wired in\n  // cli.ts to the same `tryOrchestrator(process.cwd(), …)` path bare `neat` uses.\n  orchestrator?: (cwd: string, opts?: OrchestratorOverrides) => Promise<number>\n  /** True when `--no-instrument` or `--dry-run` was already given, so the front door\n   *  doesn't ask a question the person has answered on the command line. */\n  instrumentFlagGiven?: boolean\n  /** A dry run does not install or start the graph, so it cannot offer a ready prompt. */\n  dryRun?: boolean\n  /** Reads the machine project registry through `registry.ts`, which owns that file's\n   *  authority (ADR-048 §8). Used to spot a name collision before one happens. */\n  readRegistry?: () => Promise<{ projects: { name: string; path: string }[] }>\n  /** Resolve the daemon started by the local build, for the actual REST port. */\n  readDaemon?: (project: string) => Promise<{ projectPath: string; restPort: number } | undefined>\n  // The working directory handed to the orchestrator. Defaults to process.cwd().\n  cwd?: string\n}\n\n// Print the wordmark + version header through the injected sink.\nfunction printHeader(out: (line: string) => void): void {\n  for (const line of WORDMARK) out(line)\n  out('')\n  out(`  neat.is  ·  v${readPackageVersion()}`)\n  out('')\n}\n\n/**\n * The front door. Returns a process exit code.\n *\n *   1) Log me into Hosted Neat      → the hosted login flow (browser method)\n *   2) Self-host or use it locally  → run the local orchestrator on cwd, then\n *                                     offer a copy-paste graph directive\n *\n * Navigable with the arrow keys when the terminal can hand us raw keys, and the\n * numbered prompt when it cannot.\n *\n * A reader that returns undefined (no terminal / EOF) falls through to the\n * self-hosted orchestrator — the same behaviour a bare `neat` has today — so the\n * front door never dead-ends waiting on input nobody can give.\n */\nexport async function runWelcome(deps: WelcomeDeps = {}): Promise<number> {\n  const out = deps.out ?? ((line: string) => console.log(line))\n  try {\n    return await runFrontDoor(deps, out)\n  } catch (err) {\n    // Ctrl-C in the front door is a person saying \"not this\". Leave the way a\n    // terminal program should — a fresh line and the conventional 128+SIGINT\n    // code — rather than a stack trace from inside node's readline.\n    if (isPromptCancelled(err)) {\n      out('')\n      return 130\n    }\n    throw err\n  }\n}\n\n/** Thrown by a reader when the person interrupted the prompt rather than answered it. */\nexport class PromptCancelled extends Error {\n  constructor() {\n    super('prompt cancelled')\n    this.name = 'PromptCancelled'\n  }\n}\n\n// `readline/promises` rejects a pending `question()` with an AbortError carrying\n// `ABORT_ERR` when Ctrl-C arrives. Both that and our own sentinel count, so an\n// injected reader can signal a cancel without reproducing node's error shape.\nfunction isPromptCancelled(err: unknown): boolean {\n  if (err instanceof PromptCancelled) return true\n  const e = err as { code?: unknown; name?: unknown } | null\n  return e?.code === 'ABORT_ERR' || e?.name === 'AbortError'\n}\n\nasync function runFrontDoor(deps: WelcomeDeps, out: (line: string) => void): Promise<number> {\n  const readLine = deps.readLine ?? defaultReadLine\n  const login = deps.login ?? (() => Promise.resolve(0))\n  const orchestrator = deps.orchestrator ?? (() => Promise.resolve(0))\n  const cwd = deps.cwd ?? process.cwd()\n  const flagGiven = deps.instrumentFlagGiven ?? false\n  const readRegistry = deps.readRegistry ?? (() => readRegistryFile())\n  const readDaemon =\n    deps.readDaemon ??\n    (async (project: string) => {\n      const daemon = await findDaemonByProject(project)\n      return daemon?.live\n        ? { projectPath: daemon.record.projectPath, restPort: daemon.record.ports.rest }\n        : undefined\n    })\n\n  printHeader(out)\n  out(\"Welcome to NEAT. Let's get you a graph of this system.\")\n  out('')\n\n  // A navigable menu when the terminal can give us keys one at a time; the\n  // numbered prompt otherwise. Both end in the same two flows.\n  const keyReader =\n    deps.readKey !== undefined ? { read: deps.readKey, done: () => {} } : createKeyReader()\n  const picked =\n    keyReader !== null\n      ? await selectOption(out, keyReader, deps.moveCursorUp ?? defaultMoveCursorUp)\n      : await selectByNumber(out, readLine)\n\n  // No answer (EOF, no terminal, cancelled) → the self-hosted path, matching the\n  // behaviour bare `neat` already has.\n  if (picked === undefined)\n    return runSelfHosted(\n      out,\n      readLine,\n      orchestrator,\n      cwd,\n      readRegistry,\n      readDaemon,\n      flagGiven,\n      deps.dryRun === true,\n    )\n  // Default method is the browser loopback login (login-cli.ts §--browser).\n  if (picked === 0) return login(['--browser'])\n  return runSelfHosted(\n    out,\n    readLine,\n    orchestrator,\n    cwd,\n    readRegistry,\n    readDaemon,\n    flagGiven,\n    deps.dryRun === true,\n  )\n}\n\n/** The two doors, in order. Index 0 is hosted, index 1 is local. */\nexport const MENU_OPTIONS: readonly string[] = [\n  'Log me into Hosted Neat',\n  \"I'd like to self-host or use it locally (copy a prompt)\",\n]\n\n/** A keypress, normalised so the menu never parses escape sequences itself. */\nexport type MenuKey = 'up' | 'down' | 'enter' | 'select-1' | 'select-2' | 'cancel' | 'ignore'\n\ninterface KeyReader {\n  read: () => Promise<MenuKey | undefined>\n  done: () => void\n}\n\n// Render the rows once, then redraw in place on every move. Returns the chosen\n// index, or undefined when the reader gives us nothing (EOF) or the user cancels.\nasync function selectOption(\n  out: (line: string) => void,\n  reader: KeyReader,\n  moveCursorUp: (rows: number) => void,\n): Promise<number | undefined> {\n  let cursor = 0\n  const render = (): void => {\n    for (const [i, label] of MENU_OPTIONS.entries()) {\n      out(i === cursor ? `  ❯ ${i + 1}) ${label}` : `    ${i + 1}) ${label}`)\n    }\n  }\n  try {\n    render()\n    out('')\n    out('  ↑/↓ to move · Enter to choose · 1 or 2 to jump')\n    for (;;) {\n      const key = await reader.read()\n      // EOF is \"nobody can answer\" and falls through to the local path, as a bare\n      // `neat` already does. Ctrl-C and Escape are a deliberate \"not this\", so they\n      // leave instead of quietly starting the extraction the person just refused.\n      if (key === undefined) return undefined\n      if (key === 'cancel') throw new PromptCancelled()\n      if (key === 'enter') return cursor\n      if (key === 'select-1') return 0\n      if (key === 'select-2') return 1\n      if (key === 'up') cursor = (cursor + MENU_OPTIONS.length - 1) % MENU_OPTIONS.length\n      else if (key === 'down') cursor = (cursor + 1) % MENU_OPTIONS.length\n      else continue // an unbound key redraws nothing\n      // Step back over the rows plus the blank line and the hint, and repaint.\n      moveCursorUp(MENU_OPTIONS.length + 2)\n      render()\n      out('')\n      out('  ↑/↓ to move · Enter to choose · 1 or 2 to jump')\n    }\n  } finally {\n    reader.done()\n  }\n}\n\n// The pre-existing numbered prompt, kept verbatim in behaviour for any terminal\n// that cannot hand us raw keys.\nasync function selectByNumber(\n  out: (line: string) => void,\n  readLine: (prompt: string) => Promise<string | undefined>,\n): Promise<number | undefined> {\n  for (const [i, label] of MENU_OPTIONS.entries()) out(`  ${i + 1}) ${label}`)\n  out('')\n  for (;;) {\n    const choice = (await readLine('Choose 1 or 2 (default 2): '))?.trim()\n    if (choice === undefined) return undefined\n    if (choice === '1') return 0\n    if (choice === '2' || choice === '') return 1\n    out(`\"${choice}\" isn't 1 or 2 — try again, or press Enter for the local path.`)\n  }\n}\n\n// Raw-mode keypresses from the real terminal. Returns null when the terminal\n// cannot do it — no TTY, or no `setRawMode` — so the caller falls back to the\n// numbered prompt rather than hanging. Raw mode is entered once and restored in\n// `done()`, so an aborted run never leaves the shell in raw mode.\nfunction createKeyReader(): KeyReader | null {\n  const stdin = process.stdin\n  if (!stdin.isTTY || typeof stdin.setRawMode !== 'function') return null\n  stdin.setRawMode(true)\n  stdin.resume()\n  let closed = false\n  // Watched once for the reader's whole life. Registering the end listener per\n  // read would miss an EOF that arrived between reads — or before the first one —\n  // and the menu would then wait on input that can never arrive.\n  let ended = false\n  const markEnded = (): void => {\n    ended = true\n  }\n  stdin.once('end', markEnded)\n  stdin.once('close', markEnded)\n  return {\n    read: () =>\n      new Promise<MenuKey | undefined>((resolve) => {\n        if (ended) {\n          resolve(undefined)\n          return\n        }\n        const finish = (value: MenuKey | undefined): void => {\n          stdin.removeListener('data', onData)\n          stdin.removeListener('end', onClosed)\n          stdin.removeListener('close', onClosed)\n          resolve(value)\n        }\n        const onData = (buf: Buffer): void => finish(decodeKey(buf))\n        const onClosed = (): void => {\n          ended = true\n          finish(undefined)\n        }\n        stdin.on('data', onData)\n        stdin.once('end', onClosed)\n        stdin.once('close', onClosed)\n      }),\n    done: () => {\n      if (closed) return\n      closed = true\n      stdin.removeListener('end', markEnded)\n      stdin.removeListener('close', markEnded)\n      stdin.setRawMode(false)\n      stdin.pause()\n    },\n  }\n}\n\nfunction decodeKey(buf: Buffer): MenuKey {\n  const s = buf.toString('utf8')\n  if (s === '\\u001b[A' || s === 'k') return 'up'\n  if (s === '\\u001b[B' || s === 'j') return 'down'\n  if (s === '\\r' || s === '\\n') return 'enter'\n  if (s === '1') return 'select-1'\n  if (s === '2') return 'select-2'\n  // Ctrl-C and a bare Escape both mean \"I didn't want this\" — treated as no\n  // answer, which lands on the local path exactly as EOF already does.\n  if (s === '\\u0003' || s === '\\u001b') return 'cancel'\n  return 'ignore'\n}\n\nfunction defaultMoveCursorUp(rows: number): void {\n  if (rows > 0) process.stdout.write(`\\u001b[${rows}A`)\n}\n\n// Menu option 2: build the local graph, then offer an agent prompt with real values.\nasync function runSelfHosted(\n  out: (line: string) => void,\n  readLine: (prompt: string) => Promise<string | undefined>,\n  orchestrator: (cwd: string, opts?: OrchestratorOverrides) => Promise<number>,\n  cwd: string,\n  readRegistry: () => Promise<{ projects: { name: string; path: string }[] }>,\n  readDaemon: (project: string) => Promise<{ projectPath: string; restPort: number } | undefined>,\n  instrumentFlagGiven: boolean,\n  dryRun: boolean,\n): Promise<number> {\n  // A project's name is its directory's basename, and names are unique across the\n  // machine — so a second `api` or `app` collides with one registered somewhere else.\n  // Ask here, before anything is written, rather than let the run reach the registry\n  // and fail with advice (`pass --project`) that a menu offers no way to take.\n  const project = await resolveProjectName(out, readLine, cwd, readRegistry)\n\n  // Then ask before editing their files. Instrumentation is the point of the local\n  // path — it is what fills the OBSERVED layer — so Enter takes it. But it writes to a\n  // manifest and runs a package manager, and doing that to someone's repo without\n  // saying so first is the kind of thing they find out about in `git status`.\n  // Someone who already passed `--no-instrument` or `--dry-run` has answered.\n  // Naming comes first: it decides what this project IS, and it is the question that\n  // has to be settled before anything is written anywhere.\n  const declined = instrumentFlagGiven ? undefined : await askToInstrument(out, readLine)\n\n  out('Building your local graph now…')\n  out('')\n  // The instrument answer given here IS the answer — the orchestrator has its own\n  // interactive prompt (`orchestrator.ts`, gated on `opts.yes`), and asking the same\n  // question twice in a row is worse than never having asked. Accepting carries\n  // `yes` so that prompt stays quiet; declining carries `--no-instrument`, which\n  // skips it for the same reason.\n  // The door's wordmark and version are the header for this run, so the\n  // orchestrator is told not to introduce the product a second time (#1242).\n  const overrides: OrchestratorOverrides = {\n    headerShown: true,\n    ...(project !== undefined ? { project } : {}),\n    ...(declined === undefined ? {} : declined ? { noInstrument: true } : { yes: true }),\n  }\n  const code = await orchestrator(cwd, overrides)\n  if (code !== 0 || dryRun) return code\n\n  const wantsPrompt = (\n    await readLine('Print a copy-paste setup prompt for your coding agent? [Y/n]: ')\n  )\n    ?.trim()\n    .toLowerCase()\n  // Default (empty / Enter / no terminal) is yes; only an explicit no skips it.\n  if (wantsPrompt !== 'n' && wantsPrompt !== 'no') {\n    const projectName = project ?? path.basename(path.resolve(cwd))\n    const daemon = await readDaemon(projectName).catch(() => undefined)\n    const port =\n      daemon && path.resolve(daemon.projectPath) === path.resolve(cwd) ? daemon.restPort : undefined\n    out('')\n    out('─── copy the directive below into your coding agent ───')\n    out('')\n    out(renderAgentSetupPrompt(projectName, port))\n    out('')\n    out('────────────────────────────────────────────────────')\n    out('')\n  }\n  return code\n}\n\n/** Overrides the front door hands the orchestrator from what the person chose. */\nexport interface OrchestratorOverrides {\n  /** A name chosen at the door because the directory's own basename was taken. */\n  project?: string\n  noInstrument?: boolean\n  /** Suppresses the orchestrator's own instrument prompt — the door already asked. */\n  yes?: boolean\n  /** The door printed the wordmark and version, so the orchestrator skips its banner. */\n  headerShown?: boolean\n}\n\n// Returns true when they declined — the value `--no-instrument` carries.\nasync function askToInstrument(\n  out: (line: string) => void,\n  readLine: (prompt: string) => Promise<string | undefined>,\n): Promise<boolean> {\n  out('Instrument the services for OpenTelemetry now?')\n  out('This edits package.json / requirements.txt / go.mod and runs the package manager.')\n  const answer = (await readLine('[Y/n]: '))?.trim().toLowerCase()\n  const declined = answer === 'n' || answer === 'no'\n  if (declined) {\n    out('')\n    out('Skipping instrumentation — the graph will hold the declared side only.')\n    out('Run `npx neat.is init . --apply` when you want the runtime half.')\n  }\n  out('')\n  return declined\n}\n\n// Returns a name to register under, or undefined to let the orchestrator use the\n// basename as it always has. Never throws: an unreadable registry means we cannot\n// know there is a collision, and guessing would be worse than the existing error.\nasync function resolveProjectName(\n  out: (line: string) => void,\n  readLine: (prompt: string) => Promise<string | undefined>,\n  cwd: string,\n  readRegistry: () => Promise<{ projects: { name: string; path: string }[] }>,\n): Promise<string | undefined> {\n  const here = path.resolve(cwd)\n  const base = path.basename(here)\n  let taken: Map<string, string>\n  try {\n    const { projects } = await readRegistry()\n    taken = new Map(projects.map((p) => [p.name, p.path]))\n  } catch {\n    return undefined\n  }\n\n  const clash = taken.get(base)\n  // No entry, or the entry IS this directory — a re-run, which registers idempotently.\n  if (clash === undefined || path.resolve(clash) === here) return undefined\n\n  out('')\n  out(`A project named \\`${base}\\` is already registered (${clash}).`)\n  const suggested = firstFreeName(base, taken)\n  for (;;) {\n    const answer = (await readLine(`Name this one: [${suggested}] `))?.trim()\n    // No terminal to answer with → take the suggestion rather than dead-end.\n    if (answer === undefined) return suggested\n    const chosen = answer.length === 0 ? suggested : answer\n    if (!isUsableProjectName(chosen)) {\n      out(`\"${chosen}\" won't work as a project name — letters, digits, dot, dash and underscore.`)\n      continue\n    }\n    const other = taken.get(chosen)\n    if (other !== undefined && path.resolve(other) !== here) {\n      out(`\\`${chosen}\\` is registered too (${other}).`)\n      continue\n    }\n    out('')\n    return chosen\n  }\n}\n\n// `<base>-2`, `-3`, … — the first that nothing holds.\nfunction firstFreeName(base: string, taken: Map<string, string>): string {\n  for (let n = 2; ; n++) {\n    const candidate = `${base}-${n}`\n    if (!taken.has(candidate)) return candidate\n  }\n}\n\n// The registry only requires a non-empty string, but a name becomes a filename\n// (`pathsForProject` writes `<name>.json`), so a separator or a traversal segment\n// would escape `neat-out/`. Keep it to what a directory basename can safely be.\nfunction isUsableProjectName(name: string): boolean {\n  return name.length > 0 && name !== '.' && name !== '..' && /^[A-Za-z0-9._-]+$/.test(name)\n}\n\nexport interface WelcomeGateDeps {\n  // Whether stdin / stdout are terminals. Default: the real process streams.\n  // Injected in tests so gating never needs a real TTY.\n  stdinIsTTY?: boolean\n  stdoutIsTTY?: boolean\n  // The directory the question is asked about. Default: process.cwd().\n  cwd?: string\n  // Reads the machine project registry through `registry.ts`, which owns that\n  // file's authority (ADR-048 §8) — nothing here names or touches it directly.\n  // An entry whose `path` resolves to `cwd` means this directory is already a\n  // NEAT project.\n  readRegistry?: () => Promise<{ projects: { path: string }[] }>\n  // Whether this directory already holds an extracted graph — a `neat-out/` with\n  // a snapshot in it. Default: a real fs check. Injected so the gate is testable\n  // without laying down files.\n  hasSnapshot?: (cwd: string) => Promise<boolean>\n}\n\n/**\n * Whether a bare, no-command `neat` should open the front door rather than run\n * the orchestrator directly. True only when:\n *   - the session is interactive (both stdin and stdout are TTYs), AND\n *   - this directory is not yet a NEAT project — no registry entry resolving to\n *     it, and no `neat-out/` snapshot sitting in it.\n *\n * The question is about the **project**, not the machine. Gating on the profile\n * store meant one `neat login` anywhere closed the door for every future project\n * on that machine, so the first run in a new repo — the moment the door exists\n * for — dropped straight into an extraction. A returning user still falls through\n * immediately in any directory they have already set up, which is the case the\n * profile gate was really protecting.\n *\n * Conservative by design: anything uncertain (an unreadable registry, a failed\n * read) returns false so the caller keeps the exact current behaviour. It never\n * throws.\n */\nexport async function shouldShowWelcome(deps: WelcomeGateDeps = {}): Promise<boolean> {\n  const stdinTTY = deps.stdinIsTTY ?? Boolean(process.stdin.isTTY)\n  const stdoutTTY = deps.stdoutIsTTY ?? Boolean(process.stdout.isTTY)\n  // Non-interactive (piped, CI, redirected) → never a menu; the orchestrator\n  // path handles scripted use exactly as before.\n  if (!stdinTTY || !stdoutTTY) return false\n\n  const cwd = deps.cwd ?? process.cwd()\n  const readRegistry = deps.readRegistry ?? (() => readRegistryFile())\n  const hasSnapshot = deps.hasSnapshot ?? defaultHasSnapshot\n\n  try {\n    const here = path.resolve(cwd)\n    const { projects } = await readRegistry()\n    // Registered under any name → already a project, whatever it is called.\n    if (projects.some((p) => path.resolve(p.path) === here)) return false\n    // Extracted here before without being registered (a bare run in a checkout,\n    // an `init` that never registered) → still not a first run.\n    if (await hasSnapshot(here)) return false\n    return true\n  } catch {\n    // Uncertain → fall back to current behaviour rather than guess.\n    return false\n  }\n}\n\n// `neat-out/` holding a snapshot is the on-disk mark that this directory has been\n// extracted before. The default project writes `graph.json`; a named project\n// writes `<name>.json` (`pathsForProject`), so any `.json` in there counts rather\n// than only the default's filename.\nasync function defaultHasSnapshot(cwd: string): Promise<boolean> {\n  try {\n    const entries = await fs.readdir(path.join(cwd, 'neat-out'))\n    return entries.some((e) => e.endsWith('.json'))\n  } catch {\n    // No `neat-out/` at all is the common case and means no snapshot.\n    return false\n  }\n}\n\n// Prompt for a line, echoed, from the terminal — the same shape login-cli.ts\n// uses. Returns undefined when stdin is not a TTY so a scripted run falls\n// through rather than hanging on a prompt nobody can answer.\nasync function defaultReadLine(prompt: string): Promise<string | undefined> {\n  if (!process.stdin.isTTY) return undefined\n  const rl = readline.createInterface({ input: process.stdin, output: process.stdout })\n  try {\n    return await rl.question(prompt)\n  } finally {\n    rl.close()\n  }\n}\n","// Generated by scripts/sync-agent-skill.mjs from packages/claude-skill/SKILL.md.\n// Do not edit this file directly.\nexport const AGENT_DIRECTIVE =\n  '## Let NEAT investigate before you search files\\n\\nThis project has NEAT. It does the investigation for this system so you can\\nspend your effort on the code: what exists, what actually ran, where a failure\\nbegan, and what a change will reach. It answers from a live graph that fuses\\ncode, data and infrastructure declarations with runtime traffic, incidents and\\nsupported provider telemetry. The graph is deterministic: you supply the\\nreasoning about the fix; NEAT resolves named nodes and traverses recorded\\nevidence rather than asking an LLM to infer architecture from file names.\\n\\nEvery claim carries provenance and confidence. `EXTRACTED` comes from recognized\\nsource or configuration, `OBSERVED` from spans or supported provider signals,\\n`INFERRED` from a bridged relationship, and `STALE` marks an observed edge that\\nwent quiet. Missing runtime evidence does not prove a path never runs.\\n\\n**For questions about this system\\'s behavior, structure, data dependencies,\\nfailures, or change impact, call the MCP `ask` tool (`mcp__neat__ask`) before\\nRead/Grep/Glob/Bash.** You do not need an exact node id. `ask` resolves names\\nand routes to the relevant graph traversal, returning provenance-tagged facts.\\nWhen MCP is unavailable, use the same door through the CLI:\\n\\n```\\nnpx neat.is ask \"why is checkout failing?\"\\nnpx neat.is ask \"what breaks if I change the orders table?\"\\nnpx neat.is ask \"what does the payments service depend on at runtime?\"\\n```\\n\\nFor a failing system, start with `investigate` — give it the service or the\\nsymptom and it composes one work order: the recorded failure with its deploy/env\\ncontext, the likely cause chain with provenance, the blast radius, the governing\\npolicies, and where declared and observed behaviour diverge. (`get_incident_card`\\ncomposes the same from an exact node id; `ask` what is failing first if you don\\'t\\nknow the node.) It is one view of the incident, not a separate source of truth;\\nNEAT also pushes this card to you when it detects a failure worth one (via `neat\\nmonitor`), the work order handed to you rather than fetched. Then\\n`get_incident_history` and `get_root_cause` for the parts, and `expand` one hop at\\na time with `relate` to test whether a suspected cause and symptom share a signal.\\n\\nBefore a change, use `get_blast_radius` and `check_policies` to see dependents\\nand advisory architectural rules. Use `get_divergences` to compare declared\\nintent with observed behavior, `get_graph_diff` to compare a saved snapshot\\nwith the live graph, and `get_recent_stale_edges` when traffic goes quiet.\\n`get_dependencies` maps a node\\'s outgoing graph; `get_observed_dependencies`\\nshows only seen runtime/provider calls. `semantic_search` finds node labels,\\nnot arbitrary source text.\\n\\nTrust the graph\\'s answer by its provenance, and stop when the fault is localized\\n— the failing node and what is wrong with it. Match one query to the symptom\\nrather than re-running the same query or sweeping every tool; a provenance-tagged\\nresult is the answer, not a cue to re-confirm it by reading source.\\n\\nRead source when the graph does not model what you need: comments, arbitrary\\nstring literals, config details, unsupported syntax, or a repository that has\\nnot been extracted or connected. If a graph answer is empty, check the daemon\\nwith `npx neat.is list` or restart it with `npx neat.is up`; wire MCP with\\n`npx neat.is skill --apply`.\\n'\n","// `neat hooks` — install the Claude Code affordances that make an agent reach\n// for NEAT's graph before it grep-scans a repo.\n//\n// Two things ship here, and they cover different audiences:\n//\n//   1. A PreToolUse search-nudge hook. When the agent calls Grep/Glob (or a\n//      Bash grep|rg|find), Claude Code runs the hook, which injects a note\n//      steering the agent to NEAT's MCP tools first. It is a gentle nudge —\n//      the search still runs. This is a Claude-Code-specific affordance.\n//\n//   2. Agent-agnostic graph-first guidance (GRAPH_FIRST.md). A markdown block\n//      a user pastes into CLAUDE.md / AGENTS.md / .cursorrules so an agent on\n//      any harness — not just Claude Code — knows to query the graph first.\n//\n// Both artifacts live in @neat.is/claude-skill and are read from there at run\n// time. `--apply` copies the hook script to a stable ~/.neat/hooks/ path and\n// merges a PreToolUse entry into ~/.claude/settings.json without disturbing a\n// user's existing hooks. It is idempotent — re-running refreshes the path and\n// never double-registers.\n//\n// This is a config command family (like `neat connector`), not a query verb,\n// so it stays off the ADR-050 locked allowlist and parses its own argv.\n\nimport path from 'node:path'\nimport os from 'node:os'\nimport { promises as fs } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\n\nexport const HOOK_FILENAME = 'neat-search-nudge.mjs'\nexport const GUIDE_FILENAME = 'GRAPH_FIRST.md'\n// The materialised guide gets a lowercased name so it sits tidily beside the\n// other ~/.neat state; the package copy keeps the SCREAMING doc name.\nexport const GUIDE_INSTALL_NAME = 'neat-graph-first.md'\n// One matcher covers the dedicated search tools, Bash, and NEAT's own MCP tools;\n// the hook self-filters Bash down to grep-family commands and ops probes, so a\n// broad Bash match is a cheap no-op. The mcp__neat__ calls are how the hook\n// learns the graph was consulted this session (ADR-261).\nexport const HOOK_MATCHER = 'Grep|Glob|Bash|mcp__neat__.*'\n\n// Same dual-format base-dir idiom banner.ts uses: __dirname in the CJS build,\n// import.meta.url in the ESM one (tsup emits both).\nfunction moduleDir(): string {\n  return typeof __dirname !== 'undefined'\n    ? __dirname\n    : path.dirname(fileURLToPath(import.meta.url))\n}\n\n// Locate a file shipped in @neat.is/claude-skill. The @neat.is/ scope directory\n// mirrors the packages/ layout, so a fixed `../../claude-skill` walk lands in\n// both the published install (node_modules/@neat.is/{core,claude-skill}/…) and\n// the monorepo (packages/{core,claude-skill}/…). The extra candidates are\n// belt-and-suspenders for unusual dist depths.\nexport async function readSkillAsset(rel: string): Promise<string> {\n  const here = moduleDir()\n  const candidates = [\n    path.resolve(here, '../../claude-skill', rel),\n    path.resolve(here, '../../../claude-skill', rel),\n    path.resolve(here, '../claude-skill', rel),\n  ]\n  for (const candidate of candidates) {\n    try {\n      return await fs.readFile(candidate, 'utf8')\n    } catch {\n      // try the next candidate\n    }\n  }\n  throw new Error(\n    `neat hooks: could not find @neat.is/claude-skill/${rel} — is the package installed?`,\n  )\n}\n\n// ~/.neat, overridable via NEAT_HOME for tests (matches registry.ts).\nfunction neatHome(): string {\n  const override = process.env.NEAT_HOME\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(os.homedir(), '.neat')\n}\n\n// Claude Code's user-level settings file — where hooks live (distinct from\n// ~/.claude.json, which holds MCP servers; `neat skill` owns that one).\n// Overridable via NEAT_CLAUDE_SETTINGS so tests never touch the real file.\nfunction claudeSettingsPath(): string {\n  const override = process.env.NEAT_CLAUDE_SETTINGS\n  if (override && override.length > 0) return path.resolve(override)\n  const home = process.env.HOME ?? process.env.USERPROFILE ?? os.homedir()\n  return path.join(home, '.claude', 'settings.json')\n}\n\nfunction installedHookPath(): string {\n  return path.join(neatHome(), 'hooks', HOOK_FILENAME)\n}\n\n// The persisted gate flag. Its mere existence flips the hook from nudge to gate\n// mode (the hook reads the same path under NEAT_HOME). `--apply --gate` writes\n// it; `--apply` without `--gate` removes it; NEAT_SEARCH_GATE=0/1 overrides at\n// run time. Exported so the gate tests can assert the flag's presence.\nexport function gateFlagPath(): string {\n  return path.join(neatHome(), 'hooks', 'gate-enabled')\n}\n\ninterface PreToolUseEntry {\n  matcher?: string\n  hooks?: Array<{ type?: string; command?: string }>\n}\n\n// True when this settings entry is our search-nudge — keyed on the script\n// filename in the command, so a user who moved the file still gets refreshed\n// rather than duplicated.\nfunction isNeatSearchEntry(entry: PreToolUseEntry): boolean {\n  return (entry.hooks ?? []).some(\n    (h) => typeof h.command === 'string' && h.command.includes(HOOK_FILENAME),\n  )\n}\n\nfunction neatHookEntry(command: string): PreToolUseEntry {\n  return { matcher: HOOK_MATCHER, hooks: [{ type: 'command', command }] }\n}\n\n// The shell command Claude Code runs. Quoted so a home dir with spaces works.\nfunction hookCommand(scriptPath: string): string {\n  return `node \"${scriptPath}\"`\n}\n\nexport interface HooksOptions {\n  apply: boolean\n  printHook: boolean\n  printGuide: boolean\n  printSettings: boolean\n  // Opt into the hard-gate mode (ADR-198). With `--apply --gate` the hook denies\n  // Grep/Glob/grep-Bash until `neat ask` has run this session; plain `--apply`\n  // keeps the default nudge. Optional — absent/false is the default nudge.\n  gate?: boolean\n}\n\nexport async function runHooks(opts: HooksOptions): Promise<{ exitCode: number }> {\n  if (opts.printHook) {\n    process.stdout.write(await readSkillAsset(`hooks/${HOOK_FILENAME}`))\n    return { exitCode: 0 }\n  }\n\n  if (opts.printGuide) {\n    process.stdout.write(await readSkillAsset(GUIDE_FILENAME))\n    return { exitCode: 0 }\n  }\n\n  if (opts.printSettings) {\n    // Show the block a manual installer would paste, pointing at the path\n    // `--apply` would materialise.\n    const block = {\n      hooks: { PreToolUse: [neatHookEntry(hookCommand(installedHookPath()))] },\n    }\n    process.stdout.write(JSON.stringify(block, null, 2) + '\\n')\n    return { exitCode: 0 }\n  }\n\n  if (opts.apply) {\n    const hookScript = await readSkillAsset(`hooks/${HOOK_FILENAME}`)\n    const guide = await readSkillAsset(GUIDE_FILENAME)\n\n    // 1. Materialise the hook script to a stable, upgrade-surviving path.\n    const scriptPath = installedHookPath()\n    await fs.mkdir(path.dirname(scriptPath), { recursive: true })\n    await fs.writeFile(scriptPath, hookScript, { mode: 0o755 })\n\n    // 2. Drop the agent-agnostic guidance beside it for easy reference.\n    const guidePath = path.join(neatHome(), GUIDE_INSTALL_NAME)\n    await fs.writeFile(guidePath, guide, 'utf8')\n\n    // 3. Merge the PreToolUse entry into ~/.claude/settings.json, leaving any\n    //    hooks the user wired by hand in place.\n    const settingsFile = claudeSettingsPath()\n    let settings: Record<string, unknown> = {}\n    try {\n      settings = JSON.parse(await fs.readFile(settingsFile, 'utf8'))\n    } catch (err) {\n      if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n        console.error(\n          `neat hooks: failed to read ${settingsFile} — ${(err as Error).message}`,\n        )\n        return { exitCode: 1 }\n      }\n    }\n\n    const hooks = (settings.hooks ?? {}) as Record<string, unknown>\n    const preToolUse = Array.isArray(hooks.PreToolUse)\n      ? [...(hooks.PreToolUse as PreToolUseEntry[])]\n      : []\n\n    const command = hookCommand(scriptPath)\n    const existingIdx = preToolUse.findIndex(isNeatSearchEntry)\n    if (existingIdx >= 0) {\n      preToolUse[existingIdx] = neatHookEntry(command)\n    } else {\n      preToolUse.push(neatHookEntry(command))\n    }\n\n    const merged = {\n      ...settings,\n      hooks: { ...hooks, PreToolUse: preToolUse },\n    }\n    await fs.mkdir(path.dirname(settingsFile), { recursive: true })\n    await fs.writeFile(settingsFile, JSON.stringify(merged, null, 2) + '\\n', 'utf8')\n\n    // 4. Persist the mode. `--gate` writes the flag the hook reads to switch to\n    //    hard-gate; a plain `--apply` clears it so the mode reflects the flags\n    //    given (deterministic + idempotent). NEAT_SEARCH_GATE=0/1 overrides at\n    //    run time either way.\n    const flag = gateFlagPath()\n    if (opts.gate) {\n      await fs.mkdir(path.dirname(flag), { recursive: true })\n      await fs.writeFile(flag, '1\\n', 'utf8')\n    } else {\n      await fs.rm(flag, { force: true })\n    }\n\n    const mode = opts.gate ? 'GATE (deny search until you ask the graph)' : 'nudge (search still runs)'\n    console.log(`neat hooks: installed the search hook in ${opts.gate ? 'gate' : 'nudge'} mode`)\n    console.log(`  script:   ${scriptPath}`)\n    console.log(`  settings: ${settingsFile} (PreToolUse → ${HOOK_MATCHER})`)\n    console.log(`  guidance: ${guidePath}`)\n    console.log(`  mode:     ${mode}`)\n    console.log('')\n    if (opts.gate) {\n      console.log('restart Claude Code to load the hook. A Grep/Glob or Bash grep is now DENIED')\n      console.log('until you run `neat ask \"<question>\"` (or the ask MCP tool) once this session;')\n      console.log('after that, search is allowed as a fallback. Set NEAT_SEARCH_GATE=0 to fall')\n      console.log('back to nudge-only without re-running.')\n    } else {\n      console.log('restart Claude Code to load the hook. On a Grep/Glob or a Bash grep,')\n      console.log('your agent will now be nudged to query NEAT first (the search still runs).')\n      console.log('Re-run with --gate to hard-force the graph-first orientation.')\n    }\n    console.log('')\n    console.log('The hook is Claude-Code-specific. For agents on other harnesses, paste')\n    console.log(`the guidance above into your project instructions (CLAUDE.md / AGENTS.md).`)\n    return { exitCode: 0 }\n  }\n\n  usage()\n  return { exitCode: 0 }\n}\n\nfunction usage(): void {\n  console.log('neat hooks — wire NEAT into your agent so it queries the graph before grepping')\n  console.log('')\n  console.log('  --apply          install the Claude Code search hook and write the')\n  console.log('                   graph-first guidance to ~/.neat/, merging into')\n  console.log('                   ~/.claude/settings.json without touching your other hooks')\n  console.log('  --gate           with --apply, enable hard-gate mode: DENY Grep/Glob/grep-Bash')\n  console.log('                   until `neat ask` has run this session (default is nudge-only).')\n  console.log('                   Toggle off at run time with NEAT_SEARCH_GATE=0.')\n  console.log('  --print-hook     print the hook script to stdout')\n  console.log('  --print-guide    print the agent-agnostic graph-first guidance to stdout')\n  console.log('  --print-settings print the settings.json PreToolUse block --apply would add')\n  console.log('')\n  console.log('By default the hook is a gentle, non-blocking nudge — searches still run.')\n  console.log('--gate turns it into a hard forcing mechanism. It is Claude-Code-specific;')\n  console.log('other harnesses get the same steer from the graph-first guidance.')\n}\n\n// Parse this command family's own argv and dispatch. Mirrors runConnectorCommand\n// — a config command, not a locked query verb.\nexport async function runHooksCommand(args: string[]): Promise<number> {\n  const opts: HooksOptions = {\n    apply: false,\n    printHook: false,\n    printGuide: false,\n    printSettings: false,\n    gate: false,\n  }\n  for (const arg of args) {\n    switch (arg) {\n      case '--apply':\n        opts.apply = true\n        break\n      case '--gate':\n        opts.gate = true\n        break\n      case '--print-hook':\n        opts.printHook = true\n        break\n      case '--print-guide':\n        opts.printGuide = true\n        break\n      case '--print-settings':\n        opts.printSettings = true\n        break\n      case '-h':\n      case '--help':\n        usage()\n        return 0\n      default:\n        console.error(`neat hooks: unknown flag \"${arg}\"`)\n        usage()\n        return 2\n    }\n  }\n  try {\n    const { exitCode } = await runHooks(opts)\n    return exitCode\n  } catch (err) {\n    console.error((err as Error).message)\n    return 1\n  }\n}\n","// `neat claude` — make the investigate-first directive always-on for Claude Code by\n// writing a `## neat` section into the project's local CLAUDE.md (ADR-198).\n//\n// This mirrors `graphify claude install`: no manual trigger, no slash command —\n// CLAUDE.md is loaded on every session, so the directive is in front of the\n// agent from the first turn. It is the third leg of the enforcer:\n//\n//   1. `neat ask` gives the graph a plain-language door (lower friction than grep).\n//   2. GRAPH_FIRST.md turns the guidance imperative.\n//   3. `neat claude install` injects that imperative into the always-on CLAUDE.md.\n//\n// A config command family (like `neat hooks` / `neat codex`), not a query verb,\n// so it stays off the ADR-050 locked allowlist and parses its own argv.\n// Idempotent: `install` appends the `## neat` section or replaces the one\n// already there, never duplicating; `uninstall` removes it. A re-run of\n// `install` writes byte-identical content.\n\nimport path from 'node:path'\nimport { promises as fs } from 'node:fs'\n\nexport const NEAT_SECTION_HEADING = '## neat'\n\n// The investigate-first directive. Pointed at `neat ask` — the one door that fronts\n// the whole tool surface — so the agent never has to know which structured tool\n// or which exact node id to reach for. Kept tight and imperative.\nexport const NEAT_DIRECTIVE_BODY = `This project has NEAT wired in. NEAT does the investigation for you: it keeps a\nlive, fused semantic graph of the system — code and runtime behaviour in one model,\nevery fact tagged with its provenance (EXTRACTED / OBSERVED / INFERRED / STALE) and\na confidence — so you can spend your effort on the code instead of reconstructing\nhow the system works.\n\nFor ANY question about this system's behaviour, dependencies, failures, root cause,\nor blast radius, ask NEAT FIRST — before Read, Grep, Glob, or Bash. Use the \\`ask\\`\nMCP tool (\\`mcp__neat__ask\\`) when NEAT's MCP server is wired in, or the CLI:\n\n    neat ask \"why is checkout failing?\"\n    neat ask \"what breaks if I change the orders table?\"\n    neat ask \"what does the payments service depend on at runtime?\"\n\n\\`ask\\` resolves your question to graph nodes and routes it to the right traversal,\nreturning one compact, provenance-tagged answer — you do not need an exact node id.\n\nWhen something is failing, query the incident: \\`get_incident_history\\` and\n\\`get_root_cause\\` on the service, file, or symbol return the recorded errors with\ntheir deploy/env context and the likely cause chain. \\`get_incident_card\\` composes\nthese into one work order — one view of the incident, not a separate truth. Use\n\\`expand\\` and \\`relate\\` to confirm the cause. Before a change, \\`get_blast_radius\\`\nand \\`check_policies\\` show what it reaches and the rules that govern it, and\n\\`get_divergences\\` shows where code and production disagree.\n\nTrust a result by its provenance and stop when the fault is localized — the failing\nnode and what is wrong with it. Match one query to the symptom instead of re-running\nthe same one or sweeping every tool; a provenance-tagged answer is the answer, not a\ncue to re-confirm it by reading source.\n\nFall back to Read/Grep for what the graph does not model — comments, string literals,\nconfig minutiae, or a repo with no graph yet. If NEAT errors, the daemon may be down\n(\\`neat list\\`) — start it with \\`neat up\\`, then retry.`\n\n// The full section, heading included. One trailing newline so it sits cleanly\n// between other content.\nexport function neatSection(): string {\n  return `${NEAT_SECTION_HEADING}\\n\\n${NEAT_DIRECTIVE_BODY}\\n`\n}\n\n// CLAUDE.md at the project root (cwd). Overridable via NEAT_CLAUDE_MD so tests\n// never touch a real file.\nexport function claudeMdPath(): string {\n  const override = process.env.NEAT_CLAUDE_MD\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(process.cwd(), 'CLAUDE.md')\n}\n\n// Split existing CLAUDE.md content around NEAT's `## neat` section. The section\n// runs from its heading to the next level-2 (`## `) heading or end of file, so\n// removing/replacing it leaves every other section byte-intact. Returns the\n// text before and after the section (each already newline-trimmed at the seam),\n// and whether a section was present.\ninterface Split {\n  before: string\n  after: string\n  found: boolean\n}\n\nfunction splitAroundSection(raw: string): Split {\n  const lines = raw.split('\\n')\n  // A heading line that is exactly `## neat` (allowing trailing whitespace).\n  const startIdx = lines.findIndex((l) => l.replace(/\\s+$/, '') === NEAT_SECTION_HEADING)\n  if (startIdx === -1) {\n    // Trim the trailing newline(s) so appending the section adds exactly one\n    // blank-line gap — the same seam the found case produces, so a first install\n    // and a re-install land byte-identical.\n    return { before: raw.replace(/\\n*$/, ''), after: '', found: false }\n  }\n  // The section ends at the next level-2+ heading (`## ` … but not our own line)\n  // or the end of the file.\n  let endIdx = lines.length\n  for (let i = startIdx + 1; i < lines.length; i++) {\n    if (/^#{1,2}\\s+/.test(lines[i] ?? '')) {\n      endIdx = i\n      break\n    }\n  }\n  const before = lines.slice(0, startIdx).join('\\n').replace(/\\n*$/, '')\n  const after = lines.slice(endIdx).join('\\n').replace(/^\\n*/, '')\n  return { before, after, found: true }\n}\n\n// Compose the final file text: NEAT's section, with the user's own content (the\n// part before and after the old section) preserved around it. Ends in exactly\n// one trailing newline.\nfunction compose(before: string, after: string): string {\n  const parts: string[] = []\n  if (before.length > 0) parts.push(before)\n  parts.push(neatSection().replace(/\\n+$/, ''))\n  if (after.length > 0) parts.push(after)\n  return parts.join('\\n\\n').replace(/\\n*$/, '') + '\\n'\n}\n\nexport interface ClaudeResult {\n  exitCode: number\n}\n\nasync function readIfExists(file: string): Promise<string | null> {\n  try {\n    return await fs.readFile(file, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null\n    throw err\n  }\n}\n\n// Wires the MCP server the directive names into the agent's config and returns a\n// line saying where; injected by cli.ts, which owns that writer (ADR-259, #1397).\ntype WireMcp = () => Promise<string>\n\nasync function runInstall(wireMcp?: WireMcp): Promise<ClaudeResult> {\n  const file = claudeMdPath()\n  const raw = (await readIfExists(file)) ?? ''\n  const { before, after, found } = splitAroundSection(raw)\n  const next = compose(before, after)\n  await fs.mkdir(path.dirname(file), { recursive: true })\n  await fs.writeFile(file, next, 'utf8')\n  const verb = raw.length === 0 ? 'created' : found ? 'refreshed' : 'added'\n  console.log(`neat claude: ${verb} the \\`${NEAT_SECTION_HEADING}\\` section in ${file}`)\n  if (wireMcp) {\n    try {\n      console.log(`neat claude: ${await wireMcp()}`)\n    } catch (err) {\n      console.error(`neat claude: could not wire the MCP server — ${(err as Error).message}`)\n      console.error('Run `npx neat.is skill --apply` to wire it by hand.')\n      return { exitCode: 1 }\n    }\n  } else {\n    console.log('Wire the MCP tools the directive names: `npx neat.is skill --apply`.')\n  }\n  console.log('Your agent will now reach for `neat ask` before Read/Grep/Bash. Restart the')\n  console.log('session (or reload CLAUDE.md) to pick it up.')\n  return { exitCode: 0 }\n}\n\nasync function runUninstall(): Promise<ClaudeResult> {\n  const file = claudeMdPath()\n  const raw = await readIfExists(file)\n  if (raw === null) {\n    console.log(`neat claude: no CLAUDE.md at ${file} — nothing to remove.`)\n    return { exitCode: 0 }\n  }\n  const { before, after, found } = splitAroundSection(raw)\n  if (!found) {\n    console.log(`neat claude: no \\`${NEAT_SECTION_HEADING}\\` section in ${file} — nothing to remove.`)\n    return { exitCode: 0 }\n  }\n  const remaining = [before, after].filter((s) => s.length > 0).join('\\n\\n')\n  const next = remaining.length > 0 ? remaining.replace(/\\n*$/, '') + '\\n' : ''\n  await fs.writeFile(file, next, 'utf8')\n  console.log(`neat claude: removed the \\`${NEAT_SECTION_HEADING}\\` section from ${file}.`)\n  return { exitCode: 0 }\n}\n\nfunction usage(): void {\n  console.log('neat claude — make the query-first directive always-on in Claude Code')\n  console.log('')\n  console.log('  install     write (or refresh) a `## neat` section in ./CLAUDE.md so your')\n  console.log('              agent reaches for `neat ask` before Read/Grep/Bash')\n  console.log('  uninstall   remove the `## neat` section from ./CLAUDE.md')\n  console.log('  print       print the directive block to stdout (for a manual paste)')\n  console.log('')\n  console.log('Idempotent: re-running install replaces its own section, never duplicates it.')\n  console.log('Target file overridable via NEAT_CLAUDE_MD.')\n}\n\n// Parse this command family's own argv and dispatch. Mirrors runHooksCommand.\nexport async function runClaudeCommand(args: string[], wireMcp?: WireMcp): Promise<number> {\n  const sub = args[0]\n  if (sub === '-h' || sub === '--help' || sub === undefined) {\n    usage()\n    return sub === undefined ? 2 : 0\n  }\n  try {\n    switch (sub) {\n      case 'install':\n        return (await runInstall(wireMcp)).exitCode\n      case 'uninstall':\n        return (await runUninstall()).exitCode\n      case 'print':\n        process.stdout.write(neatSection())\n        return 0\n      default:\n        console.error(`neat claude: unknown subcommand \"${sub}\"`)\n        usage()\n        return 2\n    }\n  } catch (err) {\n    console.error(`neat claude: ${(err as Error).message}`)\n    return 1\n  }\n}\n","// `neat codex` — one-command install of NEAT into the OpenAI Codex CLI.\n//\n// NEAT already ships a one-install Claude Code plugin (ADR-159) and the\n// `neat skill`/`neat hooks` à-la-carte commands for Claude Code. Every other\n// MCP-capable agent has to be wired by hand. This closes the Codex gap ADR-159\n// named (\"both Claude Code and Codex\"), mirroring the skill/hooks shape:\n//\n//   1. Add an `[mcp_servers.neat]` table to `~/.codex/config.toml` — the MCP\n//      server invocation is `npx -y @neat.is/mcp`, the same one the Claude\n//      skill writes. Codex reads MCP servers from that TOML file under\n//      `[mcp_servers.<name>]` (command + optional args + optional env for a\n//      local stdio server). Any existing servers and all other config are\n//      preserved; a re-run only refreshes NEAT's own table.\n//\n//   2. Write NEAT's agent-agnostic graph-first guidance (GRAPH_FIRST.md, the\n//      same block the hooks command materialises) into `AGENTS.md` at the\n//      project root, delimited by stable markers so a re-run replaces only\n//      NEAT's block and leaves the user's own instructions alone.\n//\n// Plan by default (print the diff, write nothing); `--apply` to write. A\n// malformed existing config.toml is a clear error and no partial write — a\n// wrong config is worse than none. This is a config command family (like\n// `neat connector` / `neat hooks`), not a locked query verb, so it parses its\n// own argv.\n\nimport path from 'node:path'\nimport os from 'node:os'\nimport { promises as fs } from 'node:fs'\nimport { isDeepStrictEqual } from 'node:util'\nimport { parse as parseToml, stringify as stringifyToml } from 'smol-toml'\nimport { GUIDE_FILENAME, readSkillAsset } from './hooks-cli.js'\n\n// The MCP server NEAT registers with Codex. The invocation matches the Claude\n// skill (`npx -y @neat.is/mcp`); NEAT_CORE_URL is the canonical env var the MCP\n// server reads for the daemon URL, defaulting to the local daemon.\nexport const CODEX_MCP_SERVER = {\n  command: 'npx',\n  args: ['-y', '@neat.is/mcp'],\n  env: { NEAT_CORE_URL: 'http://localhost:8080' },\n} as const\n\n// The canonical `[mcp_servers.neat]` block, rendered deterministically. All\n// values are fixed constants with no TOML-special characters, so a template is\n// exact; the block is re-parsed and verified before anything is written.\nexport const CODEX_NEAT_BLOCK = [\n  '[mcp_servers.neat]',\n  'command = \"npx\"',\n  'args = [\"-y\", \"@neat.is/mcp\"]',\n  'env = { NEAT_CORE_URL = \"http://localhost:8080\" }',\n].join('\\n')\n\n// Stable delimiters around NEAT's graph-first block in AGENTS.md, so a re-run\n// replaces only NEAT's block and never the user's own guidance.\nexport const NEAT_GRAPH_FIRST_START = '<!-- neat:graph-first -->'\nexport const NEAT_GRAPH_FIRST_END = '<!-- /neat:graph-first -->'\n\n// ~/.codex/config.toml — Codex CLI's user-level config. Overridable via\n// NEAT_CODEX_CONFIG so tests never touch the real file.\nexport function codexConfigPath(): string {\n  const override = process.env.NEAT_CODEX_CONFIG\n  if (override && override.length > 0) return path.resolve(override)\n  const home = process.env.HOME ?? process.env.USERPROFILE ?? os.homedir()\n  return path.join(home, '.codex', 'config.toml')\n}\n\n// AGENTS.md at the project root (cwd). Overridable via NEAT_CODEX_AGENTS so\n// tests can point it at a temp file without changing the process cwd.\nexport function agentsFilePath(): string {\n  const override = process.env.NEAT_CODEX_AGENTS\n  if (override && override.length > 0) return path.resolve(override)\n  return path.join(process.cwd(), 'AGENTS.md')\n}\n\n// A TOML table/array-of-tables header line, e.g. `[mcp_servers.neat]`.\nfunction isTableHeader(line: string): boolean {\n  return /^\\s*\\[\\[?[^\\]]+\\]\\]?\\s*$/.test(line)\n}\n\n// The dotted name inside a header line, whitespace-trimmed.\nfunction tableName(line: string): string {\n  return line.trim().replace(/^\\[\\[?/, '').replace(/\\]\\]?$/, '').trim()\n}\n\nfunction isNeatHeader(line: string): boolean {\n  return isTableHeader(line) && tableName(line) === 'mcp_servers.neat'\n}\n\n// True when a header belongs to NEAT's own table (the table itself or a\n// sub-table like `[mcp_servers.neat.env]`), so a re-run consumes and refreshes\n// the whole definition rather than leaving a stale sub-table behind.\nfunction isNeatChildHeader(line: string): boolean {\n  if (!isTableHeader(line)) return false\n  const name = tableName(line)\n  return name === 'mcp_servers.neat' || name.startsWith('mcp_servers.neat.')\n}\n\n// Splice NEAT's `[mcp_servers.neat]` block into an existing config.toml,\n// preserving every other table, key, value, and comment. Returns the new text\n// and whether it differs from the input. Throws on malformed TOML (fail\n// honest — the caller turns that into a clear error with no write).\n//\n// The common path is a byte-preserving splice (only the whitespace directly\n// around NEAT's own block is normalised); it is then re-parsed and deep-compared\n// against the original parse, and any mismatch falls back to a full smol-toml\n// round-trip that is guaranteed to preserve every key. Either way an unverified\n// config is never returned.\nexport function upsertCodexConfig(raw: string): { text: string; changed: boolean } {\n  const trimmed = raw.trim()\n  const parsed = (trimmed.length > 0 ? parseToml(raw) : {}) as Record<string, unknown>\n\n  // Already exactly what we'd write? Report no change without reformatting.\n  const existingServers = (parsed.mcp_servers ?? {}) as Record<string, unknown>\n  const spliced = spliceNeatBlock(raw)\n\n  let text: string\n  if (verifyPreserved(raw, spliced, parsed)) {\n    text = spliced\n  } else {\n    // Fallback: the real serializer. Preserves every key; loses only comments\n    // and exact layout. Used only when the splice can't be proven lossless.\n    const merged = {\n      ...parsed,\n      mcp_servers: { ...existingServers, neat: CODEX_MCP_SERVER },\n    }\n    text = stringifyToml(merged)\n    if (!text.endsWith('\\n')) text += '\\n'\n  }\n\n  return { text, changed: text !== raw }\n}\n\n// Textual splice of the neat block, boundary-detected by table headers.\nfunction spliceNeatBlock(raw: string): string {\n  const block = CODEX_NEAT_BLOCK\n  const lines = raw.length > 0 ? raw.split('\\n') : []\n\n  const start = lines.findIndex(isNeatHeader)\n  if (start === -1) {\n    const base = raw.replace(/\\n+$/, '')\n    return base.length > 0 ? `${base}\\n\\n${block}\\n` : `${block}\\n`\n  }\n\n  // Consume NEAT's header, its body, and any of its own sub-tables; stop at the\n  // first unrelated table header (or EOF).\n  let end = start + 1\n  for (;;) {\n    while (end < lines.length && !isTableHeader(lines[end])) end++\n    if (end < lines.length && isNeatChildHeader(lines[end])) {\n      end++\n      continue\n    }\n    break\n  }\n\n  const before = lines.slice(0, start).join('\\n').replace(/\\n*$/, '')\n  const after = lines.slice(end).join('\\n').replace(/^\\n*/, '')\n\n  let text = ''\n  if (before.length > 0) text += `${before}\\n\\n`\n  text += `${block}\\n`\n  if (after.length > 0) text += `\\n${after}`\n  return `${text.replace(/\\n*$/, '')}\\n`\n}\n\n// Confirm the spliced text parses, carries exactly our neat server, and left\n// every other table/key byte-equal to the original parse.\nfunction verifyPreserved(\n  raw: string,\n  spliced: string,\n  original: Record<string, unknown>,\n): boolean {\n  let next: Record<string, unknown>\n  try {\n    next = parseToml(spliced) as Record<string, unknown>\n  } catch {\n    return false\n  }\n\n  const origServers = (original.mcp_servers ?? {}) as Record<string, unknown>\n  const nextServers = (next.mcp_servers ?? {}) as Record<string, unknown>\n\n  if (!isDeepStrictEqual(nextServers.neat, CODEX_MCP_SERVER)) return false\n  for (const name of Object.keys(origServers)) {\n    if (name === 'neat') continue\n    if (!isDeepStrictEqual(nextServers[name], origServers[name])) return false\n  }\n  for (const name of Object.keys(nextServers)) {\n    if (name !== 'neat' && !(name in origServers)) return false\n  }\n  for (const key of Object.keys(original)) {\n    if (key === 'mcp_servers') continue\n    if (!isDeepStrictEqual(next[key], original[key])) return false\n  }\n  for (const key of Object.keys(next)) {\n    if (key !== 'mcp_servers' && !(key in original)) return false\n  }\n  return true\n}\n\n// The AGENTS.md graph-first block: NEAT's guidance wrapped in the stable\n// markers.\nexport function agentsBlock(guide: string): string {\n  return `${NEAT_GRAPH_FIRST_START}\\n${guide.replace(/\\s+$/, '')}\\n${NEAT_GRAPH_FIRST_END}\\n`\n}\n\n// Write (or refresh) NEAT's graph-first block in AGENTS.md, replacing only the\n// delimited block and preserving the user's other content byte-for-byte.\nexport function upsertAgents(raw: string, guide: string): { text: string; changed: boolean } {\n  const block = agentsBlock(guide)\n  if (raw.length === 0) return { text: block, changed: true }\n\n  const startIdx = raw.indexOf(NEAT_GRAPH_FIRST_START)\n  const endIdx = raw.indexOf(NEAT_GRAPH_FIRST_END)\n  if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {\n    const before = raw.slice(0, startIdx)\n    const after = raw.slice(endIdx + NEAT_GRAPH_FIRST_END.length)\n    const text = `${before}${block.replace(/\\n+$/, '')}${after}`\n    return { text, changed: text !== raw }\n  }\n\n  const base = raw.replace(/\\n+$/, '')\n  const text = base.length > 0 ? `${base}\\n\\n${block}` : block\n  return { text, changed: text !== raw }\n}\n\nexport interface CodexOptions {\n  apply: boolean\n  printConfig: boolean\n  printGuide: boolean\n}\n\nasync function readGuide(): Promise<string> {\n  return readSkillAsset(GUIDE_FILENAME)\n}\n\nexport async function runCodex(opts: CodexOptions): Promise<{ exitCode: number }> {\n  if (opts.printConfig) {\n    process.stdout.write(`${CODEX_NEAT_BLOCK}\\n`)\n    return { exitCode: 0 }\n  }\n\n  if (opts.printGuide) {\n    process.stdout.write(agentsBlock(await readGuide()))\n    return { exitCode: 0 }\n  }\n\n  const configPath = codexConfigPath()\n  const agentsPath = agentsFilePath()\n\n  // Read what's there (absent files are fine — we create them on apply).\n  let configRaw = ''\n  try {\n    configRaw = await fs.readFile(configPath, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n      console.error(`neat codex: failed to read ${configPath} — ${(err as Error).message}`)\n      return { exitCode: 1 }\n    }\n  }\n\n  let agentsRaw = ''\n  try {\n    agentsRaw = await fs.readFile(agentsPath, 'utf8')\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n      console.error(`neat codex: failed to read ${agentsPath} — ${(err as Error).message}`)\n      return { exitCode: 1 }\n    }\n  }\n\n  // A malformed existing config is a hard stop — no partial write.\n  let config: { text: string; changed: boolean }\n  try {\n    config = upsertCodexConfig(configRaw)\n  } catch (err) {\n    console.error(\n      `neat codex: ${configPath} is not valid TOML — ${(err as Error).message}`,\n    )\n    console.error('neat codex: fix the file and re-run; nothing was written.')\n    return { exitCode: 1 }\n  }\n\n  const guide = await readGuide()\n  const agents = upsertAgents(agentsRaw, guide)\n\n  if (!opts.apply) {\n    // Plan by default: describe the change, write nothing.\n    console.log('neat codex — plan (nothing written; re-run with --apply to write)')\n    console.log('')\n    console.log(`  Codex MCP config: ${configPath}`)\n    console.log(\n      config.changed\n        ? `    ${configRaw ? 'update' : 'create'} the [mcp_servers.neat] table:`\n        : '    already up to date — [mcp_servers.neat] matches',\n    )\n    if (config.changed) {\n      for (const line of CODEX_NEAT_BLOCK.split('\\n')) console.log(`      ${line}`)\n    }\n    console.log('')\n    console.log(`  Project instructions: ${agentsPath}`)\n    console.log(\n      agents.changed\n        ? `    ${agentsRaw ? 'update' : 'create'} the graph-first block (between ${NEAT_GRAPH_FIRST_START} markers)`\n        : '    already up to date — graph-first block matches',\n    )\n    console.log('')\n    console.log('The MCP server reads NEAT_CORE_URL for the daemon URL — edit that value in')\n    console.log('the generated table to point Codex at a non-default daemon.')\n    return { exitCode: 0 }\n  }\n\n  // Apply: write only what actually changed.\n  if (config.changed) {\n    await fs.mkdir(path.dirname(configPath), { recursive: true })\n    await fs.writeFile(configPath, config.text, 'utf8')\n    console.log(`neat codex: wrote [mcp_servers.neat] to ${configPath}`)\n  } else {\n    console.log(`neat codex: ${configPath} already has NEAT's MCP server`)\n  }\n\n  if (agents.changed) {\n    await fs.mkdir(path.dirname(agentsPath), { recursive: true })\n    await fs.writeFile(agentsPath, agents.text, 'utf8')\n    console.log(`neat codex: wrote the graph-first block to ${agentsPath}`)\n  } else {\n    console.log(`neat codex: ${agentsPath} already has the graph-first block`)\n  }\n\n  console.log('')\n  console.log('restart Codex to pick up the new MCP server. NEAT_CORE_URL in the table')\n  console.log('points the server at the local daemon — edit it for a non-default one.')\n  return { exitCode: 0 }\n}\n\nfunction usage(): void {\n  console.log('neat codex — install NEAT into the OpenAI Codex CLI (MCP server + AGENTS.md)')\n  console.log('')\n  console.log('  (no flag)        plan: print what would change, write nothing')\n  console.log('  --apply          add [mcp_servers.neat] to ~/.codex/config.toml and write')\n  console.log('                   the graph-first block into ./AGENTS.md, merging into both')\n  console.log('                   without touching your other servers or instructions')\n  console.log('  --print-config   print the [mcp_servers.neat] TOML block to stdout')\n  console.log('  --print-guide    print the AGENTS.md graph-first block to stdout')\n  console.log('')\n  console.log('Existing config is preserved and a re-run is a no-op. A malformed')\n  console.log('config.toml is a clear error with no partial write.')\n}\n\n// Parse this command family's own argv and dispatch. Mirrors runHooksCommand /\n// runConnectorCommand — a config command, not a locked query verb.\nexport async function runCodexCommand(args: string[]): Promise<number> {\n  const opts: CodexOptions = { apply: false, printConfig: false, printGuide: false }\n  for (const arg of args) {\n    switch (arg) {\n      case '--apply':\n        opts.apply = true\n        break\n      case '--print-config':\n        opts.printConfig = true\n        break\n      case '--print-guide':\n        opts.printGuide = true\n        break\n      case '-h':\n      case '--help':\n        usage()\n        return 0\n      default:\n        console.error(`neat codex: unknown flag \"${arg}\"`)\n        usage()\n        return 2\n    }\n  }\n  try {\n    const { exitCode } = await runCodex(opts)\n    return exitCode\n  } catch (err) {\n    console.error((err as Error).message)\n    return 1\n  }\n}\n","// `neat cursor` / `neat devin` / `neat gemini` / `neat qwen` / `neat amazonq` /\n// `neat roocode` / `neat zed` / `neat opencode` / `neat crush` — one-command\n// install of NEAT's stdio MCP server into the agent clients that each read a\n// standard MCP config but keep it in their own file, so a Claude Code user's\n// setup does nothing for them.\n//\n// NEAT already ships a one-install Claude Code plugin (ADR-159), the à-la-carte\n// `neat skill` / `neat hooks` commands, `neat codex`, and a VS Code / Open VSX\n// extension (ADR-171). These verbs extend the same shape to the rest of the\n// stdio-MCP client family (ADR-172, ADR-176): each writes NEAT's MCP server into\n// the client's own config, merge-never-clobber, and — where the client has a\n// single always-on rules file we can verify — drops the agent-agnostic\n// graph-first guidance (GRAPH_FIRST.md, the same block `neat hooks` hands out)\n// into it.\n//\n// The shape mirrors the precedent exactly — plan by default, `--apply` to write,\n// idempotent, additive (never clobbers a server or rule the user set by hand).\n// One implementation, one descriptor per client carrying the few things that\n// differ: where the MCP config lives, the key the server is keyed under, the\n// file format, the server object itself (most clients take the flat\n// `{ command, args }`; OpenCode and Crush carry their own shape), and\n// (optionally) the rules file NEAT's guidance lands in.\n//\n// Config surfaces were verified against the clients' own docs (Aug 2026):\n//   Cursor    ~/.cursor/mcp.json, top-level `mcpServers` — docs.cursor.com/context/mcp\n//   Devin     ~/.codeium/windsurf/mcp_config.json (Cascade kept the legacy\n//             Codeium path), `mcpServers` — docs.devin.ai/desktop/cascade/mcp\n//   Gemini    ~/.gemini/settings.json, `mcpServers` — github.com/google-gemini/gemini-cli\n//   Qwen      ~/.qwen/settings.json, `mcpServers` (gemini-cli fork) —\n//             qwenlm.github.io/qwen-code-docs\n//   Amazon Q  ~/.aws/amazonq/mcp.json, `mcpServers` — docs.aws.amazon.com/amazonq\n//   Roo Code  <project>/.roo/mcp.json, `mcpServers`, project-scoped and meant to\n//             be committed — roocodeinc.github.io/Roo-Code\n//   Zed       ~/.config/zed/settings.json (Windows %APPDATA%\\Zed\\settings.json),\n//             `context_servers`, JSONC — zed.dev/docs/ai/mcp\n//   OpenCode  ~/.config/opencode/opencode.json (XDG-aware), `mcp` —\n//             opencode.ai/docs/mcp-servers\n//   Crush     ~/.config/crush/crush.json (XDG-aware), `mcp` —\n//             charmbracelet-crush.mintlify.app/configuration/mcp\n// The first seven take NEAT's stdio server as the flat `{ command, args }` keyed\n// by name (Zed's schema is the flat `command`-string form, verified against\n// crates/settings_content). OpenCode and Crush share the `mcp` key but each\n// carries its own server-object shape, so the descriptor sets `serverEntry`.\n//\n// This is a config command family (like `neat connector` / `neat hooks`), not a\n// locked ADR-050 query verb, so it parses its own argv.\n\nimport path from 'node:path'\nimport os from 'node:os'\nimport { promises as fs } from 'node:fs'\nimport { isDeepStrictEqual } from 'node:util'\nimport * as jsonc from 'jsonc-parser'\nimport { readSkillAsset, GUIDE_FILENAME } from './hooks-cli.js'\n\n// The MCP server entry every client gets. `npx -y @neat.is/mcp` is NEAT's\n// stdio MCP server; it finds its daemon itself (the cwd's project, else the one\n// running daemon, ADR-259), and NEAT_CORE_URL overrides. Minimal on purpose — this is exactly the\n// object the clients' docs show for an stdio server, Zed's flat form included.\nexport const NEAT_MCP_SERVER = {\n  command: 'npx',\n  args: ['-y', '@neat.is/mcp'],\n} as const\n\n// OpenCode's server-object shape differs from the flat form above: the command\n// is an ARRAY, the server declares `type: \"local\"`, and it carries `enabled`\n// (verified against opencode.ai/docs/mcp-servers, Aug 2026).\nexport const NEAT_OPENCODE_SERVER = {\n  type: 'local',\n  command: ['npx', '-y', '@neat.is/mcp'],\n  enabled: true,\n} as const\n\n// Crush wants an explicit `type: \"stdio\"` alongside the string command + args\n// (verified against charmbracelet-crush.mintlify.app/configuration/mcp, Aug 2026).\nexport const NEAT_CRUSH_SERVER = {\n  type: 'stdio',\n  command: 'npx',\n  args: ['-y', '@neat.is/mcp'],\n} as const\n\n// Marker pair that fences NEAT's block inside the rules file, so a re-run\n// replaces only our block and leaves everything the user wrote untouched.\nexport const GRAPH_FIRST_MARKER_OPEN = '<!-- neat:graph-first -->'\nexport const GRAPH_FIRST_MARKER_CLOSE = '<!-- /neat:graph-first -->'\n\nexport type EditorClientId =\n  | 'cursor'\n  | 'devin'\n  | 'gemini'\n  | 'qwen'\n  | 'amazonq'\n  | 'roocode'\n  | 'zed'\n  | 'opencode'\n  | 'crush'\n\nexport interface EditorClient {\n  id: EditorClientId\n  label: string\n  docsUrl: string\n  // Absolute path to the client's MCP config file. Env override so tests never\n  // touch the real file (mirrors NEAT_CLAUDE_CONFIG for `skill`).\n  mcpConfigPath: () => string\n  // The object the server is keyed under. `mcpServers` for every client except\n  // Zed, which uses `context_servers`.\n  mcpContainerKey: string\n  // The config file's format. `json` — parse and rewrite. `jsonc` (Zed) — edit\n  // in place so the comments a fresh settings.json ships with survive.\n  format: 'json' | 'jsonc'\n  // The object written under `<mcpContainerKey>.neat`. Omitted for the clients\n  // that take the flat `{ command, args }` shape (they inherit NEAT_MCP_SERVER);\n  // OpenCode and Crush set their own shape here.\n  serverEntry?: Readonly<Record<string, unknown>>\n  // The single always-on rules/context file NEAT's guidance lands in, at the\n  // project root. Omitted for clients whose rules surface is a directory rather\n  // than one verifiable file (Amazon Q, Roo Code) — those verbs are\n  // MCP-config-only.\n  rulesFileName?: string\n}\n\nfunction homeDir(): string {\n  return process.env.HOME ?? process.env.USERPROFILE ?? os.homedir()\n}\n\n// The base directory OpenCode and Crush resolve their global config under:\n// $XDG_CONFIG_HOME when set, else ~/.config — both honour the XDG spec (verified\n// against their docs, Aug 2026).\nfunction xdgConfigDir(): string {\n  const xdg = process.env.XDG_CONFIG_HOME\n  return xdg && xdg.length > 0 ? path.resolve(xdg) : path.join(homeDir(), '.config')\n}\n\n// Read an env override, resolved to an absolute path, or undefined when unset.\nfunction envOverride(name: string): string | undefined {\n  const v = process.env[name]\n  return v && v.length > 0 ? path.resolve(v) : undefined\n}\n\nexport const CURSOR_CLIENT: EditorClient = {\n  id: 'cursor',\n  label: 'Cursor',\n  docsUrl: 'https://docs.cursor.com/context/mcp',\n  mcpConfigPath: () => envOverride('NEAT_CURSOR_CONFIG') ?? path.join(homeDir(), '.cursor', 'mcp.json'),\n  mcpContainerKey: 'mcpServers',\n  format: 'json',\n  // Cursor still reads a single `.cursorrules` at the project root (the modern\n  // `.cursor/rules/*.mdc` split is one-rule-per-file with frontmatter — a worse\n  // fit for a marker-fenced block). GRAPH_FIRST.md names this file directly.\n  rulesFileName: '.cursorrules',\n}\n\n// Devin Desktop is Cognition's successor to Windsurf; its Cascade agent reads\n// MCP servers from the unchanged legacy Codeium path (verified Aug 2026 against\n// docs.devin.ai/desktop/cascade/mcp). The MCP config is the load-bearing,\n// verified half. The rules file is the legacy `.windsurfrules` the Cascade agent\n// inherited from Windsurf — Devin's current docs don't re-document an always-on\n// rules file, so this half is best-effort: additive, marker-fenced, harmless if\n// a given Cascade build ignores it.\nexport const DEVIN_CLIENT: EditorClient = {\n  id: 'devin',\n  label: 'Devin Desktop (Cascade)',\n  docsUrl: 'https://docs.devin.ai/desktop/cascade/mcp',\n  mcpConfigPath: () =>\n    envOverride('NEAT_DEVIN_CONFIG') ?? path.join(homeDir(), '.codeium', 'windsurf', 'mcp_config.json'),\n  mcpContainerKey: 'mcpServers',\n  format: 'json',\n  rulesFileName: '.windsurfrules',\n}\n\n// Google's Gemini CLI reads MCP servers from ~/.gemini/settings.json under\n// `mcpServers`, the standard stdio shape. Its always-on context file is\n// GEMINI.md at the project root (loaded every prompt), a verified single-file\n// convention — so guidance lands there.\nexport const GEMINI_CLIENT: EditorClient = {\n  id: 'gemini',\n  label: 'Gemini CLI',\n  docsUrl: 'https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md',\n  mcpConfigPath: () => envOverride('NEAT_GEMINI_CONFIG') ?? path.join(homeDir(), '.gemini', 'settings.json'),\n  mcpContainerKey: 'mcpServers',\n  format: 'json',\n  rulesFileName: 'GEMINI.md',\n}\n\n// Qwen Code is a gemini-cli fork; it keeps the same settings.json + `mcpServers`\n// shape at ~/.qwen/settings.json, and renames the context file to QWEN.md\n// (loaded every session, verified against the Qwen Code memory docs).\nexport const QWEN_CLIENT: EditorClient = {\n  id: 'qwen',\n  label: 'Qwen Code',\n  docsUrl: 'https://qwenlm.github.io/qwen-code-docs/en/users/features/mcp/',\n  mcpConfigPath: () => envOverride('NEAT_QWEN_CONFIG') ?? path.join(homeDir(), '.qwen', 'settings.json'),\n  mcpContainerKey: 'mcpServers',\n  format: 'json',\n  rulesFileName: 'QWEN.md',\n}\n\n// The Amazon Q Developer CLI reads MCP servers from ~/.aws/amazonq/mcp.json\n// under `mcpServers` (the directory is usually absent, so apply mkdir -p's it).\n// Its rules surface is a directory (.amazonq/rules/*), not a single file, so\n// this verb is MCP-config-only — no guidance file.\nexport const AMAZONQ_CLIENT: EditorClient = {\n  id: 'amazonq',\n  label: 'Amazon Q Developer CLI',\n  docsUrl: 'https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-configuration.html',\n  mcpConfigPath: () =>\n    envOverride('NEAT_AMAZONQ_CONFIG') ?? path.join(homeDir(), '.aws', 'amazonq', 'mcp.json'),\n  mcpContainerKey: 'mcpServers',\n  format: 'json',\n}\n\n// Roo Code's project-scoped MCP config is <project>/.roo/mcp.json under\n// `mcpServers` — meant to be committed and shared with the team, which is why we\n// target it rather than the OS-variant globalStorage blob its docs steer you\n// away from. Its rules surface is a directory (.roo/rules/*), so MCP-config-only.\nexport const ROOCODE_CLIENT: EditorClient = {\n  id: 'roocode',\n  label: 'Roo Code',\n  docsUrl: 'https://roocodeinc.github.io/Roo-Code/features/mcp/using-mcp-in-roo',\n  mcpConfigPath: () => envOverride('NEAT_ROOCODE_CONFIG') ?? path.join(process.cwd(), '.roo', 'mcp.json'),\n  mcpContainerKey: 'mcpServers',\n  format: 'json',\n}\n\n// Zed keeps MCP servers under `context_servers` in a JSONC settings.json that\n// ships with `//` comments, so this one is edited in place (comments preserved)\n// rather than reparsed-and-rewritten. Path is ~/.config/zed/settings.json on\n// macOS/Linux and %APPDATA%\\Zed\\settings.json on Windows. Zed reads a `.rules`\n// file at the project root (highest-priority project instruction file), so\n// guidance lands there.\nexport const ZED_CLIENT: EditorClient = {\n  id: 'zed',\n  label: 'Zed',\n  docsUrl: 'https://zed.dev/docs/ai/mcp',\n  mcpConfigPath: () => {\n    const override = envOverride('NEAT_ZED_CONFIG')\n    if (override) return override\n    if (process.platform === 'win32') {\n      const appData = process.env.APPDATA\n      if (appData && appData.length > 0) return path.join(appData, 'Zed', 'settings.json')\n    }\n    return path.join(homeDir(), '.config', 'zed', 'settings.json')\n  },\n  mcpContainerKey: 'context_servers',\n  format: 'jsonc',\n  rulesFileName: '.rules',\n}\n\n// OpenCode reads MCP servers from opencode.json under the `mcp` key, but its\n// server object is the array-command form: `{ type: \"local\", command: [...],\n// enabled: true }`. Global config is ~/.config/opencode/opencode.json (XDG-aware);\n// a project opencode.json is the same shape. Its always-on instructions file is\n// AGENTS.md at the project root (the agent-agnostic file `neat codex` also uses),\n// so guidance lands there.\nexport const OPENCODE_CLIENT: EditorClient = {\n  id: 'opencode',\n  label: 'OpenCode',\n  docsUrl: 'https://opencode.ai/docs/mcp-servers/',\n  mcpConfigPath: () =>\n    envOverride('NEAT_OPENCODE_CONFIG') ?? path.join(xdgConfigDir(), 'opencode', 'opencode.json'),\n  mcpContainerKey: 'mcp',\n  format: 'json',\n  serverEntry: NEAT_OPENCODE_SERVER,\n  rulesFileName: 'AGENTS.md',\n}\n\n// Crush (Charmbracelet) also keys MCP servers under `mcp`, but wants an explicit\n// `type: \"stdio\"` with a string command + args. Global config is\n// ~/.config/crush/crush.json (XDG-aware); a project crush.json / .crush.json is\n// the same shape. Crush reads CRUSH.md and AGENTS.md as context files; guidance\n// lands in the agent-agnostic AGENTS.md.\nexport const CRUSH_CLIENT: EditorClient = {\n  id: 'crush',\n  label: 'Crush',\n  docsUrl: 'https://charmbracelet-crush.mintlify.app/configuration/mcp',\n  mcpConfigPath: () =>\n    envOverride('NEAT_CRUSH_CONFIG') ?? path.join(xdgConfigDir(), 'crush', 'crush.json'),\n  mcpContainerKey: 'mcp',\n  format: 'json',\n  serverEntry: NEAT_CRUSH_SERVER,\n  rulesFileName: 'AGENTS.md',\n}\n\nconst CLIENTS: Record<EditorClientId, EditorClient> = {\n  cursor: CURSOR_CLIENT,\n  devin: DEVIN_CLIENT,\n  gemini: GEMINI_CLIENT,\n  qwen: QWEN_CLIENT,\n  amazonq: AMAZONQ_CLIENT,\n  roocode: ROOCODE_CLIENT,\n  zed: ZED_CLIENT,\n  opencode: OPENCODE_CLIENT,\n  crush: CRUSH_CLIENT,\n}\n\ninterface McpConfig {\n  [key: string]: unknown\n}\n\n// Merge NEAT's server into the client's container object (JSON path), preserving\n// every other server and top-level key. `changed` is false when the entry\n// already matches, so a re-run is a clean no-op.\nfunction mergeJsonMcp(\n  existing: McpConfig,\n  containerKey: string,\n  serverEntry: unknown,\n): { merged: McpConfig; changed: boolean } {\n  const servers = (existing[containerKey] ?? {}) as Record<string, unknown>\n  const already = isDeepStrictEqual(servers.neat, serverEntry)\n  const merged: McpConfig = {\n    ...existing,\n    [containerKey]: { ...servers, neat: serverEntry },\n  }\n  return { merged, changed: !already }\n}\n\n// Merge NEAT's server into a JSONC file (Zed) without disturbing the rest.\n// jsonc-parser.modify computes a minimal edit that inserts only\n// `<container>.neat`; applyEdits splices it in, so every comment and every other\n// setting is preserved byte-for-byte. No JSON.stringify round-trip. A missing or\n// empty file starts from `{}`. `changed` is false when the entry already matches.\nfunction mergeJsoncMcp(\n  raw: string,\n  containerKey: string,\n  serverEntry: unknown,\n): { text: string; changed: boolean } {\n  const base = raw.trim().length > 0 ? raw : '{}'\n  const parsed = (jsonc.parse(base) ?? {}) as Record<string, unknown>\n  const servers = (parsed[containerKey] ?? {}) as Record<string, unknown>\n  if (isDeepStrictEqual(servers.neat, serverEntry)) {\n    return { text: raw, changed: false }\n  }\n  const edits = jsonc.modify(base, [containerKey, 'neat'], serverEntry, {\n    formattingOptions: { tabSize: 2, insertSpaces: true },\n  })\n  let text = jsonc.applyEdits(base, edits)\n  if (!text.endsWith('\\n')) text += '\\n'\n  return { text, changed: text !== raw }\n}\n\nfunction escapeRegExp(s: string): string {\n  return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n// The fenced block, guide content verbatim between the markers.\nfunction buildGuidanceBlock(guide: string): string {\n  return `${GRAPH_FIRST_MARKER_OPEN}\\n${guide.trim()}\\n${GRAPH_FIRST_MARKER_CLOSE}\\n`\n}\n\n// Splice NEAT's block into the rules file: replace an existing fenced block in\n// place, otherwise append it after the user's content. Anything outside the\n// markers is preserved exactly.\nfunction mergeRulesFile(existing: string, block: string): string {\n  const region = new RegExp(\n    `${escapeRegExp(GRAPH_FIRST_MARKER_OPEN)}[\\\\s\\\\S]*?${escapeRegExp(GRAPH_FIRST_MARKER_CLOSE)}\\\\n?`,\n  )\n  if (region.test(existing)) return existing.replace(region, block)\n  if (existing.trim().length === 0) return block\n  return `${existing.replace(/\\s+$/, '')}\\n\\n${block}`\n}\n\nexport interface EditorInstallOptions {\n  apply: boolean\n  // Where the rules file lands. Defaults to the caller's cwd in the CLI; tests\n  // pass a temp directory.\n  projectDir: string\n}\n\n// Read the client's MCP config and compute the merged text + whether it changed,\n// validating the format. Returns null after printing an error on a hard stop\n// (malformed existing config, unreadable file).\nasync function planMcp(\n  client: EditorClient,\n  mcpPath: string,\n): Promise<{ text: string; changed: boolean } | null> {\n  const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER\n  let raw = ''\n  try {\n    raw = await fs.readFile(mcpPath, 'utf8')\n  } catch (err) {\n    const e = err as NodeJS.ErrnoException\n    if (e.code === 'ENOENT') {\n      raw = ''\n    } else {\n      console.error(`neat ${client.id}: failed to read ${mcpPath} — ${e.message}`)\n      return null\n    }\n  }\n\n  if (client.format === 'jsonc') {\n    // A fresh Zed settings.json ships with `//` comments — those are valid JSONC,\n    // not an error. Only genuine syntax damage (beyond comments and trailing\n    // commas) is a hard stop, so the user's file is never rewritten blindly.\n    if (raw.trim().length > 0) {\n      const errors: jsonc.ParseError[] = []\n      jsonc.parse(raw, errors, { allowTrailingComma: true })\n      if (errors.length > 0) {\n        const first = errors[0]\n        console.error(\n          `neat ${client.id}: ${mcpPath} is not valid JSONC — ` +\n            `${jsonc.printParseErrorCode(first.error)} at offset ${first.offset}. ` +\n            `Fix it (or move it aside) and re-run; nothing was written.`,\n        )\n        return null\n      }\n    }\n    return mergeJsoncMcp(raw, client.mcpContainerKey, serverEntry)\n  }\n\n  // JSON path.\n  let existing: McpConfig = {}\n  if (raw.trim().length > 0) {\n    try {\n      existing = JSON.parse(raw) as McpConfig\n    } catch (err) {\n      console.error(\n        `neat ${client.id}: ${mcpPath} is not valid JSON — ${(err as Error).message}. ` +\n          `Fix it (or move it aside) and re-run; nothing was written.`,\n      )\n      return null\n    }\n  }\n  const { merged, changed } = mergeJsonMcp(existing, client.mcpContainerKey, serverEntry)\n  return { text: JSON.stringify(merged, null, 2) + '\\n', changed }\n}\n\nexport async function runEditorInstall(\n  client: EditorClient,\n  opts: EditorInstallOptions,\n): Promise<{ exitCode: number }> {\n  const mcpPath = client.mcpConfigPath()\n  const serverEntry = client.serverEntry ?? NEAT_MCP_SERVER\n  const hasRules = typeof client.rulesFileName === 'string'\n  const rulesPath = hasRules ? path.join(opts.projectDir, client.rulesFileName as string) : ''\n\n  // ── Phase 1: read + validate everything before writing anything ──────────\n  // A malformed existing MCP config is a hard stop with nothing written — no\n  // partial state, and the operator is told exactly which file to fix.\n  const mcp = await planMcp(client, mcpPath)\n  if (mcp === null) return { exitCode: 1 }\n\n  let existingRules = ''\n  let newRules = ''\n  let rulesChanged = false\n  let block = ''\n  if (hasRules) {\n    try {\n      existingRules = await fs.readFile(rulesPath, 'utf8')\n    } catch (err) {\n      if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n        console.error(`neat ${client.id}: failed to read ${rulesPath} — ${(err as Error).message}`)\n        return { exitCode: 1 }\n      }\n    }\n    const guide = await readSkillAsset(GUIDE_FILENAME)\n    block = buildGuidanceBlock(guide)\n    newRules = mergeRulesFile(existingRules, block)\n    rulesChanged = newRules !== existingRules\n  }\n\n  // ── Plan mode (default): show what would change, write nothing ───────────\n  if (!opts.apply) {\n    console.log(`neat ${client.id} — wire NEAT into ${client.label} (plan; nothing written)`)\n    console.log('')\n    console.log(`MCP server → ${mcpPath}`)\n    console.log(\n      mcp.changed\n        ? `  would add ${client.mcpContainerKey}.neat:`\n        : `  ${client.mcpContainerKey}.neat already present and current — no change:`,\n    )\n    console.log(indent(JSON.stringify({ neat: serverEntry }, null, 2)))\n    if (hasRules) {\n      console.log('')\n      console.log(`Graph-first guidance → ${rulesPath}`)\n      console.log(\n        rulesChanged\n          ? existingRules.includes(GRAPH_FIRST_MARKER_OPEN)\n            ? '  would refresh the neat:graph-first block:'\n            : '  would add the neat:graph-first block:'\n          : '  neat:graph-first block already present and current — no change.',\n      )\n      if (rulesChanged) console.log(indent(block.trimEnd()))\n    }\n    console.log('')\n    console.log(\n      hasRules\n        ? `Re-run with --apply to write both files. Existing servers and rules are kept.`\n        : `Re-run with --apply to write the config. Existing servers are kept.`,\n    )\n    return { exitCode: 0 }\n  }\n\n  // ── Apply mode: write ────────────────────────────────────────────────────\n  await fs.mkdir(path.dirname(mcpPath), { recursive: true })\n  await fs.writeFile(mcpPath, mcp.text, 'utf8')\n  if (hasRules) {\n    await fs.mkdir(path.dirname(rulesPath), { recursive: true })\n    await fs.writeFile(rulesPath, newRules, 'utf8')\n  }\n\n  console.log(`neat ${client.id}: wired NEAT into ${client.label}`)\n  console.log(`  MCP server: ${mcpPath} (${client.mcpContainerKey}.neat → npx -y @neat.is/mcp)`)\n  if (hasRules) console.log(`  guidance:   ${rulesPath} (neat:graph-first block)`)\n  console.log('')\n  console.log(`restart ${client.label} to pick up the MCP server. Point it at a non-default`)\n  console.log(`daemon by setting NEAT_CORE_URL in the neat server's env in that config.`)\n  return { exitCode: 0 }\n}\n\nfunction indent(text: string): string {\n  return text\n    .split('\\n')\n    .map((line) => (line.length > 0 ? `    ${line}` : line))\n    .join('\\n')\n}\n\nfunction usage(client: EditorClient): void {\n  const hasRules = typeof client.rulesFileName === 'string'\n  console.log(\n    hasRules\n      ? `neat ${client.id} — install NEAT's MCP server + graph-first guidance into ${client.label}`\n      : `neat ${client.id} — install NEAT's MCP server into ${client.label}`,\n  )\n  console.log('')\n  console.log(\n    hasRules\n      ? '  --apply   write the MCP config and the rules file (default: plan only)'\n      : '  --apply   write the MCP config (default: plan only)',\n  )\n  console.log('')\n  console.log(\"Writes NEAT's stdio MCP server (npx -y @neat.is/mcp) into\")\n  console.log(`  ${client.mcpConfigPath()}`)\n  if (hasRules) {\n    console.log(`and the graph-first guidance block into ./${client.rulesFileName}, both`)\n    console.log('additively — existing servers and rules are preserved, a re-run is a no-op.')\n  } else {\n    console.log('additively — existing servers are preserved, a re-run is a no-op.')\n  }\n  console.log('')\n  console.log(`See ${client.docsUrl} for ${client.label}'s MCP config format.`)\n}\n\n// Parse this command family's own argv and dispatch. Mirrors runHooksCommand.\nexport async function runEditorCommand(\n  clientId: EditorClientId,\n  args: string[],\n  projectDir: string = process.cwd(),\n): Promise<number> {\n  const client = CLIENTS[clientId]\n  let apply = false\n  for (const arg of args) {\n    switch (arg) {\n      case '--apply':\n        apply = true\n        break\n      case '-h':\n      case '--help':\n        usage(client)\n        return 0\n      default:\n        console.error(`neat ${client.id}: unknown flag \"${arg}\"`)\n        usage(client)\n        return 2\n    }\n  }\n  try {\n    const { exitCode } = await runEditorInstall(client, { apply, projectDir })\n    return exitCode\n  } catch (err) {\n    console.error((err as Error).message)\n    return 1\n  }\n}\n","// `neat monitor` — stream high-signal graph facts to stdout, one human line\n// per fact (ADR-159 decision 2, extended by ADR-162, and by ADR-221 for\n// incidents). The monitor is a client of surface NEAT already ships: the SSE\n// `/events` bus is the trigger, the REST reads are the context. The bus grew to\n// nine types when ADR-221 added `incident` — the one append-only fact it must\n// push rather than recompute; everything else here stays a computed read.\n//\n// What it emits, and where each fact comes from:\n//   • a fresh divergence — read from `GET /graph/divergences` (the graph's own\n//     computed declared-vs-observed query), on a debounced trigger. At column\n//     grain it names the drifting column (`orders.amount`), not just the table\n//     (ADR-157).\n//   • a stale integration — from a `stale-transition` SSE payload; the edge id\n//     parses back to source/target via the graph's own id encoding.\n//   • a new observed runtime dependency — from an OBSERVED `edge-added` SSE\n//     payload, gated to the dependency edge types.\n//   • a freshly-tripped policy violation — read from `GET /policies/violations`\n//     (the soft guardrail, ADR-108) on a `policy-violation` trigger; the \"before\n//     you edit\" fact made ambient (ADR-162).\n//   • an incident — the composed work-order card, read from\n//     `GET /graph/incident-card/:node?errorId=` on an `incident` trigger (ADR-221).\n//     Event-driven, not a re-read of derivable state, so there is no baseline\n//     dump on connect: only incidents that land while watching reach stdout.\n//\n// It holds a seen-set so each fact prints once and stays silent when nothing\n// is new. It never fabricates: only facts the graph already computed reach\n// stdout, and no reachable daemon means a clean exit with no output. This is a\n// lifecycle/config-style verb (like `watch`/`connector`/`hooks`), read-only,\n// additive to the CLI surface — not one of the locked query verbs.\n\nimport type {\n  Divergence,\n  DivergenceResult,\n  GraphEdge,\n  IncidentCard,\n  PoliciesViolationsResponse,\n  PolicyViolation,\n} from '@neat.is/types'\nimport { EdgeType, parseEdgeId, Provenance } from '@neat.is/types'\nimport { flagMismatchPhrase } from './incidents-render.js'\nimport { createHttpClient, type HttpClient, TransportError } from './cli-client.js'\n\n// The edge types that represent runtime dependencies — the CALLS family plus\n// cross-service and connection edges. Mirrors divergences.ts's\n// OBSERVABLE_EDGE_TYPES on purpose: a new OBSERVED edge of one of these types\n// is a real \"runtime just started depending on X\" fact. Structural OBSERVED\n// edges (CONTAINS ownership of a file/symbol) are not dependencies, so an\n// `+ observed` line for them would mislead — keep them off this surface.\nconst OBSERVED_DEP_EDGE_TYPES: ReadonlySet<string> = new Set([\n  EdgeType.CALLS,\n  EdgeType.CONNECTS_TO,\n  EdgeType.PUBLISHES_TO,\n  EdgeType.CONSUMES_FROM,\n])\n\n// ──────────────────────────────────────────────────────────────────────────\n// Fact identity + formatting (pure, unit-tested)\n// ──────────────────────────────────────────────────────────────────────────\n\n// A stable key for a divergence so a re-read dedupes it. Divergences carry no\n// id (they are re-derived each call, no persistence — ADR-060), so the key is\n// built from the fields that identify one: type, endpoints, and the\n// type-specific discriminators (column, versions, host, compat rule).\nexport function divergenceKey(d: Divergence): string {\n  const column = 'column' in d && d.column ? d.column : ''\n  const edgeType = 'edgeType' in d && d.edgeType ? d.edgeType : ''\n  let extra = ''\n  switch (d.type) {\n    case 'version-mismatch':\n      extra = `${d.extractedVersion}->${d.observedVersion}`\n      break\n    case 'host-mismatch':\n      extra = `${d.extractedHost}->${d.observedHost}`\n      break\n    case 'compat-violation':\n      extra = `${d.rule.kind}:${d.rule.package ?? ''}`\n      break\n    case 'observed-failing':\n      // Two failure families can land on one node (source == target at the\n      // incident locus), so key on kind + declaring location to keep them\n      // distinct across re-reads.\n      extra = `${d.failureKind}:${d.location ?? ''}`\n      break\n    default:\n      extra = ''\n  }\n  return `div|${d.type}|${d.source}|${d.target}|${edgeType}|${column}|${extra}`\n}\n\n// The short table label for a column-locus divergence — the node id the graph\n// carries. Not massaged into a bare table name; the id is what the graph knows.\nfunction tableLabel(d: Divergence): string {\n  return ('table' in d && d.table ? d.table : d.source)\n}\n\n// One greppable line per divergence, prefixed `⚠ divergence [<type>]`.\nexport function formatDivergenceLine(d: Divergence): string {\n  switch (d.type) {\n    case 'missing-observed':\n      if (d.column) {\n        return `⚠ divergence [missing-observed] ${tableLabel(d)}.${d.column} declared, never observed in production`\n      }\n      return `⚠ divergence [missing-observed] ${d.source} → ${d.target} declared, never observed in production`\n    case 'missing-extracted':\n      if (d.column) {\n        return `⚠ divergence [missing-extracted] production writes ${tableLabel(d)}.${d.column} — not declared in code`\n      }\n      return `⚠ divergence [missing-extracted] production ${d.source} → ${d.target} — not declared in code`\n    case 'version-mismatch':\n      return `⚠ divergence [version-mismatch] ${d.source} → ${d.target} declared ${d.extractedVersion}, observed ${d.observedVersion} (${d.compatibility})`\n    case 'host-mismatch':\n      return `⚠ divergence [host-mismatch] ${d.source} → ${d.target} declared host ${d.extractedHost}, observed host ${d.observedHost}`\n    case 'compat-violation':\n      return `⚠ divergence [compat-violation] ${d.source} → ${d.target} — ${d.rule.kind}${d.rule.package ? ` (${d.rule.package})` : ''}`\n    case 'observed-symbol-mismatch': {\n      // Symbol/field-grain (ADR-215) — the code declares access to a member the\n      // runtime object lacks; name the member and the declaring file:line.\n      const at = d.location ? ` at ${d.location}` : ''\n      const member = d.symbol ? ` ${d.symbol}` : ' a member'\n      return `⚠ divergence [observed-symbol-mismatch] ${d.source}${at} reads${member} the runtime object does not have (${d.mismatchKind})`\n    }\n    case 'observed-failing': {\n      // Behavioral-failure (ADR-220) — a declared dependency observed failing.\n      if (d.edgeType) {\n        const rate = d.errorRate !== undefined ? `, ${Math.round(d.errorRate * 100)}% errors` : ''\n        return `⚠ divergence [observed-failing] ${d.source} → ${d.target} declared and observed, but failing (${d.failureKind}${rate})`\n      }\n      const at = d.location ? ` at ${d.location}` : ''\n      return `⚠ divergence [observed-failing] ${d.source}${at} declares a call observed failing (${d.failureKind})`\n    }\n    case 'deploy-mismatch':\n      // Deploy divergence (ADR-225) — the manifest and the running pods\n      // disagree on one service node. The stuck rollout reaches the stream with\n      // no incident behind it, so this line is the whole signal.\n      if (d.kind === 'image') {\n        return `⚠ divergence [deploy-mismatch] ${d.source} declares image ${d.declaredImage ?? 'unknown'}, running ${d.observedImage ?? 'unknown'}`\n      }\n      return `⚠ divergence [deploy-mismatch] ${d.source} declares ${d.declaredReplicas ?? 'unknown'} replicas, ${d.observedReplicas ?? 'unknown'} ready`\n    case 'flag-mismatch':\n      // Flag grain (ADR-242): a flag running in a state nobody committed.\n      return `⚠ divergence [flag-mismatch] ${d.source} — ${flagMismatchPhrase(d)}`\n    default: {\n      // A type added to the union but not here still reaches the stream named.\n      const other = d as Divergence\n      return `⚠ divergence [${other.type}] ${other.source} → ${other.target}`\n    }\n  }\n}\n\n// A stale-transition SSE payload carries only the edge id. The OBSERVED edge id\n// encodes `${type}:OBSERVED:${source}->${target}` (identity.ts), so parseEdgeId\n// — the graph's own decoder — recovers source/target. Falls back to the raw id\n// when the shape is unexpected, so the line always renders something truthful.\nexport function formatStaleLine(edgeId: string): string {\n  const parsed = parseEdgeId(edgeId)\n  if (parsed) {\n    return `⋯ stale  ${parsed.source} → ${parsed.target}  (observed edge went quiet)`\n  }\n  return `⋯ stale  ${edgeId}  (observed edge went quiet)`\n}\n\n// A new OBSERVED edge is a runtime dependency the graph just saw. It is framed\n// as exactly that and nothing more: an OBSERVED edge can coexist with an\n// EXTRACTED twin (the coexistence rule, contracts.md Rule 2), so \"the code does\n// not declare it\" is not knowable from the event alone — the undeclared subset\n// surfaces separately and authoritatively as a `missing-extracted` divergence.\nexport function formatObservedEdgeLine(edge: GraphEdge): string {\n  return `+ observed  ${edge.source} → ${edge.target}  (new runtime dependency)`\n}\n\n// `--json` fact shapes — one object per line for non-Claude consumers.\nexport function divergenceJson(d: Divergence): string {\n  return JSON.stringify({ kind: 'divergence', ...d })\n}\nexport function staleJson(edgeId: string): string {\n  const parsed = parseEdgeId(edgeId)\n  return JSON.stringify({\n    kind: 'stale',\n    edgeId,\n    ...(parsed ? { source: parsed.source, target: parsed.target, edgeType: parsed.type } : {}),\n  })\n}\nexport function observedEdgeJson(edge: GraphEdge): string {\n  return JSON.stringify({\n    kind: 'observed',\n    id: edge.id,\n    source: edge.source,\n    target: edge.target,\n    edgeType: edge.type,\n    provenance: edge.provenance,\n  })\n}\n\n// A policy violation carries a deterministic id (`${policyId}:${context}`,\n// ADR-043), so the id is the dedupe key — a re-read of /policies/violations\n// keys off exactly the same string.\nexport function policyKey(v: PolicyViolation): string {\n  return `policy|${v.id}`\n}\n\n// The node / edge / path a violation points at — the locus an agent is about\n// to touch. Node first (the common \"before you edit this node\" case), then\n// edge, then a rule path.\nfunction policySubject(v: PolicyViolation): string {\n  const s = v.subject\n  if (s.nodeId) return s.nodeId\n  if (s.edgeId) return s.edgeId\n  if (s.path && s.path.length > 0) return s.path.join(' → ')\n  return ''\n}\n\n// One greppable line per fresh policy violation, prefixed `⚠ policy [<severity>]`.\n// The message is the evaluator's own human-readable text; the subject locus is\n// appended so the agent knows exactly where the rule bites before it edits.\nexport function formatPolicyLine(v: PolicyViolation): string {\n  const subject = policySubject(v)\n  const where = subject ? `  (${subject})` : ''\n  return `⚠ policy [${v.severity}] ${v.policyName} — ${v.message}${where}`\n}\n\nexport function policyJson(v: PolicyViolation): string {\n  return JSON.stringify({ kind: 'policy', ...v })\n}\n\n// One greppable line per incident, prefixed `✖ incident [<kind>]` (ADR-221). The\n// headline is the composed sentence; the trailing tag carries the root-cause\n// classification, its confidence, and the per-hop provenance mix — so an agent\n// sees at a glance how much of the chain is OBSERVED fact vs INFERRED stitch.\nexport function formatIncidentLine(card: IncidentCard): string {\n  let tag = ''\n  if (card.rootCause) {\n    const rc = card.rootCause\n    const provs = rc.chain.map((h) => h.provenance).join('·')\n    const cls = rc.classification ? `${rc.classification} ` : ''\n    tag = `  · ${cls}${rc.confidence.toFixed(2)}${provs ? ` [${provs}]` : ''}`\n  }\n  // The grade's number and band (ADR-238); the factor table is in --json and the card.\n  const grade = card.grade ? `  · grade ${card.grade.G.toFixed(2)} ${card.grade.band}` : ''\n  return `✖ incident [${card.incidentKind}]  ${card.headline}${tag}${grade}`\n}\n\nexport function incidentJson(card: IncidentCard): string {\n  return JSON.stringify(card)\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Emitter — the seen-set + write. Network-free, so tests drive it directly.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface EmitterOptions {\n  json: boolean\n  write: (line: string) => void\n}\n\nexport class MonitorEmitter {\n  private readonly seen = new Set<string>()\n  constructor(private readonly opts: EmitterOptions) {}\n\n  private out(line: string): void {\n    this.opts.write(line + '\\n')\n  }\n\n  // Emit every not-yet-seen divergence in a fresh result. Returns the count\n  // newly emitted (0 → nothing printed, the silent path). Idempotent across\n  // re-reads: the seen-set keys off divergenceKey.\n  emitDivergences(result: DivergenceResult): number {\n    let emitted = 0\n    for (const d of result.divergences) {\n      const key = divergenceKey(d)\n      if (this.seen.has(key)) continue\n      this.seen.add(key)\n      this.out(this.opts.json ? divergenceJson(d) : formatDivergenceLine(d))\n      emitted++\n    }\n    return emitted\n  }\n\n  // Emit a stale-transition once, keyed on the edge id.\n  emitStale(edgeId: string): boolean {\n    const key = `stale|${edgeId}`\n    if (this.seen.has(key)) return false\n    this.seen.add(key)\n    this.out(this.opts.json ? staleJson(edgeId) : formatStaleLine(edgeId))\n    return true\n  }\n\n  // Emit a new OBSERVED runtime dependency once, keyed on the edge id. Silently\n  // ignores non-OBSERVED edges and non-dependency edge types (structural\n  // ownership), so only real runtime dependencies reach stdout.\n  emitObservedEdge(edge: GraphEdge): boolean {\n    if (edge.provenance !== Provenance.OBSERVED) return false\n    if (!OBSERVED_DEP_EDGE_TYPES.has(edge.type)) return false\n    const key = `edge|${edge.id}`\n    if (this.seen.has(key)) return false\n    this.seen.add(key)\n    this.out(this.opts.json ? observedEdgeJson(edge) : formatObservedEdgeLine(edge))\n    return true\n  }\n\n  // Emit every not-yet-seen policy violation in a fresh /policies/violations\n  // read. Returns the count newly emitted (0 → nothing printed, the silent\n  // path). Idempotent across re-reads: the seen-set keys off the violation id.\n  emitPolicies(response: PoliciesViolationsResponse): number {\n    let emitted = 0\n    for (const v of response.violations) {\n      const key = policyKey(v)\n      if (this.seen.has(key)) continue\n      this.seen.add(key)\n      this.out(this.opts.json ? policyJson(v) : formatPolicyLine(v))\n      emitted++\n    }\n    return emitted\n  }\n\n  // Emit one incident card once, keyed on the incident id. Unlike the other\n  // facts this is event-driven, not a re-read of derivable state, so there is no\n  // baseline dump on connect — only incidents that arrive live after the monitor\n  // is watching reach stdout.\n  emitIncident(card: IncidentCard): boolean {\n    const key = `incident|${card.id}`\n    if (this.seen.has(key)) return false\n    this.seen.add(key)\n    this.out(this.opts.json ? incidentJson(card) : formatIncidentLine(card))\n    return true\n  }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// SSE reader — a minimal EventSource-shaped reader over fetch (Node 20 has\n// global fetch + ReadableStream). Parses `event:`/`data:` frames; ignores the\n// `:open`/`:heartbeat` comment lines the daemon writes (streaming.ts).\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface SseFrame {\n  event: string\n  data: string\n}\n\nfunction parseFrame(raw: string): SseFrame | null {\n  let event = 'message'\n  const dataLines: string[] = []\n  for (const line of raw.split('\\n')) {\n    if (line.length === 0 || line.startsWith(':')) continue // comment / blank\n    if (line.startsWith('event:')) {\n      event = line.slice('event:'.length).trim()\n    } else if (line.startsWith('data:')) {\n      dataLines.push(line.slice('data:'.length).replace(/^ /, ''))\n    }\n  }\n  if (dataLines.length === 0) return null\n  return { event, data: dataLines.join('\\n') }\n}\n\n// Drain a response body stream, splitting on the SSE frame separator (`\\n\\n`)\n// and handing each complete frame to `onFrame`. Resolves when the stream ends\n// or the signal aborts; rejects only on a transport read error.\nasync function drainSse(\n  body: ReadableStream<Uint8Array>,\n  onFrame: (frame: SseFrame) => void,\n): Promise<void> {\n  const reader = body.getReader()\n  const decoder = new TextDecoder()\n  let buf = ''\n  try {\n    for (;;) {\n      const { done, value } = await reader.read()\n      if (done) break\n      buf += decoder.decode(value, { stream: true })\n      // Normalise CRLF so the frame split is robust to either newline style.\n      buf = buf.replace(/\\r\\n/g, '\\n')\n      let idx: number\n      while ((idx = buf.indexOf('\\n\\n')) !== -1) {\n        const rawFrame = buf.slice(0, idx)\n        buf = buf.slice(idx + 2)\n        const frame = parseFrame(rawFrame)\n        if (frame) onFrame(frame)\n      }\n    }\n  } finally {\n    try {\n      reader.releaseLock()\n    } catch {\n      // ignore — the stream may already be torn down on abort\n    }\n  }\n}\n\nfunction safeParse(data: string): Record<string, unknown> | null {\n  try {\n    return JSON.parse(data) as Record<string, unknown>\n  } catch {\n    return null\n  }\n}\n\n// Same project-routing shape the CLI verbs use: undefined → the legacy\n// unprefixed routes the server maps to `default`; a name → `/projects/:name/...`.\nfunction projectPath(project: string | undefined, suffix: string): string {\n  if (!project) return suffix\n  return `/projects/${encodeURIComponent(project)}${suffix}`\n}\n\nfunction backoffDelay(attempt: number, capMs: number): number {\n  return Math.min(capMs, 500 * 2 ** Math.min(attempt, 6))\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// Injectable transport + a debounced reader. Both keep runMonitor testable\n// without a live daemon: a test injects the SSE source and the REST client and\n// drives real triggers through the same onFrame path production uses.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface EventsResponse {\n  ok: boolean\n  status: number\n  body: ReadableStream<Uint8Array> | null\n}\n\n// Opens the SSE `/events` connection. Defaults to a thin wrapper over global\n// fetch; a test swaps in a scripted stream.\nexport type OpenEvents = (\n  url: string,\n  headers: Record<string, string>,\n  signal: AbortSignal | undefined,\n) => Promise<EventsResponse>\n\nconst defaultOpenEvents: OpenEvents = async (url, headers, signal) => {\n  const res = await fetch(url, { headers, signal })\n  return { ok: res.ok, status: res.status, body: res.body }\n}\n\n// A debounced, self-coalescing REST read. A burst of triggers collapses into\n// one read; a trigger that lands while a read is in flight coalesces into a\n// single trailing re-read. Transient read failures are swallowed — the next\n// trigger retries; a hard daemon-down surfaces on the SSE side as a disconnect.\ninterface DebouncedReader {\n  schedule: () => void\n  runNow: () => Promise<void>\n  cancel: () => void\n}\n\nfunction makeDebouncedReader(read: () => Promise<void>, debounceMs: number): DebouncedReader {\n  let timer: ReturnType<typeof setTimeout> | null = null\n  let running = false\n  let pending = false\n  const cancel = (): void => {\n    if (timer) {\n      clearTimeout(timer)\n      timer = null\n    }\n  }\n  const run = async (): Promise<void> => {\n    if (running) {\n      pending = true\n      return\n    }\n    running = true\n    try {\n      await read()\n    } catch {\n      // Transient. Stay silent; a later trigger re-reads.\n    } finally {\n      running = false\n      if (pending) {\n        pending = false\n        schedule()\n      }\n    }\n  }\n  const schedule = (): void => {\n    cancel()\n    timer = setTimeout(() => {\n      timer = null\n      void run()\n    }, debounceMs)\n    if (typeof timer.unref === 'function') timer.unref()\n  }\n  return {\n    schedule,\n    runNow: async () => {\n      cancel()\n      await run()\n    },\n    cancel,\n  }\n}\n\n// ──────────────────────────────────────────────────────────────────────────\n// runMonitor — the orchestrator. Daemon resolution happens in cli.ts (reusing\n// the query-verb resolution) and lands here as a concrete baseUrl + project.\n// ──────────────────────────────────────────────────────────────────────────\n\nexport interface RunMonitorOptions {\n  baseUrl: string\n  project: string | undefined\n  json: boolean\n  authToken?: string | undefined\n  // Injectable for tests; defaults to stdout.\n  write?: (line: string) => void\n  // Abort to shut the monitor down (SIGINT/SIGTERM, or a test).\n  signal?: AbortSignal\n  // Debounce window before a triggered read. Small for tests.\n  debounceMs?: number\n  // Cap on the reconnect backoff interval.\n  backoffCapMs?: number\n  // Bound the reconnect loop (Infinity for a real long-lived run).\n  maxReconnects?: number\n  // Injectable transport for tests; default to the real REST client + SSE fetch.\n  httpClient?: HttpClient\n  openEvents?: OpenEvents\n}\n\nexport async function runMonitor(opts: RunMonitorOptions): Promise<number> {\n  const write = opts.write ?? ((line: string) => process.stdout.write(line))\n  const debounceMs = opts.debounceMs ?? 400\n  const backoffCapMs = opts.backoffCapMs ?? 10_000\n  const maxReconnects = opts.maxReconnects ?? Number.POSITIVE_INFINITY\n\n  const client: HttpClient = opts.httpClient ?? createHttpClient(opts.baseUrl, opts.authToken)\n  const openEvents: OpenEvents = opts.openEvents ?? defaultOpenEvents\n  const emitter = new MonitorEmitter({ json: opts.json, write })\n\n  const divergencesPath = projectPath(opts.project, '/graph/divergences')\n  const policiesPath = projectPath(opts.project, '/policies/violations')\n  const eventsUrl = `${opts.baseUrl.replace(/\\/$/, '')}${projectPath(opts.project, '/events')}`\n\n  // Two debounced reads, same shape, one per live query the monitor watches:\n  // the divergence view (declared-vs-observed, down to the drifting column) and\n  // the soft-guardrail policy violations. Each dedupes through the emitter's\n  // seen-set, so a re-read prints only what is genuinely new.\n  const divergences = makeDebouncedReader(async () => {\n    const result = await client.get<DivergenceResult>(divergencesPath)\n    emitter.emitDivergences(result)\n  }, debounceMs)\n  const policies = makeDebouncedReader(async () => {\n    const result = await client.get<PoliciesViolationsResponse>(policiesPath)\n    emitter.emitPolicies(result)\n  }, debounceMs)\n\n  // Incidents are events, not derivable state — each carries its own id, so the\n  // monitor fetches exactly the one card its bus event named (ADR-221) rather\n  // than re-reading a list. Fire-and-forget from onFrame; a transient read\n  // failure is swallowed — the incident stays in the store and can be pulled with\n  // get_incident_card. Deduped on the card id in the emitter.\n  const readIncidentCard = async (incidentId: string, affectedNode: string): Promise<void> => {\n    try {\n      const card = await client.get<IncidentCard>(\n        projectPath(\n          opts.project,\n          `/graph/incident-card/${encodeURIComponent(affectedNode)}?errorId=${encodeURIComponent(incidentId)}`,\n        ),\n      )\n      emitter.emitIncident(card)\n    } catch {\n      // Transient — the incident persists in errors.ndjson; nothing to print now.\n    }\n  }\n\n  const onFrame = (frame: SseFrame): void => {\n    switch (frame.event) {\n      case 'extraction-complete':\n        divergences.schedule()\n        break\n      case 'stale-transition': {\n        const payload = safeParse(frame.data)\n        const edgeId = payload && typeof payload.edgeId === 'string' ? payload.edgeId : undefined\n        if (edgeId) emitter.emitStale(edgeId)\n        divergences.schedule()\n        break\n      }\n      case 'edge-added': {\n        const payload = safeParse(frame.data)\n        const edge = payload?.edge as GraphEdge | undefined\n        if (edge && edge.provenance === Provenance.OBSERVED) {\n          emitter.emitObservedEdge(edge)\n          divergences.schedule()\n        }\n        break\n      }\n      case 'policy-violation':\n        // A freshly-evaluated violation is the \"before you edit\" fact (ADR-108).\n        // Read the authoritative /policies/violations list rather than the event\n        // payload, so the seen-set dedupes against the same set the baseline read\n        // saw and a reconnect can't double-print.\n        policies.schedule()\n        break\n      case 'incident': {\n        // A production failure just landed (ADR-221). The bus payload is a lean\n        // trigger — fetch the full work-order card for exactly this incident.\n        const payload = safeParse(frame.data)\n        const incidentId =\n          payload && typeof payload.incidentId === 'string' ? payload.incidentId : undefined\n        const affectedNode =\n          payload && typeof payload.affectedNode === 'string' ? payload.affectedNode : undefined\n        if (incidentId && affectedNode) void readIncidentCard(incidentId, affectedNode)\n        break\n      }\n      default:\n        // node-added / node-updated / node-removed / edge-removed — not monitor\n        // triggers.\n        break\n    }\n  }\n\n  const headers: Record<string, string> = { accept: 'text/event-stream' }\n  if (opts.authToken && opts.authToken.length > 0) {\n    headers.authorization = `Bearer ${opts.authToken}`\n  }\n\n  let connectedOnce = false\n  let firstConnect = true\n  for (let attempt = 0; ; attempt++) {\n    if (opts.signal?.aborted) break\n\n    let conn: EventsResponse\n    try {\n      conn = await openEvents(eventsUrl, headers, opts.signal)\n    } catch (err) {\n      if ((err as { name?: string }).name === 'AbortError') break\n      // Connection refused / DNS / timeout. If we never connected, the daemon\n      // is down — exit clean with no output (the monitor does not fabricate).\n      if (!connectedOnce || attempt >= maxReconnects) break\n      await sleep(backoffDelay(attempt, backoffCapMs), opts.signal)\n      continue\n    }\n\n    if (!conn.ok || !conn.body) {\n      // Drain the body so the socket frees, then decide. A non-2xx on first\n      // contact is treated the same as unreachable — quiet exit.\n      await conn.body?.cancel().catch(() => {})\n      if (!connectedOnce || attempt >= maxReconnects) break\n      await sleep(backoffDelay(attempt, backoffCapMs), opts.signal)\n      continue\n    }\n\n    connectedOnce = true\n    attempt = 0\n\n    // Baseline on the first successful connect: read the present divergences\n    // and policy violations so an agent starting a session is told the current\n    // state, not only what changes mid-session. On a reconnect, schedule a\n    // catch-up read of both — the seen-set keeps either from reprinting.\n    if (firstConnect) {\n      firstConnect = false\n      await divergences.runNow()\n      await policies.runNow()\n    } else {\n      divergences.schedule()\n      policies.schedule()\n    }\n\n    try {\n      await drainSse(conn.body, onFrame)\n    } catch {\n      // Read error mid-stream — fall through to reconnect.\n    }\n\n    if (opts.signal?.aborted) break\n    if (attempt >= maxReconnects) break\n    await sleep(backoffDelay(attempt, backoffCapMs), opts.signal)\n  }\n\n  divergences.cancel()\n  policies.cancel()\n  return 0\n}\n\n// Abortable sleep. Resolves on timeout or immediately when the signal aborts.\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n  return new Promise((resolve) => {\n    if (signal?.aborted) {\n      resolve()\n      return\n    }\n    const timer = setTimeout(() => {\n      signal?.removeEventListener('abort', onAbort)\n      resolve()\n    }, ms)\n    if (typeof timer.unref === 'function') timer.unref()\n    const onAbort = (): void => {\n      clearTimeout(timer)\n      resolve()\n    }\n    signal?.addEventListener('abort', onAbort, { once: true })\n  })\n}\n\n// Re-export for the dispatcher — TransportError is the daemon-down signal the\n// cli.ts monitor branch maps to a clean exit.\nexport { TransportError }\n","/**\n * Lifecycle-verb implementations for the CLI. Query verbs live in\n * `cli-client.ts` next to the REST client; lifecycle verbs (currently\n * `neat sync`) live here because they orchestrate filesystem work and\n * daemon-state probes rather than wrapping a single REST endpoint.\n */\n\nimport path from 'node:path'\nimport type { RegistryEntry } from '@neat.is/types'\nimport {\n  applyInstallersOver,\n  extractAndPersist,\n  type ExtractAndPersistResult,\n} from './orchestrator.js'\nimport { listProjects, normalizeProjectPath } from './registry.js'\nimport { saveGraphToDisk, SCHEMA_VERSION, type PersistedGraph } from './persist.js'\nimport {\n  HttpError,\n  pushSnapshotToRemote,\n  resolveAuthToken,\n  resolveRemoteProjectName,\n  TransportError,\n} from './cli-client.js'\n\nexport interface SyncOptions {\n  // Project name from `--project <name>`. When absent, sync resolves the\n  // project by matching the cwd against the registered project paths.\n  project?: string\n  // Push the snapshot to a remote daemon URL. When absent, sync runs against\n  // the local daemon on http://localhost:8080.\n  to?: string\n  // Bearer token for the remote daemon. Falls back to NEAT_REMOTE_TOKEN env.\n  token?: string\n  // Skip writing the snapshot or notifying the daemon. Mirrors `neat <path>\n  // --dry-run`.\n  dryRun: boolean\n  // Skip the SDK install apply step.\n  noInstrument: boolean\n  // ADR-232 — use source-edit injection instead of runtime attachment.\n  sourceEdit?: boolean\n  // Emit a structured JSON payload on stdout instead of human text.\n  json: boolean\n  // Override the local daemon URL. Defaults to NEAT_API_URL or\n  // http://localhost:8080. Useful for tests.\n  daemonUrl?: string\n  // Working directory the verb resolves against when `--project` isn't\n  // passed. Defaults to process.cwd(); tests override.\n  cwd?: string\n}\n\nexport interface SyncResult {\n  exitCode: number\n  // Stable shape across human / json output paths. cli.ts decides which\n  // formatter to invoke based on `--json`.\n  project: string\n  scanPath: string\n  nodesAdded: number\n  edgesAdded: number\n  snapshotPath: string | null\n  // Tracks which branch the run took for `--json` consumers.\n  mode: 'dry-run' | 'local' | 'remote'\n  daemon: 'reloaded' | 'down' | 'remote-ok' | 'skipped'\n  apply: {\n    instrumented: number\n    alreadyInstrumented: number\n    libOnly: number\n    skipped: boolean\n  }\n  // Soft warning lines surfaced to stderr in the human path. Empty when the\n  // run was fully clean.\n  warnings: string[]\n}\n\nasync function resolveProjectEntry(opts: SyncOptions): Promise<RegistryEntry | null> {\n  const entries = await listProjects()\n  if (opts.project) {\n    const match = entries.find((e) => e.name === opts.project)\n    return match ?? null\n  }\n  const cwd = opts.cwd ?? process.cwd()\n  const resolvedCwd = await normalizeProjectPath(cwd)\n  // Match by path: the cwd must be inside (or equal to) the registered path.\n  for (const entry of entries) {\n    if (\n      resolvedCwd === entry.path ||\n      resolvedCwd.startsWith(`${entry.path}${path.sep}`)\n    ) {\n      return entry\n    }\n  }\n  return null\n}\n\nasync function checkDaemonHealth(baseUrl: string): Promise<boolean> {\n  try {\n    const res = await fetch(`${baseUrl.replace(/\\/$/, '')}/health`, {\n      signal: AbortSignal.timeout(1500),\n    })\n    return res.ok\n  } catch {\n    return false\n  }\n}\n\n// Pull the daemon's `hint` out of a \"project not found\" 404 body so the sync\n// error can lead with it. Best-effort — a non-JSON or hint-less body yields\n// undefined and the caller supplies the generic pointer.\nfunction daemonHint(body: string): string | undefined {\n  try {\n    const parsed = JSON.parse(body) as { hint?: unknown }\n    return typeof parsed.hint === 'string' ? parsed.hint : undefined\n  } catch {\n    return undefined\n  }\n}\n\nfunction snapshotForGraph(persisted: ExtractAndPersistResult): PersistedGraph {\n  return {\n    // Stamp the live schema version the daemon validates against on the\n    // receiving `/snapshot` merge. Tracking the constant keeps the push\n    // aligned with the current snapshot shape across schema migrations.\n    schemaVersion: SCHEMA_VERSION,\n    exportedAt: new Date().toISOString(),\n    graph: persisted.graph.export(),\n  }\n}\n\nfunction emitResult(result: SyncResult, json: boolean): void {\n  if (json) {\n    process.stdout.write(JSON.stringify(result, null, 2) + '\\n')\n    return\n  }\n  const verb =\n    result.mode === 'dry-run'\n      ? 'dry-run'\n      : result.mode === 'remote'\n        ? 'pushed'\n        : 'synced'\n  console.log(\n    `${verb}: ${result.project} — ${result.nodesAdded} node(s) and ${result.edgesAdded} edge(s) added` +\n      (result.snapshotPath ? `; snapshot at ${result.snapshotPath}` : ''),\n  )\n  if (!result.apply.skipped) {\n    const { instrumented, alreadyInstrumented, libOnly } = result.apply\n    console.log(\n      `instrumented ${instrumented}, already ${alreadyInstrumented}, lib-only ${libOnly}`,\n    )\n  } else {\n    console.log('skipped instrumentation (--no-instrument)')\n  }\n  for (const warn of result.warnings) console.error(warn)\n}\n\nexport async function runSync(opts: SyncOptions): Promise<SyncResult> {\n  const entry = await resolveProjectEntry(opts)\n  if (!entry) {\n    const target = opts.project ?? opts.cwd ?? process.cwd()\n    console.error(\n      `neat sync: no registered project ${\n        opts.project ? `named \"${opts.project}\"` : `covers ${target}`\n      }. Run \\`neat <path>\\` or \\`neat init <path>\\` first.`,\n    )\n    return {\n      exitCode: 1,\n      project: opts.project ?? '',\n      scanPath: target,\n      nodesAdded: 0,\n      edgesAdded: 0,\n      snapshotPath: null,\n      mode: opts.to ? 'remote' : 'local',\n      daemon: 'skipped',\n      apply: { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, skipped: true },\n      warnings: [],\n    }\n  }\n\n  // ── Step 1 + 2: discovery + extraction (no snapshot in dry-run) ─────\n  const persisted = await extractAndPersist({\n    scanPath: entry.path,\n    project: entry.name,\n    projectExplicit: true,\n    dryRun: true,\n  })\n\n  let snapshotPath: string | null = null\n  if (!opts.dryRun) {\n    const target = persisted.snapshotPath\n    await saveGraphToDisk(persisted.graph, target)\n    snapshotPath = target\n  }\n\n  // ── Step 3: SDK install apply (default yes; --dry-run + --no-instrument skip)\n  const skipApply = opts.dryRun || opts.noInstrument\n  const applyTally = skipApply\n    ? { instrumented: 0, alreadyInstrumented: 0, libOnly: 0, browserBundle: 0, reactNative: 0 }\n    : await applyInstallersOver(persisted.services, entry.name, { sourceEdit: opts.sourceEdit })\n\n  // ── Step 4: daemon notify ────────────────────────────────────────────\n  const warnings: string[] = []\n  let daemonState: SyncResult['daemon'] = 'skipped'\n  let exitCode = 0\n  const mode: SyncResult['mode'] = opts.dryRun ? 'dry-run' : opts.to ? 'remote' : 'local'\n  // The name the snapshot is actually pushed under. Stays the local project\n  // name for local + dry-run; a remote push may resolve it to the target\n  // daemon's hosted project (below).\n  let pushedProject = entry.name\n\n  if (!opts.dryRun) {\n    const snapshot = snapshotForGraph(persisted)\n    if (opts.to) {\n      const token = opts.token ?? process.env.NEAT_REMOTE_TOKEN\n      // A hosted tenant daemon hosts exactly one project, named by the control\n      // plane — not by the local directory. Resolve that name from the target\n      // before pushing so a repo whose local name differs from the hosted\n      // project still syncs. Falls back to the local name for local/self-host\n      // sync (see resolveRemoteProjectName).\n      pushedProject = await resolveRemoteProjectName({\n        baseUrl: opts.to,\n        token,\n        fallback: entry.name,\n      })\n      try {\n        await pushSnapshotToRemote({\n          baseUrl: opts.to,\n          token,\n          project: pushedProject,\n          snapshot,\n        })\n        daemonState = 'remote-ok'\n      } catch (err) {\n        if (err instanceof HttpError) {\n          if (err.status === 404) {\n            // Even after resolving, the push can 404 — a daemon serving nothing,\n            // or a name that moved. Lead with the daemon's own hint so the\n            // operator knows to check GET /projects rather than reading a raw\n            // status line.\n            const hint = daemonHint(err.responseBody)\n            console.error(\n              `neat sync: the daemon at ${opts.to} has no project \"${pushedProject}\" to receive this snapshot. ` +\n                (hint ?? 'GET /projects lists what it serves (see hostedHere).'),\n            )\n          } else {\n            console.error(`neat sync: ${err.message}`)\n          }\n          exitCode = 1\n        } else if (err instanceof TransportError) {\n          console.error(`neat sync: ${err.message}`)\n          exitCode = 3\n        } else {\n          console.error(`neat sync: ${(err as Error).message}`)\n          exitCode = 1\n        }\n        daemonState = 'skipped'\n      }\n    } else {\n      const daemonUrl =\n        opts.daemonUrl ?? process.env.NEAT_API_URL ?? 'http://localhost:8080'\n      const healthy = await checkDaemonHealth(daemonUrl)\n      if (healthy) {\n        try {\n          await pushSnapshotToRemote({\n            baseUrl: daemonUrl,\n            token: resolveAuthToken(),\n            project: entry.name,\n            snapshot,\n          })\n          daemonState = 'reloaded'\n        } catch (err) {\n          warnings.push(\n            `neat sync: daemon merge failed — ${(err as Error).message}. Snapshot is on disk at ${snapshotPath}.`,\n          )\n          daemonState = 'down'\n          exitCode = 2\n        }\n      } else {\n        warnings.push(\n          'neat sync: daemon not running; snapshot updated, run `neatd start` to serve it',\n        )\n        daemonState = 'down'\n        exitCode = 2\n      }\n    }\n  }\n\n  const result: SyncResult = {\n    exitCode,\n    project: pushedProject,\n    scanPath: entry.path,\n    nodesAdded: persisted.nodesAdded,\n    edgesAdded: persisted.edgesAdded,\n    snapshotPath,\n    mode,\n    daemon: daemonState,\n    apply: { ...applyTally, skipped: skipApply },\n    warnings,\n  }\n\n  emitResult(result, opts.json)\n  return result\n}\n"],"mappings":"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","names":["isLoopbackHost","path","path","ok","import_node_url","import_node_path","import_node_crypto","path","protobuf","msg","reshapeGrpcRequest","zlib","Fastify","import_node_path","import_node_url","usage","import_node_path","import_node_os","import_node_fs","indent","path","entry","GraphDefault","import_node_fs","import_node_path","import_node_fs","import_node_path","fs","path","import_node_fs","import_node_path","import_types","import_node_fs","import_node_path","path","os","semver","fs","import_types","path","walk","serviceId","sym","frontierId","fs","path","import_types","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_tree_sitter_python","import_tree_sitter_go","import_types","import_node_fs","import_node_path","import_types","fs","path","ok","parseYaml","import_node_fs","import_node_path","fs","path","fs","path","import_node_fs","import_node_path","import_types","import_node_fs","import_node_path","fs","path","ignore","path","walk","fs","entry","import_node_fs","import_node_path","import_types","module","walk","fs","path","import_node_path","import_node_fs","import_types","Parser","JavaScript","Python","Go","firstArg","fs","path","entry","snippet","goImports","PARSE_CHUNK","parseSource","makeJsParser","Parser","JavaScript","makePyParser","Python","makeGoParser","Go","Ruby","Php","Rust","fn","leaf","path","parseSource","path","plural","tokens","makeJsParser","apply","makePyParser","makeGoParser","import_types","entry","status","entry","import_types","import_types","provenance","import_types","status","grpc","stable","toPosix","path","entry","named","provenance","latencyHist","latencyMs","lastError","status","path","frontierId","serviceId","fs","path","error","import_node_fs","import_node_path","import_ignore","import_minimatch","import_types","import_node_fs","import_node_path","entry","path","fs","parseToml","import_node_fs","import_node_path","import_types","moduleDir","walk","fs","entry","path","module","main","import_node_fs","import_node_path","import_types","fs","path","import_node_path","import_types","path","import_node_fs","import_node_path","import_types","fs","entry","path","import_node_fs","import_node_path","import_types","path","fs","import_node_fs","import_node_path","import_types","fs","entry","path","import_node_fs","import_node_path","import_smol_toml","import_types","path","parseToml","fs","import_node_fs","import_node_path","import_types","path","fs","import_node_fs","import_node_path","import_types","fs","entry","path","import_node_fs","import_node_path","path","fs","path","fs","ignore","entry","import_node_path","import_node_fs","import_yaml","import_types","serviceId","path","compose","fs","entry","import_node_path","path","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_tree_sitter_python","import_tree_sitter_go","import_tree_sitter_ruby","import_tree_sitter_php","import_tree_sitter_rust","import_types","PARSE_CHUNK","TypeScript","JavaScript","Python","Go","Ruby","Php","CSharp","Java","Kotlin","Rust","Cpp","parseSource","join","firstChildOfType","parserForExt","Parser","path","import_node_path","import_tree_sitter","import_types","parserForExt","Parser","path","parseSource","walk","import_node_path","import_tree_sitter","import_types","Parser","path","parseSource","walk","import_node_path","import_tree_sitter","import_types","Parser","path","parseSource","t","import_node_path","import_tree_sitter","import_types","stringLiteralText","named","parserForExt","Parser","path","parseSource","fn","import_node_path","import_types","import_node_path","path","import_node_fs","import_node_path","import_node_fs","import_node_path","fs","path","parse","fs","entry","path","import_node_path","parse","path","parse","parse","import_node_path","parse","path","entry","parse","import_node_path","parse","path","entry","import_node_fs","import_node_path","path","fs","parse","pg","import_node_fs","import_node_path","import_yaml","parse","path","fs","import_node_path","parse","path","path","import_node_fs","import_node_path","import_types","path","walk","fs","entry","configFiles","import_node_fs","import_node_path","import_types","import_yaml","isRecord","parseYaml","STRING_LITERAL_RE","path","fs","node","import_node_path","import_tree_sitter","import_tree_sitter_java","import_types","PARSE_CHUNK","parseSource","Parser","Java","path","import_node_path","import_tree_sitter","import_tree_sitter_python","import_types","PARSE_CHUNK","parseSource","walk","table","entry","Parser","Python","path","import_node_fs","import_node_path","import_yaml","import_types","CONFIG_FILES","HTTP_METHODS","resolvePlaceholders","path","fs","edge","import_node_fs","import_node_path","import_types","lineAt","rm","path","walk","fs","entry","import_types","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_tree_sitter_typescript","import_tree_sitter_python","import_types","PARSE_CHUNK","parseSource","GRAMMAR_BY_EXT","TypeScript","JavaScript","Python","Parser","path","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","PARSE_CHUNK","parseSource","makeJsParser","Parser","JavaScript","walk","entry","path","dedupKey","fileNodeId","n","e","import_node_path","import_types","path","import_node_path","import_types","path","import_node_path","import_types","findAll","path","import_node_path","import_types","readImports","path","import_node_path","import_types","readImports","path","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","parserForExt","Parser","JavaScript","stringLiteralText","walk","parseSource","path","entry","import_node_path","import_types","path","named","import_node_path","import_tree_sitter","import_tree_sitter_python","import_types","PARSE_CHUNK","makePyParser","Parser","Python","parseSource","namedChildren","pyStaticStringText","walk","path","table","import_node_path","import_tree_sitter","import_tree_sitter_python","import_types","PARSE_CHUNK","makePyParser","Parser","Python","parseSource","namedChildren","walk","pyStaticStringText","path","import_node_path","import_tree_sitter","import_tree_sitter_python","import_types","PARSE_CHUNK","makePyParser","Parser","Python","parseSource","namedChildren","pyStaticStringText","walk","path","table","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","parserForExt","Parser","JavaScript","namedChildren","stringLiteralText","keyName","parseSource","path","walk","tableName","table","import_node_path","import_types","path","import_node_path","import_tree_sitter","import_tree_sitter_ruby","import_types","PARSE_CHUNK","makeRubyParser","Parser","Ruby","parseSource","walk","rubyLiteral","rubyArgs","rubyPositional","rubyKwarg","table","path","import_node_path","import_tree_sitter","import_tree_sitter_php","import_types","PARSE_CHUNK","makePhpParser","Parser","Php","parseSource","walk","phpStaticString","phpArgumentValues","phpFirstString","pluralize","tableize","table","path","modelTable","import_node_path","import_tree_sitter","import_tree_sitter_go","import_types","PARSE_CHUNK","makeGoParser","Parser","Go","parseSource","walk","path","table","import_node_path","import_tree_sitter","import_tree_sitter_go","import_types","PARSE_CHUNK","makeGoParser","Parser","Go","parseSource","walk","pluralize","path","table","import_node_path","import_tree_sitter","import_tree_sitter_c_sharp","import_types","PARSE_CHUNK","Parser","CSharp","parseSource","walk","firstArg","path","table","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","parserForExt","Parser","JavaScript","namedChildren","stringLiteralValue","path","parseSource","walk","table","import_node_path","import_tree_sitter","import_tree_sitter_python","import_types","PARSE_CHUNK","makePyParser","Parser","Python","parseSource","namedChildren","walk","enclosingFunction","nearestAssignmentValue","path","table","import_node_path","import_tree_sitter","import_tree_sitter_java","import_types","PARSE_CHUNK","parseSource","walk","baseName","endpoint","table","path","Parser","Java","http","import_node_path","import_tree_sitter","import_tree_sitter_java","import_types","PARSE_CHUNK","HTTP_METHODS","parseSource","makeJavaParser","Parser","Java","walk","stringLiteral","buildRouteIndex","path","import_types","import_node_path","import_types","path","compose","import_node_path","import_node_fs","import_types","path","fs","import_node_fs","import_node_path","import_types","fs","entry","path","lineAt","import_node_fs","import_node_path","import_yaml","import_types","walkYamlFiles","fs","entry","path","import_node_fs","import_node_path","import_smol_toml","import_types","path","fs","parseToml","lineContaining","entry","import_node_fs","import_node_path","import_types","path","fs","import_node_fs","import_node_path","import_smol_toml","import_types","path","fs","parseToml","import_node_fs","import_node_path","import_smol_toml","import_types","path","fs","parseToml","import_node_fs","import_node_path","import_types","path","tokens","fs","compose","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","parserForExt","Parser","JavaScript","namedChildren","stringLiteralText","keyName","parseSource","path","import_types","import_node_path","import_node_fs","import_node_path","import_types","endpoint","path","path","import_types","buckets","provenance","entry","serviceId","import_node_fs","import_node_path","import_types","fs","path","import_node_fs","import_node_path","path","fs","import_types","import_node_fs","import_node_path","import_fastify","import_node_crypto","import_types","import_node_fs","import_node_path","import_node_os","import_node_fs","import_node_path","exists","fs","path","fileExists","fs","path","walk","entry","snippet","os","allDeps","registryResolve","registryList","import_types","import_types","CODE_FILEPATH_ATTR","CODE_LINENO_ATTR","grainOf","cause","round","import_types","matched","named","entry","import_node_fs","fs","entry","import_node_path","path","import_node_fs","import_node_os","import_node_path","import_types","path","os","fs","path","fs","entry","path","status","entry","DAY_MS","fs","entry","status","import_node_fs","import_types","import_node_crypto","import_node_fs","import_node_os","import_node_path","import_node_fs","MARKER","MARKER","import_types","import_node_os","import_node_path","fs","http","clone","status","fs","path","os","walk","entry","import_node_os","import_node_path","import_node_fs","neatHome","path","os","fs","entry","import_types","ok","import_node_crypto","status","error","path","buckets","nowIso","table","pg","import_types","import_types","DEFAULT_MAX_LOOKBACK_MS","DEFAULT_LOG_LIMIT","DEFAULT_LOG_LIMIT","bucketKey","status","buckets","entry","DEFAULT_MAX_LOOKBACK_MS","path","ERROR_STATUS_THRESHOLD","entry","import_types","import_types","path","findRoute","import_types","import_node_crypto","HTTP_METHODS","ERROR_STATUS_THRESHOLD","path","DEFAULT_MAX_LOOKBACK_MS","path","import_pg","Client","pg","table","import_types","DEFAULT_LOOKBACK_MS","ENTRIES_LIST_URL","PAGE_SIZE","MAX_PAGES","FIELD_SEP","path","CLOUD_RUN_RESOURCE_TYPE","pathFromRequestUrl","ERROR_STATUS_THRESHOLD","mapLogEntryToSignal","entry","path","mapLogEntriesToSignals","import_types","findMatchingRouteNode","path","DEFAULT_LOOKBACK_MS","mapLogEntriesToSignals","DEFAULT_LOOKBACK_MS","ENTRIES_LIST_URL","PAGE_SIZE","MAX_PAGES","FIELD_SEP","path","GCP_LB_RESOURCE_TYPE","pathFromRequestUrl","ERROR_STATUS_THRESHOLD","mapLogEntryToSignal","entry","path","mapLogEntriesToSignals","import_types","findMatchingRouteNode","path","DEFAULT_LOOKBACK_MS","boundedSinceIso","mapLogEntriesToSignals","import_types","entry","DEFAULT_MAX_LOOKBACK_MS","ROUTE_TARGET_KIND","UNMATCHED_ROUTE_TARGET_KIND","bucketKey","isHttpErrorStatus","status","upsertBucket","buckets","entry","DEFAULT_MAX_LOOKBACK_MS","DEFAULT_MAX_LOOKBACK_MS","table","import_types","DEFAULT_MAX_LOOKBACK_MS","FIELD_SEP","DEFAULT_MAX_LOOKBACK_MS","incidentMessage","import_types","NO_ENV","boundedSinceIso","DEFAULT_MAX_LOOKBACK_MS","entry","status","named","entry","error","violations","blocking","Fastify","cors","import_types","httpsRequest","status","path","import_node_fs","import_yaml","parseYaml","FIELD_SEP","DEFAULT_MAX_LOG_BYTES","DEFAULT_MAX_LOG_BYTES","nowIso","named","import_types","NO_ENV","import_promises","import_node_os","import_node_path","path","os","entry","import_promises","import_node_os","import_node_path","endpoint","http2","endpoint","defaultHome","path","os","entry","import_node_fs","import_node_path","import_promises","import_node_path","import_node_fs","import_node_path","import_types","path","fs","import_node_fs","import_node_path","import_node_crypto","warn","fs","path","entry","idx","path","fs","chokidar","import_node_fs","import_node_path","import_node_child_process","import_node_crypto","renderOtelEnvBlock","path","fs","import_node_fs","import_node_path","import_semver","import_instrumentation_registry","serviceNodeName","path","fs","exists","readPackageJson","semver","entry","resolveRegistry","tokens","import_node_fs","import_node_path","SDK_PACKAGES","OTEL_ENV","fs","path","exists","detect","plan","entrypointEdits","reqs","dependencyEdits","apply","rollback","import_node_fs","import_node_path","exists","fs","path","entry","detect","plan","main","apply","import_node_fs","import_node_path","NEAT_OTEL_STAMP","path","endpoint","exists","fs","detect","plan","writeFileAtomic","rollback","apply","import_node_fs","import_node_path","NEAT_OTEL_FILENAME","NEAT_OTEL_STAMP","endpoint","exists","fs","detect","path","require","plan","writeFileAtomic","rollback","apply","plan","plan","import_node_fs","import_node_net","import_node_path","import_node_url","import_node_child_process","path","runInstall","plan","readline","http","ok","projects","net","path","fs","named","projectPath","path","fs","entry","import_node_readline","readline","entry","status","import_node_child_process","import_node_http","import_node_child_process","import_node_crypto","import_node_fs","import_node_os","import_node_path","neatHome","path","os","MODE_MASK_LOOSER_THAN_0600","warnIfModeLooserThan0600","fs","validateConfig","entry","validateEntry","endpoint","LOCK_RETRY_MS","LOCK_TIMEOUT_MS","acquireLock","releaseLock","endpoint","import_node_child_process","import_node_fs","import_node_path","fs","path","detect","sleep","defaultOpenBrowser","sleep","import_node_fs","import_node_path","import_types","status","path","provenance","resolveDeps","ok","fs","path","import_node_path","entry","path","import_promises","sleep","endpoint","readline","import_node_fs","import_node_path","import_promises","endpoint","defaultReadLine","readRegistry","finish","path","fs","readline","import_node_path","import_node_os","import_node_fs","import_node_url","path","fs","neatHome","os","entry","import_node_path","import_node_fs","path","readIfExists","fs","usage","import_node_path","import_node_os","import_node_fs","import_node_util","import_smol_toml","path","os","tableName","parseToml","stringifyToml","text","fs","usage","import_node_path","import_node_os","import_node_fs","import_node_util","os","path","fs","usage","apply","import_types","formatDivergenceLine","projectPath","import_node_path","entry","path","warn","import_types","usage","status","plan","fs","path","entry","snippet","usage","named","orchestratorCode","apply","os","projectPath","renderOtelEnvBlock","endpoint","isLoopbackHost"]}