# Scratchpad — Contract Auto-Renewal and Renewals Queue - Plan slug: `contract-auto-renewal-and-renewals-queue` - Created: `2026-02-21` ## What This Is Rolling implementation memory for renewal settings + actionable renewals queue + automation ticketing. ## Decisions - (2026-02-21) Build an **actionable queue** (not read-only report). - (2026-02-21) Ship **both** dashboard entry and full queue page (`Client Contracts` widget + `Renewals` tab). - (2026-02-21) Primary operational date is **renewal decision due date**. - (2026-02-21) Due-date behavior is configurable with **tenant defaults + optional per-contract override**. - (2026-02-21) Default automation target at due date: **create internal ticket**. - (2026-02-21) Minimum queue actions for v1: `Mark renewing`, `Mark non-renewing`, `Create renewal draft`, `Snooze`. - (2026-02-21) Default queue horizon: **90 days**, grouped `0-30`, `31-60`, `61-90`. - (2026-02-21) Queue includes **fixed-term + evergreen anniversaries**. - (2026-02-21) `Mark renewing` should **auto-create renewal draft** and open it. - (2026-02-21) Release approach: **single release** scope. - (2026-02-21) Automation runtime note: support **pg-boss for on-prem** and **Temporal for hosted/EE**. ## Discoveries / Constraints - (2026-02-21) Runtime selection already exists in `server/src/lib/jobs/JobRunnerFactory.ts` with config/env-based choice and fallback behavior; default is pg-boss unless configured otherwise. - (2026-02-21) Existing scheduled jobs in `server/src/lib/jobs/initializeScheduledJobs.ts` explicitly branch for enterprise/temporal behavior in some paths; renewal automation should follow same compatibility pattern. - (2026-02-21) Contract lifecycle already emits `CONTRACT_CREATED` and `CONTRACT_RENEWAL_UPCOMING` in both `packages/clients/src/actions/clientContractActions.ts` and `packages/billing/src/actions/contractWizardActions.ts`. - (2026-02-21) `CONTRACT_RENEWAL_UPCOMING` computation today is window-based (`DEFAULT_CONTRACT_RENEWAL_UPCOMING_WINDOW_DAYS = 30`) in `shared/workflow/streams/domainEventBuilders/contractEventBuilders.ts`; queue design requires broader 90-day horizon and due-date semantics. - (2026-02-21) Existing contract expiration report is currently `end_date`-driven (`packages/billing/src/actions/contractReportActions.ts`, `server/src/lib/reports/definitions/contracts/expiration.ts`). - (2026-02-21) Billing settings already provide tenant defaults in `default_billing_settings` with client override pattern in `client_billing_settings`; actions in `packages/billing/src/actions/billingSettingsActions.ts` and shared helpers in `shared/billingClients/billingSettings.ts` are reusable design patterns. - (2026-02-21) Billing UI insertion points are clear: - tabs config: `packages/billing/src/components/billing-dashboard/billingTabsConfig.ts` - tab content host: `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx` - queue/widget host: `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx` - wizard basics: `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx` - (2026-02-21) Contract assignment data shape in `server/src/interfaces/contract.interfaces.ts` is assignment-level and suitable for renewal metadata on `IClientContract`. ## Commands / Runbooks - (2026-02-21) Inspect billing dashboard contract files: - `rg -n "ContractWizard|ClientContractsTab|billingTabsConfig|ContractBasicsStep" packages/billing/src/components/billing-dashboard` - (2026-02-21) Inspect runtime selection + scheduling: - `rg -n "JobRunnerFactory|initializeScheduledJobs|EDITION|JOB_RUNNER_TYPE" server/src/lib/jobs` - (2026-02-21) Inspect contract renewal event publishing: - `rg -n "CONTRACT_RENEWAL_UPCOMING|computeContractRenewalUpcoming" packages/billing packages/clients shared/workflow` - (2026-02-21) Validate plan artifacts: - `python3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-02-21-contract-auto-renewal-and-renewals-queue` ## Links / References - Key plan path: `ee/docs/plans/2026-02-21-contract-auto-renewal-and-renewals-queue` - Runtime selection: `server/src/lib/jobs/JobRunnerFactory.ts` - Scheduled job init: `server/src/lib/jobs/initializeScheduledJobs.ts` - Job scheduler infra: `server/src/lib/jobs/jobScheduler.ts` - Renewal event builders: `shared/workflow/streams/domainEventBuilders/contractEventBuilders.ts` - Contract wizard save path: `packages/billing/src/actions/contractWizardActions.ts` - Client contract actions: `packages/clients/src/actions/clientContractActions.ts` - Billing settings actions: `packages/billing/src/actions/billingSettingsActions.ts` - Billing settings shared helpers: `shared/billingClients/billingSettings.ts` - Billing dashboard tabs host: `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx` - Client contracts tab: `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx` - Wizard basics step: `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx` ## Implementation Log - (2026-02-21) Completed `F001`. - Added renewal fields to `ContractWizardData` in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`: - `renewal_mode?: 'none' | 'manual' | 'auto'` - `notice_period_days?: number` - `renewal_term_months?: number` - `use_tenant_renewal_defaults?: boolean` - Rationale: establish typed wizard-state shape early so subsequent UI rendering, defaults/hydration, validation, and submission features can build on stable field names. - (2026-02-21) Completed `T001`. - Added `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`. - Test covers type-level contract for the four renewal fields and validates the allowed `renewal_mode` domain values. - Runbook: - `npx vitest run packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` - (2026-02-21) Completed `F002`. - Added `createDefaultContractWizardData()` in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`. - Renewal defaults for new contracts now initialize as: - `renewal_mode: 'manual'` - `notice_period_days: 30` - `renewal_term_months: undefined` - `use_tenant_renewal_defaults: true` - Updated wizard initialization/reset paths to use the shared factory, keeping default behavior deterministic across first render, open/reset, and edit-merge flows. - (2026-02-21) Completed `T002`. - Extended `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` with default-state assertions using `createDefaultContractWizardData()`. - Validates default renewal state for new contracts: mode `manual`, notice `30`, no term months, tenant-default toggle enabled. - (2026-02-21) Completed `F003`. - Extended `DraftContractWizardData` in `packages/billing/src/actions/contractWizardActions.ts` with renewal fields. - Updated `getDraftContractForResume` to hydrate renewal settings from `client_contracts`: - normalized `renewal_mode` (`none|manual|auto`) - sanitized integer `notice_period_days` (non-negative) - sanitized positive integer `renewal_term_months` - hydrated `use_tenant_renewal_defaults` when boolean - Rationale: resumed drafts now carry renewal metadata into `editingContract` so wizard state merge can restore renewal settings. - (2026-02-21) Completed `T003`. - Added `packages/billing/src/actions/contractWizardActions.renewalDraftResumeWiring.test.ts`. - Test validates: - renewal fields are present on `DraftContractWizardData`, - `getDraftContractForResume` returns hydrated renewal values, - numeric renewal values are sanitized before payload return. - (2026-02-21) Completed `F004`. - Added `buildInitialContractWizardData(editingContract)` in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`. - Edit-mode initialization now explicitly normalizes renewal fields during hydration: - validates `renewal_mode` domain, - normalizes non-negative `notice_period_days`, - normalizes positive `renewal_term_months`, - preserves explicit boolean `use_tenant_renewal_defaults`. - Wired both initial state and open-effect initialization to use this shared edit-hydration path. - (2026-02-21) Completed `T004`. - Extended `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts`. - Added assertions proving edit hydration path uses `buildInitialContractWizardData(editingContract)` and renewal normalization helpers for mode/notice/term. - (2026-02-21) Completed `F005`. - Added a fixed-term renewal UI container to `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`. - New `Renewal Settings` card renders only when `data.end_date` is present (`data-automation-id=\"renewal-settings-fixed-term-card\"`). - (2026-02-21) Completed `T005`. - Added `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts`. - Test asserts fixed-term card conditional wiring on `data.end_date` and verifies the automation id/heading token. - (2026-02-21) Completed `F006`. - Added evergreen variant UI in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`. - New `Evergreen Review Settings` card renders when `data.end_date` is absent (`data-automation-id=\"renewal-settings-evergreen-card\"`). - (2026-02-21) Completed `T006`. - Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts` with evergreen-card assertions. - Verifies absent-end-date branch and `renewal-settings-evergreen-card` wiring. - (2026-02-21) Completed `F007`. - Added renewal mode selector UI to both fixed-term and evergreen renewal cards in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`. - Options now explicitly include `none`, `manual`, and `auto`, bound to `data.renewal_mode`. - (2026-02-21) Completed `T007`. - Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts`. - Added assertions for `renewalModeOptions` values (`none|manual|auto`) and `updateData` binding back to `renewal_mode`. - (2026-02-21) Completed `F008`. - Added `Notice Period (Days)` input to both renewal cards in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`. - Input is conditionally rendered only when renewal mode is enabled (`manual` or `auto`), with non-negative integer coercion on change. - (2026-02-21) Completed `T008`. - Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts` with notice-period assertions. - Confirms `isRenewalEnabled` gate and both notice input IDs (`fixed` and `evergreen`) are present in the renewal-enabled branch. - (2026-02-21) Completed `F009`. - Added auto-renew specific `Renewal Term (Months)` inputs to fixed-term and evergreen renewal cards in `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.tsx`. - Input is gated by `isAutoRenew` and writes sanitized positive integer values to `renewal_term_months`. - (2026-02-21) Completed `F010`. - Confirmed auto-renew term controls are hidden unless `effectiveRenewalMode === 'auto'` via `isAutoRenew` conditional rendering in `ContractBasicsStep.tsx`. - (2026-02-21) Completed `T009`. - Extended `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ContractBasicsStep.renewalCards.test.ts` with auto-term wiring assertions. - Verifies both term input IDs and positive-integer assignment path for `renewal_term_months`. - (2026-02-21) Completed `T010`. - Added explicit `isAutoRenew` gating assertions in `ContractBasicsStep.renewalCards.test.ts`. - Verifies auto-specific term controls are conditionally rendered only in `auto` mode. - (2026-02-21) Completed `F011`. - Added step-0 wizard validation in `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.tsx`: - if `end_date` is set and `renewal_mode` is missing, progression is blocked with inline error. - (2026-02-21) Completed `F012`. - Added notice-period validation bounds in `ContractWizard.tsx` (`MIN_NOTICE_PERIOD_DAYS=0`, `MAX_NOTICE_PERIOD_DAYS=3650`). - Step-0 validation now requires notice period to be an integer and within bounds whenever renewal mode is enabled. - (2026-02-21) Completed `F013`. - Added step-0 validation rule in `ContractWizard.tsx` requiring `renewal_term_months` to be a positive integer when provided. - (2026-02-21) Completed `F014`. - Renewal validation errors from step-0 rules (`F011`-`F013`) now surface through the wizard’s existing inline step error panel before progression. - (2026-02-21) Completed `T011`. - Extended `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` with assertions for required renewal mode when `end_date` is set. - (2026-02-21) Completed `T012`. - Marked covered by the same `ContractWizard.renewalFields.test.ts` additions that assert notice-period integer/bounds validation wiring. - (2026-02-21) Completed `T013`. - Marked covered by existing `ContractWizard.renewalFields.test.ts` assertions for positive renewal-term validation when value is provided. - (2026-02-21) Completed `T014`. - Marked covered by existing `ContractWizard.renewalFields.test.ts` assertion that inline step error rendering (`errors[currentStep]`) is present for renewal validation failures. - (2026-02-21) Completed `F015`. - Extended `ContractBasicsStep` summary alert to include renewal preview fields: - renewal mode label, - notice period (for renewal-enabled modes), - renewal term months (auto-renew mode). - (2026-02-21) Completed `F016`. - Extended `ReviewContractStep` “Contract Basics” card to preview renewal fields before submit: - renewal mode, - notice period, - renewal term (auto mode). - (2026-02-21) Completed `F017`. - Added renewal fields to `ClientContractWizardSubmission` (`packages/billing/src/actions/contractWizardActions.ts`). - Updated `buildSubmissionData()` in `ContractWizard.tsx` to include renewal mode, notice period, renewal term, and tenant-default toggle in outgoing wizard payload. - (2026-02-21) Completed `F018`. - Updated `createClientContractFromWizard` insert path for `client_contracts` to persist renewal fields. - Added schema-compat guards (`hasColumn`) so renewal columns are written when available without breaking pre-migration environments. - (2026-02-21) Completed `T015`. - Extended `ContractBasicsStep.renewalCards.test.ts` to assert renewal mode/notice/term rows are present in the Contract Basics summary preview. - (2026-02-21) Completed `T016`. - Added `packages/billing/src/components/billing-dashboard/contracts/wizard-steps/ReviewContractStep.renewalPreview.test.ts`. - Test covers renewal preview rows and mode-gated rendering conditions in the review step. - (2026-02-21) Completed `T017`. - Extended `ContractWizard.renewalFields.test.ts` to assert `buildSubmissionData()` includes all renewal fields in outgoing wizard payload. - (2026-02-21) Completed `T018`. - Extended `contractWizardActions.renewalDraftResumeWiring.test.ts` to assert draft/client save path writes renewal fields into `client_contracts` with schema-guarded `hasColumn` checks. - (2026-02-21) Completed `F019`. - Extended tenant default billing settings model surface in `packages/billing/src/actions/billingSettingsActions.ts` and `server/src/interfaces/billing.interfaces.ts` with renewal-default fields (including default renewal mode) using schema-guarded writes for compatibility. - (2026-02-21) Completed `F020`. - Included `defaultNoticePeriodDays` mapping (`default_notice_period_days`) in tenant default billing settings model and guarded write path. - (2026-02-21) Completed `F021`. - Included `renewalDueDateActionPolicy` mapping (`renewal_due_date_action_policy`) with normalized fallback in tenant billing settings model. - (2026-02-21) Completed `F022`. - Included tenant default renewal ticket board field mapping (`renewal_ticket_board_id`) in billing settings model/read-write path. - (2026-02-21) Completed `F023`. - Included tenant default renewal ticket status field mapping (`renewal_ticket_status_id`) in billing settings model/read-write path. - (2026-02-21) Completed `F024`. - Included tenant default renewal ticket priority field mapping (`renewal_ticket_priority`) in billing settings model/read-write path. - (2026-02-21) Completed `F025`. - Included tenant default renewal ticket assignee field mapping (`renewal_ticket_assignee_id`) in billing settings model/read-write path. - (2026-02-21) Completed `F026`. - `getDefaultBillingSettings` now returns renewal default fields (mode, notice days, due-date policy, ticket routing defaults) with deterministic fallbacks. - (2026-02-21) Completed `F027`. - `updateDefaultBillingSettings` now writes renewal default fields via schema-guarded update/insert payloads. - (2026-02-21) Completed `T019`. - Added `packages/billing/src/actions/billingSettingsActions.renewalDefaultsWiring.test.ts` and marked renewal-mode model coverage. - (2026-02-21) Completed `T020`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `defaultNoticePeriodDays`. - (2026-02-21) Completed `T021`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalDueDateActionPolicy`. - (2026-02-21) Completed `T022`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketBoardId`. - (2026-02-21) Completed `T023`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketStatusId`. - (2026-02-21) Completed `T024`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketPriority`. - (2026-02-21) Completed `T025`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `renewalTicketAssigneeId`. - (2026-02-21) Completed `T026`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for `getDefaultBillingSettings` renewal default response mapping. - (2026-02-21) Completed `T027`. - Covered by existing `billingSettingsActions.renewalDefaultsWiring.test.ts` assertions for schema-guarded renewal default persistence in update writes. - (2026-02-21) Completed `T028`. - Extended renewal UI/source tests to assert `Use Tenant Renewal Defaults` toggle controls and payload field wiring (`use_tenant_renewal_defaults`). - (2026-02-21) Completed `T029`. - Covered by `ContractWizard.renewalFields.test.ts` assertions that tenant defaults are applied in submission resolution when toggle is enabled. - (2026-02-21) Completed `T030`. - Covered by `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` assertion: - `prefers explicit contract override values when tenant defaults are disabled`. - Validation run: - `cd server && npx vitest run --coverage.enabled=false ../packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` - (2026-02-21) Completed `T031`. - Covered by `packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` assertion: - `uses deterministic fallback precedence for partial override/default state`. - Validation run: - `cd server && npx vitest run --coverage.enabled=false ../packages/billing/src/components/billing-dashboard/contracts/ContractWizard.renewalFields.test.ts` - (2026-02-21) Completed `F028`. - Added explicit `Use Tenant Renewal Defaults` toggle controls to both fixed-term and evergreen renewal settings cards in `ContractBasicsStep.tsx`, bound to `use_tenant_renewal_defaults`. - (2026-02-21) Completed `F029`. - Updated `buildSubmissionData()` in `ContractWizard.tsx` to resolve renewal mode + notice period from tenant defaults when `use_tenant_renewal_defaults` is enabled. - (2026-02-21) Completed `F030`. - Submission resolution now prefers explicit contract-level renewal values when `use_tenant_renewal_defaults` is disabled. - (2026-02-21) Completed `F031`. - Implemented deterministic renewal fallback order in submission resolution: - explicit contract values (when overrides enabled), - tenant defaults, - hard defaults (`manual`, `30`). - (2026-02-21) Completed `F032`. - Extended contract-assignment read APIs to expose normalized/effective renewal settings in both shared and clients data-access layers: - `shared/billingClients/clientContracts.ts` - `packages/clients/src/models/clientContract.ts` - Added schema-guarded tenant-default joins (`default_billing_settings`) for read paths and computed: - `effective_renewal_mode` - `effective_notice_period_days` - Added type surface fields on `IClientContract` in: - `packages/types/src/interfaces/contract.interfaces.ts` - `server/src/interfaces/contract.interfaces.ts` - Validation run: - `npm -w @alga-psa/shared run typecheck` - `npm -w @alga-psa/clients run typecheck` - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F033`. - Added fixed-term `decision_due_date` computation in assignment normalization paths: - `shared/billingClients/clientContracts.ts` - `packages/clients/src/models/clientContract.ts` - Formula implemented with date-only semantics for fixed-term contracts: - `decision_due_date = end_date - effective_notice_period_days` - Added `decision_due_date` to contract interfaces: - `packages/types/src/interfaces/contract.interfaces.ts` - `server/src/interfaces/contract.interfaces.ts` - Expanded test coverage in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`. - (2026-02-21) Completed `F034`. - Added evergreen annual-review anchor computation based on contract start-date anniversary rules. - New shared helper: - `computeNextEvergreenReviewAnchorDate` in `shared/billingClients/clientContracts.ts` - Exposed normalized field on active evergreen assignments: - `evergreen_review_anchor_date` - Mirrored logic in clients model read normalization for parity: - `packages/clients/src/models/clientContract.ts` - Expanded tests in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`. - (2026-02-21) Completed `F035`. - Added evergreen `decision_due_date` computation from annual anchor minus effective notice period. - New shared helper: - `computeEvergreenDecisionDueDate` in `shared/billingClients/clientContracts.ts` - Applied in both read normalization paths (shared + clients model) so evergreen assignments now expose date-only `decision_due_date`. - Expanded deterministic date-math coverage in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`. - (2026-02-21) Completed `F036`. - Confirmed and codified date-only normalization for `decision_due_date` math using `normalizeDateOnly` + UTC midnight subtraction paths. - Added regression test proving timestamp `end_date` inputs are normalized to date-only before subtraction: - `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F037`. - Confirmed `decision_due_date` recalculates from current assignment state when fixed-term `end_date` changes. - Added regression coverage: - `recomputes fixed-term decision_due_date when end_date changes` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F038`. - Confirmed fixed-term `decision_due_date` recalculates when notice period changes. - Added regression coverage: - `recomputes fixed-term decision_due_date when notice period changes` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F039`. - Made `decision_due_date` generation renewal-mode-aware in read normalization: - mode `none` suppresses due date generation for non-evergreen entries. - Added regression coverage for mode transitions: - `recomputes decision_due_date when renewal mode changes between none/manual/auto` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F040`. - Confirmed evergreen `decision_due_date` recomputes when anniversary anchor basis changes (start-date basis change). - Added deterministic coverage: - `recomputes evergreen decision_due_date when anniversary anchor basis changes` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F041`. - Added lifecycle suppression in due-date normalization: - no `decision_due_date` generation for inactive, terminated, or expired assignment/contract lifecycle state. - Included `contract_status` from joined contract reads in shared/clients assignment APIs to enforce lifecycle gating. - Added regression test: - `skips decision_due_date generation for inactive/terminated assignments` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F042`. - Verified suppression path for `renewal_mode = none` when no evergreen anchor is available (e.g. fixed-term assignment) remains enforced. - Covered by existing regression test: - `recomputes decision_due_date when renewal mode changes between none/manual/auto` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F043`. - Added derived per-cycle dedupe key in read normalization: - `renewal_cycle_key` (`fixed-term:` or `evergreen:`) - Exposed in both shared and clients assignment APIs plus contract interfaces. - Added regression coverage: - `creates one renewal_cycle_key per computed contract cycle for deduplication` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F044`. - Added deterministic dedupe guard for active assignment rows by composite key: - `tenant + client_contract_id + renewal_cycle_key` - Applied dedupe in list read APIs: - `shared/billingClients/clientContracts.ts` - `packages/clients/src/models/clientContract.ts` - Added regression test: - `deduplicates active rows by tenant + client_contract_id + renewal_cycle_key` - in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F045`. - Added explicit cycle boundary fields in normalization: - `renewal_cycle_start` - `renewal_cycle_end` - Fixed-term boundaries map directly to assignment `start_date`/`end_date`. - Evergreen boundaries now use annual cycle bounds helper: - `computeEvergreenCycleBounds` in `shared/billingClients/clientContracts.ts` - Added deterministic coverage in `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts`. - (2026-02-21) Completed `F046`. - Added derived `days_until_due` field to assignment normalization and contract interfaces. - New date-only helper: - `computeDaysUntilDate` in `shared/billingClients/clientContracts.ts` - Added deterministic coverage for positive/negative day deltas and normalized row field presence in: - `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F047`. - Added clamp bounds to `days_until_due` derivation to preserve overdue visibility while preventing extreme negative/positive corruption: - `MAX_ABSOLUTE_DAYS_UNTIL_DUE = 36500` - Applied in shared and clients normalization helpers. - Added deterministic clamp coverage in: - `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - (2026-02-21) Completed `F048`. - Added `renewals` tab value to billing tab union/config metadata in: - `packages/billing/src/components/billing-dashboard/billingTabsConfig.ts` - Added tab definition (`label=Renewals`, `href=/msp/billing?tab=renewals`) and icon mapping. - Added coverage: - `packages/billing/tests/billingTabsConfig.renewals.test.ts` - (2026-02-21) Completed `F049`. - Added `Tabs.Content value=\"renewals\"` route to billing dashboard tab host in: - `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx` - Added initial placeholder content for the renewals route host. - Added route-wiring coverage: - `packages/billing/tests/BillingDashboard.renewalsRoute.test.ts` - (2026-02-21) Completed `F050`. - Added dedicated renewals queue page component: - `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx` - Updated `BillingDashboard` renewals route to render ``. - Added component + wiring coverage: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - `packages/billing/tests/BillingDashboard.renewalsRoute.test.ts` - (2026-02-21) Completed `F051`. - Added server action to load renewal queue rows: - `packages/billing/src/actions/renewalsQueueActions.ts` - Renewals page now calls `listRenewalQueueRows()` on mount via `useEffect` and renders loading/empty/error/data states. - Exported renewals queue actions via: - `packages/billing/src/actions/index.ts` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F052`. - Added default 90-day horizon behavior to renewals queue loading: - `DEFAULT_RENEWALS_HORIZON_DAYS = 90` in `renewalsQueueActions.ts` - server-side filtering for `days_until_due` in range `[0, horizonDays]` - Updated renewals UI copy to indicate default horizon window. - Extended wiring coverage in: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F053`. - Added renewals queue bucket quick filters in `RenewalsQueueTab`: - `All`, `0-30 Days`, `31-60 Days`, `61-90 Days` - Implemented client-side bucket filtering against `days_until_due`. - Extended component coverage in: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F054`. - Added owner filter UI + behavior in `RenewalsQueueTab`: - owner options derive from queue row `assigned_to` values with `unassigned` fallback. - Extended queue row shape from server action with `assigned_to`. - Added wiring coverage updates in: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - (2026-02-21) Completed `F055`. - Added queue status mapping + filter support for: - `pending`, `renewing`, `non_renewing`, `snoozed`, `completed` - Added status filter UI + filtering behavior in `RenewalsQueueTab`. - Extended action/component wiring coverage in: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F056`. - Added renewal mode filter support in queue UI for: - `none`, `manual`, `auto` - Queue row mapping already includes `effective_renewal_mode`; UI filtering now applies this dimension. - Extended action/component wiring coverage in: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F057`. - Added contract type filter support in queue UI for: - `fixed-term`, `evergreen` - Filter operates on queue row `contract_type`. - Extended component wiring coverage in: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F058`. - Enforced default queue sort by `decision_due_date` ascending in renewals list action. - Sorting now occurs after normalization/horizon filtering in: - `packages/billing/src/actions/renewalsQueueActions.ts` - Added wiring coverage update in: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - (2026-02-21) Completed `F059`. - Added days-remaining visual badge state logic in queue rows: - `overdue`, `due-soon`, `upcoming` - Rendering now surfaces overdue and due-soon emphasis states via row badge styles. - Added component coverage update in: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F060`. - Added `Upcoming Renewals` summary widget to `ClientContractsTab` with queue-derived total count. - Widget data source now loads via `listRenewalQueueRows()` during tab fetch flow. - Added coverage: - `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts` - (2026-02-21) Completed `F061`. - Updated `Upcoming Renewals` widget to display 90-day bucket counts: - `0-30`, `31-60`, `61-90` - Counts now derive from renewal queue row `days_until_due`. - Added coverage update in: - `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts` - (2026-02-21) Completed `F062`. - Added widget-to-queue navigation with preserved bucket context in: - `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx` - Bucket count badges now route to: - `/msp/billing?tab=renewals&bucket=0-30|31-60|61-90` - Added queue hydration from URL bucket query param in: - `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx` - Added/updated coverage in: - `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F063`. - Added queue-to-widget refresh wiring in billing dashboard: - `packages/billing/src/components/billing-dashboard/BillingDashboard.tsx` - `BillingDashboard` now increments `renewalsQueueRefreshTrigger` when renewals queue refreshes after mutation pathways. - Passed refresh trigger into `ClientContractsTab` so upcoming renewals bucket counts are recomputed. - `RenewalsQueueTab` now accepts `onQueueMutationComplete` and emits it after successful queue row reloads: - `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx` - Added wiring coverage in: - `packages/billing/tests/BillingDashboard.renewalsRoute.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts` - (2026-02-21) Completed `F064`. - Defined centralized renewal queue status enum in shared contract interfaces: - `packages/types/src/interfaces/contract.interfaces.ts` - `server/src/interfaces/contract.interfaces.ts` - Added renewal work-item interface model (`IClientContractRenewalWorkItem`) with `status: RenewalWorkItemStatus`. - Updated queue row model/status normalization to consume `RenewalWorkItemStatus` from shared types: - `packages/billing/src/actions/renewalsQueueActions.ts` - Updated wiring coverage: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts` - `npm -w @alga-psa/server run typecheck` (workspace alias not present in root workspaces) - (2026-02-21) Completed `F065`. - Added queue mutation action to transition pending work items to renewing: - `markRenewalQueueItemRenewing(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts` - Transition behavior: - validates required `clientContractId` - enforces tenant-scoped active row lookup - requires current status to resolve as `pending` - updates status to `renewing` and writes `updated_at` - Added mutation response payload shape: - `RenewalQueueMutationResult` - Added/updated wiring coverage: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts` - (2026-02-21) Completed `F066`. - Added queue mutation action to transition pending work items to non-renewing: - `markRenewalQueueItemNonRenewing(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts` - Transition behavior mirrors mark-renewing safeguards: - validates required `clientContractId` - verifies status column availability - enforces tenant-scoped active row lookup - requires current status to resolve as `pending` - updates status to `non_renewing` and writes `updated_at` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.markNonRenewing.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts` - (2026-02-21) Completed `F067`. - Added renewal draft action for eligible queue entries: - `createRenewalDraftForQueueItem(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts` - Action behavior: - requires non-empty `clientContractId` - resolves eligible statuses to `pending|renewing` only - creates a new draft contract + draft client contract assignment - reuses existing linked draft when `created_draft_contract_id` is already present and valid - links original row via `created_draft_contract_id` when column exists - Added response type: - `RenewalDraftCreationResult` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.createDraft.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts` - (2026-02-21) Completed `F068`. - Added snooze mutation action: - `snoozeRenewalQueueItem(clientContractId, snoozedUntil)` in `packages/billing/src/actions/renewalsQueueActions.ts` - Action behavior: - validates required `clientContractId` + `snoozedUntil` - verifies `status` + `snoozed_until` columns exist - normalizes `snoozed_until` to date-only (`YYYY-MM-DD`) - blocks snoozing from terminal statuses (`completed`, `non_renewing`) - updates status to `snoozed` and returns `RenewalSnoozeResult` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.snooze.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts` - (2026-02-21) Completed `F069`. - Added assign-owner mutation action: - `assignRenewalQueueItemOwner(clientContractId, assignedTo)` in `packages/billing/src/actions/renewalsQueueActions.ts` - Action behavior: - validates required `clientContractId` - allows `assignedTo` as user id string or `null` (unassign) - verifies `status` + `assigned_to` columns exist - updates `assigned_to` with tenant-scoped row filtering - returns `RenewalAssignmentResult` with current status + updated timestamp - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.assignOwner.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.assignOwner.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts` - (2026-02-21) Completed `F070`. - Added automatic unsnooze transition during queue list refresh in: - `packages/billing/src/actions/renewalsQueueActions.ts` - Behavior: - checks `status` + `snoozed_until` columns - moves eligible rows from `snoozed` to `pending` when `snoozed_until <= today` - clears `snoozed_until` and updates `updated_at` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.unsnooze.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.unsnooze.wiring.test.ts tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts` - (2026-02-21) Completed `F071`. - Added actor audit persistence helper flow in renewal queue actions: - `resolveActorUserId(user)` - `withActionActor(updateData, hasLastActionByColumn, actorUserId)` - User-initiated queue mutations now persist `last_action_by` when column exists: - `markRenewalQueueItemRenewing` - `markRenewalQueueItemNonRenewing` - `createRenewalDraftForQueueItem` - `snoozeRenewalQueueItem` - `assignRenewalQueueItemOwner` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.actorAudit.wiring.test.ts` - Updated wiring expectations for mark actions: - `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts` - `packages/billing/tests/renewalsQueueActions.markNonRenewing.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts` - (2026-02-21) Completed `F072`. - Added timestamp audit persistence helper in renewal queue actions: - `withActionTimestamp(updateData, hasLastActionAtColumn, actionAt)` - User-initiated queue mutations now persist `last_action_at` when column exists: - `markRenewalQueueItemRenewing` - `markRenewalQueueItemNonRenewing` - `createRenewalDraftForQueueItem` - `snoozeRenewalQueueItem` - `assignRenewalQueueItemOwner` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.timestampAudit.wiring.test.ts` - Updated wiring expectations for mark/actor tests: - `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts` - `packages/billing/tests/renewalsQueueActions.markNonRenewing.wiring.test.ts` - `packages/billing/tests/renewalsQueueActions.actorAudit.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts` - (2026-02-21) Completed `F073`. - Added optional queue action note support across mutation actions: - `markRenewalQueueItemRenewing(..., note?)` - `markRenewalQueueItemNonRenewing(..., note?)` - `createRenewalDraftForQueueItem(..., note?)` - `snoozeRenewalQueueItem(..., note?)` - `assignRenewalQueueItemOwner(..., note?)` - Added note helpers: - `normalizeActionNote(note)` - `withActionNote(updateData, hasLastActionNoteColumn, note)` - Mutations now persist `last_action_note` when column exists and note is non-empty. - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.noteAudit.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.noteAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts` - (2026-02-21) Completed `F074`. - Added explicit completed-status guard in automatic unsnooze pending-transition path: - `packages/billing/src/actions/renewalsQueueActions.ts` - Unsnooze update now includes: - `.andWhereNot('status', 'completed')` - This ensures completed work items never implicitly transition back to pending without an explicit reopen flow. - Updated coverage: - `packages/billing/tests/renewalsQueueActions.unsnooze.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.unsnooze.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts` - (2026-02-21) Completed `F075`. - Added explicit override guard to renewing transition: - `markRenewalQueueItemRenewing` now rejects `previousStatus === 'non_renewing'` with an override-required error. - This preserves strict non-renewal intent unless a dedicated override flow is implemented. - Updated wiring coverage: - `packages/billing/tests/renewalsQueueActions.markRenewing.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewing.wiring.test.ts` - (2026-02-21) Completed `F076`. - Added future-date enforcement for snooze action validation: - `snoozeRenewalQueueItem` now rejects `snoozedUntil <= today` - Added explicit error path: - `Snooze target date must be in the future` - Updated wiring coverage: - `packages/billing/tests/renewalsQueueActions.snooze.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.snooze.wiring.test.ts tests/renewalsQueueActions.unsnooze.wiring.test.ts` - (2026-02-21) Completed `F077`. - Added row-level action availability model based on effective queue status: - `RenewalQueueAction` union - `getAvailableActionsForStatus(status)` in `packages/billing/src/actions/renewalsQueueActions.ts` - `listRenewalQueueRows` now returns `available_actions` for each row. - Renewals queue UI now surfaces available actions per row: - `Actions: {row.available_actions.join(', ')}` in `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx` - Updated coverage: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F078`. - Added queue row action controls for: - `Mark renewing` - `Mark non-renewing` - Implemented optimistic in-flight UI behavior in `RenewalsQueueTab`: - per-row pending state map (`pendingRowActions`) - immediate optimistic status/action updates before server response - in-row pending indicator (`Updating action...`) - action buttons disabled while row mutation is in-flight - Mutation handlers call server actions: - `markRenewalQueueItemRenewing` - `markRenewalQueueItemNonRenewing` - Updated coverage: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts` - (2026-02-21) Completed `F079`. - Added targeted row refresh helper after successful mutation responses: - `refreshQueueRowFromServer(clientContractId)` in `RenewalsQueueTab` - Success path now refreshes only the affected row from server state: - `await refreshQueueRowFromServer(rowId)` - Fallback path still supports full refresh when row cannot be resolved. - Updated coverage: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F080`. - Extended renewal queue row model with draft linkage: - `created_draft_contract_id?: string | null` in `RenewalQueueRow` - Queue list action now maps draft linkage field from row source: - `created_draft_contract_id: (row as any).created_draft_contract_id ?? null` - Renewals queue UI now shows linked draft id when present: - `Draft contract: {row.created_draft_contract_id}` - Updated coverage: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts` - (2026-02-21) Completed `F081`. - Extended renewal queue row model with ticket linkage: - `created_ticket_id?: string | null` in `RenewalQueueRow` - Queue list action now maps ticket linkage: - `created_ticket_id: (row as any).created_ticket_id ?? null` - Renewals queue UI now shows linked ticket id when present: - `Ticket: {row.created_ticket_id}` - Updated coverage: - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/RenewalsQueueTab.component.test.ts` - (2026-02-21) Completed `F082`. - Added activation-confirmed completion action: - `completeRenewalQueueItemForActivation(clientContractId, activatedContractId?, note?)` - in `packages/billing/src/actions/renewalsQueueActions.ts` - Completion rules: - source work item must be `renewing` - target renewal contract must exist with `status = active` - on success, work item transitions to `completed` with audit metadata - Added result type: - `RenewalCompletionResult` - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.completeOnActivation.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.completeOnActivation.wiring.test.ts tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.createDraft.wiring.test.ts` - (2026-02-21) Completed `F083`. - Added non-renewal finalization completion action: - `completeRenewalQueueItemForNonRenewal(clientContractId, note?)` - in `packages/billing/src/actions/renewalsQueueActions.ts` - Completion rules: - source work item must be `non_renewing` - on success, work item transitions to `completed` with audit metadata - Added wiring coverage: - `packages/billing/tests/renewalsQueueActions.completeNonRenewal.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.completeNonRenewal.wiring.test.ts tests/renewalsQueueActions.completeOnActivation.wiring.test.ts` - (2026-02-21) Completed `F084`. - Added a scheduled renewal queue processor job handler: - `processRenewalQueueHandler(data)` in `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts` - scans active contracts whose `decision_due_date` falls within `today..horizonDays` - defaults horizon to `90` days and validates `tenantId` - Registered new job name and scheduling helpers: - pg-boss handler registration in `server/src/lib/jobs/index.ts` - recurring scheduling helper `scheduleRenewalQueueProcessingJob(...)` - tenant startup scheduling hook in `server/src/lib/jobs/initializeScheduledJobs.ts` (daily at `0 5 * * *`) - abstraction-layer handler registration + available handler list in `server/src/lib/jobs/registerAllHandlers.ts` - Added wiring test under included Vitest paths: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F085`. - Extended renewal queue processor to upsert work-item state for newly eligible cycles: - processor now loads active contract assignments, normalizes effective renewal state, and filters by computed `decision_due_date` within `today..horizon` - upserts `decision_due_date`, `renewal_cycle_start`, `renewal_cycle_end`, and `renewal_cycle_key` when drift/new cycle is detected - resets cycle-scoped linkage fields (`created_ticket_id`, `created_draft_contract_id`) when cycle key rolls - normalizes unknown/invalid statuses (or cycle changes) back to `pending` - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F086`. - Scheduled renewal processing now explicitly resolves tenant default due-date action policy: - reads `default_billing_settings.renewal_due_date_action_policy` when available - normalizes policy (`queue_only | create_ticket`) with deterministic fallback to `create_ticket` - During upsert, processor applies tenant policy to work-item rows when contract-level policy column exists: - updates `client_contracts.renewal_due_date_action_policy` to tenant effective value - tracks policy distribution in logs (`queueOnlyPolicyCount`, `createTicketPolicyCount`) - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F087`. - Scheduled renewal processing now applies contract-level due-date policy overrides with deterministic precedence: - resolve `use_tenant_renewal_defaults` (default `true`) - resolve contract-level policy from `client_contracts.renewal_due_date_action_policy` when valid - compute effective policy as: - tenant policy when `use_tenant_renewal_defaults = true` - contract override when defaults are disabled and explicit contract policy exists - tenant fallback when override is missing/invalid - Processor now logs override utilization: - `contractOverridePolicyCount` - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F088`. - Added due-date ticket automation execution in renewal processor: - computes `shouldCreateTicketAtDueDate` for eligible rows where: - effective policy is `create_ticket` - decision due date is due (`<= today`) - no `created_ticket_id` is already linked - builds renewal-context title/description payloads - uses configured renewal routing defaults (board/status/priority/assignee) when present - Processor now persists ticket linkage on success: - `updates.created_ticket_id = createdTicketId` - Added direct ticket-creation fallback path for resilience when workflow action execution is unavailable. - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F089`. - Integrated renewal ticket automation with workflow runtime business action path: - initializes runtime v2 action registry (`initializeWorkflowRuntimeV2`) - resolves and invokes `tickets.create@v1` from `getActionRegistryV2` - validates both input and output schemas via registered action definitions - Retained direct-ticket fallback path when runtime action execution is unavailable/fails to keep automation robust. - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F090`. - Added renewal ticket title builder with explicit client + contract context: - `buildRenewalTicketTitle(row, decisionDueDate)` - title shape: `Renewal Decision Due {date}: {clientName} / {contractName}` - Renewal automation now uses this title for both workflow-action and direct-fallback ticket creation paths. - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F091`. - Added renewal ticket description builder with due-date + renewal-settings context: - `buildRenewalTicketDescription(row, normalized, decisionDueDate)` - includes decision due date, effective renewal mode, effective notice period, and cycle key metadata - Renewal automation now uses this description for workflow-action and direct-fallback ticket creation paths. - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F092`. - Renewal ticket routing now uses effective defaults with tenant/contract precedence: - tenant defaults from `default_billing_settings`: - `renewal_ticket_board_id` - `renewal_ticket_status_id` - `renewal_ticket_priority` - `renewal_ticket_assignee_id` - optional contract-level overrides from `client_contracts` are applied when `use_tenant_renewal_defaults = false` - deterministic fallback to tenant defaults for any missing contract-level routing values - Added processor visibility metric: - `routingOverrideAppliedCount` - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F093`. - Renewal processor now persists ticket linkage on successful automation: - captures ticket id from workflow-action/direct-fallback creation result - writes `created_ticket_id` on the client-contract renewal work item update payload - This makes ticket linkage visible in queue APIs/UI and supports downstream idempotency checks. - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F094`. - Added deterministic renewal ticket idempotency key builder: - shape: `renewal-ticket:{tenantId}:{clientContractId}:{cycleKey}` - Processor now uses this idempotency key for: - workflow runtime `tickets.create` invocation input (`idempotency_key`) - direct fallback ticket attributes (`idempotency_key`) for duplicate-detection context - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F095`. - Added duplicate-prevention lookup before renewal ticket creation: - checks existing `tickets` rows for matching `attributes.idempotency_key` - if found, links existing ticket id to work item and skips create path - Both workflow and direct ticket creation paths now receive shared ticket attributes including idempotency metadata. - Added processor metric: - `duplicateTicketSkipCount` - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F096`. - Renewal processor now records automation failures on work items when ticket creation fails: - reads optional `client_contracts.automation_error` column - writes failure reason on create-path errors - records missing-routing-defaults as explicit automation error for `create_ticket` policy - clears `automation_error` when ticket creation succeeds - Added processor metric: - `automationErrorCount` - Updated wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F097`. - Added manual retry queue action for failed renewal ticket automation: - `retryRenewalQueueTicketCreation(clientContractId)` in `packages/billing/src/actions/renewalsQueueActions.ts` - Retry action behavior: - validates work item + due-date eligibility - resolves effective due-date policy and routing defaults with tenant/contract precedence - reuses cycle idempotency key to avoid duplicates - links existing idempotent ticket when present - otherwise re-attempts ticket creation and updates `created_ticket_id` / `automation_error` - Exposed `automation_error` in renewal queue row payload model. - Updated coverage: - `packages/billing/tests/renewalsQueueActions.retryTicket.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.retryTicket.wiring.test.ts tests/renewalsQueueActions.wiring.test.ts` - (2026-02-21) Completed `F098`. - Queue-only policy behavior is enforced in both automation paths: - scheduled processor only enters ticket-create path when `effectiveDueDateActionPolicy === 'create_ticket'` - manual retry action returns without creating tickets when effective policy is `queue_only` - This preserves queue visibility/workflow without forcing ticket side effects. - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - `packages/billing/tests/renewalsQueueActions.retryTicket.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.retryTicket.wiring.test.ts tests/renewalsQueueActions.wiring.test.ts` - (2026-02-21) Completed `F099`. - Updated contract renewal-upcoming domain-event builders/schemas for queue-compatible semantics: - expanded default window from 30 to 90 days - `computeContractRenewalUpcoming` now supports decision-due date and renewal cycle key inputs - payload now includes: - `decisionDueDate` - `daysUntilDecisionDue` - `renewalCycleKey` - Updated event publishers in: - `packages/billing/src/actions/contractWizardActions.ts` - `packages/clients/src/actions/clientContractActions.ts` - `CONTRACT_RENEWAL_UPCOMING` idempotency keys now prefer cycle-key/decision-due identity where available. - Added wiring coverage: - `packages/billing/tests/contractRenewalUpcomingEvent.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `npm -w @alga-psa/clients run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/renewalsQueueActions.retryTicket.wiring.test.ts` - Note: - direct execution of `shared/workflow/streams/domainEventBuilders/__tests__/contractEventBuilders.test.ts` under current Vitest include globs returned “No test files found”; wiring assertions were added in billing tests to cover this change. - (2026-02-21) Completed `F100`. - Confirmed evergreen renewal queue generation path in scheduled processor: - processor normalizes each contract with `normalizeClientContract` (which computes evergreen annual-cycle decision dates) - upserts normalized cycle boundaries and cycle key: - `renewal_cycle_start` - `renewal_cycle_end` - `renewal_cycle_key` - includes evergreen entries whenever computed decision due date is within the processing horizon - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npm run typecheck` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F101`. - Added explicit per-row contract type badge rendering in Renewals queue UI: - evergreen rows now show `Evergreen` badge - fixed-term rows show `Fixed-term` badge - Implemented in: - `packages/billing/src/components/billing-dashboard/contracts/RenewalsQueueTab.tsx` - Added component wiring assertions: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F102`. - Added evergreen cycle anchor detail to renewal queue rows. - Queue row model now surfaces: - `evergreen_cycle_anchor_date` (from `evergreen_review_anchor_date`, fallback `renewal_cycle_end`) - UI now renders evergreen-only row detail: - `Evergreen anchor: ` - Updated wiring coverage: - `packages/billing/tests/RenewalsQueueTab.component.test.ts` - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F103`. - Confirmed evergreen entries share the same mark-renewing transition path as fixed-term entries: - queue action availability is status-driven (`pending` includes `mark_renewing`) - mark-renewing mutation path has no contract-type/end-date gate - Added dedicated wiring coverage: - `packages/billing/tests/renewalsQueueActions.markRenewingEvergreen.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markRenewing.wiring.test.ts tests/renewalsQueueActions.markRenewingEvergreen.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F104`. - Confirmed evergreen entries share the same mark-non-renewing transition path as fixed-term entries: - queue action availability remains status-driven - mark-non-renewing mutation path has no contract-type/end-date gate - Added dedicated wiring coverage: - `packages/billing/tests/renewalsQueueActions.markNonRenewingEvergreen.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.markNonRenewing.wiring.test.ts tests/renewalsQueueActions.markNonRenewingEvergreen.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F105`. - Confirmed create-renewal-draft action supports evergreen entries: - mutation eligibility is status-driven (`pending` / `renewing`) - draft assignment creation logic supports null `end_date` (evergreen) while preserving start-date semantics - Added dedicated wiring coverage: - `packages/billing/tests/renewalsQueueActions.createDraftEvergreen.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.createDraftEvergreen.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F106`. - Confirmed evergreen cycle rollover semantics in scheduled renewal processing: - when cycle key advances, processor treats it as a new cycle (`cycleChanged`) - status normalization reopens work item to `pending` - updated cycle key is persisted and cycle-change counters increment - Added explicit rollover wiring coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` - (2026-02-21) Completed `F107`. - Added cycle-level deduplication guard in scheduled renewal processing to prevent duplicate handling of the same contract/cycle period: - dedupe identity: `client_contract_id + cycleKey` (fallback to `decision_due_date`) - duplicate entries are skipped and counted in processor metrics - This hardens evergreen annual-cycle processing against duplicate row inputs from upstream query/join behavior. - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` - (2026-02-21) Completed `F108`. - Added regression coverage confirming evergreen decision due date uses contract-level notice-period override when tenant defaults are disabled. - Covered both branches: - tenant defaults enabled => tenant notice period drives evergreen decision date - tenant defaults disabled => contract override notice period drives evergreen decision date - Updated coverage: - `packages/billing/tests/clientContractEffectiveRenewalSettings.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F109`. - Updated `ClientContractsTab` upcoming-renewals widget bucketing to explicitly include both contract types: - `fixed-term` - `evergreen` - Added explicit widget wiring coverage to ensure evergreen entries are included in bucket counts. - Updated files: - `packages/billing/src/components/billing-dashboard/contracts/ClientContractsTab.tsx` - `packages/billing/tests/ClientContractsTab.upcomingRenewalsWidget.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F110`. - Extended expiration-report action payload to include `decision_due_date` alongside `end_date` when present. - Updated `ContractExpiration` type and query mapping in: - `packages/billing/src/actions/contractReportActions.ts` - Added wiring coverage: - `packages/billing/tests/contractReportActions.expiration.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F111`. - Extended expiration-report rows to include `renewal_mode`. - Updated report contract type in: - `packages/billing/src/actions/contractReportActions.ts` - Expanded wiring coverage: - `packages/billing/tests/contractReportActions.expiration.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F112`. - Extended expiration-report rows to include renewal queue state when present (`queue_status` from `client_contracts.status`). - Updated files: - `packages/billing/src/actions/contractReportActions.ts` - `packages/billing/tests/contractReportActions.expiration.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F113`. - Preserved existing fixed-term expiration inclusion semantics while adding renewal metadata: - expiration rows still key off `end_date` presence - no hard requirement for `renewal_mode` to be set - Added explicit compatibility coverage in: - `packages/billing/tests/contractReportActions.expiration.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F114`. - Preserved expiration-report sort compatibility for existing consumers: - primary ordering remains `cc.end_date ASC` - dedupe key remains based on contract/client/end-date identity - Added explicit compatibility assertions in: - `packages/billing/tests/contractReportActions.expiration.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F115`. - Extended report summary payload with `atRiskDecisionCount` for dashboard consumption. - At-risk metric now counts active client-contract assignments with `decision_due_date` in the next 90 days. - Updated files: - `packages/billing/src/actions/contractReportActions.ts` - `packages/billing/tests/contractReportActions.summary.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.summary.wiring.test.ts tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F116`. - Updated Contract Reports expiration tab copy to reference renewal decisions in addition to expirations. - Updated UX copy in: - `packages/billing/src/components/billing-dashboard/reports/ContractReports.tsx` - Added wiring coverage: - `packages/billing/tests/ContractReports.expirationCopy.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/ContractReports.expirationCopy.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/contractReportActions.expiration.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F117`. - Updated expiration-report row construction so legacy `auto_renew` display derives from effective renewal mode values. - Effective renewal mode now resolves with tenant-default precedence logic: - honors `use_tenant_renewal_defaults` - falls back deterministically between contract/tenant/default (`manual`) - `auto_renew` now maps to `effectiveRenewalMode === 'auto'`. - Updated files: - `packages/billing/src/actions/contractReportActions.ts` - `packages/billing/tests/contractReportActions.expiration.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - `npm -w @alga-psa/billing run typecheck` - (2026-02-21) Completed `F118`. - Confirmed renewal scheduled processor registration in the on-prem pg-boss scheduled initialization path: - tenant loop schedules `process-renewal-queue` via `scheduleRenewalQueueProcessingJob(tenantId, 90, cron)` - includes both first-schedule and singleton-already-scheduled handling logs - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` - (2026-02-21) Completed `F119`. - Added Temporal runner coverage proving renewal scheduled processing can be registered as a recurring Temporal workflow: - schedules `process-renewal-queue` with tenant + horizon payload - validates Temporal schedule action carries renewal job name/data - Updated coverage: - `ee/server/src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - Validation: - `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - Note: - `npm --prefix ee/server run test:unit -- src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` executes the full unit suite in this workspace and currently surfaces unrelated pre-existing failures in other unit files; targeted execution of the modified test passes. - (2026-02-21) Completed `F120`. - Confirmed renewal processing uses a shared core handler callable from both runtime adapters: - legacy pg-boss registration path (`index.ts`) calls `processRenewalQueueHandler` - centralized handler registry (`registerAllHandlers.ts`) also calls the same handler for Temporal/runner abstraction execution - `initializeJobRunner.ts` bridges registered handlers into runner implementations - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` - (2026-02-21) Completed `F121`. - Added parity coverage confirming queue-creation payload shape is equivalent across runner paths: - pg-boss scheduling uses `process-renewal-queue` with `{ tenantId, horizonDays }` - Temporal recurring workflow action forwards `jobName`, `tenantId`, and `data` through `genericJobWorkflow` - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` - (2026-02-21) Completed `F122`. - Added runtime-parity coverage confirming ticket idempotency behavior is shared across runner paths because both execute the same renewal processor core: - shared idempotency key construction - duplicate-ticket lookup by idempotency attribute - shared duplicate-skip semantics - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` - (2026-02-21) Completed `F123`. - Added wiring coverage confirming runtime selection stays in `JobRunnerFactory` and renewal business logic remains runner/edition agnostic: - runner type resolution via config/env (`JOB_RUNNER_TYPE`) - renewal processor contains no edition/runtime branching - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - `cd server && npm run typecheck` ## Open Questions - Should renewal ticket defaults be a brand-new billing settings card, or an extension of existing default ticket settings patterns? - Should evergreen annual review use contract start-date anniversary or configurable anchor date in v1? - Should renewal status transitions hard-lock contract activation behavior, or remain advisory with warnings in v1? - (2026-02-21) Completed `F124`. - Added explicit runtime-fallback coverage confirming Temporal bootstrap failures gracefully fall back to pg-boss when fallback is enabled. - Assertions verify: - Temporal path attempted first for EE/runtime selection - fallback gate checks `config?.fallbackToPgBoss !== false` - fallback execution calls `createPgBossRunner(config)` - Temporal bootstrap/import failures remain surfaced and handled by fallback branch - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F125`. - Added tenant-scope parity coverage across pg-boss and Temporal renewal runtime paths. - Assertions verify: - scheduler payload requires and forwards tenant id for renewal processing - renewal processor enforces tenant id and scopes reads/writes by tenant - Temporal runner enforces tenant id in job data and propagates tenant scope into workflow/job persistence - Updated coverage: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F126`. - Enforced billing read authorization on renewals queue list endpoint. - `listRenewalQueueRows` now gates access via `hasPermission(user, 'billing', 'read')` and throws `Permission denied: Cannot read renewals queue` when unauthorized. - Updated files: - `packages/billing/src/actions/renewalsQueueActions.ts` - `packages/billing/tests/renewalsQueueActions.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F127`. - Enforced billing update authorization on all renewals queue mutation endpoints. - Added shared guard `requireBillingUpdatePermission(user)` and applied it to: - `markRenewalQueueItemRenewing` - `markRenewalQueueItemNonRenewing` - `createRenewalDraftForQueueItem` - `snoozeRenewalQueueItem` - `assignRenewalQueueItemOwner` - `completeRenewalQueueItemForActivation` - `completeRenewalQueueItemForNonRenewal` - `retryRenewalQueueTicketCreation` - Updated files: - `packages/billing/src/actions/renewalsQueueActions.ts` - `packages/billing/tests/renewalsQueueActions.permissions.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts tests/renewalsQueueActions.permissions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F128`. - Enforced billing settings update authorization on renewal default writes. - `updateDefaultBillingSettings` now requires `hasPermission(user, 'billing_settings', 'update')` and rejects unauthorized callers. - Updated files: - `packages/billing/src/actions/billingSettingsActions.ts` - `packages/billing/tests/billingSettingsActions.renewalPermissions.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/billingSettingsActions.renewalPermissions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F129`. - Added explicit wiring coverage that renewal work-item read paths are tenant-scoped by default. - Coverage asserts tenant filtering across list/read query builders in renewals queue actions. - Updated file: - `packages/billing/tests/renewalsQueueActions.tenantReads.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.tenantReads.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F130`. - Added wiring coverage that renewal work-item mutation/write paths remain tenant-filtered by default. - Coverage checks tenant-scoped update/insert/lookup clauses in renewals queue action writes. - Updated file: - `packages/billing/tests/renewalsQueueActions.tenantWrites.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.tenantWrites.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F131`. - Enhanced renewal transition auditing to capture action metadata (`last_action`) alongside actor/timestamp/note. - Added `withActionLabel(...)` and `last_action` column checks across mutation paths so transitions now record action labels such as: - `mark_renewing`, `mark_non_renewing`, `create_renewal_draft`, `snooze`, `assign_owner`, `complete_after_activation`, `complete_after_non_renewal` - Updated files: - `packages/billing/src/actions/renewalsQueueActions.ts` - `packages/billing/tests/renewalsQueueActions.transitionAudit.wiring.test.ts` - `packages/billing/tests/renewalsQueueActions.actorAudit.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F132`. - Added automation-linkage audit metadata in renewal processor when due-date ticket linkage succeeds. - When a ticket is linked, handler now records (when columns exist): - `last_action = 'system_ticket_automation_linked'` - `last_action_by = null` (system actor) - `last_action_at = nowIso` - Updated files: - `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts` - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F133`. - Added explicit draft-linkage audit coverage ensuring renewal draft creation linkage persists with actor/timestamp metadata. - Coverage validates draft link persistence and action metadata chain (`withActionLabel` + `withActionActor` + `withActionTimestamp`). - Updated file: - `packages/billing/tests/renewalsQueueActions.createDraftAudit.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.createDraft.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F134`. - Added explicit cross-tenant identifier rejection in queue mutation validation: - owner assignment now rejects `assignedTo` user IDs found only in another tenant - activation completion now rejects `activatedContractId` values belonging to another tenant - Added explicit error paths for cross-tenant and not-in-tenant owner identifiers. - Updated files: - `packages/billing/src/actions/renewalsQueueActions.ts` - `packages/billing/tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.assignOwner.wiring.test.ts tests/renewalsQueueActions.completeOnActivation.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F135`. - Added note sanitization prior to persistence/render for renewal queue action notes. - `normalizeActionNote` now sanitizes input by stripping HTML tags, removing angle brackets/control chars, normalizing whitespace, and trimming. - Updated files: - `packages/billing/src/actions/renewalsQueueActions.ts` - `packages/billing/tests/renewalsQueueActions.noteSanitization.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.noteAudit.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T032`. - Verified effective renewal settings exposure in contract assignment read paths. - Validation: - `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T033`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T034`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T035`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T036`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T037`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T038`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T039`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T040`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T041`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T042`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T043`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T044`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T045`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T046`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T047`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/clientContractEffectiveRenewalSettings.test.ts --coverage=false` - (2026-02-21) Completed `T048`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T049`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T050`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T051`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T052`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T053`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T054`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T055`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T056`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T057`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T058`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T059`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/billingTabsConfig.renewals.test.ts tests/BillingDashboard.renewalsRoute.test.ts tests/RenewalsQueueTab.component.test.ts tests/renewalsQueueActions.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T060`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false` - (2026-02-21) Completed `T061`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false` - (2026-02-21) Completed `T062`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false` - (2026-02-21) Completed `T063`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/ClientContractsTab.upcomingRenewalsWidget.test.ts tests/BillingDashboard.renewalsRoute.test.ts --coverage=false` - (2026-02-21) Completed `T064`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T065`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T066`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T067`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T068`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T069`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T070`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T071`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T072`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T073`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T074`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T075`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T076`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T077`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T078`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T079`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T080`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T081`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T082`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T083`. - Validation: `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false` - (2026-02-21) Completed `T084`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T085`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T086`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T087`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T088`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T089`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T090`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T091`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T092`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T093`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T094`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T095`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T096`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T097`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T098`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T099`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T100`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T101`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T102`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T103`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T104`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T105`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T106`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T107`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T108`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T109`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts`; `cd packages/billing && npx vitest run $(rg --files tests | rg 'renewalsQueueActions') tests/RenewalsQueueTab.component.test.ts --coverage=false`; `npm -w @alga-psa/billing exec vitest run tests/contractRenewalUpcomingEvent.wiring.test.ts tests/clientContractEffectiveRenewalSettings.test.ts tests/ClientContractsTab.upcomingRenewalsWidget.test.ts --coverage=false` - (2026-02-21) Completed `T110`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T111`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T112`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T113`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T114`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T115`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T116`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T117`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/contractReportActions.expiration.wiring.test.ts tests/contractReportActions.summary.wiring.test.ts tests/ContractReports.expirationCopy.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T118`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T119`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T120`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T121`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T122`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T123`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T124`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T125`. - Validation: `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false`; `cd ee/server && npx vitest run src/__tests__/unit/temporalJobRunner.scheduleRecurringJob.test.ts` - (2026-02-21) Completed `T126`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T127`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T128`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T129`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T130`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T131`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T132`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T133`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T134`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T135`. - Validation: `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.permissions.wiring.test.ts tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/renewalsQueueActions.tenantReads.wiring.test.ts tests/renewalsQueueActions.tenantWrites.wiring.test.ts tests/renewalsQueueActions.transitionAudit.wiring.test.ts tests/renewalsQueueActions.createDraftAudit.wiring.test.ts tests/renewalsQueueActions.crossTenantValidation.wiring.test.ts tests/renewalsQueueActions.noteSanitization.wiring.test.ts tests/renewalsQueueActions.actorAudit.wiring.test.ts tests/renewalsQueueActions.timestampAudit.wiring.test.ts tests/renewalsQueueActions.noteAudit.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T136`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T137`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T138`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T139`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T140`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T141`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T142`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T143`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T144`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T145`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T146`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T147`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T148`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T149`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T150`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T151`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T152`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T153`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T154`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T155`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T156`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T157`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T158`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T159`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T160`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T161`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T162`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T163`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T164`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T165`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T166`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T167`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T168`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T169`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T170`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T171`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T172`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T173`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T174`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T175`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T176`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T177`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T178`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T179`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T180`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T181`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T182`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T183`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T184`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T185`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T186`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T187`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T188`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T189`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T190`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T191`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T192`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T193`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T194`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T195`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T196`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T197`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T198`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T199`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T200`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T201`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T202`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T203`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T204`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T205`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T206`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T207`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T208`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T209`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T210`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T211`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T212`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T213`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T214`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T215`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T216`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T217`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T218`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T219`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T220`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T221`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T222`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T223`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T224`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T225`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T226`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T227`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T228`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T229`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T230`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T231`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T232`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T233`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T234`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T235`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T236`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T237`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T238`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T239`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T240`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T241`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T242`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `T243`. - Validation: consolidated renewal billing/server/ee suites executed and passing in this session. - (2026-02-21) Completed `F136`. - Added migration: - `server/migrations/202602211100_add_contract_renewal_queue_status_audit_columns.cjs` - Migration adds renewal queue status/audit columns on `client_contracts`: - `status`, `snoozed_until`, `assigned_to`, `last_action`, `last_action_by`, `last_action_at`, `last_action_note` - Added queue-status check constraint: - `client_contracts_renewal_status_check` (`pending|renewing|non_renewing|snoozed|completed`) - Added tenant-scoped actor FKs (null-on-delete): - `client_contracts_assigned_to_fkey` (`tenant`, `assigned_to`) -> `users(tenant, user_id)` - `client_contracts_last_action_by_fkey` (`tenant`, `last_action_by`) -> `users(tenant, user_id)` - Migration is idempotent and Citus-safe (`ensureSequentialMode`, guarded column/constraint checks). - Validation: - `node -c server/migrations/202602211100_add_contract_renewal_queue_status_audit_columns.cjs` - (2026-02-21) Completed `F137`. - Added migration: - `server/migrations/202602211105_add_contract_renewal_cycle_columns.cjs` - Migration adds renewal-cycle fields on `client_contracts`: - `decision_due_date` - `renewal_cycle_start` - `renewal_cycle_end` - `renewal_cycle_key` - Migration remains idempotent and Citus-safe with guarded column checks. - Validation: - `node -c server/migrations/202602211105_add_contract_renewal_cycle_columns.cjs` - (2026-02-21) Completed `F138`. - Added migration: - `server/migrations/202602211110_add_contract_renewal_automation_columns.cjs` - Migration adds renewal automation linkage/policy columns on `client_contracts`: - `created_ticket_id`, `automation_error`, `renewal_due_date_action_policy` - `renewal_ticket_board_id`, `renewal_ticket_status_id`, `renewal_ticket_priority`, `renewal_ticket_assignee_id` - `created_draft_contract_id` - Added policy check constraint: - `client_contracts_renewal_due_date_action_policy_check` (`queue_only|create_ticket`) - Migration remains idempotent and Citus-safe with guarded column/constraint checks. - Validation: - `node -c server/migrations/202602211110_add_contract_renewal_automation_columns.cjs` - (2026-02-21) Completed `F139`. - Added migration: - `server/migrations/202602211115_add_contract_renewal_config_columns.cjs` - Migration adds renewal configuration columns on `client_contracts`: - `renewal_mode`, `notice_period_days`, `renewal_term_months`, `use_tenant_renewal_defaults` - Added DB constraints aligned to wizard/server validation rules: - `client_contracts_renewal_mode_check` (`none|manual|auto`) - `client_contracts_notice_period_days_check` (`>= 0`) - `client_contracts_renewal_term_months_check` (`NULL OR > 0`) - Migration remains idempotent and Citus-safe with guarded column/constraint checks. - Validation: - `node -c server/migrations/202602211115_add_contract_renewal_config_columns.cjs` - (2026-02-21) Completed `F140`. - Added migration: - `server/migrations/202602211120_add_default_billing_renewal_columns.cjs` - Migration adds renewal defaults/policy columns on `default_billing_settings`: - `default_renewal_mode`, `default_notice_period_days`, `renewal_due_date_action_policy` - `renewal_ticket_board_id`, `renewal_ticket_status_id`, `renewal_ticket_priority`, `renewal_ticket_assignee_id` - Added DB constraints for default value domains: - `default_billing_settings_default_renewal_mode_check` - `default_billing_settings_default_notice_period_days_check` - `default_billing_settings_renewal_due_date_action_policy_check` - Migration remains idempotent and Citus-safe with guarded column/constraint checks. - Validation: - `node -c server/migrations/202602211120_add_default_billing_renewal_columns.cjs` - (2026-02-21) Completed `F141`. - Added backfill migration: - `server/migrations/202602211125_backfill_active_client_contract_renewal_defaults.cjs` - Backfill scope: - active fixed-term `client_contracts` rows (`is_active=true`, joined `contracts.status='active'`, `end_date IS NOT NULL`) - Backfill behavior (only when target fields are missing): - sets deterministic defaults: `renewal_mode='manual'`, `notice_period_days=30`, `use_tenant_renewal_defaults=true` - computes initial fixed-term cycle fields: - `decision_due_date = end_date - notice_period_days` - `renewal_cycle_start = start_date::date` - `renewal_cycle_end = end_date::date` - `renewal_cycle_key = fixed-term:` - preserves existing non-null values via `COALESCE` to avoid overwriting already-migrated data - Migration is intentionally non-reversible (data backfill). - Validation: - `node -c server/migrations/202602211125_backfill_active_client_contract_renewal_defaults.cjs` - (2026-02-21) Completed `F142`. - Added migration: - `server/migrations/202602211130_add_contract_renewal_indexes_constraints.cjs` - Added renewal queue performance indexes on `client_contracts` for common filters/sorts: - `idx_client_contracts_renewal_due_status` (`tenant`, `decision_due_date`, `status`) partial active+due-date-not-null - `idx_client_contracts_renewal_owner_status` (`tenant`, `assigned_to`, `status`) partial active - `idx_client_contracts_renewal_mode_type` (`tenant`, `renewal_mode`, `end_date`) partial active - `idx_client_contracts_renewal_snooze` (`tenant`, `status`, `snoozed_until`) partial active - Added cycle dedupe uniqueness index: - `ux_client_contracts_active_cycle_key` (`tenant`, `client_contract_id`, `renewal_cycle_key`) partial active+cycle-key-not-null - Migration remains Citus-safe and guarded by column existence checks. - Validation: - `node -c server/migrations/202602211130_add_contract_renewal_indexes_constraints.cjs` - (2026-02-21) Completed `F143`. - Added renewal schema-readiness guard in queue actions: - `packages/billing/src/actions/renewalsQueueActions.ts` - `assertRenewalSchemaReady(knex)` now validates required renewal columns on: - `client_contracts` - `default_billing_settings` - all renewals queue endpoints now fail fast with actionable migration guidance when required schema is missing. - Added renewal schema-readiness enforcement in scheduled automation: - `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts` - processor now throws actionable error listing missing renewal columns/tables instead of silently skipping. - Validation: - `npm -w @alga-psa/billing run typecheck` - `cd server && npm run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts --coverage=false` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `F144`. - Removed required-column compatibility branching in strict migrated-schema paths: - `packages/billing/src/actions/renewalsQueueActions.ts` - queue list/load now uses direct migrated-schema fields for unsnooze + tenant-default joins. - queue mutation/update helpers now write action audit fields directly (no per-column optional branch). - retry-ticket flow now uses direct migrated-schema policy/routing fields. - `server/src/lib/jobs/handlers/processRenewalQueueHandler.ts` - post-guard processing now assumes migrated columns exist and applies direct policy/cycle/ticket updates. - direct tenant-default selection list + default settings join used in all renewal processor reads. - Updated strict-mode wiring assertions: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Validation: - `npm -w @alga-psa/billing run typecheck` - `cd server && npm run typecheck` - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.wiring.test.ts --coverage=false` - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T244`. - Added migration coverage for renewal queue status/audit columns on `client_contracts` in: - `server/src/test/unit/migrations/contractRenewalMigrations.test.ts` - Assertions cover required status/audit columns and status domain constraint wiring from migration `202602211100_add_contract_renewal_queue_status_audit_columns.cjs`. - Validation: - `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false` - (2026-02-21) Completed `T245`. - Extended migration coverage for renewal-cycle columns in: - `server/src/test/unit/migrations/contractRenewalMigrations.test.ts` - Assertions verify `decision_due_date`, `renewal_cycle_start`, `renewal_cycle_end`, and `renewal_cycle_key` add/drop wiring in migration `202602211105_add_contract_renewal_cycle_columns.cjs`. - Validation: - `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false` - (2026-02-21) Completed `T246`. - Extended migration coverage for renewal automation/policy linkage columns on `client_contracts` in: - `server/src/test/unit/migrations/contractRenewalMigrations.test.ts` - Assertions verify ticket link, routing override, automation error, and policy-check constraint wiring from `202602211110_add_contract_renewal_automation_columns.cjs`. - Validation: - `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false` - (2026-02-21) Completed `T247`. - Extended migration coverage for renewal default/policy columns on `default_billing_settings` in: - `server/src/test/unit/migrations/contractRenewalMigrations.test.ts` - Assertions verify default renewal mode/notice/policy columns, ticket-routing default fields, and policy/validation constraints from `202602211120_add_default_billing_renewal_columns.cjs`. - Validation: - `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false` - (2026-02-21) Completed `T248`. - Extended migration coverage for renewal backfill behavior in: - `server/src/test/unit/migrations/contractRenewalMigrations.test.ts` - Assertions verify data backfill SQL initializes deterministic renewal defaults/cycle fields and scopes updates to active fixed-term rows joined to active contracts. - Validation: - `cd server && npx vitest run src/test/unit/migrations/contractRenewalMigrations.test.ts --coverage=false` - (2026-02-21) Completed `T249`. - Added strict-schema integration wiring test for renewals queue listing in: - `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts` - Coverage verifies `listRenewalQueueRows` enforces `assertRenewalSchemaReady(knex)` and uses migrated-schema query path without legacy missing-column fallback branches. - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false` - Constraint note: - runtime-import action tests currently hit workspace package entry-resolution failures for `@alga-psa/db`; migration/strict-schema integration coverage is therefore implemented via source-level wiring assertions (same style as existing renewal wiring suites). - (2026-02-21) Completed `T250`. - Extended strict-schema integration wiring coverage for snooze mutation in: - `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts` - Assertions verify migrated-schema snooze path writes `status='snoozed'`, `snoozed_until`, and action audit metadata (`last_action`/actor/timestamp/note chain). - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false` - (2026-02-21) Completed `T251`. - Extended strict-schema integration wiring coverage for mark-renewing mutation in: - `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts` - Assertions verify pending-only transition to `renewing` plus actor/timestamp audit persistence in migrated-schema path. - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false` - (2026-02-21) Completed `T252`. - Extended renewal job integration wiring coverage in: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Added assertions that `processRenewalQueueHandler` computes/persists `decision_due_date`, `renewal_cycle_start`, `renewal_cycle_end`, and `renewal_cycle_key` for eligible rows. - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T253`. - Extended renewal job integration wiring coverage in: - `server/src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts` - Added assertions that ticket automation under `create_ticket` uses tenant+contract+cycle idempotency identity and duplicate lookup/linking so at most one ticket is linked per cycle. - Validation: - `cd server && npx vitest run src/lib/jobs/tests/renewalQueueScheduling.wiring.test.ts --coverage=false` - (2026-02-21) Completed `T254`. - Extended strict-schema integration wiring coverage for guard-failure path in: - `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts` - Assertions verify `assertRenewalSchemaReady` fails fast with actionable missing-column error text instructing migration execution. - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false` - (2026-02-21) Completed `T255`. - Extended strict-schema integration wiring coverage for guard-pass operational path in: - `packages/billing/tests/renewalsQueueActions.schemaReadiness.integration.test.ts` - Assertions verify all renewals queue endpoints invoke `assertRenewalSchemaReady(knex)` and no longer rely on legacy missing-column fallback branches in strict migrated-schema mode. - Validation: - `npm -w @alga-psa/billing exec vitest run tests/renewalsQueueActions.schemaReadiness.integration.test.ts --coverage=false`