{"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/graph.ts","../src/extract.ts","../src/extract/index.ts","../src/ingest.ts","../src/policy.ts","../src/compat.ts","../compat.json","../src/events.ts","../src/traverse.ts","../src/extract/services.ts","../src/extract/shared.ts","../src/extract/python.ts","../src/extract/owners.ts","../src/extract/errors.ts","../src/extract/aliases.ts","../src/extract/files.ts","../src/extract/calls/shared.ts","../src/extract/imports.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/docker-compose.ts","../src/extract/configs.ts","../src/extract/routes.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/infra/index.ts","../src/extract/infra/docker-compose.ts","../src/extract/infra/shared.ts","../src/extract/infra/dockerfile.ts","../src/extract/infra/terraform.ts","../src/extract/infra/k8s.ts","../src/extract/retire.ts","../src/divergences.ts","../src/persist.ts","../src/gitignore.ts","../src/summary.ts","../src/watch.ts","../src/api.ts","../src/extend/index.ts","../src/installers/package-manager.ts","../src/diff.ts","../src/projects.ts","../src/registry.ts","../src/streaming.ts","../src/daemon.ts","../src/connectors/index.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/shared.ts","../src/orchestrator.ts","../src/cli-verbs.ts","../src/cli-client.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 (or path suffixes) to leave unauthenticated. 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. Dual-mounted under `/projects/:project/` too,\n// so the check is a suffix match — `/projects/foo/health` is skipped along\n// with the top-level `/health`. ADR-073 §3 names `/healthz` and `/readyz`\n// explicitly; `/health` is the existing endpoint the web shell and CI smoke\n// already lean on, so it keeps the unauthenticated treatment. `/api/config`\n// is the public-read negotiation endpoint — the web shell hits it before any\n// authed call to learn which mode the daemon is running in.\nconst DEFAULT_UNAUTH_SUFFIXES: ReadonlyArray<string> = [\n  '/health',\n  '/healthz',\n  '/readyz',\n  '/api/config',\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 suffixes = [...DEFAULT_UNAUTH_SUFFIXES, ...(opts.extraUnauthenticatedSuffixes ?? [])]\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    for (const suffix of suffixes) {\n      if (path === suffix || path.endsWith(suffix)) {\n        done()\n        return\n      }\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 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  // 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  // 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}\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  // 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\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 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\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        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: typeof attrs['db.system'] === 'string' ? (attrs['db.system'] as string) : undefined,\n          dbName: typeof attrs['db.name'] === 'string' ? (attrs['db.name'] as string) : 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              : undefined,\n          rpcService:\n            typeof attrs['rpc.service'] === 'string' &&\n            (attrs['rpc.service'] as string).length > 0\n              ? (attrs['rpc.service'] as string)\n              : undefined,\n          rpcMethod:\n            typeof attrs['rpc.method'] === 'string' &&\n            (attrs['rpc.method'] as string).length > 0\n              ? (attrs['rpc.method'] as string)\n              : undefined,\n          websocketChannel: websocketChannelOf(attrs),\n          statusCode: span.status?.code,\n          errorMessage: span.status?.message,\n          exception: extractExceptionFromEvents(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. Per ADR-033 the\n// receiver always reports \"all accepted\" today — there's no per-span reject\n// path. Caching the bytes avoids re-running the protobuf encoder per request.\nlet cachedProtobufResponseBody: Buffer | null = null\n\nfunction encodeProtobufResponseBody(): Buffer {\n  if (cachedProtobufResponseBody) return cachedProtobufResponseBody\n  const Type = loadProtobufResponseEncoder()\n  // `partial_success` left unset = empty submessage = \"everything accepted\".\n  // verify() returns null on success; the empty payload is always valid.\n  const msg = Type.create({})\n  const encoded = Type.encode(msg).finish()\n  cachedProtobufResponseBody = Buffer.from(encoded)\n  return cachedProtobufResponseBody\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\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  // 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  // 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    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    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 { promises as fs } from 'node:fs'\nimport { printBanner, readPackageVersion } from './banner.js'\nimport { DEFAULT_PROJECT, getGraph, resetGraph } from './graph.js'\nimport { extractFromDirectory } from './extract.js'\nimport {\n  formatExtractionBanner,\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 { 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  findDaemonByProject,\n  listMachineProjects,\n  listProjects,\n  ProjectNameCollisionError,\n  pruneRegistry,\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 { 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  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'\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-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// 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.\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\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('')\n  console.log('lifecycle commands:')\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('  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('  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('  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('                   --json             emit the delta summary as JSON')\n  console.log('')\n  console.log('query commands (mirror the MCP tools, ADR-050):')\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  apply: boolean\n  dryRun: boolean\n  noInstall: boolean\n  noInstrument: 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  ['--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    apply: false,\n    dryRun: false,\n    noInstall: false,\n    noInstrument: 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 === '--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` live in banner.ts so the orchestrator\n// can print the same artwork 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 }\n\nfunction printVersion(): void {\n  process.stdout.write(`${readPackageVersion()}\\n`)\n}\n\n// One `neat list` / `neat ps` row. A discovery-backed row reports the daemon's\n// state and ports; a legacy registry row (no daemon file yet) reports\n// `registered` and the registry status so the migration window stays legible.\nfunction formatMachineProjectRow(r: MachineProject): string {\n  if (r.ports) {\n    const where = r.pid !== undefined ? `\\tpid=${r.pid}` : ''\n    return `${r.project}\\t${r.state}\\trest=${r.ports.rest} otlp=${r.ports.otlp} web=${r.ports.web}\\t${r.projectPath}${where}`\n  }\n  const status = r.registryStatus ? `\\t(${r.registryStatus})` : ''\n  return `${r.project}\\t${r.state}${status}\\t${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('=== 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): 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 })\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)\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  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) {\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  // Narrow the active-project surface to the project the operator just\n  // registered. Mirrors the bare-orchestrator behaviour so `neat init` and\n  // `neat <path>` agree on the activation contract.\n  const siblings = await listProjects()\n  const paused: string[] = []\n  for (const p of siblings) {\n    if (p.name !== currentProjectName && p.status === 'active') {\n      await setStatus(p.name, 'paused')\n      paused.push(p.name)\n    }\n  }\n  if (paused.length > 0) {\n    const plural = paused.length === 1 ? '' : 's'\n    console.log(\n      `neat: paused ${paused.length} sibling project${plural}; run \\`neat resume <name>\\` to bring one back active.`,\n    )\n  }\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  const divergenceResult = computeDivergences(graph)\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  // 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).\nexport const CLAUDE_SKILL_CONFIG = {\n  mcpServers: {\n    neat: {\n      type: 'stdio' as const,\n      command: 'npx',\n      args: ['-y', '@neat.is/mcp'],\n      env: {\n        NEAT_CORE_URL: 'http://localhost:8080',\n      },\n    },\n  },\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    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        console.error(`neat skill: failed to read ${target} — ${(err as Error).message}`)\n        return { exitCode: 1 }\n      }\n    }\n    // Merge mcpServers.neat without disturbing other entries the user\n    // might have wired up by hand.\n    const mcp =\n      (existing as { mcpServers?: Record<string, unknown> }).mcpServers ?? {}\n    const merged = {\n      ...existing,\n      mcpServers: { ...mcp, neat: CLAUDE_SKILL_CONFIG.mcpServers.neat },\n    }\n    await fs.mkdir(path.dirname(target), { recursive: true })\n    await fs.writeFile(target, JSON.stringify(merged, null, 2) + '\\n', 'utf8')\n    console.log(`neat skill: wrote mcpServers.neat to ${target}`)\n    console.log('restart Claude Code to pick up the new MCP server.')\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('The MCP server reads NEAT_CORE_URL for the daemon URL — point it at a')\n  console.log('non-default daemon by editing that value in the generated config.')\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.\n  if (cmd0 === '-h' || cmd0 === '--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  // 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    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  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      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      ...(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    for (const r of rows) {\n      console.log(formatMachineProjectRow(r))\n    }\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    const result = await runSync({\n      ...(parsed.project ? { project: parsed.project } : {}),\n      ...(parsed.to ? { to: parsed.to } : {}),\n      ...(parsed.token ? { token: parsed.token } : {}),\n      dryRun: parsed.dryRun,\n      noInstrument: parsed.noInstrument,\n      json: parsed.json,\n    })\n    if (result.exitCode !== 0) process.exit(result.exitCode)\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(cmd: string, parsed: ParsedArgs): 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    noOpen: parsed.noOpen,\n    yes: parsed.yes,\n  })\n  return result.exitCode\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])\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// still exits 3 with the existing \"is the daemon running?\" message.\nexport async function resolveProjectForVerb(\n  client: HttpClient,\n  parsed: ParsedArgs,\n): Promise<string | undefined> {\n  const explicit = resolveProjectFlag(parsed)\n  if (explicit) return explicit\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.\nexport async function resolveDaemonUrl(project?: string): Promise<string> {\n  const explicit = process.env.NEAT_API_URL ?? process.env.NEAT_CORE_URL\n  if (explicit) return explicit\n  if (project) {\n    const daemon = await findDaemonByProject(project)\n    if (daemon) return `http://localhost:${daemon.record.ports.rest}`\n  }\n  return 'http://localhost:8080'\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  const baseUrl = await resolveDaemonUrl(requestedProject)\n  // ADR-073 §3 — read the bearer once and thread it into the single client\n  // every verb shares, so no verb path can reach a secured daemon without it.\n  const client = createHttpClient(baseUrl, resolveAuthToken())\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 '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(client, parsed)\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=${baseUrl})`)\n    } else {\n      console.error(`neat ${cmd}: ${(err as Error).message}`)\n    }\n    return exitCodeForError(err)\n  }\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.\nconst entry = process.argv[1] ?? ''\nif (/[\\\\/]cli\\.(?:cjs|js)$/.test(entry) || entry.endsWith('/cli') || entry.endsWith('/neat') || entry.endsWith('/neat.is')) {\n  main().catch((err) => {\n    console.error(err)\n    process.exit(1)\n  })\n}\n","import path from 'node:path'\nimport { readFileSync } from 'node:fs'\nimport { fileURLToPath } from 'node:url'\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 ASCII banner. Shared between the CLI's `neat init` discovery report and\n// the one-command orchestrator (issue #483) so the artwork lives in exactly\n// one place — no duplicated glyphs to drift apart.\nexport function printBanner(): void {\n  console.log('███╗   ██╗███████╗ █████╗ ████████╗')\n  console.log('████╗  ██║██╔════╝██╔══██╗╚══██╔══╝')\n  console.log('██╔██╗ ██║█████╗  ███████║   ██║   ')\n  console.log('██║╚██╗██║██╔══╝  ██╔══██║   ██║   ')\n  console.log('██║ ╚████║███████╗██║  ██║   ██║   ')\n  console.log('╚═╝  ╚═══╝╚══════╝╚═╝  ╚═╝   ╚═╝   ')\n  console.log('')\n  console.log('  Network Expressive Architecting Tool')\n  console.log(`  neat.is  ·  v${readPackageVersion()}  ·  Apache 2.0`)\n  console.log('')\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\nfunction 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 { addImports } from './imports.js'\nimport { addDatabasesAndCompat } from './databases/index.js'\nimport { addConfigNodes } from './configs.js'\nimport { addRoutes } from './routes.js'\nimport { addGrpcMethods } from './proto.js'\nimport { addCallEdges } from './calls/index.js'\nimport { addInfra } from './infra/index.js'\nimport {\n  drainExtractionErrors,\n  writeExtractionErrors,\n  drainDroppedExtracted,\n  isRejectedLogEnabled,\n  writeRejectedExtracted,\n  type ExtractionError,\n  type DroppedExtractedEdge,\n} from './errors.js'\nimport path from 'node:path'\nimport { retireExtractedEdgesByMissingFile } from './retire.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  // 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  // 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}\n\nexport async function extractFromDirectory(\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\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  const importGraph = await addImports(graph, services)\n  const phase2 = await addDatabasesAndCompat(graph, services, scanPath)\n  const phase3 = await addConfigNodes(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  // 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)\n  const phase4 = await addCallEdges(graph, services)\n  const phase5 = await addInfra(graph, scanPath, 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  const ghostsRetired = retireExtractedEdgesByMissingFile(\n    graph,\n    scanPath,\n    services.map((s) => s.dir),\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\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  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  const result: ExtractResult = {\n    nodesAdded:\n      phase1Nodes +\n      fileEnum.nodesAdded +\n      importGraph.nodesAdded +\n      phase2.nodesAdded +\n      phase3.nodesAdded +\n      routePhase.nodesAdded +\n      grpcPhase.nodesAdded +\n      phase4.nodesAdded +\n      phase5.nodesAdded,\n    edgesAdded:\n      fileEnum.edgesAdded +\n      importGraph.edgesAdded +\n      phase2.edgesAdded +\n      phase3.edgesAdded +\n      routePhase.edgesAdded +\n      grpcPhase.edgesAdded +\n      phase4.edgesAdded +\n      phase5.edgesAdded,\n    frontiersPromoted,\n    extractionErrors: errorEntries.length,\n    errorEntries,\n    ghostsRetired,\n    extractedDropped: droppedEntries.length,\n    droppedEntries,\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  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 * 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  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  NodeType,\n  Provenance,\n  confidenceForObservedSignal,\n  databaseId,\n  localDatabaseId,\n  extractedEdgeId,\n  fileId,\n  frontierId,\n  graphqlOperationId,\n  grpcMethodId,\n  inferredEdgeId,\n  infraId,\n  observedEdgeId,\n  serviceId,\n  websocketChannelId,\n  type EdgeTypeValue,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport { DEFAULT_PROJECT } from './graph.js'\nimport type { ParsedSpan } from './otel.js'\nimport { emitNeatEvent } from './events.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// 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// 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// 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 injected SpanProcessor sets `code.filepath` / `code.lineno` /\n// `code.function` on CLIENT/PRODUCER spans — the exact OTel attribute names,\n// written by the emit template (installers/templates.ts) and read here. The\n// two sites are cross-referenced so the names can't drift. When present, an\n// OBSERVED relationship originates from the file rather than the service.\n// SERVER spans and the callee side carry no call site and stay service-level;\n// evidence is never fabricated (§6).\nconst CODE_FILEPATH_ATTR = 'code.filepath'\nconst CODE_LINENO_ATTR = 'code.lineno'\nconst CODE_FUNCTION_ATTR = 'code.function'\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 '.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 pos = entry.consumer.originalPositionFor({\n      line: line !== undefined && Number.isFinite(line) ? line : 1,\n      column: 0,\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// 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 = span.attributes[CODE_FILEPATH_ATTR]\n  if (typeof filepath !== 'string' || filepath.length === 0) return null\n  const linenoRaw = span.attributes[CODE_LINENO_ATTR]\n  let line =\n    typeof linenoRaw === 'number' && Number.isFinite(linenoRaw) ? linenoRaw : undefined\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).\n  if (!resolved && abs.endsWith('.js') && relPath.startsWith('dist/') && serviceNode?.name) {\n    warnNoSourceMaps(serviceNode.name)\n  }\n  const fnRaw = span.attributes[CODE_FUNCTION_ATTR]\n  const fn = typeof fnRaw === 'string' && fnRaw.length > 0 ? fnRaw : undefined\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  const relPath = reconcileObservedRelPath(graph, serviceName, callSite.relPath)\n  const fileNodeId = fileId(serviceName, relPath)\n  if (!graph.hasNode(fileNodeId)) {\n    const language = languageForExt(relPath)\n    const node: FileNode = {\n      id: fileNodeId,\n      type: NodeType.FileNode,\n      service: serviceName,\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  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\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.\nexport function ensureServiceNode(\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 node: ServiceNode = {\n    id,\n    type: NodeType.ServiceNode,\n    name: serviceName,\n    language: 'unknown',\n    discoveredVia: 'otel',\n    ...(env !== 'unknown' ? { env } : {}),\n  }\n  graph.addNode(id, node)\n  return id\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\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\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): UpsertResult | null {\n  if (!graph.hasNode(source) || !graph.hasNode(target)) return null\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    const newSignal = {\n      spanCount: newSpanCount,\n      errorCount: newErrorCount,\n      lastObservedAgeMs: 0,\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    }\n    graph.replaceEdgeAttributes(id, updated)\n    return { edge: updated, created: false }\n  }\n\n  const signal = {\n    spanCount: 1,\n    errorCount: isError ? 1 : 0,\n    lastObservedAgeMs: 0,\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    // 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\nasync function appendErrorEvent(ctx: IngestContext, ev: ErrorEvent): Promise<void> {\n  await fs.mkdir(path.dirname(ctx.errorsPath), { recursive: true })\n  await fs.appendFile(ctx.errorsPath, JSON.stringify(ev) + '\\n', 'utf8')\n}\n\n// Resolve the incident's affectedNode. When the span carries a `code.filepath`\n// call site, the incident attributes to the FileNode the failure surfaced in —\n// the same file grain OBSERVED CALLS edges land on (file-awareness.md §4) —\n// resolving a compiled `dist/...js` frame through its disk-adjacent source map\n// when one is present. Without a call site it stays at the originating service,\n// the honest fallback (§2).\n//\n// The runtime `code.filepath` is a deploy-absolute path (`/var/task/...` on\n// Lambda, `/app/...` in a container image) that need not match the daemon's\n// checkout. When the graph is available it's reconciled onto the service-\n// relative path the extractor already minted (reconcileObservedRelPath, the\n// same trailing-suffix match the OBSERVED edge origin uses), so the incident\n// lands on the ONE fused FileNode instead of a phantom keyed off the absolute\n// path — the node root-cause actually walks. Without a graph the honest runtime\n// path stands: the file node may not be materialised yet, but querying the\n// service still surfaces the incident, and the file:line is real (§6 — never\n// fabricated).\nfunction incidentAffectedNode(\n  span: ParsedSpan,\n  graph?: NeatGraph,\n  scanPath?: string,\n): string {\n  const sid = serviceId(span.service, span.env)\n  const serviceNode =\n    graph && graph.hasNode(sid)\n      ? (graph.getNodeAttributes(sid) as ServiceNode)\n      : undefined\n  const callSite = callSiteFromSpan(span, serviceNode, scanPath)\n  if (callSite) {\n    const relPath = graph\n      ? reconcileObservedRelPath(graph, span.service, callSite.relPath)\n      : callSite.relPath\n    return fileId(span.service, relPath)\n  }\n  return sid\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// Span attributes pass through verbatim so consumers can read source\n// attribution (`code.filepath`, `code.lineno`, `code.function`) and other\n// SDK-emitted context without ingest enumerating every key it cares about.\n// Coerce span attributes to a JSON-safe shape — bigint values from the\n// parsed span (long ids, high-cardinality counters) become strings so the\n// passthrough record can be serialised to the ErrorEvent shape and round-\n// tripped through ErrorEventSchema. All other types pass through verbatim.\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 (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 attrs = sanitizeAttributes(span.attributes)\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    ...(Object.keys(attrs).length > 0 ? { attributes: attrs } : {}),\n    affectedNode: incidentAffectedNode(span, graph, scanPath),\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): (span: ParsedSpan) => Promise<void> {\n  return async (span) => {\n    const ev = buildErrorEventForReceiver(span, graph, scanPath)\n    if (!ev) return\n    await fs.mkdir(path.dirname(errorsPath), { recursive: true })\n    await fs.appendFile(errorsPath, JSON.stringify(ev) + '\\n', 'utf8')\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 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    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: 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\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  const isError = span.statusCode === 2\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  // 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 — an in-process DB. Name the node by its logical\n        // database (db.name) when the span carries one, the engine otherwise.\n        const localName = span.dbName ?? span.dbSystem\n        targetId = ensureLocalDatabaseNode(\n          ctx.graph,\n          span.service,\n          localName,\n          span.dbSystem,\n        )\n      }\n      const result = upsertObservedEdge(\n        ctx.graph,\n        EdgeType.CONNECTS_TO,\n        observedSource(),\n        targetId,\n        ts,\n        isError,\n        callSiteEvidence,\n      )\n      if (result) affectedNode = targetId\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    )\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    )\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    )\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    )\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 = pickAddress(span)\n    let resolvedViaAddress = false\n    if (mintsFromCallerSide && host && host !== span.service && !isLoopbackHost(host)) {\n      const targetId = resolveServiceId(ctx.graph, host, env)\n      if (targetId && targetId !== sourceId) {\n        upsertObservedEdge(\n          ctx.graph,\n          EdgeType.CALLS,\n          observedSource(),\n          targetId,\n          ts,\n          isError,\n          callSiteEvidence,\n        )\n        affectedNode = targetId\n        resolvedViaAddress = true\n      } else if (!targetId) {\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        )\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        )\n      }\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      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        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,\n      }\n      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    // 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 (\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\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\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}\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      } 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\nexport async function readErrorEvents(errorsPath: string): Promise<ErrorEvent[]> {\n  try {\n    const raw = await fs.readFile(errorsPath, 'utf8')\n    const events = raw\n      .split('\\n')\n      .filter((line) => line.length > 0)\n      .map((line) => JSON.parse(line) as ErrorEvent)\n    return dedupeIncidents(events)\n  } catch (err) {\n    if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n    throw err\n  }\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\nexport function mergeSnapshot(\n  graph: NeatGraph,\n  snapshot: PersistedGraph,\n): MergeSnapshotResult {\n  const exported = snapshot.graph as {\n    nodes?: Array<{ key: string; attributes?: GraphNode }>\n    edges?: Array<{ key?: string; source: string; target: string; attributes?: GraphEdge }>\n  }\n\n  let nodesAdded = 0\n  let edgesAdded = 0\n\n  for (const node of exported.nodes ?? []) {\n    if (graph.hasNode(node.key)) continue\n    if (!node.attributes) continue\n    graph.addNode(node.key, node.attributes)\n    nodesAdded++\n  }\n\n  for (const edge of exported.edges ?? []) {\n    const attrs = edge.attributes\n    if (!attrs) continue\n    const id = edge.key ?? attrs.id\n    if (!id) continue\n    if (graph.hasEdge(id)) 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(id, edge.source, edge.target, attrs)\n    edgesAdded++\n  }\n\n  return { nodesAdded, edgesAdded }\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\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}\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  }\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\nexport interface CompatMatrix {\n  pairs: CompatPair[]\n  nodeEngineConstraints?: NodeEngineConstraint[]\n  packageConflicts?: PackageConflict[]\n  deprecatedApis?: DeprecatedApi[]\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  }\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","{\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}\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 is locked at eight types (ADR-051 #2). Adding a ninth type\n// requires a successor ADR.\n\nimport { EventEmitter } from 'node:events'\nimport type { GraphEdge, GraphNode, PolicyViolation, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\n// Locked event taxonomy. Eight 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] 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}\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  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  ObservedDependenciesResult,\n  RootCauseResult,\n  ServiceNode,\n  TransitiveDependenciesResult,\n  TransitiveDependency,\n} from '@neat.is/types'\nimport {\n  BlastRadiusResultSchema,\n  EdgeType,\n  NodeType,\n  ObservedDependenciesResultSchema,\n  PROV_RANK,\n  Provenance,\n  RootCauseResultSchema,\n  TransitiveDependenciesResultSchema,\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) — in a file-first\n// graph the caller on the path is a FileNode, but the dependency declaration\n// lives on the service that owns it. Anything else has no service to resolve\n// to. Returns the 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  if (attrs.type === NodeType.FileNode) {\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    }\n  }\n  return null\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.\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)) continue\n    const cur = best.get(e.source)\n    if (!cur || PROV_RANK[e.provenance] > PROV_RANK[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)) continue\n    const cur = best.get(e.target)\n    if (!cur || PROV_RANK[e.provenance] > PROV_RANK[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}\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// 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.\nconst rootCauseShapes: Partial<Record<GraphNode['type'], RootCauseShape>> = {\n  [NodeType.DatabaseNode]: databaseRootCauseShape,\n  [NodeType.ServiceNode]: serviceRootCauseShape,\n  [NodeType.FileNode]: fileRootCauseShape,\n}\n\nexport function getRootCause(\n  graph: NeatGraph,\n  errorNodeId: string,\n  errorEvent?: ErrorEvent,\n  incidents?: ErrorEvent[],\n): RootCauseResult | 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 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  // 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 crossService\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  return rootCauseFromIncidents(errorNodeId, incidents, errorEvent)\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  return ev.affectedNode === nodeId || ev.service === nodeId.replace(/^service:/, '')\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 FileNode the failure surfaced in, present only when the incident\n  // localized to a file grain. Callers walk node → file as a single OBSERVED\n  // 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  const filepath = typeof attrs['code.filepath'] === 'string' ? attrs['code.filepath'] : undefined\n  const lineno = typeof attrs['code.lineno'] === 'number' ? attrs['code.lineno'] : undefined\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 file (affectedNode is a file id), name\n  // that file as the root cause. The \"edge\" the caller walks is the captured\n  // runtime attribution; OBSERVED is honest because the file came from a real\n  // `code.*` on the failing span. Otherwise the cause sits on the node itself.\n  const localizesToFile = latest.affectedNode !== nodeId && latest.affectedNode.startsWith('file:')\n  const fileNode = localizesToFile ? 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 && (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, plus each FileNode it CONTAINS. A file-first graph anchors\n// the caller's CALLS edge on the call-site file (file-awareness.md §4), so an\n// entry service's failing call may hang off one of its files, not the bare\n// service node.\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) ids.push(e.target)\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 (PROV_RANK[e.provenance] !== PROV_RANK[curEdge.provenance]) {\n    return PROV_RANK[e.provenance] > PROV_RANK[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// 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      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    if (frame.distance > 0 && frame.edge) {\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    })\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.\"\n  let inboundObservedCount = 0\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) inboundObservedCount += 1\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  })\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 { 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\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 → 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  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 JS/TS manifest (`package.json`) or a Python manifest\n// (`pyproject.toml` / `requirements.txt` / `setup.py`). JS wins on tie.\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 (await hasPythonManifest(scanPath)) {\n      // A Python project commonly keeps its manifest at the repo root with the\n      // code in a subpackage and no package.json anywhere. The walk only visits\n      // descendants, so without this the root manifest is never seen and the\n      // whole project discovers zero 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 (await hasPythonManifest(dir)) {\n          candidateDirs.push(dir)\n        }\n      },\n    )\n  }\n\n  candidateDirs.sort()\n\n  const seen = new Map<string, 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    if (!service) continue\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\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  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 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}\n\nexport const SERVICE_FILE_EXTENSIONS = new Set(['.js', '.mjs', '.cjs', '.ts', '.tsx', '.py'])\nexport const CONFIG_FILE_EXTENSIONS = new Set(['.yaml', '.yml'])\nexport const IGNORED_DIRS = new Set([\n  'node_modules',\n  '.git',\n  '.turbo',\n  'dist',\n  'build',\n  '.next',\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])\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  // .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)\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 (seg === '__tests__' || seg === '__fixtures__' || seg === 'integration-tests') {\n      return true\n    }\n  }\n  const base = segments[segments.length - 1] ?? ''\n  return /\\.(spec|test)\\.(?: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","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 { 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","// 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'\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// 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: { file: string; line?: number; snippet?: string }\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\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 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)\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 { 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 {\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}\n\nexport async function walkSourceFiles(dir: string): Promise<string[]> {\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 (await isPythonVenvDir(full)) continue\n        await walk(full)\n      } else if (\n        entry.isFile() &&\n        SERVICE_FILE_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      ) {\n        out.push(full)\n      }\n    }\n  }\n  await walk(dir)\n  return out\n}\n\nexport async function loadSourceFiles(dir: string): Promise<SourceFile[]> {\n  const paths = await walkSourceFiles(dir)\n  const out: SourceFile[] = []\n  for (const p of paths) {\n    try {\n      const content = await fs.readFile(p, 'utf8')\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\nexport function snippet(text: string, line: number): string {\n  const lines = text.split('\\n')\n  return (lines[line - 1] ?? '').trim()\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 '.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.\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      discoveredVia: 'static',\n    }\n    graph.addNode(fileNodeId, node)\n    nodesAdded++\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","import 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 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\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\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\ninterface 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.\nasync 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).\nasync 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      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\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  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  let edgesAdded = 0\n\n  for (const service of services) {\n    const tsPaths = await loadTsPathConfig(service.dir)\n    const files = await loadSourceFiles(service.dir)\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\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 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 { 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  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        evidence: { 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\nconst CONNECTION_KEYS = new Set([\n  'DATABASE_URL',\n  'DB_URL',\n  'POSTGRES_URL',\n  'POSTGRESQL_URL',\n  'MYSQL_URL',\n  'MONGODB_URI',\n  'MONGO_URL',\n  'MONGO_URI',\n  'REDIS_URL',\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}\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\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 { readIfExists, parseConnectionString, schemeToEngine, type DbConfig } 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. URLs come in via env() so we can't resolve\n// them statically; host/database fall back to placeholders so the DatabaseNode\n// id remains deterministic per service.\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  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 { findFirst, readIfExists, parseConnectionString, schemeToEngine, type DbConfig } 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  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 { findFirst, readIfExists, parseConnectionString, type DbConfig } 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  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 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): Promise<string[]> {\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 (await isPythonVenvDir(full)) continue\n        await walk(full)\n      } else if (entry.isFile() && isConfigFile(entry.name).match) {\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)\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 path from 'node:path'\nimport Parser from 'tree-sitter'\nimport JavaScript from 'tree-sitter-javascript'\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'\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\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\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 // 'express' | 'fastify' | 'next'\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, [id] next\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// ── Express / Fastify call-expression routes ────────────────────────────────\n\n// Recognise route registrations of the shape `<router>.<method>('/path', …)`\n// and Fastify's `<fastify>.route({ method, url })`. The guard that keeps this\n// off `db.get('key')` / `_.get(obj, path)` is a string first argument that\n// starts with '/', combined with the caller-side dep gate in addRoutes (only\n// services that depend on express / fastify reach here). Mount-prefix\n// resolution (`app.use('/api', router)`) and `.route().get()` chaining are out\n// of scope for this slice — the literal declared path is captured as-is.\nexport function serverRoutesFromSource(\n  source: string,\n  parser: Parser,\n  hasExpress: boolean,\n  hasFastify: boolean,\n): ExtractedRoute[] {\n  const tree = parseSource(parser, source)\n  const out: ExtractedRoute[] = []\n  const framework = hasExpress ? 'express' : 'fastify'\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// ── producer ────────────────────────────────────────────────────────────────\n\nexport async function addRoutes(\n  graph: NeatGraph,\n  services: DiscoveredService[],\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  const jsParser = makeJsParser()\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 hasNext = deps['next'] !== undefined\n    if (!hasExpress && !hasFastify && !hasNext) continue\n\n    const files = await loadSourceFiles(service.dir)\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      if (!JS_ROUTE_EXTENSIONS.has(path.extname(file.path))) continue\n      const relFile = toPosix(path.relative(service.dir, file.path))\n\n      let routes: ExtractedRoute[]\n      try {\n        if (hasNext && (isNextAppRouteFile(relFile) || isNextPagesApiFile(relFile))) {\n          routes = nextRoutesFromFile(file.content, relFile, jsParser)\n        } else if (hasExpress || hasFastify) {\n          routes = serverRoutesFromSource(file.content, jsParser, hasExpress, hasFastify)\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      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        // `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 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`, owned by\n// the service the proto lives in through a `service ──CONTAINS──▶ method` edge.\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): Promise<string[]> {\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 (await isPythonVenvDir(full)) continue\n        await walk(full)\n      } else if (entry.isFile() && path.extname(entry.name) === PROTO_EXTENSION) {\n        out.push(full)\n      }\n    }\n  }\n  await walk(dir)\n  return out\n}\n\n// ── producer ─────────────────────────────────────────────────────────────────\n\nexport async function addGrpcMethods(\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 protoPaths = await walkProtoFiles(service.dir)\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      const relFile = toPosix(path.relative(service.dir, protoPath))\n\n      let content: string\n      try {\n        content = await fs.readFile(protoPath, 'utf8')\n      } catch (err) {\n        recordExtractionError('proto extraction', protoPath, err)\n        continue\n      }\n\n      let methods: ExtractedGrpcMethod[]\n      try {\n        methods = grpcMethodsFromProto(content, packageOf(content))\n      } catch (err) {\n        recordExtractionError('proto extraction', protoPath, err)\n        continue\n      }\n      if (methods.length === 0) continue\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          nodesAdded++\n        }\n        // `service ──CONTAINS──▶ method` — the service owns the methods its\n        // `.proto` declares, the same structural verb it has over its routes\n        // (ADR-119) and files (file-awareness.md §2). Evidence pinned to the\n        // `rpc` line. The node id is the wire-canonical FQN, so an OBSERVED\n        // execution span lands on this same node — declared and observed fuse.\n        const containsId = extractedEdgeId(service.node.id, mid, EdgeType.CONTAINS)\n        if (!graph.hasEdge(containsId)) {\n          const edge: GraphEdge = {\n            id: containsId,\n            source: service.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, service.node.id, mid, edge)\n          edgesAdded++\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  passesExtractedFloor,\n} from '@neat.is/types'\nimport { noteExtractedDropped } 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 } 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'\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)\n    const endpoints: ExternalEndpoint[] = []\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      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    }\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      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 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\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\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  const jsParser = makeJsParser()\n  const pyParser = makePyParser()\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)\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 = path.extname(file.path) === '.py' ? pyParser : jsParser\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 { 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  host: string // the known host the URL literal named (basename or pkg name)\n  method?: string // upper-cased; undefined when not statically determinable\n  pathTemplate: string // the URL path, with `:param` for interpolations\n  line: number\n  snippet: string\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// Reconstruct the URL text a string / template-string argument names. A template\n// substitution (`${id}`) becomes the literal `:param` so the reconstructed URL\n// is a valid string with a param-shaped path segment: `/users/${id}` →\n// `/users/:param`. Returns null for anything that isn't a string-ish literal.\nfunction reconstructUrl(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  if (node.type === 'template_string') {\n    let out = ''\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') out += ':param'\n    }\n    // A template with no fragments/subs (empty) — fall back to stripped text.\n    if (out.length === 0) {\n      const raw = node.text\n      return raw.length >= 2 ? raw.slice(1, -1) : ''\n    }\n    return out\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// ── 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\n  const push = (\n    urlNode: Parser.SyntaxNode,\n    method: string | undefined,\n    callNode: Parser.SyntaxNode,\n  ): void => {\n    const urlStr = reconstructUrl(urlNode)\n    if (!urlStr) return\n    const host = matchHost(urlStr, knownHosts)\n    if (!host) return\n    const p = pathOf(urlStr)\n    if (p === null) return\n    const line = callNode.startPosition.row + 1\n    out.push({\n      host,\n      method,\n      pathTemplate: p,\n      line,\n      snippet: snippet(source, line),\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)\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        const serverServiceId = hostToNodeId.get(site.host)\n        // Skip an unresolved host or a self-call (intra-service — no\n        // cross-service contract to match, 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        // A matched client↔route contract grades at verified-call-site (0.85):\n        // both endpoints are recognised — a framework-aware client shape and a\n        // parsed route definition — so it clears the floor and enters the graph\n        // (ADR-119).\n        const confidence = confidenceForExtracted('verified-call-site')\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        }\n        if (!passesExtractedFloor(confidence)) {\n          noteExtractedDropped({\n            source: fileNodeId,\n            target: match.routeNodeId,\n            type: EdgeType.CALLS,\n            confidence,\n            confidenceKind: 'verified-call-site',\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\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\nexport function kafkaEndpointsFromFile(\n  file: SourceFile,\n  serviceDir: string,\n): ExternalEndpoint[] {\n  const out: ExternalEndpoint[] = []\n  const seen = new Set<string>()\n  const make = (topic: string, edgeType: 'PUBLISHES_TO' | 'CONSUMES_FROM'): void => {\n    const key = `${edgeType}|${topic}`\n    if (seen.has(key)) return\n    seen.add(key)\n    const line = lineOf(file.content, topic)\n    out.push({\n      infraId: infraId('kafka-topic', topic),\n      name: topic,\n      kind: 'kafka-topic',\n      edgeType,\n      // `producer.send({topic: 'x'})` / `consumer.subscribe({topic: 'x'})` —\n      // framework-aware (kafkajs / node-rdkafka shape). 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\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  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\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  return out\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'\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; nothing here mutates ServiceNodes themselves.\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\n  return {\n    nodesAdded:\n      compose.nodesAdded + dockerfile.nodesAdded + terraform.nodesAdded + k8s.nodesAdded,\n    edgesAdded:\n      compose.edgesAdded + dockerfile.edgesAdded + terraform.edgesAdded + k8s.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 type { InfraNode } from '@neat.is/types'\nimport { NodeType, infraId } from '@neat.is/types'\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.\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  if (last.startsWith('postgres')) return 'postgres'\n  if (last.startsWith('mysql') || last.startsWith('mariadb')) return 'mysql'\n  if (last.startsWith('mongo')) return 'mongodb'\n  if (last.startsWith('redis')) return 'redis'\n  if (last.startsWith('rabbitmq')) return 'rabbitmq'\n  if (last.startsWith('kafka') || last.includes('kafka')) return 'kafka'\n  if (last.startsWith('memcached')) return 'memcached'\n  return 'container'\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 type { NeatGraph } from '../../graph.js'\nimport { CONFIG_FILE_EXTENSIONS, IGNORED_DIRS, isPythonVenvDir } from '../shared.js'\nimport { makeInfraNode } from './shared.js'\n\ninterface K8sDoc {\n  kind?: string\n  metadata?: { name?: string; namespace?: string }\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\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// Multi-document YAML with kind/metadata.name. We keep the matching simple:\n// any file whose first doc looks k8s-shaped. The match is on `kind` only —\n// random YAML configs (db-config.yaml, etc.) are usually flat objects with no\n// `kind` field, so they're ignored without false positives.\nexport async function addK8sResources(\n  graph: NeatGraph,\n  scanPath: string,\n): Promise<{ nodesAdded: number; edgesAdded: number }> {\n  let nodesAdded = 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    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 namespaced = doc.metadata.namespace\n        ? `${doc.metadata.namespace}/${doc.metadata.name}`\n        : doc.metadata.name\n      const node = makeInfraNode(infraKind, namespaced, 'kubernetes')\n      if (!graph.hasNode(node.id)) {\n        graph.addNode(node.id, node)\n        nodesAdded++\n      }\n    }\n  }\n  return { nodesAdded, edgesAdded: 0 }\n}\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { 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): number {\n  const orphans: string[] = []\n  graph.forEachNode((id, attrs) => {\n    if ((attrs as GraphNode).type !== NodeType.FileNode) 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.\nexport function retireExtractedEdgesByMissingFile(\n  graph: NeatGraph,\n  scanPath: string,\n  serviceDirs: readonly 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    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)\n  return toDrop.length\n}\n","// computeDivergences — the thesis surface, derived (ADR-060).\n//\n// Walks the live graph and surfaces the five locked divergence shapes:\n// missing-observed, missing-extracted, version-mismatch, host-mismatch,\n// and compat-violation. Pure: no I/O, no mutation, no async. The function\n// operates on a NeatGraph reference and returns a fresh DivergenceResult\n// 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  Divergence,\n  DivergenceResult,\n  DivergenceType,\n  EdgeTypeValue,\n  GraphEdge,\n  GraphNode,\n  ServiceNode,\n} from '@neat.is/types'\nimport {\n  databaseId,\n  DivergenceResultSchema,\n  EdgeType,\n  NodeType,\n  parseEdgeId,\n  Provenance,\n} from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\nimport {\n  checkCompatibility,\n  checkDeprecatedApi,\n  compatPairs,\n  deprecatedApis,\n} from './compat.js'\nimport { confidenceForEdge } from './traverse.js'\n\nexport interface DivergenceQueryOpts {\n  // Filter the result to a subset of divergence types. Undefined keeps all\n  // five. 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}\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\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 key = bucketKey(e.source, e.target, e.type)\n    const cur =\n      buckets.get(key) ?? { source: e.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\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  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)) {\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    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\nfunction involvesNode(d: Divergence, nodeId: string): boolean {\n  return d.source === nodeId || d.target === nodeId\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  const buckets = bucketEdges(graph)\n  for (const bucket of buckets.values()) {\n    for (const d of detectMissingDivergences(graph, bucket)) all.push(d)\n  }\n\n  // Pass 2 — per-service host + compat rules.\n  graph.forEachNode((nodeId, attrs) => {\n    const n = attrs as GraphNode\n    if (n.type !== NodeType.ServiceNode) return\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  })\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  // Filter + sort. Higher confidence first; within the same confidence,\n  // stable on (type, source, target) so callers see deterministic output.\n  let filtered = reconciled\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  }\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    return a.target.localeCompare(b.target)\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 { Provenance, observedEdgeId } from '@neat.is/types'\nimport type { NeatGraph } from './graph.js'\n\nexport const SCHEMA_VERSION = 4\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\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\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: 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  await fs.writeFile(tmp, JSON.stringify(payload), 'utf8')\n  await fs.rename(tmp, outPath)\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  let payload = JSON.parse(raw) as PersistedGraph\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 !== SCHEMA_VERSION) {\n    throw new Error(\n      `persist: unsupported snapshot schemaVersion ${payload.schemaVersion} (expected ${SCHEMA_VERSION})`,\n    )\n  }\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 { Divergence, GraphEdge, GraphNode, ServiceNode } from '@neat.is/types'\nimport { NodeType, Provenance } from '@neat.is/types'\nimport type { NeatGraph } from './graph.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=Authorization=Bearer <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\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('=== 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  // ── 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","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 { addImports } from './extract/imports.js'\nimport { addDatabasesAndCompat } from './extract/databases/index.js'\nimport { addConfigNodes } from './extract/configs.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 {\n  evaluateAllPolicies,\n  loadPolicyFile,\n  PolicyViolationsLog,\n} from './policy.js'\nimport type { Policy } from '@neat.is/types'\nimport { buildOtelReceiver, listenSteppingOtlp } from './otel.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, 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  | 'imports'\n  | 'databases'\n  | 'configs'\n  | 'calls'\n  | 'infra'\n\nconst ALL_PHASES: ExtractPhase[] = [\n  'services',\n  'aliases',\n  'files',\n  'imports',\n  'databases',\n  'configs',\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 + imports + calls\n//     (a source edit can shift both its IMPORTS and CALLS edges; 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)\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('imports')\n    phases.add('calls')\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  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  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}\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  })\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  let searchIndex: SearchIndex | undefined\n  try {\n    searchIndex = await buildSearchIndex(graph, { cachePath })\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)\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    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 cors from '@fastify/cors'\nimport type {\n  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  Policy,\n  PolicyViolation,\n  RegistryEntry,\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  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 { readErrorEvents, readStaleEvents } from './ingest.js'\nimport {\n  getBlastRadius,\n  getObservedDependencies,\n  getRootCause,\n  getTransitiveDependencies,\n  TRANSITIVE_DEPENDENCIES_DEFAULT_DEPTH,\n  TRANSITIVE_DEPENDENCIES_MAX_DEPTH,\n} from './traverse.js'\nimport { computeGraphDiff, loadSnapshotForDiff } from './diff.js'\nimport { mergeSnapshot } from './ingest.js'\nimport { SCHEMA_VERSION, 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 { getProject as getRegistryProject, listProjects as listRegistryProjects } from './registry.js'\nimport { handleSse } from './streaming.js'\nimport { mountBearerAuth, readAuthEnv } from './auth.js'\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  // 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  // 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\ninterface SerializedGraph {\n  nodes: GraphNode[]\n  edges: GraphEdge[]\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 }\n}\n\nfunction projectFromReq(req: FastifyRequest, singleProject?: string): 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. A non-single-project daemon keeps coercing a missing param to the\n  // `default` project.\n  if (singleProject) {\n    return named === undefined || named === DEFAULT_PROJECT ? singleProject : named\n  }\n  return named ?? 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)\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    void reply.code(404).send({ error: 'project not found', project: name })\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  // 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}\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  // 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      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      }\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    return computeDivergences(proj.graph, {\n      ...(typeFilter ? { type: typeFilter } : {}),\n      ...(minConfidence !== undefined ? { minConfidence } : {}),\n      ...(req.query.node ? { node: req.query.node } : {}),\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 }\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    const events = await readErrorEvents(epath)\n    const total = events.length\n    const limit = req.query.limit ? Number(req.query.limit) : 50\n    const safeLimit =\n      Number.isFinite(limit) && limit > 0 ? Math.min(limit, 200) : 50\n    const sliced = events.slice(0, safeLimit)\n    return { count: sliced.length, total, events: sliced }\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  // 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<{ Params: { project?: string; nodeId: string } }>,\n    reply: FastifyReply,\n  ): Promise<{ count: number; total: number; events: ErrorEvent[] } | undefined> => {\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    const events = await readErrorEvents(epath)\n    const filtered = events.filter(\n      (e) =>\n        e.affectedNode === nodeId || e.service === nodeId.replace(/^service:/, ''),\n    )\n    return { count: filtered.length, total: filtered.length, events: filtered }\n  }\n  scope.get<{ Params: { project?: string; nodeId: string } }>(\n    '/incidents/:nodeId',\n    incidentHistoryHandler,\n  )\n  scope.get<{ Params: { project?: string; nodeId: string } }>(\n    '/graph/incident-history/:nodeId',\n    incidentHistoryHandler,\n  )\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  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  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  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      try {\n        const snapshot = await loadSnapshotForDiff(against)\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' || snap.schemaVersion !== SCHEMA_VERSION) {\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, snap)\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      return reply.code(400).send({\n        error: 'snapshot merge failed',\n        details: (err as Error).message,\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  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\nexport async function buildApi(opts: BuildApiOptions): Promise<FastifyInstance> {\n  const app = Fastify({ logger: false })\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\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 §3 amendment — `/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 two booleans — `publicRead` and\n  // `authProxy` — and nothing else; no project list, no version, no env.\n  app.get('/api/config', async () => ({\n    publicRead: publicRead === true,\n    authProxy: trustProxy === true,\n  }))\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    scope: 'root',\n    errorsPathFor,\n    staleEventsPathFor,\n    policyFilePathFor,\n    bootstrap: opts.bootstrap,\n    singleProject: opts.singleProject?.name,\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<RegistryEntry>`, which the dashboard and the CLI's\n  // bare-verb resolver treat as a 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: RegistryEntry = {\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      }\n      return [entry]\n    }\n    try {\n      return await listRegistryProjects()\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      return { project: entry }\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\nasync function findHookFiles(scanPath: string): Promise<string[]> {\n  const entries = await fs.readdir(scanPath)\n  return entries\n    .filter(\n      (e) =>\n        (e.startsWith('instrumentation') || e.startsWith('otel-init')) &&\n        /\\.(ts|js)$/.test(e),\n    )\n    .sort()\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  const primaryFile = hookFiles[0]!\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 hook file\n  const hookContent = await fs.readFile(primaryPath, 'utf8')\n  const patched = splicedContent(hookContent, args.registration_snippet)\n  if (!patched) {\n    throw new Error(\n      `Could not find instrumentation insertion point in ${primaryFile}. ` +\n        'Expected __INSTRUMENTATION_BLOCK__, instrumentations.push(, or new NodeSDK(.',\n    )\n  }\n  await fs.writeFile(primaryPath, 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 primaryFile = hookFiles[0]!\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  const hookContent = await fs.readFile(path.join(ctx.scanPath, primaryFile), 'utf8')\n  const patched = splicedContent(hookContent, args.registration_snippet)\n  if (patched) {\n    filesTouched.push(primaryFile)\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 { 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 } 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 * 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. A live daemon dominates: while neatd\n// is alive, hand-removing the lock is never safe, so we surface the daemon\n// message even when the lock itself is an empty orphan. We never classify our\n// own process as the blocking daemon — a daemon serializing two of its own\n// 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 (\n    daemonPid !== undefined &&\n    daemonPid !== process.pid &&\n    probe.isPidAlive(daemonPid) &&\n    // The lock already names the daemon, or the daemon answers on its port.\n    // Either confirms a live daemon is in the picture (the second guards\n    // against a stale pidfile whose PID got reused).\n    (daemonPid === lockPid || (await probe.daemonResponds()))\n  ) {\n    return { kind: 'daemon', pid: daemonPid }\n  }\n  if (lockPid !== undefined && lockPid !== process.pid && probe.isPidAlive(lockPid)) {\n    return { kind: 'command', pid: lockPid }\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        `neat registry: 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. Peer commands and stale locks fall through to the retry:\n      // peers clear on their own, and a stale lock wants the timeout's guidance.\n      if (!probedHolder) {\n        probedHolder = true\n        const holder = await classifyLockHolder(lockPath, probe)\n        if (holder.kind === 'daemon') throw new Error(lockHolderMessage(holder, lockPath, timeoutMs))\n      }\n      if (Date.now() >= deadline) {\n        const holder = await classifyLockHolder(lockPath, probe)\n        throw new Error(lockHolderMessage(holder, lockPath, timeoutMs))\n      }\n      await new Promise((r) => setTimeout(r, LOCK_RETRY_MS))\n    }\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\nexport class ProjectNameCollisionError extends Error {\n  readonly projectName: string\n  constructor(name: string) {\n    super(`neat registry: 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\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 Error(`neat registry: no project named \"${name}\"`)\n    entry.status = status\n    await writeRegistry(reg)\n    return entry\n  })\n}\n\nexport async function touchLastSeen(name: string, at: string = new Date().toISOString()): 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\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 {\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}\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  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\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    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","/**\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 { startConnectorPollLoop, type ConnectorRegistration } from './connectors/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  // Applied identically to every project slot; there is no per-project\n  // config-loading here yet (that's provider-specific, later work) — a\n  // caller wanting project-scoped connectors runs a separate `startDaemon`\n  // per project (the single-project ADR-096 mode is the common case).\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  // #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.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.\n  for (const entry of projects) {\n    if (entry.status === 'paused') continue\n    if (entry.name === serviceName) 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`.\nfunction isTokenPrefix(prefix: string, full: string): boolean {\n  if (prefix.length >= full.length) return false\n  if (!full.startsWith(prefix)) return false\n  const sep = full.charAt(prefix.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).\nfunction isTokenContained(needle: string, haystack: string): boolean {\n  if (!haystack.includes(needle)) return false\n  const tokens = haystack.split(/[-_]/)\n  return tokens.includes(needle)\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 === project) 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): 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      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    await extractFromDirectory(graph, entry.path)\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    })\n    // Connectors plane (docs/contracts/connectors.md, ADR-124) — one poll\n    // loop per registered connector, same interval-loop shape as the\n    // staleness loop above and torn down alongside it (teardownSlot).\n    const stopFns = connectors.map((registration) =>\n      startConnectorPollLoop(\n        registration.connector,\n        { projectDir: entry.path, credentials: registration.credentials },\n        graph,\n        registration.resolveTarget,\n        { intervalMs: registration.intervalMs },\n      ),\n    )\n    const stopConnectors = (): void => {\n      for (const stop of stopFns) stop()\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      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 ?? [])\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 ?? [])\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      })\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    // 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        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(slot.paths.errorsPath, slot.graph, slot.entry.path)(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(slot.paths.errorsPath, slot.graph, slot.entry.path)(span)\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      console.log(`neatd: OTLP listening on ${otlpAddress}/v1/traces`)\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","// 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 type { EdgeTypeValue } from '@neat.is/types'\nimport type { NeatGraph } from '../graph.js'\nimport {\n  ensureObservedFileNode,\n  ensureServiceNode,\n  reconcileObservedRelPath,\n  upsertObservedEdge,\n  type CallSite,\n} from '../ingest.js'\nimport type { ConnectorContext, ObservedConnector, ObservedSignal } from './types.js'\n\nexport type {\n  ConnectorCallSite,\n  ConnectorContext,\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\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.\n  unresolved: number\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    // 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      : undefined\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    if (calls < 1) continue // nothing observed this window — not even a miss\n    const errors = Math.min(Math.max(Math.trunc(signal.errorCount), 0), calls)\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}\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 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        await runConnectorPoll(connector, { ...ctx, since }, graph, resolveTarget)\n        since = tickStartedAt\n      } catch (err) {\n        onError(err)\n      }\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/**\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  connector: ObservedConnector\n  credentials: Record<string, unknown>\n  resolveTarget: ResolveConnectorTarget\n  intervalMs?: number\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(): Promise<Embedder | null> {\n  const host = ollamaHost()\n  if (host && (await ollamaReachable(host))) {\n    return makeOllamaEmbedder(host)\n  }\n  return makeTransformersEmbedder()\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// ------------------------------------------------------------ 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}\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    embedder = await pickEmbedder()\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'\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=Authorization=Bearer ${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'\nexport { isEmptyPlan } from './shared.js'\nexport { javascriptInstaller } from './javascript.js'\nexport { pythonInstaller } from './python.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])\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 follows.\nexport const INSTALLERS: Installer[] = [javascriptInstaller, pythonInstaller]\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 / Ruby / .NET / Go / Rust are out of MVP 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 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  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}\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    })\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'\n\nexport function dispatchEntry(entryFile: string, pkg: PackageJsonShape): EntryFlavor {\n  const ext = path.extname(entryFile).toLowerCase()\n  if (ext === '.ts' || ext === '.tsx') return 'ts'\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') 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 === '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\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 up front so the lib-only check can read both\n  // signals together. Skipped on the framework branch — frameworks own their\n  // boot path and never need a `pkg.main` injection (the chain returns\n  // before this line runs).\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  }\n\n  if (frameworkDispatch) {\n    return frameworkDispatch()\n  }\n\n  // Issue #370 — runtime-kind detection sits between the lib-only check and\n  // vanilla Node template emission. Browser bundles (Vite) and React Native\n  // / Expo packages bucket here so the apply phase skips every write and\n  // surfaces the package in the summary instead of injecting a Node SDK hook\n  // into code that can't run it.\n  const runtimeKind = await detectRuntimeKind(serviceDir, pkg)\n  if (runtimeKind !== 'node') {\n    return { ...empty, runtimeKind }\n  }\n\n  // entryFile resolved above on the non-framework branch; the null path\n  // already returned lib-only.\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: 6 — daemon.json endpoint resolution (ADR-096) + layered file-first capture (ADR-090).'\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 ' + 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). Under\n// one-daemon-per-project the daemon allocates its OTLP port once (canonical\n// 4318, stepping to the next free port when a sibling daemon already holds it)\n// and records it in `<project>/neat-out/daemon.json`. The instrumented app must\n// read THAT port back, or a second project's app — baked to a fixed 4318 —\n// sends its spans to the first project's daemon, which has no slot for them and\n// drops them: the second project's OBSERVED layer goes dark silently. That is\n// exactly the failure this code exists to kill, so the endpoint is resolved at\n// app boot from the daemon's 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` → the bare\n//      `http://localhost:<otlp>/v1/traces` route the per-project daemon serves.\n//   3. The canonical `http://localhost:4318/v1/traces` default — the laptop\n//      happy path where the daemon took its first-choice port.\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 matches the bare `/v1/traces` route the per-project daemon\n// serves (daemon.ts) — NOT the legacy `/projects/<name>/v1/traces` form, since\n// a daemon that hosts exactly one project needs no project name to disambiguate.\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          process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = 'http://localhost:' + __rec.ports.otlp + '/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/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          process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT = 'http://localhost:' + __rec.ports.otlp + '/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/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// 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\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${neatWireCaptureSource(false)}\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\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\nimport { trace, context } from '@opentelemetry/api'\n\n${CALLSITE_PROCESSOR_JS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(false)}\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\nimport { NodeSDK } from '@opentelemetry/sdk-node'\nimport { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'\nimport { trace, context } from '@opentelemetry/api'\n\n${CALLSITE_PROCESSOR_TS}\n\nconst instrumentations = [getNodeAutoInstrumentations()]\n__INSTRUMENTATION_BLOCK__\nconst sdk = new NodeSDK({ instrumentations })\nsdk.start()\n${neatWireCaptureSource(true)}\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// the daemon serves a bare `/v1/traces` route and allocates its OTLP port once,\n// recording it 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(serviceName: string, _projectName: string): string {\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) at boot (ADR-096). This is the',\n    '# canonical default the daemon takes when its first-choice OTLP port is free.',\n    'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:4318/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// `http://localhost:4318/v1/traces` — no new env var, no new config surface\n// (framework-installers.md §7, ADR-126). `registerOTel` reads OTLP\n// endpoint/protocol/headers from `process.env` itself when `traceExporter`\n// is left at its \"auto\" default, so setting the env vars ahead of the call\n// is enough; unlike the Node file there's no filesystem probe to run 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/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`\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`\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  Installer,\n  InstallPlan,\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\nconst OTEL_ENV: EnvEdit = {\n  file: null,\n  key: 'OTEL_EXPORTER_OTLP_ENDPOINT',\n  value: 'http://localhost:4318',\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): Promise<{ manifest: string; missing: typeof SDK_PACKAGES[number][] } | 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 = SDK_PACKAGES.filter((p) => !presentNames.has(p.name.toLowerCase()))\n  return { manifest: file, missing: [...missing] }\n}\n\nasync function planProcfileEdits(serviceDir: string): 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 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 python 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 (!/^python\\b/.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): Promise<InstallPlan> {\n  const empty: InstallPlan = {\n    language: 'python',\n    serviceDir,\n    dependencyEdits: [],\n    entrypointEdits: [],\n    envEdits: [],\n  }\n\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  const entrypointEdits = await planProcfileEdits(serviceDir)\n\n  if (dependencyEdits.length === 0 && entrypointEdits.length === 0) {\n    return empty\n  }\n  return {\n    language: 'python',\n    serviceDir,\n    dependencyEdits,\n    entrypointEdits,\n    envEdits: [OTEL_ENV],\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 } = installPlan\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 (touched.size === 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  try {\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      }\n      // pyproject.toml / setup.py: MVP no-op as planned above.\n    }\n  } catch (err) {\n    await rollback(installPlan, originals)\n    throw err\n  }\n\n  return { serviceDir, outcome: 'instrumented', writtenFiles }\n}\n\nasync function rollback(\n  installPlan: InstallPlan,\n  originals: Map<string, 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 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    '',\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","/**\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}\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}\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 apply — patches manifests + writes otel-init + writes\n *      `.env.neat`. Default yes; `--no-instrument` opts out.\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).\n *      Default yes; `--no-open` and headless runs skip the launch.\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 runs apply unconditionally because the bare-`<path>` shape's\n * user intent is \"make this work end-to-end.\"\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 { 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, listProjects, ProjectNameCollisionError, setStatus } from './registry.js'\nimport { readDaemonRecord, resolveHost, type DaemonPorts } from './daemon.js'\nimport { printBanner } 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  // Skip step 5 (browser open).\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}\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    }\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\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    await saveGraphToDisk(graph, projectPaths.snapshotPath)\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}\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}\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  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 })\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        const cmd = await resolveManager(svc.dir)\n        const key = `${cmd.pm}:${cmd.cwd}`\n        if (!installPlans.has(key)) installPlans.set(key, cmd)\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  return {\n    instrumented,\n    alreadyInstrumented: already,\n    libOnly,\n    browserBundle,\n    reactNative,\n    bun,\n    deno,\n    cloudflareWorkers,\n    electron,\n    packageManagerInstalls,\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.\nconst 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\nasync function waitForDaemonReady(\n  restPort: number,\n  project: string,\n  timeoutMs: number,\n): Promise<DaemonReadyResult> {\n  const deadline = Date.now() + timeoutMs\n  let lastBootstrapping: string[] = []\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      const key = bootstrapping.slice().sort().join(',')\n      const prevKey = lastBootstrapping.slice().sort().join(',')\n      if (key !== prevKey) {\n        const plural = bootstrapping.length === 1 ? '' : 's'\n        console.log(\n          `neat: waiting on ${bootstrapping.length} project${plural}: ${bootstrapping.join(', ')}`,\n        )\n        lastBootstrapping = bootstrapping\n      }\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): Promise<DaemonReadyResult> {\n  return waitForDaemonReady(restPort, project, timeoutMs)\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// 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.\n  const here = path.dirname(new URL(import.meta.url).pathname)\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\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.\n  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  const persisted = await extractAndPersist({\n    scanPath: opts.scanPath,\n    project: opts.project,\n    projectExplicit: opts.projectExplicit,\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 and open the dashboard?')\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    console.error(`neat: ${err.message}`)\n    console.error('pass --project <other-name> to register under a different name.')\n    result.exitCode = 1\n    return result\n  }\n\n  // Narrow the active-project surface to what the operator is currently in.\n  // Every other `active` entry transitions to `paused`; `broken` is left alone\n  // so the daemon's broken-path handling still surfaces. `neat resume <name>`\n  // brings any of them back when cross-project work is the explicit intent.\n  const siblings = await listProjects()\n  const paused: string[] = []\n  for (const p of siblings) {\n    if (p.name !== currentProjectName && p.status === 'active') {\n      await setStatus(p.name, 'paused')\n      paused.push(p.name)\n    }\n  }\n  if (paused.length > 0) {\n    const plural = paused.length === 1 ? '' : 's'\n    console.log(\n      `neat: paused ${paused.length} sibling project${plural}; run \\`neat resume <name>\\` to bring one back active.`,\n    )\n  }\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)\n    result.steps.apply = { ...tally, skipped: false }\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  //\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  const timeoutMs = opts.daemonReadyTimeoutMs ?? 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.scanPath)\n  // Allocated ports the spawned daemon binds. Settled below; defaults to the\n  // canonical web port so the dashboard URL has a value even on early bailouts.\n  let allocated: AllocatedPorts | null = null\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, currentProjectName))) {\n    result.steps.daemon = 'already-running'\n    allocated = persistedPorts\n  } else {\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    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) {\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    }\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.scanPath)\n    if (!release) {\n      const reused = await waitForPeerDaemon(allocated.rest, currentProjectName, timeoutMs)\n      if (reused) {\n        result.steps.daemon = 'already-running'\n      } else {\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      }\n    } else {\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, currentProjectName)) {\n          result.steps.daemon = 'already-running'\n        } else {\n          spawnDaemonDetached({\n            project: currentProjectName,\n            projectPath: opts.scanPath,\n            ports: allocated,\n          })\n          const ready = await waitForDaemonReady(allocated.rest, currentProjectName, timeoutMs)\n          result.steps.daemon = ready.ready ? 'spawned' : 'timed-out'\n          if (!ready.ready) {\n            console.error(`neat: daemon did not become ready within ${timeoutMs}ms`)\n            if (ready.stillBootstrapping.length > 0) {\n              console.error(`neat: still bootstrapping: ${ready.stillBootstrapping.join(', ')}`)\n            }\n            if (ready.brokenProjects.length > 0) {\n              console.error(`neat: broken projects: ${ready.brokenProjects.join(', ')}`)\n            }\n            result.exitCode = 1\n            return result\n          }\n          if (ready.brokenProjects.length > 0) {\n            console.warn(\n              `neat: ${ready.brokenProjects.length} project(s) reported broken: ${ready.brokenProjects.join(', ')}`,\n            )\n          }\n        }\n      } catch (err) {\n        console.error(`neat: daemon spawn failed — ${(err as Error).message}`)\n        result.exitCode = 1\n        return result\n      } finally {\n        await release()\n      }\n    }\n  }\n\n  // ── Step 5: browser open ─────────────────────────────────────────────\n  // The dashboard lives on the daemon's allocated web port (§5), not a fixed\n  // 6328 — a second project's daemon serves its dashboard one port over.\n  const webPort = allocated?.web ?? NEAT_PORTS[2]\n  const dashboardUrl = opts.dashboardUrl ?? `http://localhost:${webPort}`\n  if (opts.noOpen || !process.stdout.isTTY) {\n    result.steps.browser = 'skipped'\n  } else {\n    result.steps.browser = openBrowser(dashboardUrl)\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, dashboardUrl, daemonLog)\n\n  return result\n}\n\nfunction printSummary(\n  result: OrchestratorResult,\n  graph: ReturnType<typeof getGraph>,\n  dashboardUrl: string,\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  console.log(`dashboard: ${dashboardUrl}`)\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\n  // NEAT_AUTH_TOKEN, the daemon enforces it and the user needs it to reach\n  // the dashboard and to route OTel — so we print the real value rather than\n  // fabricating one the daemon wouldn't accept.\n  const token = process.env.NEAT_AUTH_TOKEN\n  if (typeof token === 'string' && token.length > 0) {\n    console.log(`auth token: ${token}`)\n  } else {\n    console.log('running locally — open the dashboard, no 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  if (daemonLog !== null) {\n    console.log('')\n    console.log(`daemon running in the background (logs: ${daemonLog})`)\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","/**\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  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  // 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\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)\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\n  if (!opts.dryRun) {\n    const snapshot = snapshotForGraph(persisted)\n    if (opts.to) {\n      const token = opts.token ?? process.env.NEAT_REMOTE_TOKEN\n      try {\n        await pushSnapshotToRemote({\n          baseUrl: opts.to,\n          token,\n          project: entry.name,\n          snapshot,\n        })\n        daemonState = 'remote-ok'\n      } catch (err) {\n        if (err instanceof HttpError) {\n          console.error(`neat sync: ${err.message}`)\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: entry.name,\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","// 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  BlastRadiusAffectedNode,\n  BlastRadiusResult,\n  Divergence,\n  DivergenceResult,\n  DivergenceType,\n  ErrorEvent,\n  GraphEdge,\n  GraphNode,\n  HypotheticalAction,\n  ObservedDependenciesResult,\n  PolicyViolation,\n  RootCauseResult,\n  TransitiveDependenciesResult,\n} from '@neat.is/types'\nimport { Provenance } from '@neat.is/types'\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(baseUrl: string, bearerToken?: string): 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 fetch(`${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 fetch(`${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 blockLines: string[] = []\n    for (const ev of ordered) {\n      blockLines.push(`  ${ev.timestamp} — ${ev.service}: ${ev.errorMessage}`)\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      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  }\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// ──────────────────────────────────────────────────────────────────────────\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 `confidence: ${c} · provenance: ${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(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): HttpClient {\n  return createHttpClient(baseUrl, token && token.length > 0 ? token : undefined)\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"],"mappings":"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","names":["isLoopbackHost","path","path","import_node_url","import_node_path","import_node_crypto","path","protobuf","reshapeGrpcRequest","Fastify","import_node_path","import_node_url","import_fastify","import_node_path","import_node_fs","path","GraphDefault","import_node_fs","import_node_path","import_node_fs","import_node_path","import_types","import_node_fs","import_node_path","path","os","semver","fs","path","walk","serviceId","frontierId","fs","path","import_types","status","grpc","path","entry","fs","path","status","frontierId","serviceId","fs","path","import_node_fs","import_node_path","import_minimatch","import_types","import_node_fs","import_node_path","import_types","fs","path","parseYaml","import_node_fs","import_node_path","entry","path","fs","parseToml","import_node_fs","import_node_path","path","fs","import_node_fs","import_node_path","fs","path","fs","path","path","fs","ignore","entry","import_node_path","import_node_fs","import_yaml","import_types","serviceId","path","fs","entry","import_node_fs","import_node_path","import_types","path","walk","fs","entry","toPosix","import_node_path","toPosix","path","import_node_path","import_node_fs","import_types","Parser","JavaScript","Python","fs","path","toPosix","snippet","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_path","parse","path","toPosix","path","import_node_fs","import_node_path","import_types","walk","fs","entry","path","toPosix","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","PARSE_CHUNK","parseSource","makeJsParser","Parser","JavaScript","toPosix","path","import_node_fs","import_node_path","import_types","walk","fs","entry","path","toPosix","import_types","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_tree_sitter_python","import_types","PARSE_CHUNK","parseSource","makeJsParser","Parser","JavaScript","makePyParser","Python","path","toPosix","import_node_path","import_tree_sitter","import_tree_sitter_javascript","import_types","PARSE_CHUNK","parseSource","makeJsParser","Parser","JavaScript","walk","entry","path","toPosix","import_node_path","import_types","path","import_node_path","import_types","path","import_node_path","import_types","findAll","path","import_node_path","import_types","path","import_node_path","import_types","readImports","path","toPosix","http","import_node_path","import_types","import_types","path","import_node_path","import_node_fs","import_types","path","fs","toPosix","import_node_fs","import_node_path","import_types","fs","entry","path","lineAt","toPosix","import_node_fs","import_node_path","import_yaml","walkYamlFiles","fs","entry","path","import_node_path","import_node_fs","import_node_path","import_types","path","path","import_types","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_types","import_node_fs","import_node_path","import_node_os","import_node_fs","import_node_path","exists","fs","path","fileExists","fs","path","os","entry","snippet","allDeps","registryResolve","registryList","import_node_fs","fs","entry","import_node_path","path","import_node_fs","import_node_os","import_node_path","import_types","path","os","fs","path","entry","status","DAY_MS","fs","entry","status","violations","blocking","Fastify","cors","entry","import_node_fs","import_node_path","import_node_fs","import_node_path","import_types","path","fs","import_node_fs","import_node_path","import_node_crypto","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","path","fs","exists","readPackageJson","semver","entry","resolveRegistry","import_node_fs","import_node_path","SDK_PACKAGES","OTEL_ENV","exists","fs","detect","path","plan","apply","rollback","plan","plan","import_node_fs","import_node_path","import_node_child_process","path","plan","readline","http","projects","net","path","fs","projectPath","path","entry","fs","import_node_path","import_types","status","path","entry","path","import_types","entry","status","plan","fs","path","entry","snippet","orchestratorCode","apply","projectPath","renderOtelEnvBlock"]}