<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Overclock</title>
    <description>The latest articles on DEV Community by Overclock (@overclock-labs).</description>
    <link>https://dev.to/overclock-labs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4099605%2F412d64c3-7ed6-4d78-9de5-058dd4aaec96.png</url>
      <title>DEV Community: Overclock</title>
      <link>https://dev.to/overclock-labs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/overclock-labs"/>
    <language>en</language>
    <item>
      <title>Benchmarking Ether vs. Cursor: Achieving Better Results with 40% Less Token Usage</title>
      <dc:creator>Overclock</dc:creator>
      <pubDate>Sat, 29 Aug 2026 00:45:00 +0000</pubDate>
      <link>https://dev.to/overclock-labs/benchmarking-ether-vs-cursor-achieving-better-results-with-40-less-token-usage-27a0</link>
      <guid>https://dev.to/overclock-labs/benchmarking-ether-vs-cursor-achieving-better-results-with-40-less-token-usage-27a0</guid>
      <description>&lt;p&gt;As AI coding assistants become deeply integrated into our daily workflows, engineering teams are running into a frustrating wall: context bloat. Modern enterprise applications span multiple repositories, microservices, and databases. When you ask an AI a complex architectural question, brute-force ingestion often leads to massive token bills and hallucinated answers.&lt;/p&gt;

&lt;p&gt;Better context reduces token consumption and delivers more precise results.&lt;/p&gt;

&lt;p&gt;To prove this, I ran a head-to-head benchmark using a well-known, highly complex open-source project: &lt;strong&gt;Spring PetClinic Microservices&lt;/strong&gt;. This repository separates logic across an API Gateway, Config Server, Discovery Server, and multiple backend services. It is the perfect stress test for an AI's ability to navigate cross-module logic without getting lost in the noise.&lt;/p&gt;

&lt;p&gt;Tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ether&lt;/strong&gt; (Model: Kimi k3) You can download Ether for free at &lt;a href="https://www.overclock.it.com/features" rel="noopener noreferrer"&gt;https://www.overclock.it.com/features&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cursor&lt;/strong&gt; (Free Plan, Model: Auto)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Benchmark Prompt
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;"Trace the exact cross-service data flow when a user requests an owner's details via the API Gateway (&lt;code&gt;GET /api/gateway/owners/{ownerId}&lt;/code&gt;). Identify the specific class and method in the &lt;code&gt;api-gateway&lt;/code&gt; module that aggregates this data. Then, list the exact REST clients (WebClient or Feign) it uses to call downstream services, the specific controller classes and methods triggered in the &lt;code&gt;customers-service&lt;/code&gt; and &lt;code&gt;visits-service&lt;/code&gt;, and the underlying database tables queried in both backend microservices to assemble the final response. Do not generate any code; just provide a step-by-step architectural trace with the exact file names."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Tool 1: Ether (Kimi k3)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Analysis
&lt;/h3&gt;

&lt;p&gt;Ether utilized its context-pruning orchestration to filter out irrelevant files before querying the LLM. It traced the entire stack, identifying layers that Cursor completely missed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Consumption
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87r9ivodpa8ourrov96y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F87r9ivodpa8ourrov96y.png" alt="Ether Token Consumption" width="661" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ether Output:&lt;/strong&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Cross-Service Data Flow Trace: &lt;code&gt;GET /api/gateway/owners/{ownerId}&lt;/code&gt;
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. Entry Point (Browser / Frontend)
&lt;/h2&gt;

&lt;p&gt;The AngularJS UI issues the request from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;spring-petclinic-api-gateway/src/main/resources/static/scripts/owner-details/owner-details.controller.js&lt;/code&gt; → &lt;code&gt;$http.get('api/gateway/owners/' + $stateParams.ownerId)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This hits the API Gateway, which is the single ingress point for the Angular app (routes configured in &lt;code&gt;spring-petclinic-api-gateway/src/main/resources/application.yml&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  2. API Gateway — Aggregation Layer
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/boundary/web/ApiGatewayController.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;ApiGatewayController&lt;/code&gt; (annotated &lt;code&gt;@RestController&lt;/code&gt; + &lt;code&gt;@RequestMapping("/api/gateway")&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;getOwnerDetails(int ownerId)&lt;/code&gt; mapped via &lt;code&gt;@GetMapping(value = "owners/{ownerId}")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return type:&lt;/strong&gt; &lt;code&gt;Mono&amp;lt;OwnerDetails&amp;gt;&lt;/code&gt; (fully reactive, non-blocking WebFlux)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The aggregation logic is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;code&gt;customersServiceClient.getOwner(ownerId)&lt;/code&gt; → returns &lt;code&gt;Mono&amp;lt;OwnerDetails&amp;gt;&lt;/code&gt; containing the owner &lt;strong&gt;and their pets&lt;/strong&gt; (but no visits yet).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;flatMap&lt;/code&gt; on the owner → extract pet IDs via &lt;code&gt;owner.getPetIds()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;visitsServiceClient.getVisitsForPets(petIds)&lt;/code&gt; → returns &lt;code&gt;Mono&amp;lt;Visits&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Wrap the visits call in a Resilience4j &lt;strong&gt;circuit breaker&lt;/strong&gt; (&lt;code&gt;cbFactory.create("getOwnerDetails")&lt;/code&gt;), with fallback &lt;code&gt;emptyVisitsForPets()&lt;/code&gt; (returns empty visits list on failure — graceful degradation).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.map(addVisitsToOwner(owner))&lt;/code&gt; merges visits into each pet (matching on &lt;code&gt;petId&lt;/code&gt;) and returns the enriched &lt;code&gt;OwnerDetails&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  3. Downstream REST Clients (both use &lt;strong&gt;WebClient&lt;/strong&gt;, not Feign)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A. Customers client
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/CustomersServiceClient.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;CustomersServiceClient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;getOwner(int ownerId)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP call:&lt;/strong&gt; &lt;code&gt;GET http://customers-service/owners/{ownerId}&lt;/code&gt; (uses the &lt;code&gt;@LoadBalanced&lt;/code&gt; &lt;code&gt;WebClient.Builder&lt;/code&gt; defined in &lt;code&gt;ApiGatewayApplication.java&lt;/code&gt;, so service discovery resolves the &lt;code&gt;customers-service&lt;/code&gt; hostname)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B. Visits client
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/VisitsServiceClient.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;VisitsServiceClient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;getVisitsForPets(List&amp;lt;Integer&amp;gt; petIds)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP call:&lt;/strong&gt; &lt;code&gt;GET http://visits-service/pets/visits?petId={comma-separated IDs}&lt;/code&gt; (joins IDs via &lt;code&gt;joinIds()&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Downstream Controllers Triggered
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A. Customers Service
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;OwnerResource&lt;/code&gt; (&lt;code&gt;@RestController&lt;/code&gt;, base path &lt;code&gt;/owners&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;findOwner(int ownerId)&lt;/code&gt; → &lt;code&gt;@GetMapping("/{ownerId}")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delegates to &lt;code&gt;OwnerRepository.findById(ownerId)&lt;/code&gt; (Spring Data JPA).&lt;/li&gt;
&lt;li&gt;The returned &lt;code&gt;Owner&lt;/code&gt; entity eagerly/fetch-joins its &lt;code&gt;pets&lt;/code&gt; collection (and each pet's &lt;code&gt;PetType&lt;/code&gt;), which is what populates the pet IDs/names/birthDates/types in the gateway's &lt;code&gt;OwnerDetails&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  B. Visits Service
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;VisitResource&lt;/code&gt; (&lt;code&gt;@RestController&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;read(@RequestParam("petId") List&amp;lt;Integer&amp;gt; petIds)&lt;/code&gt; → &lt;code&gt;@GetMapping("pets/visits")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delegates to &lt;code&gt;VisitRepository.findByPetIdIn(petIds)&lt;/code&gt; (&lt;code&gt;spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/model/VisitRepository.java&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Wraps the result in its inner record &lt;code&gt;Visits(List&amp;lt;Visit&amp;gt; items)&lt;/code&gt; and returns it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Underlying Database Tables Queried
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Customers Service DB
&lt;/h3&gt;

&lt;p&gt;Schema files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;spring-petclinic-customers-service/src/main/resources/db/hsqldb/schema.sql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spring-petclinic-customers-service/src/main/resources/db/mysql/schema.sql&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tables touched when &lt;code&gt;OwnerRepository.findById()&lt;/code&gt; fetches the owner graph:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;owners&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Owner row (&lt;code&gt;id&lt;/code&gt;, &lt;code&gt;first_name&lt;/code&gt;, &lt;code&gt;last_name&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, &lt;code&gt;city&lt;/code&gt;, &lt;code&gt;telephone&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pets&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pets belonging to the owner (FK &lt;code&gt;owner_id → owners.id&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;types&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pet type lookup for each pet (FK &lt;code&gt;pets.type_id → types.id&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Visits Service DB
&lt;/h3&gt;

&lt;p&gt;Schema files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;spring-petclinic-visits-service/src/main/resources/db/hsqldb/schema.sql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;spring-petclinic-visits-service/src/main/resources/db/mysql/schema.sql&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;visits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rows filtered via &lt;code&gt;WHERE pet_id IN (...)&lt;/code&gt; by &lt;code&gt;findByPetIdIn()&lt;/code&gt; — columns &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;pet_id&lt;/code&gt;, &lt;code&gt;visit_date&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  End-to-End Sequence Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Browser (Angular owner-details.controller.js)
   │  GET /api/gateway/owners/{ownerId}
   ▼
ApiGatewayController.getOwnerDetails()                      [api-gateway]
   ├─► CustomersServiceClient.getOwner(ownerId)   (WebClient)
   │      GET http://customers-service/owners/{ownerId}
   │      ▼
   │      OwnerResource.findOwner(ownerId)                 [customers-service]
   │      ▼  OwnerRepository.findById()
   │      Tables: owners, pets, types  ◄── returns OwnerDetails(+pets)
   │
   ├─► extract owner.getPetIds()
   │
   └─► VisitsServiceClient.getVisitsForPets(petIds) (WebClient + Resilience4j CB "getOwnerDetails")
          GET http://visits-service/pets/visits?petId=1,2,...
          ▼
          VisitResource.read(petIds)                        [visits-service]
          ▼  VisitRepository.findByPetIdIn()
          Table: visits  ◄── returns Visits(items)
   ▼
addVisitsToOwner() merges visits into each pet (filter by petId)
   ▼
Mono&amp;lt;OwnerDetails&amp;gt; serialized → JSON response to browser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key architectural notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The gateway performs &lt;strong&gt;client-side service composition&lt;/strong&gt; (API composition pattern) — the two downstream calls are sequential in code (&lt;code&gt;flatMap&lt;/code&gt;), because the visits call depends on pet IDs from the owner response.&lt;/li&gt;
&lt;li&gt;Resilience is handled by a Resilience4j &lt;code&gt;ReactiveCircuitBreaker&lt;/code&gt; named &lt;code&gt;"getOwnerDetails"&lt;/code&gt; with a 10-second &lt;code&gt;TimeLimiterConfig&lt;/code&gt; (default in &lt;code&gt;ApiGatewayApplication.java&lt;/code&gt;); on visits-service failure the owner data is still returned with empty visit lists.&lt;/li&gt;
&lt;li&gt;Both clients use &lt;code&gt;@LoadBalanced WebClient.Builder&lt;/code&gt; (defined in &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/ApiGatewayApplication.java&lt;/code&gt;) with Eureka service discovery — there is &lt;strong&gt;no Feign&lt;/strong&gt; in this path.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tool 2: Cursor (Auto)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Analysis
&lt;/h3&gt;

&lt;p&gt;Cursor provided a solid, accurate trace of the backend Java services. It explored 17 files and made 13 searches. It correctly identified that the project uses &lt;code&gt;WebClient&lt;/code&gt; rather than Feign, and it mapped the downstream JPA repositories.&lt;/p&gt;

&lt;h3&gt;
  
  
  Token Consumption
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphyeccyhwx62j5yqi3ve.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fphyeccyhwx62j5yqi3ve.png" alt="Ether Token Consumption" width="772" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cursor Output:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is the exact cross-service trace for &lt;code&gt;GET /api/gateway/owners/{ownerId}&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Overview
&lt;/h4&gt;

&lt;p&gt;This is a &lt;strong&gt;BFF-style aggregation&lt;/strong&gt; in &lt;code&gt;spring-petclinic-api-gateway&lt;/code&gt;. The gateway does &lt;strong&gt;not&lt;/strong&gt; use Feign anywhere in this project. Both downstream calls use &lt;code&gt;WebClient&lt;/code&gt; (via a &lt;code&gt;@LoadBalanced WebClient.Builder&lt;/code&gt; bean in &lt;code&gt;ApiGatewayApplication.java&lt;/code&gt;).&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1 — API Gateway entry point
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/boundary/web/ApiGatewayController.java&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This method orchestrates the full response:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;customersServiceClient.getOwner(ownerId)&lt;/code&gt; to fetch owner + pets.&lt;/li&gt;
&lt;li&gt;On success, calls &lt;code&gt;visitsServiceClient.getVisitsForPets(owner.getPetIds())&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Wraps the visits call in a Resilience4j reactive circuit breaker named &lt;code&gt;"getOwnerDetails"&lt;/code&gt; (falls back to &lt;code&gt;emptyVisitsForPets()&lt;/code&gt; on failure).&lt;/li&gt;
&lt;li&gt;Merges visits into each pet via the private helper &lt;code&gt;addVisitsToOwner(OwnerDetails owner)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Returns &lt;code&gt;Mono&amp;lt;OwnerDetails&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pet IDs are extracted in &lt;code&gt;OwnerDetails.getPetIds()&lt;/code&gt; (&lt;code&gt;spring-petclinic-api-gateway/.../dto/OwnerDetails.java&lt;/code&gt;) from the &lt;code&gt;pets&lt;/code&gt; list returned by customers-service.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2 — Downstream REST clients (WebClient only)
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;2a. Customers client&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/CustomersServiceClient.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;CustomersServiceClient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;getOwner(int ownerId)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target:&lt;/strong&gt; &lt;code&gt;GET http://customers-service/owners/{ownerId}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2b. Visits client&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-api-gateway/src/main/java/org/springframework/samples/petclinic/api/application/VisitsServiceClient.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class:&lt;/strong&gt; &lt;code&gt;VisitsServiceClient&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;getVisitsForPets(List&amp;lt;Integer&amp;gt; petIds)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Target:&lt;/strong&gt; &lt;code&gt;GET http://visits-service/pets/visits?petId={id1,id2,...}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Service names (&lt;code&gt;customers-service&lt;/code&gt;, &lt;code&gt;visits-service&lt;/code&gt;) are resolved through Spring Cloud LoadBalancer because the &lt;code&gt;WebClient.Builder&lt;/code&gt; is annotated &lt;code&gt;@LoadBalanced&lt;/code&gt; in &lt;code&gt;ApiGatewayApplication.java&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3 — customers-service
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-customers-service/src/main/java/org/springframework/samples/petclinic/customers/web/OwnerResource.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;findOwner(int ownerId)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effective endpoint:&lt;/strong&gt; &lt;code&gt;GET /owners/{ownerId}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence layer:&lt;/strong&gt; &lt;code&gt;OwnerRepository.findById(ownerId)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because &lt;code&gt;Owner&lt;/code&gt; has &lt;code&gt;@OneToMany(fetch = FetchType.EAGER)&lt;/code&gt; on &lt;code&gt;pets&lt;/code&gt;, and each &lt;code&gt;Pet&lt;/code&gt; has &lt;code&gt;@ManyToOne&lt;/code&gt; on &lt;code&gt;PetType&lt;/code&gt;, a single owner lookup triggers reads from &lt;strong&gt;three tables&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;owners&lt;/code&gt;: Primary lookup via &lt;code&gt;findById&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pets&lt;/code&gt;: Eager &lt;code&gt;@OneToMany(mappedBy = "owner")&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;types&lt;/code&gt;: &lt;code&gt;@ManyToOne @JoinColumn(name = "type_id")&lt;/code&gt; on each &lt;code&gt;Pet&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The JSON response includes owner fields and pets (with type), but &lt;strong&gt;no visits&lt;/strong&gt; — those are added later by the gateway.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4 — visits-service
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;spring-petclinic-visits-service/src/main/java/org/springframework/samples/petclinic/visits/web/VisitResource.java&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Method:&lt;/strong&gt; &lt;code&gt;read(List&amp;lt;Integer&amp;gt; petIds)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effective endpoint:&lt;/strong&gt; &lt;code&gt;GET /pets/visits?petId=1,2,3&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistence layer:&lt;/strong&gt; &lt;code&gt;VisitRepository.findByPetIdIn(Collection&amp;lt;Integer&amp;gt; petIds)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Database table queried&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;visits&lt;/code&gt; (&lt;code&gt;SELECT ... FROM visits WHERE pet_id IN (...)&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Schema definition: &lt;code&gt;spring-petclinic-visits-service/src/main/resources/db/mysql/schema.sql&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 5 — Gateway aggregation and final response
&lt;/h4&gt;

&lt;p&gt;Back in &lt;code&gt;ApiGatewayController.addVisitsToOwner()&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Iterates each &lt;code&gt;PetDetails&lt;/code&gt; in the owner.&lt;/li&gt;
&lt;li&gt;Filters &lt;code&gt;Visits.items()&lt;/code&gt; where &lt;code&gt;visit.petId() == pet.id()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Appends matching visits into that pet's &lt;code&gt;visits&lt;/code&gt; list.&lt;/li&gt;
&lt;li&gt;Returns the enriched &lt;code&gt;OwnerDetails&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cursor End-to-End Sequence Summary
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ApiGatewayController.getOwnerDetails()                      [api-gateway]
   ├─► CustomersServiceClient.getOwner(ownerId)   (WebClient)
   │      GET http://customers-service/owners/{ownerId}
   │      ▼
   │      OwnerResource.findOwner(ownerId)                 [customers-service]
   │      ▼  OwnerRepository.findById()
   │      Tables: owners, pets, types  ◄── returns OwnerDetails(pets, no visits)
   │
   ├─► extract owner.getPetIds()
   │
   └─► VisitsServiceClient.getVisitsForPets(petIds) (WebClient)
          GET http://visits-service/pets/visits?petId=1,2,...
          ▼
          VisitResource.read(petIds)                        [visits-service]
          ▼  VisitRepository.findByPetIdIn()
          Table: visits  ◄── returns Visits JSON
   ▼
addVisitsToOwner() merge
   ▼
OwnerDetails (owner + pets + visits)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Final Verdict
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric / Aspect&lt;/th&gt;
&lt;th&gt;Cursor (Auto)&lt;/th&gt;
&lt;th&gt;Ether (Kimi k3)&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gross Context Usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~31.8K Tokens&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;26.1K Tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ether (18% cost efficiency)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active / Billed Tokens&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~31.8K Tokens&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;18.4K Tokens&lt;/strong&gt; &lt;em&gt;(7.7K cached)&lt;/em&gt;
&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ether (42% cost efficiency)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tracing Depth&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Started at API Gateway&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Traced back to AngularJS UI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ether&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Service Discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Omitted&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Identified Eureka Resolution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ether&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Database Schema&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inferred via JPA&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Located physical &lt;code&gt;.sql&lt;/code&gt; files&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ether&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>ai</category>
      <category>cursor</category>
      <category>agents</category>
    </item>
  </channel>
</rss>
