Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

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_default and enforce uniqueness via tenant+owner-client partial unique index; deterministic naming is System-managed default contract.
  • (2026-03-21) Centralize billing-settings row ensure in shared/billingClients/billingSettings.ts and 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 (delete when uninvoiced orphan, archive when 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.ts and **/__tests__/**/*.test.ts, so shared tests for this plan need to live under shared/__tests__/.
  • BaseService.delete is generic hard-delete behavior; without ClientService.delete override it bypasses client-domain cleanup and can skip default-contract artifact cleanup.
  • packages/clients/src/components/clients/BillingConfiguration.tsx general save is not the right surface for historical client-cycle bootstrap; ClientBillingSchedule.tsx is the existing UX entry point for schedule-specific setup.
  • shared/billingClients/createBillingCycles.ts backfills 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.ts and packages/billing/src/actions/billingScheduleActions.ts already own schedule persistence and are the natural convergence points for optional bootstrap/backfill logic.
  • Blanket backdating of default-contract client_contracts.start_date is 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/plans
    • ls -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.json
    • jq empty ee/docs/plans/2026-03-21-system-managed-default-contract-cutover/tests.json
    • python3 /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.tsx
    • sed -n '1,260p' packages/billing/src/actions/billingScheduleActions.ts
  • Inspect historical cycle creation/bootstrap behavior:
    • sed -n '1,320p' shared/billingClients/createBillingCycles.ts
    • sed -n '1,280p' shared/billingClients/billingSchedule.ts
    • sed -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.ts
    • sed -n '380,430p' packages/billing/src/actions/clientCadenceScheduleRegeneration.ts
  • 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.ts
    • shared/billingClients/billingSchedule.ts
    • packages/billing/src/actions/billingCycleAnchorActions.ts
    • packages/billing/src/actions/billingSettingsActions.ts
    • packages/billing/src/actions/creditExpirationSettingsActions.ts
    • packages/scheduling/src/lib/contractLineDisambiguation.ts
    • packages/billing/src/lib/contractLineDisambiguation.ts
    • packages/billing/src/lib/billing/billingEngine.ts
    • packages/billing/src/actions/billingAndTax.ts
    • packages/billing/src/actions/invoiceGeneration.ts
    • packages/billing/src/components/billing-dashboard/AutomaticInvoices.tsx
    • packages/scheduling/src/components/time-management/time-entry/time-sheet/ContractInfoBanner.tsx
    • packages/clients/src/actions/clientActions.ts
  • New/updated implementation files:
    • shared/billingClients/defaultContract.ts
    • shared/billingClients/billingSettings.ts
    • shared/billingClients/billingSchedule.ts
    • shared/billingClients/createBillingCycles.ts
    • packages/billing/src/actions/billingCycleAnchorActions.ts
    • packages/billing/src/actions/billingCycleActions.ts
    • packages/billing/src/actions/billingScheduleActions.ts
    • packages/billing/src/actions/billingSettingsActions.ts
    • packages/billing/src/actions/creditExpirationSettingsActions.ts
    • packages/clients/src/components/clients/ClientBillingSchedule.tsx
    • server/migrations/20260321150000_add_system_managed_default_contract_marker.cjs
    • shared/__tests__/billingSettings.defaultContract.ensure.test.ts
    • packages/clients/src/actions/clientActions.ts
    • shared/models/clientModel.ts
    • server/src/lib/api/services/ClientService.ts
    • packages/integrations/src/services/xeroCsvClientSyncService.ts
    • shared/services/emailService.ts
    • ee/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_settings as durable metadata, or used as operational input that only shapes generated client_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 contractLineDisambiguation now accept effectiveDate and apply date-window filtering using start_date <= effectiveDate(end-of-day) and end_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 uses usage_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 legacy non_contract keys; 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.ts
    • cd 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 typecheck
    • npm -w @alga-psa/integrations run typecheck
    • npm -w @alga-psa/scheduling run typecheck (currently fails due pre-existing packages/clients type 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.
  • billingAndTax now stamps persisted rows as explicit_contract vs system_managed_default_contract and unresolved rows as unresolved; 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.
  • AutomaticInvoices now 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.tsx
  • cd server && npx vitest run src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts src/test/unit/billing/nonContractDueWork.integration.test.ts
  • npm -w shared run typecheck

Notes

  • npm -w @alga-psa/billing run typecheck still reports unrelated pre-existing workspace errors outside this change set; new attribution changes compile within exercised paths.
  • Running automaticInvoices.recurringDueWork.ui.test.tsx in 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 surface System-managed default badge 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.ts
  • cd server && npx vitest run src/test/unit/billing/invoiceGeneration.unresolvedSelectionKeys.test.ts src/test/unit/billing/nonContractDueWork.integration.test.ts

Notes

  • T010 is currently implemented as a static UI contract test due test-environment import-resolution issues when rendering full ContractDetail runtime dependencies in isolation.

Progress Update (2026-03-21, F045/F046/T011)

  • Updated time-entry contract banner copy to remove default rates fallback language and use explicit system-managed default contract terminology for unmatched service lines.
  • Updated fallback contract display label to System-managed default contract while 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

  • T011 is 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 AutomaticInvoices fallback assignment-context labels to business-safe copy, replacing technical identifier leaks in grouped rows:
    • Assignment line <id> -> Assigned contract line
    • Execution <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.tsx to 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 contractActions for 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.ensure events for created, reused, and skipped_no_billing_configuration outcomes.
    • 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.routing events with decisions explicit, default, or ambiguous_or_unresolved.
    • Included ambiguous marker metric unresolved_ambiguous_count.
  • Added billing-engine reconciliation observability for unresolved write-back flow:
    • billing_engine.reconcile.unresolved events for deterministic single-match persistence and ambiguous/no-match skips.
    • Included deterministic marker unmatched_resolved_deterministically and ambiguous marker unresolved_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:
    • ensureDefaultContractForClientIfBillingConfigured gates ensure on client_billing_settings existence 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.
  • 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.md with 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.md covering 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
    • normalization occurs on ensure touchpoints without creating duplicate contracts.
  • 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.
  • 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.ts
  • cd 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_default to contractResponseSchema.
  • 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.
  • 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:
    • resolveDeterministicContractLineSelection now 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 in packages/billing)
  • npx vitest run --config vitest.config.ts tests/contractLineDisambiguation.defaultFallback.test.ts (run in packages/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:
    • T012 package action path asserts deletion of billing settings/cycles and assignment artifacts.
    • T013 API service path asserts cleanup orchestration includes default-contract assignment/header cleanup hooks.
  • Extended shared billing-settings ensure tests for null-override behavior:
    • T014 verifies deleting billing-settings override does not recreate default-contract artifacts.
  • Added migration contract test for default-contract marker migration:
    • T015 asserts table/column guards and idempotent index create/drop patterns.
  • Added recurring selection regression for cadence safety:
    • T016 verifies contract-cadence selection remains explicit-obligation scoped with unresolved fallback disabled.
  • Extended observability wiring tests:
    • T017 verifies structured logs avoid obvious PII fields in ensure/resolver/reconcile codepaths.
  • Extended integration-import regression wiring coverage:
    • T018 verifies 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.ts
  • cd 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.
  • 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.ts
    • systemManagedDefaultContracts.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.ts
  • npm -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:
    • buildRecurringChargeTimingSelection now forces cadenceOwner = client whenever is_system_managed_default is 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 billingHistoryStartDate through 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 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 (createNextBillingCycle normalization).
  • 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.ts
  • cd 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.ts
  • cd 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