Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
34 KiB
34 KiB
Scratchpad — System-Managed Default Contract Cutover
- Plan slug:
system-managed-default-contract-cutover - Created:
2026-03-21
Decisions
- (2026-03-21) Create a brand-new plan folder instead of updating
2026-03-21-client-default-contract-on-demand-routing. - (2026-03-21) Keep creation model on-demand at billing-configuration ensure touchpoints rather than eager create at client creation.
- (2026-03-21) Keep migration strategy lazy and deterministic; avoid broad forced backfill.
- (2026-03-21) Use hard cutover objective: remove primary-path non-contract fallback complexity once routing is stable.
- (2026-03-21) Persist explicit default-contract identity on
contracts.is_system_managed_defaultand enforce uniqueness via tenant+owner-client partial unique index; deterministic naming isSystem-managed default contract. - (2026-03-21) Centralize billing-settings row ensure in
shared/billingClients/billingSettings.tsand make default-contract ensure part of that shared path, then route schedule/cycle-anchor/package settings/credit-expiration updates through it. - (2026-03-21) Null client-billing-settings overrides (
settings === null) remain delete-only and do not trigger default-contract ensure; ensure is only invoked on non-null ensure/update touchpoints. - (2026-03-21) Add fallback client-create hook
ensureDefaultContractForClientIfBillingConfigured(...)in shared default-contract domain and wire it into major create paths (clients package action, shared model, API service, integration import, email service) so bypass flows still reconcile when billing settings already exist. - (2026-03-21) For API-service client deletion, enforce domain cleanup before hard delete: remove assignment/billing artifacts, then apply orphan policy to default contracts (
deletewhen uninvoiced orphan,archivewhen invoiced orphan). - (2026-03-21) Refine the target model: system-managed default contracts are attribution shells for unmatched time/usage, not recurring cadence authorities.
- (2026-03-21) Unmatched default-contract work should invoice on the client billing schedule, not on default-contract billing frequency/timing.
- (2026-03-21) System-managed default contracts should not allow contract-line authoring, recurring/service-period management, pricing-schedule authoring, or user-managed assignment date semantics.
- (2026-03-21) Add an optional client billing schedule historical bootstrap date instead of trying to encode back-dated invoiceability through default-contract assignment start dates.
- (2026-03-21) Historical bootstrap is optional, normalizes to the containing client-cycle boundary, and may move earlier only while preserving invoiced-history boundaries.
Discoveries / Constraints
- Billing settings ensure/insert logic is duplicated across shared and package layers, so hooks must be centralized or replicated safely.
- Some client create flows bypass package-level actions (integration/email/import), so client-create hook alone is insufficient.
- API generic delete path may bypass domain cleanup used by package client delete action.
- Resolver behavior currently differs by path and can use current-time filtering instead of effective-date filtering.
- Billing engine can treat some null-assigned rows as resolvable without persisting assignment; this feeds due-work ambiguity.
- UI copy has technical/non-business labels that do not communicate default-contract behavior clearly.
- Existing package wiring tests include brittle source-string assertions for exact function signatures/throw style; those tests can fail even when runtime behavior is unchanged.
- Shared vitest config only discovers
services/**/*.test.tsand**/__tests__/**/*.test.ts, so shared tests for this plan need to live undershared/__tests__/. BaseService.deleteis generic hard-delete behavior; withoutClientService.deleteoverride it bypasses client-domain cleanup and can skip default-contract artifact cleanup.packages/clients/src/components/clients/BillingConfiguration.tsxgeneral save is not the right surface for historical client-cycle bootstrap;ClientBillingSchedule.tsxis the existing UX entry point for schedule-specific setup.shared/billingClients/createBillingCycles.tsbackfills from the current/reference cycle forward, but does not automatically create historical client cycles for back-dated work unless an explicit effective date is supplied.shared/billingClients/billingSchedule.tsandpackages/billing/src/actions/billingScheduleActions.tsalready own schedule persistence and are the natural convergence points for optional bootstrap/backfill logic.- Blanket backdating of default-contract
client_contracts.start_dateis unsafe because contract-cadence and client-cadence recurring materialization both treat assignment start as the schedule-generation anchor/as-of boundary. - Back-dated billable work has a parallel gap on the client-schedule side today: a new billing configuration does not automatically create historical
client_billing_cycles, so default-contract simplification alone does not solve historical invoiceability.
Commands / Runbooks
- Inspect prior plan scaffolds:
ls -1 ee/docs/plansls -la ee/docs/plans/2026-03-21-client-default-contract-on-demand-routing
- Validate new plan:
jq empty ee/docs/plans/2026-03-21-system-managed-default-contract-cutover/features.jsonjq empty ee/docs/plans/2026-03-21-system-managed-default-contract-cutover/tests.jsonpython3 /Users/roberisaacs/.codex/skills/alga-plan/scripts/validate_plan.py ee/docs/plans/2026-03-21-system-managed-default-contract-cutover
- Verify T001 coverage for default contract ensure:
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSettings.defaultContract.ensure.test.ts
- Verify T002 concurrency coverage (same suite now includes forced race path):
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSettings.defaultContract.ensure.test.ts
- (Optional) Package wiring spot-check:
cd packages/billing && npx vitest run tests/billingSettingsActions.renewalPermissions.wiring.test.ts tests/billingSettingsActions.renewalDefaultsWiring.test.ts tests/billingSettingsActions.cadenceOwnerDefaultsWiring.test.ts
- Inspect billing schedule UI/action insertion points for optional bootstrap:
sed -n '1,260p' packages/clients/src/components/clients/ClientBillingSchedule.tsxsed -n '1,260p' packages/billing/src/actions/billingScheduleActions.ts
- Inspect historical cycle creation/bootstrap behavior:
sed -n '1,320p' shared/billingClients/createBillingCycles.tssed -n '1,280p' shared/billingClients/billingSchedule.tssed -n '1,320p' packages/billing/src/actions/billingCycleActions.ts
- Inspect recurring-materialization coupling that makes assignment-start backdating unsafe:
sed -n '360,470p' packages/billing/src/actions/contractCadenceServicePeriodMaterialization.tssed -n '380,430p' packages/billing/src/actions/clientCadenceScheduleRegeneration.ts
Links / References
- Existing stub plan folder:
ee/docs/plans/2026-03-21-client-default-contract-on-demand-routing - Related ongoing plan:
ee/docs/plans/2026-03-21-service-catalog-billing-mode-decoupling - Key current code surfaces identified by investigation:
shared/billingClients/billingSettings.tsshared/billingClients/billingSchedule.tspackages/billing/src/actions/billingCycleAnchorActions.tspackages/billing/src/actions/billingSettingsActions.tspackages/billing/src/actions/creditExpirationSettingsActions.tspackages/scheduling/src/lib/contractLineDisambiguation.tspackages/billing/src/lib/contractLineDisambiguation.tspackages/billing/src/lib/billing/billingEngine.tspackages/billing/src/actions/billingAndTax.tspackages/billing/src/actions/invoiceGeneration.tspackages/billing/src/components/billing-dashboard/AutomaticInvoices.tsxpackages/scheduling/src/components/time-management/time-entry/time-sheet/ContractInfoBanner.tsxpackages/clients/src/actions/clientActions.ts
- New/updated implementation files:
shared/billingClients/defaultContract.tsshared/billingClients/billingSettings.tsshared/billingClients/billingSchedule.tsshared/billingClients/createBillingCycles.tspackages/billing/src/actions/billingCycleAnchorActions.tspackages/billing/src/actions/billingCycleActions.tspackages/billing/src/actions/billingScheduleActions.tspackages/billing/src/actions/billingSettingsActions.tspackages/billing/src/actions/creditExpirationSettingsActions.tspackages/clients/src/components/clients/ClientBillingSchedule.tsxserver/migrations/20260321150000_add_system_managed_default_contract_marker.cjsshared/__tests__/billingSettings.defaultContract.ensure.test.tspackages/clients/src/actions/clientActions.tsshared/models/clientModel.tsserver/src/lib/api/services/ClientService.tspackages/integrations/src/services/xeroCsvClientSyncService.tsshared/services/emailService.tsee/docs/plans/2026-03-21-system-managed-default-contract-cutover/ENGINEERING_NOTES.md
Completed Checklist Progress
- (2026-03-21) Completed features:
F001-F018,F055,F056,F063,F068. - (2026-03-21) Completed tests:
T001,T002.
Open Questions
- Should default-contract pointer be persisted in billing settings or inferred by deterministic query?
- Should API base delete always delegate to domain delete orchestration for client entity type?
- What is final policy when billing settings are explicitly set to null/default state: keep default contract dormant or remove assignment?
- Should the optional historical bootstrap date be persisted in
client_billing_settingsas durable metadata, or used as operational input that only shapes generatedclient_billing_cycles? - What exact pricing source should unmatched default-contract work use once the default contract no longer authors recurring lines?
Progress Update (2026-03-21)
- Resolver/date cutover: both scheduling and billing
contractLineDisambiguationnow accepteffectiveDateand apply date-window filtering usingstart_date <= effectiveDate(end-of-day)andend_date is null || end_date >= effectiveDate(start-of-day). - Save/UI callers now pass effective dates consistently: time-entry save uses computed
work_date, usage save/update usesusage_date, and UI eligible-lines queries pass entry/usage date. - Removed display-only ambiguous default selection in
ContractInfoBanner; ambiguous multi-line matches now require explicit selection instead of showing a synthetic default. - Billing engine unresolved reconciliation now persists deterministic single eligible contract-line assignments for time/usage with
whereNull(contract_line_id)guards, then excludes those records from unresolved output. - Recurring due-work now emits primary unresolved identity keys (
schedule:*:unresolved:*) instead of legacynon_contractkeys; invoice-generation and UI parsing now support both unresolved and legacy non-contract formats for backward compatibility. - Completed features:
F019-F026. - Completed tests:
T003,T004. - Completed features:
F027-F033. - Completed tests:
T005,T006,T007. - Completed features:
F034-F037. - Completed tests:
T008.
Additional Runbooks (2026-03-21)
- Verify T003/T004 effective-date coverage:
cd packages/scheduling && npx vitest run tests/timeEntryCrud.changeRequests.test.tscd server && npx vitest run ../packages/billing/tests/usageActions.effectiveDate.test.ts
- Verify reconciliation behavior for deterministic vs ambiguous unresolved work:
cd server && npx vitest run src/test/unit/billing/billingEngine.unresolvedReconciliation.test.ts
- Verify unresolved-key candidate + generation compatibility:
cd server && npx vitest run src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts src/test/unit/billing/nonContractDueWork.integration.test.ts src/test/unit/billing/automaticInvoices.nonContractSelection.ui.test.tsx
- Re-run default-contract ensure suite after fallback hook expansion:
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSettings.defaultContract.ensure.test.ts
- Typecheck touched shared/integration workspaces:
npm -w shared run typechecknpm -w @alga-psa/integrations run typechecknpm -w @alga-psa/scheduling run typecheck(currently fails due pre-existingpackages/clientstype errors unrelated to this plan)
Progress Update (2026-03-21, F038/F039/T009)
- Added explicit recurring due-work attribution metadata on row/candidate shapes (
source, business label, completeness, missing fields) to carry grouped-row assignment context through server and UI layers. billingAndTaxnow stamps persisted rows asexplicit_contractvssystem_managed_default_contractand unresolved rows asunresolved; grouped candidates aggregate attribution summaries.- Persisted rows with incomplete contract attribution metadata are now marked non-generatable with a blocking reason before they reach grouped selection.
AutomaticInvoicesnow consumes attribution metadata for grouped-row context labels and warning copy (Assignment attribution metadata missing ...) instead of relying on heuristic-only contract field checks.- Added UI guard coverage for grouped rows: business-safe labels for system-managed default and unresolved work, plus hard-block behavior for metadata-missing rows.
- Completed features:
F038,F039. - Completed test:
T009.
Verification commands
cd server && npx vitest run src/test/unit/billing/automaticInvoices.nonContractSelection.ui.test.tsxcd server && npx vitest run src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts src/test/unit/billing/nonContractDueWork.integration.test.tsnpm -w shared run typecheck
Notes
npm -w @alga-psa/billing run typecheckstill reports unrelated pre-existing workspace errors outside this change set; new attribution changes compile within exercised paths.- Running
automaticInvoices.recurringDueWork.ui.test.tsxin the same invocation currently triggers existing router-mount test harness issues (invariant expected app router to be mounted) not introduced by this work.
Progress Update (2026-03-21, F040-F044/T010)
- Updated contract list UI (
ClientContractsTab) to surfaceSystem-managed defaultbadge and helper copy (Created automatically for uncontracted work) directly in contract-name cells. - Added system-managed lifecycle guardrails in list actions: default contracts now only expose view/details access and hide destructive/manual lifecycle operations (
Delete,Terminate,Restore,Set to Active). - Updated contract detail UI (
ContractDetail) with explicit system-managed banner/copy and read-only behavior for lifecycle/ownership-sensitive controls. - Detail view now disables ownership-changing controls (assignment edit, lifecycle selectors, save) and hides destructive delete action for system-managed default contracts.
- Added static UI contract test coverage for list/detail guardrails and copy semantics.
- Completed features:
F040,F041,F042,F043,F044. - Completed test:
T010.
Verification commands
cd server && npx vitest run src/test/unit/billing/automaticInvoices.nonContractSelection.ui.test.tsx src/test/unit/billing/systemManagedDefaultContracts.ui.static.test.tscd server && npx vitest run src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts src/test/unit/billing/nonContractDueWork.integration.test.ts
Notes
T010is currently implemented as a static UI contract test due test-environment import-resolution issues when rendering fullContractDetailruntime dependencies in isolation.
Progress Update (2026-03-21, F045/F046/T011)
- Updated time-entry contract banner copy to remove
default ratesfallback language and use explicitsystem-managed default contractterminology for unmatched service lines. - Updated fallback contract display label to
System-managed default contractwhile preserving ambiguous-state messaging that requires explicit selection before persistence. - Updated usage tracking tooltip, placeholder, and helper copy to mirror the same system-managed default terminology when client context is missing.
- Added a static UI terminology contract test covering both time-entry banner and usage tracking copy semantics, including guard text ensuring unresolved assignment remains explicit.
- Completed features:
F045,F046. - Completed test:
T011.
Verification commands
cd server && npx vitest run src/test/unit/billing/defaultContractTerminology.ui.static.test.ts
Notes
T011is currently implemented as a static source-contract test to avoid full UI runtime harness complexity while still enforcing copy semantics and unresolved-assignment wording.
Progress Update (2026-03-21, F047/F048)
- Reworked
AutomaticInvoicesfallback assignment-context labels to business-safe copy, replacing technical identifier leaks in grouped rows:Assignment line <id>->Assigned contract lineExecution <identity>->Assigned work item
- Preserved attribution-first behavior (
member.attribution.label) so explicit/default/unresolved labels continue to display when provided by due-work attribution metadata. - Added regression coverage in
automaticInvoices.nonContractSelection.ui.test.tsxto ensure mixed explicit-contract + system-managed-default rows remain combinable when billing scopes align, and still generate as a single grouped parent target. - Completed features:
F047,F048.
Verification commands
cd server && npx vitest run src/test/unit/billing/automaticInvoices.nonContractSelection.ui.test.tsx
Notes
- Broader legacy wiring suites still contain pre-existing brittle string expectations unrelated to this feature; feature verification was scoped to the recurring automatic-invoices UI integration test that exercises the changed behavior.
Progress Update (2026-03-21, F049/F050)
- Added action-layer billing permission gates in
contractActionsfor contract-view and mutation entry points used by billing contract list/detail flows (read,create,update). - Added explicit server-side mutation guardrails to block create/update payload attempts that include system-managed identity fields (
is_system_managed_default,owner_client_id). - Sanitized create/update payload stripping for protected fields to ensure no accidental pass-through into model writes.
- Added wiring coverage asserting these guardrails stay present in contract actions.
- Completed features:
F049,F050.
Verification commands
cd server && npx vitest run src/test/unit/billing/automaticInvoices.nonContractSelection.ui.test.tsx src/test/unit/billing/systemManagedContractGuardrails.wiring.test.ts
Notes
- Guardrails are implemented at action entry points so API/controller paths that call these actions inherit the same permission and mutation protections.
Progress Update (2026-03-21, F051-F054)
- Added structured ensure observability in
shared/billingClients/defaultContract.ts:default_contract.ensureevents forcreated,reused, andskipped_no_billing_configurationoutcomes.- Included metric markers:
default_contract_created,default_contract_reused, and skip marker.
- Added structured resolver routing logs in both scheduling and billing disambiguation libs:
contract_line_resolver.routingevents with decisionsexplicit,default, orambiguous_or_unresolved.- Included ambiguous marker metric
unresolved_ambiguous_count.
- Added billing-engine reconciliation observability for unresolved write-back flow:
billing_engine.reconcile.unresolvedevents for deterministic single-match persistence and ambiguous/no-match skips.- Included deterministic marker
unmatched_resolved_deterministicallyand ambiguous markerunresolved_ambiguous_count.
- Added wiring tests to lock observability contract points for ensure, resolver, and reconciliation paths.
- Completed features:
F051,F052,F053,F054.
Verification commands
cd server && npx vitest run src/test/unit/billing/defaultContractObservability.wiring.test.ts src/test/unit/billing/systemManagedContractGuardrails.wiring.test.ts src/test/unit/billing/automaticInvoices.nonContractSelection.ui.test.tsx
Notes
- Structured payloads intentionally avoid end-user fields beyond tenant/client/record identifiers already present in server action context.
Progress Update (2026-03-21, F057/F058)
- Validated and locked lazy backfill behavior via wiring coverage:
ensureDefaultContractForClientIfBillingConfiguredgates ensure onclient_billing_settingsexistence and returns{ ensured: false }otherwise.- This preserves no-forced-global-backfill behavior and first-qualifying-touchpoint creation semantics.
- Validated and locked targeted reconciliation wiring:
- Due-work unresolved collection routes through
BillingEngine.calculateUnresolvedNonContractChargesForExecutionWindow, which performs deterministic single-match write-back while leaving ambiguous/no-match rows unresolved.
- Due-work unresolved collection routes through
- Added a dedicated wiring test file for lazy-backfill + reconciliation path contracts.
- Completed features:
F057,F058.
Verification commands
cd server && npx vitest run src/test/unit/billing/defaultContractLazyBackfill.wiring.test.ts src/test/unit/billing/defaultContractObservability.wiring.test.ts
Progress Update (2026-03-21, F059)
- Added explicit sequencing runbook at
SEQUENCING_RUNBOOK.mdwith stage gates, required-state criteria, and verification commands. - Sequencing now formalizes cutover dependencies across:
- data model + ensure,
- hook coverage,
- resolver/date alignment,
- reconciliation semantics,
- invoice selection/attribution safeguards,
- UI guardrails,
- lifecycle cleanup parity,
- observability checks.
- Included rollback/safety rules to avoid partial-cutover invalid states and premature fallback removal.
- Completed feature:
F059.
Progress Update (2026-03-21, F061)
- Added
DEVELOPER_RUNBOOK.mdcovering default-contract lifecycle, routing, reconciliation, grouped-attribution behavior, and operational verification commands. - Documented forward guardrails to prevent reintroducing eager creation or identity-field bypasses.
- Completed feature:
F061.
Progress Update (2026-03-21, F069)
- Enforced canonical system-managed default contract naming convention during ensure:
- existing default-contract rows are normalized to
- name:
System-managed default contract - description:
Created automatically for uncontracted work
- name:
- normalization occurs on ensure touchpoints without creating duplicate contracts.
- existing default-contract rows are normalized to
- Added shared ensure regression coverage for legacy-named default contracts to guarantee canonical rename + assignment ensure behavior.
- Completed feature:
F069.
Verification commands
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSettings.defaultContract.ensure.test.ts
Progress Update (2026-03-21, F060/F066/F067)
- Removed obsolete legacy branch filtering in recurring invoice selection scoping:
- dropped dead
__non_contract__obligation-prefix exclusion in invoice generation, - retained legacy key parsing only at the schedule-key parser for backward compatibility.
- dropped dead
- Renamed internal selector helper in invoice generation from non-contract-centric wording to unresolved-centric wording to match cutover semantics.
- Audited integration-created client pathway (
xeroCsvClientSyncService) and confirmed first billing-config touchpoint hook still calls shared default-contract ensure. - Added/kept wiring coverage asserting package/shared billing settings + schedule/anchor paths continue to use shared ensure primitives, preventing cross-package drift.
- Completed features:
F060,F066,F067.
Verification commands
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSettings.defaultContract.ensure.test.tscd server && npx vitest run src/test/unit/billing/defaultContractCrossPackageParity.wiring.test.ts src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts
Progress Update (2026-03-21, F062)
- Updated API contract schema to expose default-contract metadata explicitly:
- added
is_system_managed_defaulttocontractResponseSchema.
- added
- Added schema unit coverage verifying:
- response payloads accept and expose
is_system_managed_default, - create/update schemas keep system-managed identity marker out of writable request payloads.
- response payloads accept and expose
- Completed feature:
F062.
Verification commands
cd server && npx vitest run src/test/unit/api/contractSchema.systemManagedDefault.schema.test.ts
Progress Update (2026-03-21, F064/F065/F070)
- Added a shared deterministic selection helper in both billing and scheduling disambiguation modules:
resolveDeterministicContractLineSelectionnow makes precedence explicit,- single explicit eligible line wins,
- system-managed default (bucket-overlay line) is used only as fallback when it is uniquely deterministic,
- ambiguous multi-active scenarios remain unresolved.
- Added package-level resolver tests in both billing and scheduling to lock fallback precedence and ambiguity behavior.
- Improved recurring invoice history attribution context:
- history row mapping now computes explicit vs system-managed-default assignment sets from invoice charge assignments,
- added stable history metadata fields (
assignmentDefaultContractIds,assignmentExplicitContractIds,assignmentSourceSummary), - replaced raw-ID assignment labels with business-safe summaries (
System-managed default contract,Explicit contract assignment,Mixed assignment).
- Added regression coverage for recurring invoice selection scoping to ensure contract-cadence execution windows remain explicit-obligation scoped and do not leak unresolved fallback selection semantics.
- Completed features:
F064,F065,F070.
Verification commands
npx vitest run --config vitest.config.ts tests/contractLineDisambiguation.defaultFallback.test.ts(run inpackages/billing)npx vitest run --config vitest.config.ts tests/contractLineDisambiguation.defaultFallback.test.ts(run inpackages/scheduling)cd server && npx vitest run src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts src/test/unit/billing/recurringInvoiceHistory.defaultContractAttribution.wiring.test.ts src/test/unit/api/contractSchema.systemManagedDefault.schema.test.ts
Progress Update (2026-03-21, T012-T018)
- Added lifecycle cleanup parity wiring tests for client delete flows:
T012package action path asserts deletion of billing settings/cycles and assignment artifacts.T013API service path asserts cleanup orchestration includes default-contract assignment/header cleanup hooks.
- Extended shared billing-settings ensure tests for null-override behavior:
T014verifies deleting billing-settings override does not recreate default-contract artifacts.
- Added migration contract test for default-contract marker migration:
T015asserts table/column guards and idempotent index create/drop patterns.
- Added recurring selection regression for cadence safety:
T016verifies contract-cadence selection remains explicit-obligation scoped with unresolved fallback disabled.
- Extended observability wiring tests:
T017verifies structured logs avoid obvious PII fields in ensure/resolver/reconcile codepaths.
- Extended integration-import regression wiring coverage:
T018verifies integration-created client flow retains first qualifying billing-config ensure hook.
Verification commands
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSettings.defaultContract.ensure.test.tscd server && npx vitest run src/test/unit/billing/defaultContractDeletionCleanup.wiring.test.ts src/test/unit/billing/defaultContractCrossPackageParity.wiring.test.ts src/test/unit/billing/defaultContractObservability.wiring.test.ts src/test/unit/migrations/systemManagedDefaultContractMarkerMigration.test.ts src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts
Progress Update (2026-03-21, F071-F074/F085)
- Reclassified system-managed default contracts as attribution-only in runtime guardrails:
- backend mutation paths now block authoring for default contracts across contract update, contract-line mapping/line/config mutations, pricing schedules, and client-contract assignment mutation paths.
- Removed system-managed default contracts from recurring cadence authority surfaces:
- contract cadence and client cadence materialization queries now explicitly exclude
contracts.is_system_managed_default = true. - recurring due-work persisted-row readers and client-cadence materialization-gap checks now exclude system-managed defaults.
- recurring service-period admin schedule listing filters out system-managed defaults, and direct management view for legacy schedule keys now hard-blocks with attribution-only messaging.
- contract cadence and client cadence materialization queries now explicitly exclude
- Updated contract UI to attribution-only semantics:
- contract detail alert copy now explains attribution-only behavior and points users to normal user-authored contracts for custom billing behavior.
- contract lines/pricing tabs are disabled on system-managed defaults; lines/pricing components run in read-only mode with explanatory copy.
- contract list helper copy now includes attribution-only wording.
- Added/updated static wiring tests locking the above behavior:
systemManagedDefaultAttributionShell.wiring.test.tssystemManagedDefaultContracts.ui.static.test.ts
Verification commands
cd server && npx vitest run src/test/unit/billing/systemManagedDefaultAttributionShell.wiring.test.ts src/test/unit/billing/systemManagedDefaultContracts.ui.static.test.ts src/test/unit/billing/systemManagedContractGuardrails.wiring.test.tsnpm -w @alga-psa/billing run typecheck(fails with pre-existing workspace errors outside this change set; no new failing assertions in targeted tests)
Completed checklist progress
- Completed features:
F071,F072,F073,F074,F085.
Progress Update (2026-03-21, F075/F076)
- Updated billing engine runtime timing resolution so system-managed default contract lines always use client-schedule cadence windows:
buildRecurringChargeTimingSelectionnow forcescadenceOwner = clientwheneveris_system_managed_defaultis true.- prevents default-contract assignments from reintroducing contract-anniversary timing semantics.
- Added legacy-safety pricing guardrails for system-managed default line charges:
- time-charge rating now skips contract-line service-config rounding/minimum/user-type overrides when line is system-managed default.
- usage-charge rating now skips contract-line service-config minimum/custom/tiered overrides when line is system-managed default.
- this keeps unmatched default-contract billing on default/service-catalog pricing semantics.
- Added wiring tests to lock client-schedule timing + pricing override bypass behavior.
- Completed features:
F075,F076.
Verification commands
cd server && npx vitest run src/test/unit/billing/defaultContractClientSchedulePricing.wiring.test.ts src/test/unit/billing/systemManagedDefaultAttributionShell.wiring.test.ts
Progress Update (2026-03-21, F077-F084/F086, T019-T024)
- Implemented optional historical billing bootstrap flow on client billing schedule save:
- Added optional
billingHistoryStartDatethrough shared schedule domain, package action, client helper, and client UI. - Added shared bootstrap preview contract with normalized boundary, uninvoiced regeneration count, and invoiced-history lock status.
- Added optional
- Added deterministic historical client-cycle regeneration/backfill behavior:
- User-entered history date normalizes to containing cycle boundary.
- Uninvoiced cycles from normalized boundary are rebuilt contiguously through current date.
- Bootstrap requests earlier than earliest invoiced cycle boundary are blocked with explicit message.
- Converged manual effective-date bootstrap + schedule bootstrap boundary behavior in shared schedule helpers (
createNextBillingCyclenormalization). - Completed attribution-shell and recurring-exclusion regression coverage:
- Added UI wiring contract test for attribution-only list/detail semantics and disabled line/pricing/assignment edit surfaces.
- Added wiring contract test for historical bootstrap + default-contract billing route semantics.
- Added wiring contract test for recurring/service-period materialization and recurring admin exclusion of system-managed defaults.
- Updated plan docs/runbooks for attribution-shell model and historical bootstrap workflow/gates (
ENGINEERING_NOTES.md,DEVELOPER_RUNBOOK.md,SEQUENCING_RUNBOOK.md). - Completed features:
F077,F078,F079,F080,F081,F082,F083,F084,F086. - Completed tests:
T019,T020,T021,T022,T023,T024.
Verification commands
npx vitest run --config shared/vitest.config.ts shared/__tests__/billingSchedule.historyBootstrap.test.tscd server && npx vitest run src/test/unit/billing/ClientBillingSchedule.ui.test.tsx src/test/unit/billing/defaultContractClientSchedulePricing.wiring.test.ts src/test/unit/billing/systemManagedDefaultAttributionShell.wiring.test.ts src/test/unit/billing/systemManagedDefaultContracts.ui.static.test.ts src/test/unit/billing/defaultContractDeletionCleanup.wiring.test.ts src/test/unit/billing/systemManagedContractGuardrails.wiring.test.tscd server && npx vitest run src/test/unit/billing/systemManagedDefaultAttributionOnly.ui.wiring.test.ts src/test/unit/billing/defaultContractHistoricalBootstrapAndBillingRoute.wiring.test.ts src/test/unit/billing/systemManagedDefaultRecurringExclusion.wiring.test.ts src/test/unit/billing/systemManagedDefaultAttributionShell.wiring.test.ts src/test/unit/billing/defaultContractClientSchedulePricing.wiring.test.ts src/test/unit/billing/systemManagedDefaultContracts.ui.static.test.ts