fix(ci): strict-mode types in three cards, photo measurements marked independent, and the strict ratchet names its errors

This commit is contained in:
Maurice
2026-10-22 17:05:02 +02:00
parent 88cd4fba6e
commit 2d40dc08ed
5 changed files with 17 additions and 4 deletions
@@ -27,7 +27,9 @@ export function bookingTabOf(type: string): 'transports' | 'buchungen' {
* that trip's planner. `map` shows its route on the plan instead.
*/
export function bookingTarget(item: BookingItem, reservationId: number, map = false): EntityTarget {
const params = map ? { booking: String(reservationId), map: '1' } : { booking: String(reservationId) };
const params: Record<string, string> = map
? { booking: String(reservationId), map: '1' }
: { booking: String(reservationId) };
const tab = map ? 'plan' : bookingTabOf(item.type);
if (item.tripTitle !== null) {
return { kind: 'page', path: `/trips/${item.tripId}?${new URLSearchParams({ tab, ...params }).toString()}` };
@@ -79,7 +79,10 @@ export function mergePayments(entries: readonly CardEntry[]): PaymentsCard | nul
/** Settle up and the share per traveller answer once: the latest card of the answer is the one shown. */
export function latestOf(entries: readonly CardEntry[], kind: 'settlement'): SettlementCard | null;
export function latestOf(entries: readonly CardEntry[], kind: 'costPerPerson'): CostPerPersonCard | null;
export function latestOf(entries: readonly CardEntry[], kind: 'settlement' | 'costPerPerson') {
export function latestOf(
entries: readonly CardEntry[],
kind: 'settlement' | 'costPerPerson'
): SettlementCard | CostPerPersonCard | null {
const cards = cardsOf(entries, kind);
return cards[cards.length - 1] ?? null;
}
@@ -60,8 +60,6 @@ export const VERB_LOOK: Readonly<Record<AssistantChangeVerbKey, VerbLook>> = {
addReservation: { Icon: Ticket, tone: 'success', labelKey: 'assistant.change.verb.addReservation' },
importBooking: { Icon: Ticket, tone: 'success', labelKey: 'assistant.change.verb.importBooking' },
rememberNote: { Icon: NotebookPen, tone: 'info', labelKey: 'assistant.change.verb.rememberNote' },
addTour: { Icon: MapPinPlus, tone: 'success', labelKey: 'assistant.change.verb.addTour' },
updateTour: { Icon: PencilLine, tone: 'info', labelKey: 'assistant.change.verb.updateTour' },
importTour: { Icon: Plus, tone: 'success', labelKey: 'assistant.change.verb.importTour' },
genericCreate: { Icon: Plus, tone: 'success', labelKey: 'assistant.change.verb.genericCreate' },
genericUpdate: { Icon: PencilLine, tone: 'info', labelKey: 'assistant.change.verb.genericUpdate' },
+3
View File
@@ -94,6 +94,9 @@ function check(argv) {
(entry ? `its baseline is ${entry}. ` : 'a file without a baseline entry may have none. ') +
'Run npx tsc -p tsconfig.strict.json --noEmit to see them; narrow the null case or type the parameter.',
);
// The first few in the log too, so a red CI job names them without a local run.
const shown = output.split('\n').filter((line) => line.startsWith(`${file}(`));
for (const line of shown.slice(0, 5)) console.error(` ${line.trim()}`);
}
const stale = staleCounts(baseline, counts);
reportStale(stale, { file: 'strict-baseline.json', command: 'lint:strict', root: serverDir, error: console.error });
@@ -86,6 +86,8 @@ export class PhotoSignalsService implements OnModuleDestroy {
* answer what is stored for them too, and the missing ones join the line
* behind the others, neither waited for nor counted: a caller asking about a
* few photos of a large gallery gets those measured first.
*
* @txIndependent each photo is measured off the event loop and stored on its own; one photo's row is complete alone.
*/
async signalsFor(
photoIds: readonly number[],
@@ -127,6 +129,11 @@ export class PhotoSignalsService implements OnModuleDestroy {
return done;
}
/**
* Starts measuring the next photos in line, a few at a time.
*
* @txIndependent one measurement per photo, each stored by itself after a worker answered.
*/
private pump(): void {
while (this.active < PARALLEL_FETCHES) {
const photoId = this.waiting.shift();