tracekite-core 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. tracekite/__init__.py +0 -0
  2. tracekite/_control_plane/confidence.yml +259 -0
  3. tracekite/_control_plane/internal_namespaces.yml +29 -0
  4. tracekite/_control_plane/promotions.yml +10 -0
  5. tracekite/_control_plane/repos.yml +9 -0
  6. tracekite/_control_plane/service_aliases.yml +9 -0
  7. tracekite/_control_plane/vendor_catalog.yml +57 -0
  8. tracekite/agent_setup.py +120 -0
  9. tracekite/answer.py +198 -0
  10. tracekite/cli.py +299 -0
  11. tracekite/cli_emit.py +19 -0
  12. tracekite/cli_explain.py +96 -0
  13. tracekite/cli_inspect.py +281 -0
  14. tracekite/completeness.py +82 -0
  15. tracekite/config.py +105 -0
  16. tracekite/db/__init__.py +0 -0
  17. tracekite/db/artifact.py +265 -0
  18. tracekite/db/artifact_diff.py +129 -0
  19. tracekite/db/artifact_migrations.py +152 -0
  20. tracekite/db/artifact_reader.py +123 -0
  21. tracekite/db/constraints.py +121 -0
  22. tracekite/db/graph_store.py +89 -0
  23. tracekite/db/impact_reader.py +64 -0
  24. tracekite/db/memory_store.py +268 -0
  25. tracekite/db/migrate.py +80 -0
  26. tracekite/db/neo4j_client.py +61 -0
  27. tracekite/db/neo4j_graph_store.py +183 -0
  28. tracekite/db/sqlite_store.py +242 -0
  29. tracekite/db/store_config.py +67 -0
  30. tracekite/engine_config.py +84 -0
  31. tracekite/engine_health.py +147 -0
  32. tracekite/facade.py +282 -0
  33. tracekite/ingest_client.py +216 -0
  34. tracekite/main.py +81 -0
  35. tracekite/mcp_envelope.py +114 -0
  36. tracekite/mcp_server.py +298 -0
  37. tracekite/metrics_export.py +143 -0
  38. tracekite/middleware/__init__.py +0 -0
  39. tracekite/middleware/auth.py +160 -0
  40. tracekite/models/__init__.py +0 -0
  41. tracekite/models/api_models.py +134 -0
  42. tracekite/models/graph_models.py +170 -0
  43. tracekite/parsers/__init__.py +0 -0
  44. tracekite/parsers/asyncapi_parser.py +288 -0
  45. tracekite/parsers/base.py +91 -0
  46. tracekite/parsers/brace_blocks.py +33 -0
  47. tracekite/parsers/config_parser.py +306 -0
  48. tracekite/parsers/cron_parser.py +69 -0
  49. tracekite/parsers/dependency_parser.py +1470 -0
  50. tracekite/parsers/docker_parser.py +262 -0
  51. tracekite/parsers/gateway_parser.py +913 -0
  52. tracekite/parsers/graphql_parser.py +175 -0
  53. tracekite/parsers/helm_refs.py +29 -0
  54. tracekite/parsers/iac_parser.py +234 -0
  55. tracekite/parsers/iac_units.py +152 -0
  56. tracekite/parsers/java_parser.py +199 -0
  57. tracekite/parsers/javascript_parser.py +211 -0
  58. tracekite/parsers/kotlin_parser.py +225 -0
  59. tracekite/parsers/kubernetes_parser.py +739 -0
  60. tracekite/parsers/mcp_manifest_parser.py +156 -0
  61. tracekite/parsers/migration_parser.py +306 -0
  62. tracekite/parsers/openapi_parser.py +73 -0
  63. tracekite/parsers/ownership_parser.py +622 -0
  64. tracekite/parsers/parser_registry.py +462 -0
  65. tracekite/parsers/pipeline_parser.py +807 -0
  66. tracekite/parsers/proto_parser.py +282 -0
  67. tracekite/parsers/python_parser.py +234 -0
  68. tracekite/parsers/scip_parser.py +115 -0
  69. tracekite/parsers/tree_sitter/README.md +36 -0
  70. tracekite/parsers/tree_sitter/__init__.py +0 -0
  71. tracekite/parsers/tree_sitter/adapter.py +668 -0
  72. tracekite/parsers/tree_sitter/core/__init__.py +0 -0
  73. tracekite/parsers/tree_sitter/core/base_parser.py +34 -0
  74. tracekite/parsers/tree_sitter/core/extractor.py +721 -0
  75. tracekite/parsers/tree_sitter/core/models.py +686 -0
  76. tracekite/parsers/tree_sitter/core/parser.py +391 -0
  77. tracekite/parsers/tree_sitter/core/queries/__init__.py +0 -0
  78. tracekite/parsers/tree_sitter/core/queries/files/__init__.py +0 -0
  79. tracekite/parsers/tree_sitter/core/queries/files/java/__init__.py +0 -0
  80. tracekite/parsers/tree_sitter/core/queries/files/java/sql_annotations.scm +13 -0
  81. tracekite/parsers/tree_sitter/core/queries/files/javascript/__init__.py +0 -0
  82. tracekite/parsers/tree_sitter/core/queries/files/kotlin/__init__.py +0 -0
  83. tracekite/parsers/tree_sitter/core/queries/files/python/__init__.py +0 -0
  84. tracekite/parsers/tree_sitter/core/queries/files/python/sql_annotations.scm +13 -0
  85. tracekite/parsers/tree_sitter/core/queries/files/typescript/__init__.py +0 -0
  86. tracekite/parsers/tree_sitter/core/queries/files/typescript/sql_annotations.scm +13 -0
  87. tracekite/parsers/tree_sitter/core/queries/query_engine.py +619 -0
  88. tracekite/parsers/tree_sitter/core/queries/query_loader.py +67 -0
  89. tracekite/parsers/yaml_shapes.py +27 -0
  90. tracekite/routes/__init__.py +0 -0
  91. tracekite/routes/graph.py +87 -0
  92. tracekite/routes/health.py +36 -0
  93. tracekite/routes/impact.py +38 -0
  94. tracekite/routes/jobs.py +45 -0
  95. tracekite/routes/links.py +237 -0
  96. tracekite/routes/repos.py +151 -0
  97. tracekite/routes/rollup.py +51 -0
  98. tracekite/routes/trace.py +243 -0
  99. tracekite/run_logging.py +126 -0
  100. tracekite/scan_meta.py +208 -0
  101. tracekite/services/__init__.py +0 -0
  102. tracekite/services/absence.py +93 -0
  103. tracekite/services/agents_extractor.py +708 -0
  104. tracekite/services/calibration.py +1377 -0
  105. tracekite/services/calibration_estates.py +271 -0
  106. tracekite/services/calibration_io.py +96 -0
  107. tracekite/services/calibration_tiers.py +129 -0
  108. tracekite/services/call_graph_resolver.py +166 -0
  109. tracekite/services/claim_sink.py +46 -0
  110. tracekite/services/claims.py +304 -0
  111. tracekite/services/control_plane.py +25 -0
  112. tracekite/services/csharp_route_extractor.py +198 -0
  113. tracekite/services/data_extractor.py +459 -0
  114. tracekite/services/env_extractor.py +149 -0
  115. tracekite/services/evidence_reverify.py +105 -0
  116. tracekite/services/extraction_coverage.py +85 -0
  117. tracekite/services/file_classifier.py +127 -0
  118. tracekite/services/file_scanner.py +165 -0
  119. tracekite/services/flag_guards.py +98 -0
  120. tracekite/services/framework_routes.py +82 -0
  121. tracekite/services/go_route_extractor.py +426 -0
  122. tracekite/services/graph_factories.py +214 -0
  123. tracekite/services/graph_properties.py +29 -0
  124. tracekite/services/graph_reader.py +405 -0
  125. tracekite/services/graph_writer.py +276 -0
  126. tracekite/services/grpc_extractor.py +169 -0
  127. tracekite/services/grpc_gateway_routes.py +144 -0
  128. tracekite/services/http_call_extractor.py +546 -0
  129. tracekite/services/http_call_js.py +141 -0
  130. tracekite/services/http_call_url.py +64 -0
  131. tracekite/services/ingest_artifacts.py +297 -0
  132. tracekite/services/ingest_claims.py +1746 -0
  133. tracekite/services/ingest_config_defs.py +148 -0
  134. tracekite/services/ingest_deps.py +112 -0
  135. tracekite/services/ingest_source.py +300 -0
  136. tracekite/services/ingest_upload.py +92 -0
  137. tracekite/services/ingestion_service.py +232 -0
  138. tracekite/services/job_handlers.py +131 -0
  139. tracekite/services/job_queue.py +229 -0
  140. tracekite/services/js_route_extractor.py +855 -0
  141. tracekite/services/jvm_route_extractor.py +267 -0
  142. tracekite/services/link_writer.py +124 -0
  143. tracekite/services/linker/__init__.py +3 -0
  144. tracekite/services/linker/alias_suggestions.py +111 -0
  145. tracekite/services/linker/base.py +507 -0
  146. tracekite/services/linker/confidence_math.py +75 -0
  147. tracekite/services/linker/contract_drift.py +80 -0
  148. tracekite/services/linker/crossings.py +48 -0
  149. tracekite/services/linker/deprecations.py +60 -0
  150. tracekite/services/linker/edge_policy.py +87 -0
  151. tracekite/services/linker/engine.py +303 -0
  152. tracekite/services/linker/history.py +185 -0
  153. tracekite/services/linker/hooks.py +125 -0
  154. tracekite/services/linker/impact.py +255 -0
  155. tracekite/services/linker/incremental.py +202 -0
  156. tracekite/services/linker/map_view.py +76 -0
  157. tracekite/services/linker/modules.py +63 -0
  158. tracekite/services/linker/normalize.py +287 -0
  159. tracekite/services/linker/partitions.py +139 -0
  160. tracekite/services/linker/path_algebra.py +124 -0
  161. tracekite/services/linker/ports.py +65 -0
  162. tracekite/services/linker/r0_alias.py +303 -0
  163. tracekite/services/linker/r10_dataset.py +135 -0
  164. tracekite/services/linker/r11_agent.py +159 -0
  165. tracekite/services/linker/r12_owner.py +89 -0
  166. tracekite/services/linker/r13_webhook.py +80 -0
  167. tracekite/services/linker/r14_operation.py +97 -0
  168. tracekite/services/linker/r1_compose.py +65 -0
  169. tracekite/services/linker/r2_k8s.py +219 -0
  170. tracekite/services/linker/r3_library.py +160 -0
  171. tracekite/services/linker/r4_gateway.py +95 -0
  172. tracekite/services/linker/r5_grpc.py +174 -0
  173. tracekite/services/linker/r6_topic.py +290 -0
  174. tracekite/services/linker/r7_http.py +259 -0
  175. tracekite/services/linker/r8_graphql.py +134 -0
  176. tracekite/services/linker/r9_env.py +105 -0
  177. tracekite/services/linker/r9_env_index.py +174 -0
  178. tracekite/services/linker/reconciliation.py +82 -0
  179. tracekite/services/linker/registry.py +169 -0
  180. tracekite/services/linker/reliability.py +138 -0
  181. tracekite/services/linker/review_labels.py +36 -0
  182. tracekite/services/linker/rollup_view.py +110 -0
  183. tracekite/services/linker/rollups.py +155 -0
  184. tracekite/services/linker/service.py +121 -0
  185. tracekite/services/linker/traverse.py +47 -0
  186. tracekite/services/linker/values.py +143 -0
  187. tracekite/services/linker/vendors.py +106 -0
  188. tracekite/services/linker_store.py +119 -0
  189. tracekite/services/manifest_lines.py +142 -0
  190. tracekite/services/messaging_extractor.py +693 -0
  191. tracekite/services/parallel_map.py +178 -0
  192. tracekite/services/parse_budget.py +54 -0
  193. tracekite/services/php_route_extractor.py +100 -0
  194. tracekite/services/rb_route_extractor.py +139 -0
  195. tracekite/services/redaction.py +152 -0
  196. tracekite/services/reingest.py +90 -0
  197. tracekite/services/repo_service.py +221 -0
  198. tracekite/services/repo_summary.py +26 -0
  199. tracekite/services/scan.py +299 -0
  200. tracekite/services/scip_import.py +132 -0
  201. tracekite/services/sharded_scan.py +110 -0
  202. tracekite/services/sink_merge.py +53 -0
  203. tracekite/source_meta.py +158 -0
  204. tracekite/status_classify.py +64 -0
  205. tracekite/telemetry.py +92 -0
  206. tracekite/utils/__init__.py +0 -0
  207. tracekite/utils/canonical.py +78 -0
  208. tracekite/utils/evidence.py +77 -0
  209. tracekite/utils/hashing.py +141 -0
  210. tracekite/utils/paths.py +110 -0
  211. tracekite/utils/rendezvous_ids.py +82 -0
  212. tracekite/wire.py +143 -0
  213. tracekite_core-0.1.1.dist-info/METADATA +78 -0
  214. tracekite_core-0.1.1.dist-info/RECORD +217 -0
  215. tracekite_core-0.1.1.dist-info/WHEEL +4 -0
  216. tracekite_core-0.1.1.dist-info/entry_points.txt +2 -0
  217. tracekite_core-0.1.1.dist-info/licenses/LICENSE +202 -0
tracekite/__init__.py ADDED
File without changes
@@ -0,0 +1,259 @@
1
+ # Confidence registry: every resolver tier's served confidence plus its
2
+ # measured P/R row (design §8). Invariant 7: no resolver tier serves
3
+ # `active` edges at or above the floor to an org-facing deployment without a
4
+ # measured row. `measured: null` marks provisional values awaiting the
5
+ # microSecEnD + adversarial-fixture calibration run (M2).
6
+ #
7
+ # This is the single copy. Loaded by tracekite/services/linker/base.py:load_confidence();
8
+ # override the directory with KG_CONFIG_DIR.
9
+ version: 1
10
+ floor: 0.6
11
+ fusion_cap: 0.99
12
+ # Most contracts one call site may match before the match is declined
13
+ # outright. A call site matching everything has matched nothing, so past this
14
+ # the resolver counts `fanout_exceeded` and emits nothing — never a truncated
15
+ # slice, which would read as a resolved match while hiding the ambiguity.
16
+ fanout_cap: 32
17
+ will_break_threshold: null # derived from the measured table (M2), never a constant
18
+ # Multiplier applied to an edge whose cited evidence no longer says what it
19
+ # said (F5 re-verification). Rot ages an assertion, it does not refute it:
20
+ # the edge is downgraded — below the floor it becomes `candidate` — and
21
+ # never deleted.
22
+ stale_evidence_factor: 0.7
23
+ # Most route-table applications a single call may chain through (edge
24
+ # gateway -> mesh -> service) before NORMALIZE declines it as unresolved.
25
+ # Deeper chains are counted, never truncated to a partial hop.
26
+ gateway_chain_max_hops: 3
27
+
28
+ # --- R0 alias ---------------------------------------------------------------
29
+ # built_from_config was removed with the config-filename BUILT_FROM exclusion:
30
+ # a Spring Cloud Config repo holding customers-service.yml must never claim to
31
+ # build that service, so no edge is ever priced at that tier.
32
+ r0:
33
+ resolved_to: 0.98
34
+ has_alias: 0.9
35
+ built_from_build_context: 0.95 # descriptor points at a directory in this repo
36
+ built_from_app_name: 0.85 # in-code application name
37
+ built_from_descriptor: 0.75 # compose/k8s names it; image may build elsewhere
38
+ belongs_to: 0.95 # module read off the evidence path
39
+
40
+ # --- R1 compose topology (benchmark-proven 0.98-0.99) -----------------------
41
+ # `links` entries fold into depends_on at emission (compose v1 legacy), so
42
+ # there is no separate links tier — a priced-but-unreachable tier is exactly
43
+ # the schema fiction Invariant 7 forbids (calibration finding).
44
+ r1:
45
+ depends_on: 0.96
46
+ env_host: 0.95
47
+ # `DB_HOST=${DB_HOST:-platform-db}`: the default that runs unless an
48
+ # operator overrides it. Authored and citable, but strictly weaker than a
49
+ # literal — an override changes the answer and nothing in the repo says
50
+ # whether one is set — so it prices below env_host, the same way route_dev
51
+ # sits below route_declared.
52
+ env_host_default: 0.85
53
+
54
+ # --- R2 kubernetes (benchmark P 0.97 / R 0.56) ------------------------------
55
+ # DNS aliases register into R0's alias table and are priced there
56
+ # (r0.has_alias); no edge is emitted at a dns_alias tier (calibration finding).
57
+ r2:
58
+ selector_match: 0.97 # Service selector matches workload pod labels
59
+ env_host: 0.95 # literal env value naming an in-cluster service
60
+ built_from_gitops: 0.97 # ArgoCD/Flux declares the source repo
61
+ deployed_as: 0.97 # the manifest itself names the workload
62
+ policy: 0.9 # mesh/network policy joined by selector
63
+
64
+ # --- R9 environment indirection ---------------------------------------------
65
+ # Multi-environment conflicts DECLINE (r9.ambiguous_across_envs) rather than
66
+ # emit at a lower tier — decline-don't-guess won (calibration finding).
67
+ r9:
68
+ env_resolved: 0.85 # code reads VAR; a manifest defines VAR's host
69
+
70
+ # --- R4 gateway route tables ------------------------------------------------
71
+ r4:
72
+ route_declared: 0.98
73
+ route_dev: 0.7 # vite/webpack devServer proxies: real wiring, dev-only
74
+
75
+ # --- R5 gRPC (globally unique proto keys; no service hint needed) -----------
76
+ r5:
77
+ declared: 0.98 # the .proto itself declares the operation
78
+ exact: 0.95 # stub names the fully-qualified package.Service
79
+ service_name: 0.9 # stub names only the service; package inferred
80
+ calls_service: 0.9
81
+
82
+ # --- R3 libraries (version-free purl keys; internal boundary gates joins) ---
83
+ r3:
84
+ publishes: 0.98 # the repo's own manifest names the coordinate
85
+ lockfile_resolved: 0.95 # consumer pin from a lockfile/SBOM
86
+ manifest_declared: 0.9 # consumer range from a manifest
87
+
88
+ # --- R11 agent contracts (MCP server name plays the role of a proto package) -
89
+ r11:
90
+ registration: 0.95 # @mcp.tool / server.tool in the implementing repo
91
+ config: 0.85 # an mcp.json entry naming the server
92
+ card: 0.95 # .well-known/agent.json declares the skill
93
+ url_resolved: 0.9 # a call site's URL matches a card's URL
94
+
95
+ # --- R10 datasets (identity strength varies by namespace) -------------------
96
+ r10:
97
+ declared: 0.95 # a migration/ORM entity/dbt schema declares the table
98
+ literal: 0.9 # a distinctive-namespace name at a call site
99
+ inferred: 0.75 # ORM entity without an explicit table name
100
+
101
+ # --- R12 ownership ----------------------------------------------------------
102
+ r13:
103
+ registered: 0.85 # callback joined to the receiver's own route
104
+
105
+ r12:
106
+ catalog: 0.95 # Backstage names owner + entity in one authored place
107
+ codeowners: 0.9 # path-pattern ownership; repo-level is exact
108
+ observability: 0.8 # a DD_TAGS team is operational, not organizational
109
+
110
+ # --- R14 cross-protocol operations ------------------------------------------
111
+ r14:
112
+ http_binding: 0.97 # the proto's own google.api.http declares it
113
+ event_schema: 0.85 # avro record name equals the rpc's qualified output
114
+
115
+ # --- R6 topics (no service hint exists or is needed; the name is the key) ---
116
+ r6:
117
+ declared: 0.98 # AsyncAPI/Terraform/Avro declares the destination
118
+ literal: 0.9 # a literal destination at a producer/consumer site
119
+ env_resolved: 0.85 # destination via env/config indirection (hmac join)
120
+ fanout: 0.95 # SNS->SQS subscription declared in IaC
121
+
122
+ # --- R8 GraphQL (Type.field carries no package, so weaker than R5) ----------
123
+ r8:
124
+ declared: 0.98 # the SDL declares the root field
125
+ federated: 0.95 # federation names the owning subgraph
126
+ field_name: 0.8 # field name only; no package, no federation
127
+
128
+ # --- R7 http contract matching ----------------------------------------------
129
+ r7:
130
+ hint_exact: 0.95 # qualified service hint + exact path template
131
+ hint_template: 0.85 # qualified service hint + positional template
132
+ # Callee named by a gateway's route table rather than by the call site.
133
+ # Strictly weaker than a direct hint: it assumes the route in force at link
134
+ # time is the one that served the call, so a stale or overridden route table
135
+ # would mislead. Rated below the direct tiers to keep that honest.
136
+ gateway_exact: 0.88
137
+ gateway_template: 0.80
138
+ exposes: 0.98 # provider-side declaration
139
+
140
+ # --- Intra-repo call graph (pre-linker) -------------------------------------
141
+ resolvers:
142
+ call_graph_resolver:
143
+ unique_match:
144
+ confidence: 0.9
145
+ measured: null # provisional — calibration lands in M2
146
+ ambiguous_match:
147
+ confidence: 0.7
148
+ measured: null # provisional — calibration lands in M2
149
+ # SCIP references are compiler-grade resolution; rated above the
150
+ # name-resolution heuristic but never 1.0 — the index can lag the tree.
151
+ scip_import:
152
+ reference:
153
+ confidence: 0.95
154
+ measured: null # provisional — labelled index corpus pending
155
+
156
+ # Resolvers not yet landed (R2 k8s, R3 library, R5 grpc, R6 topic, R9 env) add
157
+ # their tiers here as they ship. Design §6.2 targets: r2 0.97, r3 0.6-1.0 by
158
+ # tier, r5 high (globally unique keys), r6 0.85-0.95 literals.
159
+
160
+ # --- MEASURED (generated by tools/calibrate.py; do not edit) ---
161
+ measured:
162
+ corpus: fixtures-v1
163
+ at: '2026-07-29T22:46:58+00:00'
164
+ rows:
165
+ r0.belongs_to: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
166
+ r0.built_from_app_name: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
167
+ r0.built_from_build_context: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
168
+ r0.built_from_descriptor: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
169
+ r0.has_alias: {precision: 1.0, precision_lo: 0.4385, precision_hi: 1.0, recall: 1.0, support: 3, fp: 0}
170
+ r0.resolved_to: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
171
+ r1.depends_on: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
172
+ r1.env_host: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
173
+ r10.declared: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
174
+ r10.inferred: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
175
+ r10.literal: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
176
+ r11.card: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
177
+ r11.config: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
178
+ r11.registration: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
179
+ r11.url_resolved: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
180
+ r12.catalog: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
181
+ r12.codeowners: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
182
+ r12.observability: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
183
+ r13.registered: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
184
+ r2.built_from_gitops: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
185
+ r2.deployed_as: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
186
+ r2.env_host: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
187
+ r2.policy: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
188
+ r2.selector_match: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
189
+ r3.lockfile_resolved: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
190
+ r3.manifest_declared: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
191
+ r3.publishes: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
192
+ r4.route_declared: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
193
+ r4.route_dev: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
194
+ r5.calls_service: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
195
+ r5.declared: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
196
+ r5.exact: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
197
+ r5.service_name: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
198
+ r6.declared: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
199
+ r6.env_resolved: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
200
+ r6.fanout: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
201
+ r6.literal: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
202
+ r7.exposes: {precision: 1.0, precision_lo: 0.3424, precision_hi: 1.0, recall: 1.0, support: 2, fp: 0}
203
+ r7.gateway_exact: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
204
+ r7.gateway_template: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
205
+ r7.hint_exact: {precision: 1.0, precision_lo: 0.4385, precision_hi: 1.0, recall: 1.0, support: 3, fp: 0}
206
+ r7.hint_template: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
207
+ r8.declared: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
208
+ r8.federated: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
209
+ r8.field_name: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
210
+ r9.env_resolved: {precision: 1.0, precision_lo: 0.2065, precision_hi: 1.0, recall: 1.0, support: 1, fp: 0}
211
+ derived:
212
+ unattributed_labels: {tp: 0, fp: 0}
213
+ rows:
214
+ r0.belongs_to: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
215
+ r0.built_from_app_name: {served: 0.85, derived: 0.85, basis: prior, tp: 1, fp: 0}
216
+ r0.built_from_build_context: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
217
+ r0.built_from_descriptor: {served: 0.75, derived: 0.75, basis: prior, tp: 1, fp: 0}
218
+ r0.has_alias: {served: 0.9, derived: 0.9, basis: prior, tp: 3, fp: 0}
219
+ r0.resolved_to: {served: 0.98, derived: 0.98, basis: prior, tp: 2, fp: 0}
220
+ r1.depends_on: {served: 0.96, derived: 0.96, basis: prior, tp: 1, fp: 0}
221
+ r1.env_host: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
222
+ r10.declared: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
223
+ r10.inferred: {served: 0.75, derived: 0.75, basis: prior, tp: 1, fp: 0}
224
+ r10.literal: {served: 0.9, derived: 0.9, basis: prior, tp: 2, fp: 0}
225
+ r11.card: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
226
+ r11.config: {served: 0.85, derived: 0.85, basis: prior, tp: 1, fp: 0}
227
+ r11.registration: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
228
+ r11.url_resolved: {served: 0.9, derived: 0.9, basis: prior, tp: 1, fp: 0}
229
+ r12.catalog: {served: 0.95, derived: 0.95, basis: prior, tp: 2, fp: 0}
230
+ r12.codeowners: {served: 0.9, derived: 0.9, basis: prior, tp: 1, fp: 0}
231
+ r12.observability: {served: 0.8, derived: 0.8, basis: prior, tp: 1, fp: 0}
232
+ r13.registered: {served: 0.85, derived: 0.85, basis: prior, tp: 1, fp: 0}
233
+ r2.built_from_gitops: {served: 0.97, derived: 0.97, basis: prior, tp: 1, fp: 0}
234
+ r2.deployed_as: {served: 0.97, derived: 0.97, basis: prior, tp: 1, fp: 0}
235
+ r2.env_host: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
236
+ r2.policy: {served: 0.9, derived: 0.9, basis: prior, tp: 1, fp: 0}
237
+ r2.selector_match: {served: 0.97, derived: 0.97, basis: prior, tp: 2, fp: 0}
238
+ r3.lockfile_resolved: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
239
+ r3.manifest_declared: {served: 0.9, derived: 0.9, basis: prior, tp: 1, fp: 0}
240
+ r3.publishes: {served: 0.98, derived: 0.98, basis: prior, tp: 1, fp: 0}
241
+ r4.route_declared: {served: 0.98, derived: 0.98, basis: prior, tp: 2, fp: 0}
242
+ r4.route_dev: {served: 0.7, derived: 0.7, basis: prior, tp: 1, fp: 0}
243
+ r5.calls_service: {served: 0.9, derived: 0.9, basis: prior, tp: 1, fp: 0}
244
+ r5.declared: {served: 0.98, derived: 0.98, basis: prior, tp: 2, fp: 0}
245
+ r5.exact: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
246
+ r5.service_name: {served: 0.9, derived: 0.9, basis: prior, tp: 2, fp: 0}
247
+ r6.declared: {served: 0.98, derived: 0.98, basis: prior, tp: 1, fp: 0}
248
+ r6.env_resolved: {served: 0.85, derived: 0.85, basis: prior, tp: 1, fp: 0}
249
+ r6.fanout: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
250
+ r6.literal: {served: 0.9, derived: 0.9, basis: prior, tp: 2, fp: 0}
251
+ r7.exposes: {served: 0.98, derived: 0.98, basis: prior, tp: 2, fp: 0}
252
+ r7.gateway_exact: {served: 0.88, derived: 0.88, basis: prior, tp: 1, fp: 0}
253
+ r7.gateway_template: {served: 0.8, derived: 0.8, basis: prior, tp: 1, fp: 0}
254
+ r7.hint_exact: {served: 0.95, derived: 0.95, basis: prior, tp: 3, fp: 0}
255
+ r7.hint_template: {served: 0.85, derived: 0.85, basis: prior, tp: 1, fp: 0}
256
+ r8.declared: {served: 0.98, derived: 0.98, basis: prior, tp: 1, fp: 0}
257
+ r8.federated: {served: 0.95, derived: 0.95, basis: prior, tp: 1, fp: 0}
258
+ r8.field_name: {served: 0.8, derived: 0.8, basis: prior, tp: 1, fp: 0}
259
+ r9.env_resolved: {served: 0.85, derived: 0.85, basis: prior, tp: 1, fp: 0}
@@ -0,0 +1,29 @@
1
+ # Which package coordinates are *ours* (design §12).
2
+ #
3
+ # R3 links a consumed library to its Library rendezvous only when the
4
+ # coordinate is internal — matched here — or when some ingested repo publishes
5
+ # it (publish-side identity beats this file). Everything else is an external
6
+ # dependency: counted (`r3.external_skipped`), never linked, because a graph
7
+ # where every repo depends on `lodash` answers no blast-radius question.
8
+ #
9
+ # Registries are informational: they qualify where internal
10
+ # artifacts live so operators can audit the boundary; image_registries gate
11
+ # image-identity claims (R0-R2).
12
+ version: 1
13
+ ecosystems:
14
+ maven:
15
+ namespaces: [] # e.g. [org.acme, com.acme]
16
+ npm:
17
+ scopes: [] # e.g. ["@acme"]
18
+ golang:
19
+ module_prefixes: [] # e.g. [github.com/acme/]
20
+ pypi:
21
+ prefixes: [] # e.g. [acme-]
22
+ nuget:
23
+ prefixes: [] # e.g. [Acme.]
24
+ gem:
25
+ prefixes: []
26
+ cargo:
27
+ prefixes: []
28
+ registries: [] # e.g. [artifactory.acme.io, npm.pkg.github.com]
29
+ image_registries: []
@@ -0,0 +1,10 @@
1
+ # Append-only ledger of D6 human promotions, replayed by link_full so the
2
+ # graph stays disposable (design §12, invariant 12). Entries are appended by
3
+ # the review-queue UI (M3); never edit past entries.
4
+ promotions: []
5
+ # Entry shape:
6
+ # promotions:
7
+ # - claim_key: "http:GET /billing/{}"
8
+ # target: "global:HttpContract:GET /billing/{}"
9
+ # promoted_by: "user@example.com"
10
+ # at: "2026-07-26T00:00:00Z"
@@ -0,0 +1,9 @@
1
+ # The roster: which repositories belong in the graph (design §12, D11).
2
+ # The census tool can generate a first draft. auto_refresh opts a repo into
3
+ # the M2 heartbeat (git ls-remote drift detection, 6h jittered cycle).
4
+ repos: []
5
+ # Example:
6
+ # repos:
7
+ # - url: https://github.com/myorg/payment-service
8
+ # branch: main # optional, defaults to the remote default branch
9
+ # auto_refresh: true # D11 heartbeat opt-in
@@ -0,0 +1,9 @@
1
+ # Manual alias overrides — always win over resolver output (design §12, R0).
2
+ # Unused or conflicting entries are reported by the linker, never silently
3
+ # dropped. Alias keys are scope-qualified: "{scope}:{name}".
4
+ services: {}
5
+ # Example:
6
+ # services:
7
+ # payments:
8
+ # aliases: ["compose-project-a:payment", "prod:payment-svc", "discovery:PAYMENT-SERVICE"]
9
+ # repo: myorg_payment-service
@@ -0,0 +1,57 @@
1
+ # Third-party services an estate calls but does not own (roadmap C2).
2
+ #
3
+ # A call to `api.stripe.com` is qualified — the code names a host — but no
4
+ # internal service answers it, so the join declines and the call vanishes
5
+ # into `r7.unmatched_qualified`. That is indistinguishable from a broken
6
+ # internal call, and it hides a real dependency: an outage at a vendor breaks
7
+ # the same consumers an outage at an internal service would.
8
+ #
9
+ # Classifying is not linking. Nothing here creates an edge; it turns an
10
+ # anonymous decline into a named one, so "we call Stripe from three services"
11
+ # becomes a countable fact rather than an absence.
12
+ #
13
+ # `suffixes` match the end of a host, case-insensitively. Keep them specific:
14
+ # a suffix that matches too broadly would classify an internal host as a
15
+ # vendor and hide a genuine missing edge behind a plausible label.
16
+ version: 1
17
+
18
+ vendors:
19
+ stripe:
20
+ category: payments
21
+ suffixes: [api.stripe.com, files.stripe.com]
22
+ twilio:
23
+ category: messaging
24
+ suffixes: [api.twilio.com, lookups.twilio.com, verify.twilio.com]
25
+ sendgrid:
26
+ category: messaging
27
+ suffixes: [api.sendgrid.com]
28
+ segment:
29
+ category: analytics
30
+ suffixes: [api.segment.io, cdn.segment.com]
31
+ aws_s3:
32
+ category: storage
33
+ suffixes: [s3.amazonaws.com, .s3.amazonaws.com]
34
+ aws_sqs:
35
+ category: queue
36
+ suffixes: [sqs.amazonaws.com, .queue.amazonaws.com]
37
+ github:
38
+ category: vcs
39
+ suffixes: [api.github.com]
40
+ slack:
41
+ category: messaging
42
+ suffixes: [slack.com/api, hooks.slack.com, api.slack.com]
43
+ datadog:
44
+ category: observability
45
+ suffixes: [api.datadoghq.com, http-intake.logs.datadoghq.com]
46
+ openai:
47
+ category: ai
48
+ suffixes: [api.openai.com]
49
+ anthropic:
50
+ category: ai
51
+ suffixes: [api.anthropic.com]
52
+ auth0:
53
+ category: identity
54
+ suffixes: [.auth0.com]
55
+ google_maps:
56
+ category: geo
57
+ suffixes: [maps.googleapis.com]
@@ -0,0 +1,120 @@
1
+ """Explicit, fail-closed installation of the TraceKite agent skill.
2
+
3
+ MCP clients do not share a configuration schema. Registering the server is
4
+ therefore kept out of this module and documented per client; this installer
5
+ only writes skill locations whose global contract is published.
6
+ """
7
+
8
+ from dataclasses import dataclass
9
+ from pathlib import Path
10
+
11
+
12
+ SKILL_CONTENT = """---
13
+ name: tracekite
14
+ description: Cross-repository dependency, caller, and impact tracing with file:line evidence. Use for "who calls this", "who breaks if I change this", "what depends on this service", "what does this endpoint reach" — and before any filesystem search for a caller or consumer that may live in another repository.
15
+ ---
16
+
17
+ # TraceKite
18
+
19
+ TraceKite answers dependency questions from a pre-indexed evidence graph, so
20
+ one query replaces a repository-wide search.
21
+
22
+ Its edges are joined from configuration, manifests and route tables as well as
23
+ source, so they include callers no text search can reach: a URL built from an
24
+ environment variable, a route registered in another language, a gateway that
25
+ rewrites the path before forwarding it. Searching for those returns nothing
26
+ even when the dependency is real.
27
+
28
+ ## Query these before searching the filesystem
29
+
30
+ - `services()` — repository-backed services in the loaded graph.
31
+ - `consumers_of(node_id)` — active incoming edges with evidence spans.
32
+ - `trace(from_id, to_id)` — active paths between exact node IDs.
33
+ - `deprecations()` — deprecated contracts and their active consumers.
34
+
35
+ Call them inline and directly. A caller, dependency or impact question these
36
+ tools answer should not become a grep sweep or a delegated search agent: the
37
+ graph already holds the answer, with provenance, at a fraction of the context.
38
+
39
+ ## Reading a result
40
+
41
+ Every edge cites `file:line` on both sides of the join. When you need
42
+ method-level detail, open the cited location — do not re-read the file to
43
+ rediscover what the citation already names.
44
+
45
+ An empty or declined result is evidence that TraceKite could not establish the
46
+ relationship, not an invitation to infer one. A `found: false` answer carries
47
+ `candidates`; re-query with one of those rather than guessing an ID. Never
48
+ assert an edge the tools did not return.
49
+ """
50
+
51
+
52
+ class SkillConflictError(RuntimeError):
53
+ """An existing skill differs, so overwriting it would destroy user data."""
54
+
55
+
56
+ @dataclass(frozen=True)
57
+ class SkillTarget:
58
+ clients: frozenset[str]
59
+ relative_path: tuple[str, ...]
60
+ label: str
61
+
62
+
63
+ TARGETS = (
64
+ SkillTarget(frozenset({"claude"}),
65
+ (".claude", "skills", "tracekite", "SKILL.md"),
66
+ "Claude Code"),
67
+ SkillTarget(frozenset({"codex"}),
68
+ (".agents", "skills", "tracekite", "SKILL.md"),
69
+ "Codex"),
70
+ SkillTarget(frozenset({"kimi"}),
71
+ (".kimi", "skills", "tracekite", "SKILL.md"),
72
+ "Kimi"),
73
+ SkillTarget(frozenset({"antigravity"}),
74
+ (".gemini", "config", "skills", "tracekite", "SKILL.md"),
75
+ "Antigravity"),
76
+ )
77
+ SUPPORTED_CLIENTS = frozenset(c for target in TARGETS for c in target.clients)
78
+
79
+
80
+ def _selected_targets(clients: list[str] | None) -> list[SkillTarget]:
81
+ selected = set(clients or ["all"])
82
+ unknown = selected - SUPPORTED_CLIENTS - {"all"}
83
+ if unknown:
84
+ raise ValueError(f"unsupported client(s): {sorted(unknown)}")
85
+ if "all" in selected:
86
+ return list(TARGETS)
87
+ return [target for target in TARGETS if target.clients & selected]
88
+
89
+
90
+ def install_skills(clients: list[str] | None = None,
91
+ home: Path | None = None) -> list[tuple[Path, str]]:
92
+ """Install selected skills without modifying or replacing existing data."""
93
+ root = home or Path.home()
94
+ targets = [(root.joinpath(*target.relative_path), target.label)
95
+ for target in _selected_targets(clients)]
96
+
97
+ conflicts = [path for path, _label in targets
98
+ if path.exists() and path.read_text(encoding="utf-8") !=
99
+ SKILL_CONTENT]
100
+ if conflicts:
101
+ rendered = ", ".join(str(path) for path in conflicts)
102
+ raise SkillConflictError(
103
+ f"refusing to overwrite existing skill file(s): {rendered}")
104
+
105
+ for path, _label in targets:
106
+ if path.exists():
107
+ continue
108
+ path.parent.mkdir(parents=True, exist_ok=True)
109
+ path.write_text(SKILL_CONTENT, encoding="utf-8")
110
+ return targets
111
+
112
+
113
+ def cmd_install_skill(args) -> int:
114
+ targets = install_skills(getattr(args, "client", None))
115
+ print("Installed or verified TraceKite skill:")
116
+ for path, label in targets:
117
+ print(f" {label}: {path}")
118
+ print("MCP registration is client-specific; see "
119
+ "docs/plugins-and-mcp-guide.md.")
120
+ return 0