Two views rather than one chart, because the data forced it: measured on
the live database, 1 of 5 live cards has a target date and none has both
dates. target_date is client-owned and optional; start_date is only set on
Inbox acceptance. A conventional Gantt would render almost empty.
So Now/Next/Later is the default and works with zero dates, and the
timeline earns its place as clients set dates. From Dave's Gantt reference
it takes the quarter header, the Today marker, project grouping with the
client's colour, and the per-row completion percentage — which maps onto
checklist progress, the one honest source for it. The faint full-width
track is load-bearing rather than decorative: it makes a sparse chart read
as unscheduled instead of broken.
Drag-to-reschedule always writes an activity row naming the owner, because
target_date belongs to the client. A developer silently moving a date the
client chose is the failure the activity log exists to prevent.
Completes the plan set for phases 1 through 5.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4a builds the stateless interview. Every constraint that matters is
enforced in code rather than requested in the prompt: the seven-question
cap, the answer length, and what fields a brief may contain. parseBrief is
a whitelist, not a parser — a brief asserting priority or accepted loses
those at the boundary and they never reach a caller that could act on them.
4b adds a separate intake route rather than extending Plan 1a's client
card route. That route's tests were written against a two-field body;
widening the shape it accepts would leave them passing while proving less.
Both routes set column, priority, accepted and created_by_role themselves,
and both are separately proven to.
The property both plans are written to: the worst a hostile brief can
achieve is a strangely-worded card in the Inbox.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A guided interview that produces a written brief with sub-tasks, landing
in the Inbox as a draft through Plan 1c's existing accept flow.
Corrects an over-promise made during the Phase 1 discussion: the wizard
was described as grounding date proposals in measured per-card velocity,
and that data does not exist — Plan 2c deferred per-card effort because
session padding does not sum correctly across cards. This phase therefore
produces no time estimate at all, only a size band.
Names the intake as the highest-risk surface in the product: it is the
only place where text written by someone other than the developer enters
a prompt whose output creates records. The security property is that the
worst a hostile brief achieves is a strangely-worded Inbox card.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three tests cover the storage and access boundary:
- A client manager cannot list the settings collection at all (rules are
superuser-only — verified by the rejection, not by silent skip).
- The settings page HTML returned to the owner does not contain the key
value, even when the key is freshly set to a unique sentinel.
- A client manager gets 404 on /admin/settings (admin layout gates on
role, not on session presence).
helpers.ts gained ownerEmail / ownerPassword — needed by the settings test
and reusable for any owner-only integration test going forward.
3a ports the provider structure from MEGAIFRASTRUCTURE's chat/ — SDK-free
types, one adapter per provider — but deliberately not its interface: this
phase needs text in, text out, not a chat transcript and tool protocol. It
carries forward the MiniMax details that module learned the hard way: the
native /v1 route rather than the /anthropic shim, an Open Platform key, and
stripping the inline <think> blocks M2.x emits.
3b is built around one property: batch responses are matched to commits by
an echoed index, never by position. A single skipped line under positional
matching would attach fluent, confident, wrong sentences to every later
commit, with nothing raising an error.
3c is the first plan whose output a client reads, so its verification step
is to read a narrative as the client would and check it claims no
completion, states no date, and invents nothing.
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.