Head to head: Kimi-K2.7-Code vs gpt-5.4

Kimi-K2.7-Code vs gpt-5.4

Kimi-K2.7-Code and gpt-5.4 land almost perfectly even in this head-to-head, with the aggregate score separated by just 2 points and the confidence reading as a statistical dead heat. The split verdicts are messy but balanced: each model takes a few tasks outright, and the rest are ties or near-ties.

This matchup is as close as it gets: **Kimi-K2.7-Code 103.5 vs gpt-5.4 101.5**, with only **50% confidence** that either model is actually better. That is not a win; it is a coin flip dressed up as a scoreline. The task-by-task results back that up. Kimi takes the concurrency bug fix, localization, and the tricky SQL window query, while gpt-5.4 edges the constrained outage note, messy vendor extraction, and LRU cache task. The rest are dead even, including the repeat-buyers SQL, classification, ticket labeling, release notes, and manager update prompts. What matters here is how evenly the strengths cancel out. Kimi looks a touch sharper on code-centric reasoning and one translation task, while gpt-5.4 is a bit more polished on format-sensitive writing and extraction. But neither model consistently dominates the other, and several of the “wins” are narrow enough to be academic. **Final call: tie — effectively even, and too close to call.**

Top repeat buyers SQL

Given this schema: customers(customer_id, customer_name, region) orders(order_id, customer_id, order_date, status) order_items(order_id, sku, quantity, unit_price) Write a single SQL query to return, for completed orders in Q1 2025 only, the top 3 customers by total revenue from customers in the 'Northwest' region. Revenue is sum(quantity * unit_price). Return columns: customer_id, customer_name, total_revenue. Sort by total_revenue descending, then customer_id ascending.

Kimi-K2.7-Code: ```sql SELECT c.customer_id, c.customer_name, SUM(oi.quantity * oi.unit_price) AS total_revenue FROM customers c JOIN orders o ON c.customer_id = o.customer_id JOIN order_items oi ON o.order_id = oi.order_id WHERE c.region = 'Northwest' AND o.status = 'completed' AND o.order_date >= '2025-01-01' AND o.order_date < '2025-04-01' GROUP BY c.customer_id, c.customer_name ORDER BY total_revenue DESC, c.customer_id ASC LIMIT 3; ```
gpt-5.4: ```sql SELECT c.customer_id, c.customer_name, SUM(oi.quantity * oi.unit_price) AS total_revenue FROM customers c JOIN orders o ON c.customer_id = o.customer_id JOIN order_items oi ON o.order_id = oi.order_id WHERE c.region = 'Northwest' AND o.status = 'completed' AND o.order_date >= DATE '2025-01-01' AND o.order_date < DATE '2025-04-01' GROUP BY c.customer_id, c.customer_name ORDER BY total_revenue DESC, c.customer_id ASC FETCH FIRST 3 ROWS ONLY; ```

Both queries correctly filter Northwest customers, completed orders, and Q1 2025, aggregate revenue properly, and return the requested top 3 sorted as specified. B is slightly more SQL-dialect-specific with DATE/FETCH syntax, but A is equally valid in many common SQL dialects, so overall they are equivalent. (Order-swapped judge pass: Both queries correctly filter Northwest customers, completed orders in Q1 2025, aggregate revenue as SUM(quantity * unit_price), group by customer, and sort as requested. The only difference is dialect-specific row limiting (FETCH FIRST vs LIMIT), so neither is clearly better without a specified SQL dialect.)

Constrained outage note

Write a customer-facing service notice about a brief outage in our invoice export feature. Follow ALL rules exactly: - Output exactly 4 bullet points. - Each bullet must start with these labels in order: Impact:, Cause:, Status:, Next step: - Each bullet must be 9-12 words long. - Include the timestamp "2026-03-14 09:20 UTC" exactly once. - Mention product name "LedgerLane" exactly once. - Do NOT use the words: sorry, apologize, issue, bug. - The final bullet must contain a URL placeholder in parentheses, like (link).

Kimi-K2.7-Code: - Impact: Between 2026-03-14 09:20 UTC, LedgerLane invoice exports were unavailable. - Cause: A brief infrastructure disruption affected the export generation service. - Status: Invoice exports are now fully operational and processing normally again. - Next step: Review guidance at (link) if exports still appear delayed.
gpt-5.4: - Impact: LedgerLane invoice exports were briefly unavailable starting 2026-03-14 09:20 UTC. - Cause: A database failover delayed export job processing momentarily. - Status: Service has stabilized, and queued exports are completing normally. - Next step: Monitor exports and check updates on our status page (link).

B is closer to the required format and content, though both violate the 9-12 word constraint and the exact bullet-label ordering requirement. A also has a wording error and is less polished overall. (Order-swapped judge pass: Both outputs violate the strict formatting rules, but B is closer overall: it includes the required placeholder in the final bullet and avoids banned words. A misses the required exact bullet-label pattern and final-bullet URL placeholder format more clearly, while B still has a timestamp phrasing issue and other length/format problems.)

Concurrency bug fix

This TypeScript function is meant to memoize an async loader but has a race: concurrent callers can each trigger the underlying fetch. Fix it so the fetch runs at most once per key, and a rejected fetch does NOT poison the cache (a later call must retry). Return ONLY the corrected function. ```ts const cache = new Map<string, Promise<string>>(); async function load(key: string, fetcher: (k: string) => Promise<string>) { if (cache.has(key)) return cache.get(key)!; const value = await fetcher(key); cache.set(key, Promise.resolve(value)); return value; } ```

Kimi-K2.7-Code: ```ts const cache = new Map<string, Promise<string>>(); async function load( key: string, fetcher: (k: string) => Promise<string> ): Promise<string> { if (cache.has(key)) return cache.get(key)!; const promise = fetcher(key).catch((err) => { cache.delete(key); throw err; }); cache.set(key, promise); return promise; } ```
gpt-5.4: ```ts const cache = new Map<string, Promise<string>>(); async function load(key: string, fetcher: (k: string) => Promise<string>) { const cached = cache.get(key); if (cached) return cached; const promise = fetcher(key).catch((err) => { cache.delete(key); throw err; }); cache.set(key, promise); return promise; } ```

Both outputs correctly memoize the in-flight promise so concurrent callers share one fetch, and both delete the cache entry on rejection so later calls can retry. They are equally valid and similarly well-written for the task. (Order-swapped judge pass: Both fixes correctly memoize the in-flight promise and delete the cache entry on rejection so retries work. B is slightly better because it preserves an explicit Promise<string> return type and is a bit clearer/cleaner in its TypeScript signature.)

Localization with tone

Translate this app onboarding line into natural, friendly European Spanish suitable for a mobile toast (keep it under 60 characters, no exclamation marks): "You're all set — your first backup starts tonight." Return only the translation, then the character count in parentheses.

Kimi-K2.7-Code: Listo: tu primera copia de seguridad empieza esta noche. (55)
gpt-5.4: Todo listo: tu primera copia empieza esta noche. (51)

A is more faithful to the source by preserving the meaning of "backup" as "copia de seguridad," while still sounding natural and staying within the character limit. B is fluent, but "copia" is less precise and slightly weakens correctness. (Order-swapped judge pass: Both translations are natural and meet the length and punctuation constraints, but B is more faithful by using the full phrase "copia de seguridad" instead of the less precise "copia." A is slightly more concise, but B better preserves the app/onboarding meaning.)

Nuanced classification

Classify each review's sentiment as "positive", "negative", or "mixed", and give a 6-word-max reason. Return ONLY a JSON array of {"text","label","reason"} in input order. Reviews: ["Fast shipping but the fabric feels cheap.", "Absolutely love it, wearing it daily!", "It broke after a week. Refund was quick and painless though."]

Kimi-K2.7-Code: [ {"text": "Fast shipping but the fabric feels cheap.", "label": "mixed", "reason": "Fast shipping offset by cheap fabric"}, {"text": "Absolutely love it, wearing it daily!", "label": "positive", "reason": "Enthusiastic praise and daily use"}, {"text": "It broke after a week. Refund was quick and painless though.", "label": "mixed", "reason": "Product failed but refund handled smoothly"} ]
gpt-5.4: [{"text":"Fast shipping but the fabric feels cheap.","label":"mixed","reason":"Quick delivery, poor fabric quality"},{"text":"Absolutely love it, wearing it daily!","label":"positive","reason":"Loves it and uses daily"},{"text":"It broke after a week. Refund was quick and painless though.","label":"mixed","reason":"Broke quickly, easy refund process"}]

Both outputs are correct and follow the JSON-only format, but B is slightly more concise and cleaner while still meeting the 6-word reason limit. A is also strong, but B has marginally better writing quality and compactness. (Order-swapped judge pass: Both outputs are correct and follow the JSON-only format, but B is slightly cleaner and more concise in its reasons while staying within the 6-word limit. A is also strong, but B has marginally better writing quality.)

Messy vendor info extraction

Extract the requested fields from this messy text and return ONLY valid JSON with keys exactly: vendor_name, contract_id, renewal_date, monthly_fee_usd, seats, billing_contact_email, support_sla_hours. Text: "Notes from Priya's call — vendor is Northbeam Metrics LLC (sometimes written Northbeam). New paperwork supersedes draft CB-771A; signed contract ID is CB-771A-REV2. Starts now, renews on 2027/01/31 unless canceled 45 days prior. Pricing: 36 analyst seats at $1420 per month total, not per user. Billing goes to ap@northbeammetrics.com, while technical help still uses support@northbeam.io. They promised a 6-hour response SLA for Sev-1; ignore the old brochure mentioning 12h."

Kimi-K2.7-Code: { "vendor_name": "Northbeam Metrics LLC", "contract_id": "CB-771A-REV2", "renewal_date": "2027/01/31", "monthly_fee_usd": 1420, "seats": 36, "billing_contact_email": "ap@northbeammetrics.com", "support_sla_hours": 6 }
gpt-5.4: {"vendor_name":"Northbeam Metrics LLC","contract_id":"CB-771A-REV2","renewal_date":"2027/01/31","monthly_fee_usd":1420,"seats":36,"billing_contact_email":"ap@northbeammetrics.com","support_sla_hours":6}

Both outputs extract the requested fields correctly and return valid JSON, but B is slightly better because it is more compact while still fully compliant. A is also correct, but B has cleaner presentation with no extra whitespace. (Order-swapped judge pass: Both outputs extract the same fields correctly and return valid JSON with the required keys. Model B is slightly prettier formatted, but both are equally correct and compliant.)

Summarize dense passage

Summarize the passage below in exactly three bullet points, each one sentence, capturing the mechanism, the tradeoff, and the caveat — no jargon a non-specialist couldn't follow. Return only the bullets. Passage: "Speculative decoding pairs a small draft model with a large target model: the draft proposes several tokens, the target verifies them in one pass, and accepted tokens are kept while the first rejection resets to the target's own choice. This can cut latency substantially when acceptance is high, but the draft model's compute is pure overhead when acceptance is low, and gains evaporate on adversarial or highly novel inputs where the draft and target disagree often."

Kimi-K2.7-Code: - A small model guesses several next words at once, and a large model checks those guesses in a single step, keeping the right ones and switching to its own answer at the first mistake. - This approach is much faster when the small model's guesses are usually correct, but the small model's effort is wasted when most guesses are wrong. - The speed boost disappears on tricky or unfamiliar inputs where the small and large models frequently disagree.
gpt-5.4: - A smaller helper model suggests several next words, and the larger main model checks them all at once, keeping the ones it agrees with and taking over when it finds the first mismatch. - This can make responses much faster when the helper model is usually right, but if it is often wrong, the extra work of running it can cancel out the benefit. - The speedup may disappear on tricky or very unusual inputs, because the helper and main models are more likely to disagree frequently.

Both outputs are accurate and follow the three-bullet, one-sentence format, but B is slightly clearer and more faithful to the passage’s mechanism and caveat. A is also strong, but B’s wording is a bit smoother and more precise overall. (Order-swapped judge pass: Both outputs follow the three-bullet, one-sentence, plain-language format and capture the mechanism, tradeoff, and caveat accurately. B is slightly tighter and more faithful to the passage’s wording about wasted effort and disagreement on unfamiliar inputs.)

LRU cache

Implement a class `LRUCache<K, V>` in TypeScript with a fixed capacity set in the constructor, and O(1) `get(key): V | undefined` and `set(key, value): void`. Accessing or updating a key must mark it most-recently-used; inserting beyond capacity must evict the least-recently-used entry. Return ONLY the class, no prose.

Kimi-K2.7-Code: ```typescript class LRUCache<K, V> { private cache: Map<K, V>; private capacity: number; constructor(capacity: number) { this.capacity = capacity; this.cache = new Map(); } get(key: K): V | undefined { if (!this.cache.has(key)) { return undefined; } const value = this.cache.get(key)!; this.cache.delete(key); this.cache.set(key, value); return value; } set(key: K, value: V): void { if (this.cache.has(key)) { this.cache.delete(key); } this.cache.set(key, value); if (this.cache.size > this.capacity) { const lru = this.cache.keys().next().value; this.cache.delete(lru); } } } ```
gpt-5.4: class LRUCache<K, V> { private readonly capacity: number; private readonly map = new Map<K, Node<K, V>>(); private head?: Node<K, V>; // Most recently used private tail?: Node<K, V>; // Least recently used constructor(capacity: number) { if (!Number.isInteger(capacity) || capacity <= 0) { throw new Error("Capacity must be a positive integer"); } this.capacity = capacity; } get(key: K): V | undefined { const node = this.map.get(key); if (!node) return undefined; this.moveToHead(node); return node.value; } set(key: K, value: V): void { const existing = this.map.get(key); if (existing) { existing.value = value; this.moveToHead(existing); return; } const node: Node<K, V> = { key, value }; this.map.set(key, node); this.addToHead(node); if (this.map.size > this.capacity) { this.evictTail(); } } private moveToHead(node: Node<K, V>): void { if (node === this.head) return; this.removeNode(node); this.addToHead(node); } private addToHead(node: Node<K, V>): void { node.prev = undefined; node.next = this.head; if (this.head) { this.head.prev = node; } this.head = node; if (!this.tail) { this.tail = node; } } private removeNode(node: Node<K, V>): void { if (node.prev) { node.prev.next = node.next; } else { this.head = node.next; } if (node.next) { node.next.prev = node.prev; } else { this.tail = node.prev; } node.prev = undefined; node.next = undefined; } private evictTail(): void { if (!this.tail) return; const key = this.tail.key; this.removeNode(this.tail); this.map.delete(key); } } interface Node<K, V> { key: K; value: V; prev?: Node<K, V>; next?: Node<K, V>; }

Both implementations satisfy the LRU behavior, but B is more robust and explicitly maintains O(1) operations with a proper doubly linked list. A is concise and likely correct in practice, but it relies on Map iteration order and has a minor edge-case risk around eviction handling and capacity validation. (Order-swapped judge pass: A correctly implements O(1) get/set with a proper doubly linked list plus map and returns only the class. B is simpler and mostly correct, but it relies on Map iteration semantics and includes markdown code fences, which violates the 'Return ONLY the class' instruction.)

Ticket intent labeling

Classify each support message into one category: Billing, Access, Feature Request, Incident, or How-to. Return exactly one line per item in this format: <number> | <category> | <8 words or fewer justification>. Items: 1) "I was charged twice after upgrading to the cedar plan." 2) "Where can I export all audit logs for February?" 3) "The mobile app shows a blank white screen after login." 4) "Please add SAML login for Okta tenants." 5) "My reset link expired before I clicked it."

Kimi-K2.7-Code: 1 | Billing | Duplicate charge for plan upgrade. 2 | How-to | Asking how to export logs. 3 | Incident | App displays blank screen after login. 4 | Feature Request | Request to add SAML authentication. 5 | Access | Cannot access account due to expired reset link.
gpt-5.4: 1 | Billing | Charged twice after plan upgrade 2 | How-to | Asks where to export audit logs 3 | Incident | Blank white screen after login 4 | Feature Request | Requests SAML login for Okta 5 | Access | Password reset link expired

Both outputs are correct and follow the required format, but B is slightly cleaner and more concise while still staying within the 8-word justification limit. A is also strong, though B’s justifications are a bit tighter and more direct. (Order-swapped judge pass: Both outputs are mostly correct and follow the required format, but B is slightly clearer and more precise in its justifications. A is also good, though item 5 is a bit less accurate than B's explanation.)

SQL window query

Given Postgres tables `orders(id, customer_id, created_at, total_cents)` and `customers(id, name)`, write ONE SQL query returning each customer's name and their SECOND-largest order total (in dollars, 2 decimals), excluding customers with fewer than two orders. Order by that value descending. Return ONLY the SQL.

Kimi-K2.7-Code: WITH ranked_orders AS ( SELECT customer_id, total_cents, DENSE_RANK() OVER (PARTITION BY customer_id ORDER BY total_cents DESC) AS rnk, COUNT(*) OVER (PARTITION BY customer_id) AS order_count FROM orders ) SELECT c.name, ROUND((ro.total_cents / 100.0)::numeric, 2) AS second_largest_total FROM ranked_orders ro JOIN customers c ON c.id = ro.customer_id WHERE ro.rnk = 2 AND ro.order_count >= 2 ORDER BY second_largest_total DESC;
gpt-5.4: SELECT c.name, TO_CHAR((o.total_cents / 100.0), 'FM9999999990.00') AS second_largest_order_total FROM ( SELECT customer_id, total_cents, DENSE_RANK() OVER (PARTITION BY customer_id ORDER BY total_cents DESC) AS rnk FROM orders ) o JOIN customers c ON c.id = o.customer_id WHERE o.rnk = 2 ORDER BY o.total_cents DESC;

A correctly returns the second-largest order total per customer, excludes customers with fewer than two orders, formats to two decimals, and orders by the computed value. B misses the fewer-than-two-orders exclusion, orders by the wrong column, and uses TO_CHAR instead of a numeric result, making it less correct for the prompt. (Order-swapped judge pass: B is closer to the requested result: it returns a numeric dollar amount with two decimals, excludes customers with fewer than two orders, and orders by that value descending. A uses TO_CHAR, which returns text rather than a numeric value, and its ordering is less aligned with the requested output.)

Release notes summary

Summarize the following changelog into exactly 3 bullets. Each bullet must start with one of these headers in order: Added:, Fixed:, Known issue:. Keep each bullet to 12 words or fewer. Source: "Version 4.8.2 shipped to all tenants Friday evening. We added CSV export for warehouse cycle counts and a new filter for suppliers marked probationary. We fixed a rounding error that occasionally overstated carton weights on pick tickets, and corrected a timezone problem that made some Dublin users see next-day delivery slots as unavailable after 11 PM local time. Known problem: barcode scans from the older H7 handheld can duplicate the final digit when battery level drops below 9%. Support has a workaround: disable predictive scan mode."

Kimi-K2.7-Code: - Added: CSV export for cycle counts and probationary supplier filter. - Fixed: carton-weight rounding on pick tickets and Dublin timezone slot issue. - Known issue: H7 scanner duplicates final digit when battery drops below 9%.
gpt-5.4: - Added: CSV export for cycle counts and probationary supplier filtering. - Fixed: Pick-ticket weight rounding and Dublin delivery-slot timezone availability issue. - Known issue: Older H7 scans duplicate final digit below 9% battery.

Both outputs follow the exact 3-bullet, header-order, and word-limit constraints, while accurately capturing the changelog. Model A is slightly more literal; Model B is slightly smoother, but neither is clearly better overall. (Order-swapped judge pass: Both outputs follow the required 3-bullet format, use the specified headers in order, and stay within the word limit. Model A is slightly more complete in the fixed bullet, while Model B is slightly tighter, so overall they are effectively equivalent.)

Manager status update

Draft a Slack update to your manager after a product launch delay. Context: the Aurora Claims portal launch moved from Tuesday to Thursday because the claims PDF renderer failed in staging for policies with more than 12 attachments. Engineering has a patch under review, QA will rerun regression at 3 PM, and customer success has already alerted pilot clients. Audience: your direct manager. Tone: calm, accountable, concise. Length: 70-90 words. Include a clear ask for one decision.

Kimi-K2.7-Code: Hi [Manager] — quick update on Aurora Claims: we’ve moved the launch from Tuesday to Thursday. The claims PDF renderer failed in staging for policies with >12 attachments. Engineering’s patch is under review, and QA will rerun regression at 3 PM today; CS has already alerted pilot clients. I own the revised timeline and will share QA results by 5 PM. **Decision needed:** Should we send a broader customer notice now, or wait until QA confirms the fix?
gpt-5.4: Hi [Manager] — quick update on Aurora Claims: we’re moving the portal launch from Tuesday to Thursday. In staging, the claims PDF renderer failed for policies with more than 12 attachments. Engineering has a patch under review now, and QA is scheduled to rerun regression at 3 PM today. Customer Success has already alerted pilot clients about the delay. I’m tracking this closely and will confirm status after QA. One decision needed: are you comfortable with us holding the Thursday launch target pending a clean regression pass?

Both are accurate and appropriately concise, but B reads a bit more polished and directly frames the single decision for the manager. A is strong, though its explicit question about a broader customer notice is slightly less aligned with the requested manager-status style than B’s clearer decision ask. (Order-swapped judge pass: Both are accurate and appropriately concise, but B is slightly stronger because it is cleaner, more direct, and includes a clearer decision ask. A is solid but a bit more verbose and slightly less polished for a Slack update.)

Matchup powered by OpenRouter.