MiniMax M2.x reasons inside <think> tags in the normal content field, and
that reasoning is billed against max_tokens. At 4096 the heavier batches
spent the entire budget thinking, were truncated before writing a single
answer, and stripThinking correctly removed the unclosed block — leaving an
empty response.
The signature was distinctive: batches returned 25/25 or 0/25, never
anything partial. 193 of 779 commits went unsummarised with no error
anywhere. At 16384 the same 193 completed 8/8 batches with zero failures.
The interview's question call had the same bug at 1024, where it would have
returned an empty question and silently ended the interview on the first
turn. Now 8192.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
dnd-kit derives the id of its accessibility description element from an
internal counter that starts fresh on the server and is already advanced on
the client. Every sortable card rendered aria-describedby="DndDescribedBy-0"
server-side and "DndDescribedBy-3" client-side, and React reported a
hydration mismatch across the whole board.
A stable id makes both sides agree.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The test overwrote ai_api_key with a marker and then restored it to ""
rather than to its previous value, so every run of the integration suite
silently wiped the AI provider key. Symptom appears much later and looks
nothing like a test problem: AI features quietly stop working.
Captures the existing value first and restores it in a finally block, so a
failed assertion cannot leave the marker in place either. Deletes the
record instead when the test created it.
The suite runs against the shared instance — there is no separate test
database — so anything it touches, it must put back exactly.
feat(board): give the owner both a quick box and Plan with AI
The Phase 4 spec made the intake wizard client-facing only, reasoning that
the developer creates cards directly. That was wrong about how he wants to
work. The quick box stays the default for lines he already understands;
Plan with AI runs the same interview for work that is genuinely unformed.
Hidden entirely when no provider is configured.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The effect that syncs server state re-ran whenever `busy` flipped, which it
does at the end of every drag. It then called setCards(initialCards) with
the snapshot it already had — the server had not re-rendered — discarding
the optimistic move. The card visibly returned to its original column while
the database held the correct value.
Tracks the last adopted snapshot in a ref so the effect only acts on a
genuinely new one, and calls router.refresh() after a successful move so a
new snapshot actually arrives.
Also hardens the timeline drag: the pointerup handler compared against
`dragging` state, which updates asynchronously, so it could read the
pre-drag value and return early with the drag never committing and no error
anywhere. Reads a ref instead, and clears on pointercancel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The methodology panel already explains that hours are estimated from
commit timing — the pill on the tile was redundant. With the pill gone
the tile row reads as four plain figures, and the methodology is the
single place a client goes to interrogate any of them.
The chart column was flex-1 inside h-40, but had no explicit height of
its own. The bar inside used height: X% which has nothing to compute
against when the parent is auto-sized — Tailwind's percent utilities
collapse to 0 without a definite parent.
Wrap the bar in a flex-1 container that consumes the remaining vertical
space. The percentage now resolves against that container's actual height,
so the 154h August bar fills three-quarters of the way up the column,
the 5h May bar barely peeks above the baseline, and the rest sit between.
The neutral (gray) pill read as a status badge rather than an integral
annotation. The brand tone ties the indicator visually to the brand,
making it part of the figure rather than an overlay. The meaning is the
same — 'this number is not measured, it is computed' — and the methodology
panel still explains exactly how.
The 'Hours here are estimated' phrasing was redundant with the 'estimated'
pill on the Hours KPI tile — the pill is the visual signal, the methodology
doesn't need to repeat it. Left is just 'Git records what changed and when,
but not how long it took.' which sets up the next paragraph.
The methodology panel still explains 'what hours are' and 'what they cannot
see'. The session-clustering detail — the constants — was the part a client
might want to interrogate rather than just be told. With this removed, the
constants are still stored inside the payload (so a future question can be
answered) but the visible panel is shorter.
Also dropped the now-unused destructured local in Methodology().
The integration project now aliases server-only to a tiny empty stub
so tests can import modules that carry 'import "server-only"' without
the throwing real implementation firing during prepare. Unit tests do
NOT get the alias — a pure module with a server import is exactly the
kind of leak the unit project's missing condition is meant to surface.
The plan's summariseSessions test expected 2 sessions for four commits
spanning two 3-hour gaps, but with the default 120-minute gap three hours
is too far and produces 3 sessions. The implementation matches the boundary
rule defined in the plan (strictly less than the gap continues a session);
the test was off. Adjusted to a 90-minute follow-up which keeps the same
session and verifies total + longest correctly.
- ingestProject now calls relinkProject after every store
- updateCard relinks when scopeScope rule is in the patch
- acceptCard, archiveCard, unlinkCommitArchiveCard relink after their change
- three owner Server Actions for the tray: relinkProjectAction, linkCommitAction, unlinkCommitAction
- number field on cards, unique per project
- backfilled existing cards in created order
- both create paths (owner action, client API) assign on creation
- seed script is idempotent across re-runs
Verified against the live instance: status 200, total 787 commits, first
sha 1bc0da40... 'feat(customers): lift active/inactive toggle to top of
customer form'.
Palette:
#051a2d Deep Navy -> page (dark base) + text-primary (light)
#068187 Teal Green -> brand (light mode, AA contrast on white)
#10bbc3 Aqua Blue -> brand (dark mode, vibrant on navy)
#fea24f Sunset Orange -> priority-high
#a60e35 Crimson Red -> accent + priority-critical
The plan's reservation rules are preserved: the crimson accent still appears
only on overdue dates, the inbox count badge, and critical priority.
activeId clears the instant the pointer is released, so gating the
focus-refresh on it alone left a window between drop and server
confirmation where a refresh could overwrite the optimistic position with
stale state and the card would appear to snap back. Tracks a separate
saving flag, and reverts on a thrown fetch as well as a non-ok response.
Also corrects a comment: sensors are created unconditionally; what keeps a
client manager from dragging is that they never render DndContext.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>