trueppm-api 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trueppm_api/__init__.py +27 -0
- trueppm_api/apps/access/__init__.py +0 -0
- trueppm_api/apps/access/apps.py +19 -0
- trueppm_api/apps/access/groups.py +518 -0
- trueppm_api/apps/access/management/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/__init__.py +0 -0
- trueppm_api/apps/access/management/commands/create_admin.py +346 -0
- trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
- trueppm_api/apps/access/management/commands/revoke_api_tokens.py +483 -0
- trueppm_api/apps/access/migrations/0001_initial.py +61 -0
- trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +184 -0
- trueppm_api/apps/access/migrations/0002_alter_projectmembership_id.py +29 -0
- trueppm_api/apps/access/migrations/0003_projectmembership_soft_delete.py +24 -0
- trueppm_api/apps/access/migrations/0004_alter_projectmembership_role.py +34 -0
- trueppm_api/apps/access/migrations/0005_program_entity_and_membership.py +76 -0
- trueppm_api/apps/access/migrations/0006_role_ordinal_spacing.py +113 -0
- trueppm_api/apps/access/migrations/0007_projectmembership_joined_at_and_more.py +35 -0
- trueppm_api/apps/access/migrations/0008_projectmembership_source_group.py +25 -0
- trueppm_api/apps/access/migrations/0009_projectmembership_pm_proj_serverver_idx.py +20 -0
- trueppm_api/apps/access/migrations/0010_programmembership_joined_at_and_more.py +38 -0
- trueppm_api/apps/access/migrations/0011_alter_programmembership_unique_together_and_more.py +36 -0
- trueppm_api/apps/access/migrations/0012_programmembership_role_title.py +17 -0
- trueppm_api/apps/access/migrations/0013_squashed_0019_release_0_4.py +302 -0
- trueppm_api/apps/access/migrations/0013_userdefinedmentiongroup.py +82 -0
- trueppm_api/apps/access/migrations/0014_programmembership_progm_serverver_idx.py +19 -0
- trueppm_api/apps/access/migrations/0015_programuserdefinedmentiongroup.py +86 -0
- trueppm_api/apps/access/migrations/0016_externalstakeholder.py +67 -0
- trueppm_api/apps/access/migrations/0017_viewer_ordinal_one.py +143 -0
- trueppm_api/apps/access/migrations/0018_programmembership_sync_seq_and_more.py +52 -0
- trueppm_api/apps/access/migrations/0019_programmembership_reinstated_at_and_more.py +22 -0
- trueppm_api/apps/access/migrations/__init__.py +0 -0
- trueppm_api/apps/access/minter_role.py +38 -0
- trueppm_api/apps/access/models.py +588 -0
- trueppm_api/apps/access/permissions.py +3263 -0
- trueppm_api/apps/access/serializers.py +1007 -0
- trueppm_api/apps/access/services.py +878 -0
- trueppm_api/apps/access/signals.py +171 -0
- trueppm_api/apps/access/tasks.py +50 -0
- trueppm_api/apps/access/throttles.py +96 -0
- trueppm_api/apps/access/urls.py +191 -0
- trueppm_api/apps/access/views.py +1965 -0
- trueppm_api/apps/agents/__init__.py +6 -0
- trueppm_api/apps/agents/apps.py +11 -0
- trueppm_api/apps/agents/canonical.py +73 -0
- trueppm_api/apps/agents/deferred.py +108 -0
- trueppm_api/apps/agents/management/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/__init__.py +0 -0
- trueppm_api/apps/agents/management/commands/audit_prune.py +137 -0
- trueppm_api/apps/agents/management/commands/audit_verify.py +101 -0
- trueppm_api/apps/agents/middleware.py +44 -0
- trueppm_api/apps/agents/migrations/0001_initial.py +231 -0
- trueppm_api/apps/agents/migrations/0001_squashed_0003_release_0_4.py +344 -0
- trueppm_api/apps/agents/migrations/0002_agentactioncheckpoint.py +71 -0
- trueppm_api/apps/agents/migrations/0003_agentactionrefusaldetail.py +58 -0
- trueppm_api/apps/agents/migrations/__init__.py +0 -0
- trueppm_api/apps/agents/models.py +371 -0
- trueppm_api/apps/agents/refusal.py +103 -0
- trueppm_api/apps/agents/serializers.py +85 -0
- trueppm_api/apps/agents/services.py +397 -0
- trueppm_api/apps/agents/signals.py +30 -0
- trueppm_api/apps/agents/urls.py +15 -0
- trueppm_api/apps/agents/views.py +109 -0
- trueppm_api/apps/csvimport/__init__.py +12 -0
- trueppm_api/apps/csvimport/apps.py +11 -0
- trueppm_api/apps/csvimport/mapping.py +363 -0
- trueppm_api/apps/csvimport/migrations/0001_initial.py +74 -0
- trueppm_api/apps/csvimport/migrations/0001_squashed_0003_release_0_4.py +90 -0
- trueppm_api/apps/csvimport/migrations/0002_schedule_outline_batch_operations.py +37 -0
- trueppm_api/apps/csvimport/migrations/0003_csvimportrequest_date_order_and_more.py +26 -0
- trueppm_api/apps/csvimport/migrations/__init__.py +0 -0
- trueppm_api/apps/csvimport/models.py +111 -0
- trueppm_api/apps/csvimport/parser.py +1825 -0
- trueppm_api/apps/csvimport/services.py +48 -0
- trueppm_api/apps/csvimport/tasks.py +459 -0
- trueppm_api/apps/csvimport/template.py +37 -0
- trueppm_api/apps/csvimport/urls.py +50 -0
- trueppm_api/apps/csvimport/views.py +793 -0
- trueppm_api/apps/history/__init__.py +0 -0
- trueppm_api/apps/history/apps.py +12 -0
- trueppm_api/apps/history/changelog.py +359 -0
- trueppm_api/apps/history/diff_policy.py +178 -0
- trueppm_api/apps/history/serializers.py +104 -0
- trueppm_api/apps/history/signals.py +82 -0
- trueppm_api/apps/history/tasks.py +105 -0
- trueppm_api/apps/history/urls.py +38 -0
- trueppm_api/apps/history/views.py +443 -0
- trueppm_api/apps/idempotency/__init__.py +0 -0
- trueppm_api/apps/idempotency/apps.py +11 -0
- trueppm_api/apps/idempotency/migrations/0001_initial.py +71 -0
- trueppm_api/apps/idempotency/migrations/__init__.py +0 -0
- trueppm_api/apps/idempotency/mixins.py +226 -0
- trueppm_api/apps/idempotency/models.py +75 -0
- trueppm_api/apps/idempotency/tasks.py +61 -0
- trueppm_api/apps/integrations/__init__.py +13 -0
- trueppm_api/apps/integrations/apps.py +59 -0
- trueppm_api/apps/integrations/connections.py +806 -0
- trueppm_api/apps/integrations/encryption.py +92 -0
- trueppm_api/apps/integrations/external_sources.py +863 -0
- trueppm_api/apps/integrations/git_automation_services.py +231 -0
- trueppm_api/apps/integrations/git_webhook_auth.py +243 -0
- trueppm_api/apps/integrations/http.py +597 -0
- trueppm_api/apps/integrations/me_work.py +218 -0
- trueppm_api/apps/integrations/migrations/0001_initial.py +64 -0
- trueppm_api/apps/integrations/migrations/0001_squashed_0006_tasklink_description_tasklink_preview_type_and_more.py +187 -0
- trueppm_api/apps/integrations/migrations/0002_tasklink.py +67 -0
- trueppm_api/apps/integrations/migrations/0003_tasklink_tasklink_serverver_idx.py +17 -0
- trueppm_api/apps/integrations/migrations/0004_tasklink_custom_title_tasklink_labels.py +25 -0
- trueppm_api/apps/integrations/migrations/0005_boardautomation.py +56 -0
- trueppm_api/apps/integrations/migrations/0006_tasklink_description_tasklink_preview_type_and_more.py +40 -0
- trueppm_api/apps/integrations/migrations/0007_squashed_0014_release_0_4.py +225 -0
- trueppm_api/apps/integrations/migrations/0007_tasklink_created_at.py +23 -0
- trueppm_api/apps/integrations/migrations/0008_integrationcredential_config_externalworkitem.py +66 -0
- trueppm_api/apps/integrations/migrations/0009_externalsyncrequest_and_more.py +96 -0
- trueppm_api/apps/integrations/migrations/0010_externalworkitem_due_date.py +17 -0
- trueppm_api/apps/integrations/migrations/0011_tasklink_sync_seq_tasklink_tasklink_syncseq_idx.py +22 -0
- trueppm_api/apps/integrations/migrations/0012_boardautomation_last_delivery_at_and_more.py +42 -0
- trueppm_api/apps/integrations/migrations/0013_externalsyncrequest_attempt_count_and_more.py +26 -0
- trueppm_api/apps/integrations/migrations/0014_tasklink_created_by.py +27 -0
- trueppm_api/apps/integrations/migrations/__init__.py +0 -0
- trueppm_api/apps/integrations/models.py +635 -0
- trueppm_api/apps/integrations/notification_channels.py +57 -0
- trueppm_api/apps/integrations/opengraph.py +229 -0
- trueppm_api/apps/integrations/outgoing.py +201 -0
- trueppm_api/apps/integrations/providers.py +528 -0
- trueppm_api/apps/integrations/registry.py +345 -0
- trueppm_api/apps/integrations/serializers.py +453 -0
- trueppm_api/apps/integrations/services.py +171 -0
- trueppm_api/apps/integrations/tasks.py +734 -0
- trueppm_api/apps/integrations/throttles.py +165 -0
- trueppm_api/apps/integrations/urls.py +77 -0
- trueppm_api/apps/integrations/views.py +1158 -0
- trueppm_api/apps/jiraimport/__init__.py +8 -0
- trueppm_api/apps/jiraimport/apps.py +11 -0
- trueppm_api/apps/jiraimport/migrations/0001_initial.py +72 -0
- trueppm_api/apps/jiraimport/migrations/__init__.py +0 -0
- trueppm_api/apps/jiraimport/models.py +70 -0
- trueppm_api/apps/jiraimport/parser.py +350 -0
- trueppm_api/apps/jiraimport/services.py +46 -0
- trueppm_api/apps/jiraimport/tasks.py +280 -0
- trueppm_api/apps/jiraimport/urls.py +15 -0
- trueppm_api/apps/jiraimport/views.py +153 -0
- trueppm_api/apps/msproject/__init__.py +0 -0
- trueppm_api/apps/msproject/apps.py +11 -0
- trueppm_api/apps/msproject/dataclasses.py +153 -0
- trueppm_api/apps/msproject/exporter.py +551 -0
- trueppm_api/apps/msproject/extended_attributes.py +77 -0
- trueppm_api/apps/msproject/importer.py +1095 -0
- trueppm_api/apps/msproject/migrations/0001_import_request.py +77 -0
- trueppm_api/apps/msproject/migrations/0001_squashed_0002_importrequest_creates_project.py +80 -0
- trueppm_api/apps/msproject/migrations/0002_importrequest_creates_project.py +15 -0
- trueppm_api/apps/msproject/migrations/__init__.py +0 -0
- trueppm_api/apps/msproject/models.py +81 -0
- trueppm_api/apps/msproject/parser.py +1276 -0
- trueppm_api/apps/msproject/serializers.py +136 -0
- trueppm_api/apps/msproject/services.py +58 -0
- trueppm_api/apps/msproject/tasks.py +439 -0
- trueppm_api/apps/msproject/urls.py +39 -0
- trueppm_api/apps/msproject/views.py +531 -0
- trueppm_api/apps/notifications/__init__.py +7 -0
- trueppm_api/apps/notifications/apps.py +15 -0
- trueppm_api/apps/notifications/backfill.py +79 -0
- trueppm_api/apps/notifications/categories.py +112 -0
- trueppm_api/apps/notifications/delivery_limits.py +258 -0
- trueppm_api/apps/notifications/digests.py +462 -0
- trueppm_api/apps/notifications/email_backend.py +350 -0
- trueppm_api/apps/notifications/email_health.py +128 -0
- trueppm_api/apps/notifications/migrations/0001_initial.py +207 -0
- trueppm_api/apps/notifications/migrations/0001_squashed_0006_notification_task.py +299 -0
- trueppm_api/apps/notifications/migrations/0002_project_notification_preference.py +67 -0
- trueppm_api/apps/notifications/migrations/0003_projectnotificationpreference_paused.py +17 -0
- trueppm_api/apps/notifications/migrations/0004_clean_unknown_matrix_keys.py +30 -0
- trueppm_api/apps/notifications/migrations/0005_notification_body_notification_event_type_and_more.py +27 -0
- trueppm_api/apps/notifications/migrations/0006_notification_task.py +25 -0
- trueppm_api/apps/notifications/migrations/0007_squashed_0011_release_0_4.py +204 -0
- trueppm_api/apps/notifications/migrations/0007_workspaceemailsettings.py +80 -0
- trueppm_api/apps/notifications/migrations/0008_notification_snoozed_until.py +17 -0
- trueppm_api/apps/notifications/migrations/0009_usernotificationsettings.py +43 -0
- trueppm_api/apps/notifications/migrations/0010_projectnotificationpreference_schema_version.py +20 -0
- trueppm_api/apps/notifications/migrations/0011_usernotificationsettings_digest_hour_and_more.py +96 -0
- trueppm_api/apps/notifications/migrations/__init__.py +0 -0
- trueppm_api/apps/notifications/models.py +1148 -0
- trueppm_api/apps/notifications/receivers.py +155 -0
- trueppm_api/apps/notifications/schema_migrations.py +56 -0
- trueppm_api/apps/notifications/serializers.py +1094 -0
- trueppm_api/apps/notifications/services.py +1489 -0
- trueppm_api/apps/notifications/tasks.py +762 -0
- trueppm_api/apps/notifications/throttles.py +98 -0
- trueppm_api/apps/notifications/urls.py +97 -0
- trueppm_api/apps/notifications/views.py +919 -0
- trueppm_api/apps/observability/__init__.py +0 -0
- trueppm_api/apps/observability/apps.py +31 -0
- trueppm_api/apps/observability/logging.py +213 -0
- trueppm_api/apps/observability/migrations/0001_initial.py +35 -0
- trueppm_api/apps/observability/migrations/0001_squashed_0003_alter_purgerun_trigger.py +154 -0
- trueppm_api/apps/observability/migrations/0002_purgerun_retentionpolicy_retentionschedule.py +131 -0
- trueppm_api/apps/observability/migrations/0003_alter_purgerun_trigger.py +21 -0
- trueppm_api/apps/observability/migrations/0004_alter_retentionpolicy_key.py +28 -0
- trueppm_api/apps/observability/migrations/__init__.py +0 -0
- trueppm_api/apps/observability/models.py +141 -0
- trueppm_api/apps/observability/otel/__init__.py +45 -0
- trueppm_api/apps/observability/otel/attributes.py +247 -0
- trueppm_api/apps/observability/otel/export_health.py +533 -0
- trueppm_api/apps/observability/otel/instrumentation.py +351 -0
- trueppm_api/apps/observability/otel/metrics.py +566 -0
- trueppm_api/apps/observability/otel/provider.py +511 -0
- trueppm_api/apps/observability/otel/request_attributes.py +204 -0
- trueppm_api/apps/observability/purge_registry.py +124 -0
- trueppm_api/apps/observability/retention.py +139 -0
- trueppm_api/apps/observability/selectors.py +993 -0
- trueppm_api/apps/observability/serializers.py +142 -0
- trueppm_api/apps/observability/services.py +407 -0
- trueppm_api/apps/observability/tasks.py +266 -0
- trueppm_api/apps/observability/urls.py +27 -0
- trueppm_api/apps/observability/views.py +537 -0
- trueppm_api/apps/profiles/__init__.py +0 -0
- trueppm_api/apps/profiles/apps.py +15 -0
- trueppm_api/apps/profiles/constants.py +54 -0
- trueppm_api/apps/profiles/migrations/0001_initial.py +55 -0
- trueppm_api/apps/profiles/migrations/0001_squashed_0004_userprofile_role_context.py +125 -0
- trueppm_api/apps/profiles/migrations/0002_userprofile_hidden_views.py +17 -0
- trueppm_api/apps/profiles/migrations/0003_projectvisit.py +63 -0
- trueppm_api/apps/profiles/migrations/0004_userprofile_role_context.py +26 -0
- trueppm_api/apps/profiles/migrations/0005_squashed_0009_release_0_4.py +128 -0
- trueppm_api/apps/profiles/migrations/0005_userprofile_schedule_in_deliver.py +20 -0
- trueppm_api/apps/profiles/migrations/0006_userprofile_date_format_userprofile_timezone.py +36 -0
- trueppm_api/apps/profiles/migrations/0007_userpin.py +91 -0
- trueppm_api/apps/profiles/migrations/0008_remove_userprofile_schedule_in_deliver.py +71 -0
- trueppm_api/apps/profiles/migrations/0009_auth_user_email_upper_idx.py +81 -0
- trueppm_api/apps/profiles/migrations/__init__.py +0 -0
- trueppm_api/apps/profiles/models.py +276 -0
- trueppm_api/apps/profiles/serializers.py +199 -0
- trueppm_api/apps/profiles/services.py +541 -0
- trueppm_api/apps/profiles/views.py +124 -0
- trueppm_api/apps/projects/__init__.py +0 -0
- trueppm_api/apps/projects/actual_date_rules.py +163 -0
- trueppm_api/apps/projects/amend.py +133 -0
- trueppm_api/apps/projects/apps.py +38 -0
- trueppm_api/apps/projects/asset_feed.py +459 -0
- trueppm_api/apps/projects/asset_views.py +317 -0
- trueppm_api/apps/projects/attachment_policy.py +278 -0
- trueppm_api/apps/projects/authentication.py +458 -0
- trueppm_api/apps/projects/backfill.py +459 -0
- trueppm_api/apps/projects/backlog_services.py +324 -0
- trueppm_api/apps/projects/backlog_views.py +302 -0
- trueppm_api/apps/projects/batch_operation_views.py +264 -0
- trueppm_api/apps/projects/blocker_services.py +510 -0
- trueppm_api/apps/projects/board_activity.py +462 -0
- trueppm_api/apps/projects/board_activity_views.py +186 -0
- trueppm_api/apps/projects/board_lanes.py +134 -0
- trueppm_api/apps/projects/bulk_settings.py +194 -0
- trueppm_api/apps/projects/bundled_templates.py +215 -0
- trueppm_api/apps/projects/calendar_settings.py +180 -0
- trueppm_api/apps/projects/ceremony_views.py +244 -0
- trueppm_api/apps/projects/commit_moment.py +212 -0
- trueppm_api/apps/projects/config_notice.py +1330 -0
- trueppm_api/apps/projects/custom_field_values.py +266 -0
- trueppm_api/apps/projects/decisions_services.py +132 -0
- trueppm_api/apps/projects/decisions_views.py +97 -0
- trueppm_api/apps/projects/estimation_scale.py +126 -0
- trueppm_api/apps/projects/export_bundle.py +423 -0
- trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4278 -0
- trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2001 -0
- trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1827 -0
- trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1909 -0
- trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1410 -0
- trueppm_api/apps/projects/guardrail_policy_source.py +269 -0
- trueppm_api/apps/projects/inbound_sync.py +555 -0
- trueppm_api/apps/projects/iteration_label.py +85 -0
- trueppm_api/apps/projects/key_views.py +468 -0
- trueppm_api/apps/projects/keys.py +205 -0
- trueppm_api/apps/projects/lifecycle.py +191 -0
- trueppm_api/apps/projects/management/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/__init__.py +0 -0
- trueppm_api/apps/projects/management/commands/backfill_in_progress_status.py +92 -0
- trueppm_api/apps/projects/management/commands/create_demo_share_link.py +368 -0
- trueppm_api/apps/projects/management/commands/export_program.py +50 -0
- trueppm_api/apps/projects/management/commands/import_seed.py +165 -0
- trueppm_api/apps/projects/management/commands/load_sample_project.py +514 -0
- trueppm_api/apps/projects/management/commands/seed_capacity.py +406 -0
- trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +192 -0
- trueppm_api/apps/projects/management/commands/shift_sample_dates.py +120 -0
- trueppm_api/apps/projects/mcp_settings.py +305 -0
- trueppm_api/apps/projects/methodology.py +178 -0
- trueppm_api/apps/projects/migration_helpers.py +75 -0
- trueppm_api/apps/projects/migrations/0001_initial.py +208 -0
- trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5659 -0
- trueppm_api/apps/projects/migrations/0002_alter_uuid_pk_serialize_false.py +57 -0
- trueppm_api/apps/projects/migrations/0003_rename_task_project_index.py +25 -0
- trueppm_api/apps/projects/migrations/0004_soft_delete_and_dependency_versioned.py +70 -0
- trueppm_api/apps/projects/migrations/0005_task_assignee.py +33 -0
- trueppm_api/apps/projects/migrations/0006_task_utilization_index.py +31 -0
- trueppm_api/apps/projects/migrations/0007_task_is_milestone.py +28 -0
- trueppm_api/apps/projects/migrations/0008_baseline.py +119 -0
- trueppm_api/apps/projects/migrations/0009_historicaldependency_historicalproject_and_more.py +210 -0
- trueppm_api/apps/projects/migrations/0010_risk.py +229 -0
- trueppm_api/apps/projects/migrations/0011_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0012_task_status.py +27 -0
- trueppm_api/apps/projects/migrations/0013_task_planned_start.py +24 -0
- trueppm_api/apps/projects/migrations/0014_short_hex_ids.py +74 -0
- trueppm_api/apps/projects/migrations/0015_backfill_short_ids.py +48 -0
- trueppm_api/apps/projects/migrations/0016_task_actual_dates.py +42 -0
- trueppm_api/apps/projects/migrations/0017_boardcolumnconfig.py +43 -0
- trueppm_api/apps/projects/migrations/0018_estimation_governance.py +62 -0
- trueppm_api/apps/projects/migrations/0019_backfill_wbs_paths.py +28 -0
- trueppm_api/apps/projects/migrations/0020_task_status_5col.py +65 -0
- trueppm_api/apps/projects/migrations/0021_boardsavedview.py +64 -0
- trueppm_api/apps/projects/migrations/0022_task_status_changed_at_priority_rank.py +35 -0
- trueppm_api/apps/projects/migrations/0023_risk_framework_fields.py +96 -0
- trueppm_api/apps/projects/migrations/0024_riskcomment.py +52 -0
- trueppm_api/apps/projects/migrations/0025_sprint.py +352 -0
- trueppm_api/apps/projects/migrations/0026_project_methodology.py +30 -0
- trueppm_api/apps/projects/migrations/0027_sprint_retro.py +89 -0
- trueppm_api/apps/projects/migrations/0028_normalize_notes_field.py +42 -0
- trueppm_api/apps/projects/migrations/0029_complete_implies_full_progress.py +38 -0
- trueppm_api/apps/projects/migrations/0030_review_implies_full_progress.py +37 -0
- trueppm_api/apps/projects/migrations/0031_task_remaining_points.py +22 -0
- trueppm_api/apps/projects/migrations/0032_task_is_subtask_and_sprint_scope_change.py +90 -0
- trueppm_api/apps/projects/migrations/0033_task_my_work_index.py +38 -0
- trueppm_api/apps/projects/migrations/0034_inbound_task_sync.py +313 -0
- trueppm_api/apps/projects/migrations/0035_retro_versioned_and_suggested_assignee.py +173 -0
- trueppm_api/apps/projects/migrations/0036_program_entity_and_membership.py +157 -0
- trueppm_api/apps/projects/migrations/0037_sprint_capacity_points.py +20 -0
- trueppm_api/apps/projects/migrations/0038_taskcomment_commentreaction_commentacknowledgement_and_more.py +233 -0
- trueppm_api/apps/projects/migrations/0039_apitoken_and_more.py +88 -0
- trueppm_api/apps/projects/migrations/0040_program_general_fields.py +119 -0
- trueppm_api/apps/projects/migrations/0041_ceremony_template_and_phase_gate_config.py +210 -0
- trueppm_api/apps/projects/migrations/0041_project_general_fields.py +106 -0
- trueppm_api/apps/projects/migrations/0042_merge_20260522_0410.py +12 -0
- trueppm_api/apps/projects/migrations/0042_program_rollup_config.py +95 -0
- trueppm_api/apps/projects/migrations/0042_workflow_color_and_custom_fields.py +94 -0
- trueppm_api/apps/projects/migrations/0043_merge_20260522_1118.py +10 -0
- trueppm_api/apps/projects/migrations/0044_merge_20260522_rollup.py +10 -0
- trueppm_api/apps/projects/migrations/0044_project_archive_program_close.py +119 -0
- trueppm_api/apps/projects/migrations/0045_program_risk_policy.py +78 -0
- trueppm_api/apps/projects/migrations/0046_merge_20260523_2248.py +12 -0
- trueppm_api/apps/projects/migrations/0047_apitokenauditentry_program_and_more.py +55 -0
- trueppm_api/apps/projects/migrations/0048_historicalprogram_color_program_color.py +32 -0
- trueppm_api/apps/projects/migrations/0049_backlog_item.py +112 -0
- trueppm_api/apps/projects/migrations/0050_backlog_item_trgm_search.py +26 -0
- trueppm_api/apps/projects/migrations/0051_alter_calendar_working_days_alter_dependency_lag_and_more.py +144 -0
- trueppm_api/apps/projects/migrations/0052_recurring_tasks.py +278 -0
- trueppm_api/apps/projects/migrations/0053_dependency_dep_pred_serverver_idx_and_more.py +56 -0
- trueppm_api/apps/projects/migrations/0054_sprintscopechange_goal_impact_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0055_historicaltask_sprint_pending_and_more.py +51 -0
- trueppm_api/apps/projects/migrations/0056_historicalproject_prioritization_model_and_more.py +276 -0
- trueppm_api/apps/projects/migrations/0057_historicalsprint_binding_committed_snapshot_and_more.py +58 -0
- trueppm_api/apps/projects/migrations/0058_historicaltask_delivery_mode_and_more.py +72 -0
- trueppm_api/apps/projects/migrations/0059_forecastsnapshot.py +80 -0
- trueppm_api/apps/projects/migrations/0060_historicalprojectsignalprivacypolicy_and_more.py +90 -0
- trueppm_api/apps/projects/migrations/0061_baselinetask_story_points.py +17 -0
- trueppm_api/apps/projects/migrations/0062_project_is_sample.py +22 -0
- trueppm_api/apps/projects/migrations/0063_historicalsprint_wip_limit_sprint_wip_limit.py +22 -0
- trueppm_api/apps/projects/migrations/0064_sprinttaskoutcome.py +97 -0
- trueppm_api/apps/projects/migrations/0065_historicalsprint_goal_outcome_sprint_goal_outcome.py +32 -0
- trueppm_api/apps/projects/migrations/0066_historicalproject_lead_project_lead.py +38 -0
- trueppm_api/apps/projects/migrations/0067_sprint_exclude_from_velocity.py +22 -0
- trueppm_api/apps/projects/migrations/0068_project_recalculated_at.py +23 -0
- trueppm_api/apps/projects/migrations/0069_iteration_label.py +22 -0
- trueppm_api/apps/projects/migrations/0070_historicalprogram_iteration_label_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0071_backfill_iteration_label_inherit.py +35 -0
- trueppm_api/apps/projects/migrations/0072_pulseresponse_retroboarditem.py +129 -0
- trueppm_api/apps/projects/migrations/0073_sprinttaskoutcome_demo_ready.py +17 -0
- trueppm_api/apps/projects/migrations/0074_historicaltask_blocked_reason_task_blocked_reason.py +30 -0
- trueppm_api/apps/projects/migrations/0075_risk_decimal_short_id.py +42 -0
- trueppm_api/apps/projects/migrations/0076_sprinttaskoutcome_review_polish.py +45 -0
- trueppm_api/apps/projects/migrations/0077_task_blocker_fields.py +111 -0
- trueppm_api/apps/projects/migrations/0078_alter_risktask_unique_together_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0079_historicalproject_status_date_project_status_date.py +22 -0
- trueppm_api/apps/projects/migrations/0080_alter_historicaltask_type_alter_task_type.py +46 -0
- trueppm_api/apps/projects/migrations/0081_historicalprogram_allow_guests_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0082_project_last_sync_version.py +90 -0
- trueppm_api/apps/projects/migrations/0083_historicalprogram_mc_history_attribution_audience_and_more.py +108 -0
- trueppm_api/apps/projects/migrations/0084_tasknote.py +71 -0
- trueppm_api/apps/projects/migrations/0085_sprint_ix_sprint_velocity.py +33 -0
- trueppm_api/apps/projects/migrations/0086_board_card_search_trgm.py +33 -0
- trueppm_api/apps/projects/migrations/0087_historicalprogram_task_duration_change_percent_policy_and_more.py +155 -0
- trueppm_api/apps/projects/migrations/0088_historicalprogram_allowed_attachment_types_and_more.py +61 -0
- trueppm_api/apps/projects/migrations/0089_signalceilingraiseproposal_signalceilingraisevote_and_more.py +157 -0
- trueppm_api/apps/projects/migrations/0090_historicaltask_proj_histdate_index.py +59 -0
- trueppm_api/apps/projects/migrations/0091_project_board_cadence.py +39 -0
- trueppm_api/apps/projects/migrations/0092_program_target_date.py +22 -0
- trueppm_api/apps/projects/migrations/0093_cross_project_dependency_consent.py +58 -0
- trueppm_api/apps/projects/migrations/0094_project_decisions_policy.py +90 -0
- trueppm_api/apps/projects/migrations/0095_poker_session_vote.py +127 -0
- trueppm_api/apps/projects/migrations/0095_squashed_0097_release_0_3.py +225 -0
- trueppm_api/apps/projects/migrations/0096_crossprojectslipconflict.py +91 -0
- trueppm_api/apps/projects/migrations/0097_backlogitem_backlogitem_tags_gin_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0098_historicalproject_show_baselines_and_more.py +52 -0
- trueppm_api/apps/projects/migrations/0099_apitoken_scopes.py +48 -0
- trueppm_api/apps/projects/migrations/0100_task_dep_serverver_idx_concurrent.py +75 -0
- trueppm_api/apps/projects/migrations/0101_dependency_deleted_at_task_deleted_at.py +22 -0
- trueppm_api/apps/projects/migrations/0102_project_deleted_at_project_proj_isdel_deletedat_idx.py +25 -0
- trueppm_api/apps/projects/migrations/0103_taskdurationchangeevent_task_dur_evt_sprint_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0104_historicalproject_stale_task_threshold_days_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0104_trash_restore_1113.py +38 -0
- trueppm_api/apps/projects/migrations/0105_historical_changelog_indexes.py +76 -0
- trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -0
- trueppm_api/apps/projects/migrations/0106_squashed_0158_release_0_4.py +2357 -0
- trueppm_api/apps/projects/migrations/0107_task_activity_event.py +70 -0
- trueppm_api/apps/projects/migrations/0108_remove_apitoken_api_token_scope_xor_and_more.py +117 -0
- trueppm_api/apps/projects/migrations/0109_projectexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0110_sharelink.py +123 -0
- trueppm_api/apps/projects/migrations/0111_projectcalendarlayer.py +67 -0
- trueppm_api/apps/projects/migrations/0112_sharelink_expires_at_alter_sharelink_content_kind.py +31 -0
- trueppm_api/apps/projects/migrations/0113_alter_historicaltask_percent_complete_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0114_historicalproject_default_member_role_and_more.py +28 -0
- trueppm_api/apps/projects/migrations/0115_historicalproject_end_date_shift_threshold_days_and_more.py +22 -0
- trueppm_api/apps/projects/migrations/0116_alter_taskactivityevent_event_type.py +28 -0
- trueppm_api/apps/projects/migrations/0117_label_tasklabel_label_tasks_and_more.py +126 -0
- trueppm_api/apps/projects/migrations/0118_programexportjob.py +82 -0
- trueppm_api/apps/projects/migrations/0119_historicalprogram_calendar_program_calendar.py +36 -0
- trueppm_api/apps/projects/migrations/0120_alter_backlogitem_item_type.py +29 -0
- trueppm_api/apps/projects/migrations/0121_task_three_point_estimate_ordered.py +64 -0
- trueppm_api/apps/projects/migrations/0122_task_relation.py +173 -0
- trueppm_api/apps/projects/migrations/0123_remove_historicalproject_agile_features_and_more.py +20 -0
- trueppm_api/apps/projects/migrations/0124_dependency_is_driving.py +17 -0
- trueppm_api/apps/projects/migrations/0125_historicalprogram_estimation_scale_and_more.py +68 -0
- trueppm_api/apps/projects/migrations/0126_projectcustomfield_show_on_card_taskcustomfieldvalue.py +80 -0
- trueppm_api/apps/projects/migrations/0127_historicalprogram_mcp_enabled_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0128_acceptancecriterion_sync_seq_apitoken_sync_seq_and_more.py +192 -0
- trueppm_api/apps/projects/migrations/0129_sharelink_show_milestone_dates.py +20 -0
- trueppm_api/apps/projects/migrations/0130_programimportjob.py +85 -0
- trueppm_api/apps/projects/migrations/0131_historicalprogram_sprint_picker_ready_only_default_and_more.py +32 -0
- trueppm_api/apps/projects/migrations/0132_task_scheduled_start.py +17 -0
- trueppm_api/apps/projects/migrations/0133_project_status_date_floor_armed_at.py +17 -0
- trueppm_api/apps/projects/migrations/0134_task_edited_at_task_seeded_at_task_source_id_and_more.py +65 -0
- trueppm_api/apps/projects/migrations/0135_projecttemplate_templateapplication_and_more.py +175 -0
- trueppm_api/apps/projects/migrations/0136_schedule_outline_batch_operations.py +118 -0
- trueppm_api/apps/projects/migrations/0137_collapse_dual_scope_api_tokens.py +54 -0
- trueppm_api/apps/projects/migrations/0138_apitokenauditentry_api_token_audit_owner_idx.py +18 -0
- trueppm_api/apps/projects/migrations/0139_historicaltask_duration_unit_task_duration_unit.py +32 -0
- trueppm_api/apps/projects/migrations/0140_historicaltask_auto_container_and_more.py +113 -0
- trueppm_api/apps/projects/migrations/0141_historicalproject_draft_started_at_and_more.py +44 -0
- trueppm_api/apps/projects/migrations/0142_baseline_calendar_hours_per_day_and_more.py +31 -0
- trueppm_api/apps/projects/migrations/0143_sprintcloserequest_failure_reason_and_more.py +42 -0
- trueppm_api/apps/projects/migrations/0144_projecttemplate_source_project_and_more.py +35 -0
- trueppm_api/apps/projects/migrations/0145_seed_bundled_templates.py +65 -0
- trueppm_api/apps/projects/migrations/0146_historicaltask_board_lane_task_board_lane.py +32 -0
- trueppm_api/apps/projects/migrations/0147_structuraloperation.py +128 -0
- trueppm_api/apps/projects/migrations/0148_task_unique_task_wbs_path_per_project_live.py +76 -0
- trueppm_api/apps/projects/migrations/0149_drop_workshops_tables.py +42 -0
- trueppm_api/apps/projects/migrations/0150_clear_uncommitted_cpm_output.py +130 -0
- trueppm_api/apps/projects/migrations/0151_config_notice_request.py +70 -0
- trueppm_api/apps/projects/migrations/0152_aggregate_task_wbs_name_idx.py +20 -0
- trueppm_api/apps/projects/migrations/0153_program_sample_anchor_date.py +22 -0
- trueppm_api/apps/projects/migrations/0154_object_keys.py +184 -0
- trueppm_api/apps/projects/migrations/0155_task_milestone_at_day_end.py +20 -0
- trueppm_api/apps/projects/migrations/0156_program_import_job_replaced_project_ids.py +17 -0
- trueppm_api/apps/projects/migrations/0157_forecastsnapshot_cpm_finish_at_day_start.py +17 -0
- trueppm_api/apps/projects/migrations/0158_baselinetask_finish_at_day_start.py +17 -0
- trueppm_api/apps/projects/migrations/__init__.py +0 -0
- trueppm_api/apps/projects/models.py +9209 -0
- trueppm_api/apps/projects/poker_services.py +154 -0
- trueppm_api/apps/projects/poker_views.py +398 -0
- trueppm_api/apps/projects/product_backlog_services.py +450 -0
- trueppm_api/apps/projects/program_label_services.py +94 -0
- trueppm_api/apps/projects/program_label_views.py +189 -0
- trueppm_api/apps/projects/program_rollup.py +903 -0
- trueppm_api/apps/projects/program_schedule.py +767 -0
- trueppm_api/apps/projects/program_views.py +3445 -0
- trueppm_api/apps/projects/project_templates.py +422 -0
- trueppm_api/apps/projects/receivers.py +234 -0
- trueppm_api/apps/projects/refusal_codes.py +140 -0
- trueppm_api/apps/projects/reorder_services.py +145 -0
- trueppm_api/apps/projects/restructure_hooks.py +54 -0
- trueppm_api/apps/projects/retro_board_services.py +368 -0
- trueppm_api/apps/projects/retro_services.py +285 -0
- trueppm_api/apps/projects/risk_import.py +396 -0
- trueppm_api/apps/projects/row_identity.py +113 -0
- trueppm_api/apps/projects/schema_migrations.py +228 -0
- trueppm_api/apps/projects/schemas/seed_v1.json +492 -0
- trueppm_api/apps/projects/schemas/seed_v2.json +891 -0
- trueppm_api/apps/projects/seed/__init__.py +61 -0
- trueppm_api/apps/projects/seed/demo_landing_overlay.py +532 -0
- trueppm_api/apps/projects/seed/exporter.py +1717 -0
- trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
- trueppm_api/apps/projects/seed/importer.py +2764 -0
- trueppm_api/apps/projects/seed/reanchor.py +551 -0
- trueppm_api/apps/projects/seed/reldates.py +126 -0
- trueppm_api/apps/projects/seed/replace.py +128 -0
- trueppm_api/apps/projects/seed/replay.py +1695 -0
- trueppm_api/apps/projects/seed/replay_ctx.py +41 -0
- trueppm_api/apps/projects/seed/samples.py +427 -0
- trueppm_api/apps/projects/seed/validation.py +1169 -0
- trueppm_api/apps/projects/serializers.py +12904 -0
- trueppm_api/apps/projects/services.py +7525 -0
- trueppm_api/apps/projects/share_serializers.py +142 -0
- trueppm_api/apps/projects/share_services.py +373 -0
- trueppm_api/apps/projects/share_views.py +395 -0
- trueppm_api/apps/projects/sharing_settings.py +187 -0
- trueppm_api/apps/projects/signal_privacy_services.py +910 -0
- trueppm_api/apps/projects/signal_privacy_views.py +485 -0
- trueppm_api/apps/projects/signals.py +132 -0
- trueppm_api/apps/projects/slip_conflict.py +288 -0
- trueppm_api/apps/projects/sprint_cadence.py +453 -0
- trueppm_api/apps/projects/sprint_picker_settings.py +132 -0
- trueppm_api/apps/projects/standup.py +304 -0
- trueppm_api/apps/projects/standup_views.py +99 -0
- trueppm_api/apps/projects/structural_operation_services.py +727 -0
- trueppm_api/apps/projects/structural_operation_views.py +311 -0
- trueppm_api/apps/projects/surface_visibility.py +126 -0
- trueppm_api/apps/projects/task_batch_services.py +379 -0
- trueppm_api/apps/projects/task_bulk.py +1244 -0
- trueppm_api/apps/projects/task_classification.py +561 -0
- trueppm_api/apps/projects/task_classification_defaults.py +95 -0
- trueppm_api/apps/projects/task_duration_settings.py +142 -0
- trueppm_api/apps/projects/task_grouping.py +754 -0
- trueppm_api/apps/projects/tasks.py +1979 -0
- trueppm_api/apps/projects/template_divergence.py +168 -0
- trueppm_api/apps/projects/template_services.py +160 -0
- trueppm_api/apps/projects/template_tasks.py +261 -0
- trueppm_api/apps/projects/template_views.py +829 -0
- trueppm_api/apps/projects/throttles.py +311 -0
- trueppm_api/apps/projects/urls.py +1016 -0
- trueppm_api/apps/projects/utilization.py +909 -0
- trueppm_api/apps/projects/views.py +21225 -0
- trueppm_api/apps/projects/wbs_paths.py +119 -0
- trueppm_api/apps/resources/__init__.py +0 -0
- trueppm_api/apps/resources/apps.py +8 -0
- trueppm_api/apps/resources/capacity.py +121 -0
- trueppm_api/apps/resources/migrations/0001_initial.py +68 -0
- trueppm_api/apps/resources/migrations/0001_squashed_0013_alter_projectresource_unique_together_and_more.py +281 -0
- trueppm_api/apps/resources/migrations/0002_alter_uuid_pk_serialize_false.py +36 -0
- trueppm_api/apps/resources/migrations/0003_resource_soft_delete.py +30 -0
- trueppm_api/apps/resources/migrations/0004_add_taskresource_resource_index.py +25 -0
- trueppm_api/apps/resources/migrations/0005_resource_job_role.py +20 -0
- trueppm_api/apps/resources/migrations/0006_skill.py +34 -0
- trueppm_api/apps/resources/migrations/0007_resource_skill.py +63 -0
- trueppm_api/apps/resources/migrations/0008_project_resource.py +63 -0
- trueppm_api/apps/resources/migrations/0009_task_skill_requirement.py +60 -0
- trueppm_api/apps/resources/migrations/0010_alter_resourceskill_options_and_more.py +20 -0
- trueppm_api/apps/resources/migrations/0011_alter_projectresource_notes.py +17 -0
- trueppm_api/apps/resources/migrations/0012_add_resource_user_fk.py +26 -0
- trueppm_api/apps/resources/migrations/0013_alter_projectresource_unique_together_and_more.py +53 -0
- trueppm_api/apps/resources/migrations/0014_projectresource_sync_seq_resource_sync_seq_and_more.py +37 -0
- trueppm_api/apps/resources/migrations/0014_squashed_0015_release_0_4.py +47 -0
- trueppm_api/apps/resources/migrations/0015_projectresource_deactivated_with_resource.py +17 -0
- trueppm_api/apps/resources/migrations/__init__.py +0 -0
- trueppm_api/apps/resources/models.py +298 -0
- trueppm_api/apps/resources/serializers.py +426 -0
- trueppm_api/apps/resources/services.py +465 -0
- trueppm_api/apps/resources/urls.py +28 -0
- trueppm_api/apps/resources/views.py +1752 -0
- trueppm_api/apps/scheduling/__init__.py +0 -0
- trueppm_api/apps/scheduling/apps.py +153 -0
- trueppm_api/apps/scheduling/calendars.py +144 -0
- trueppm_api/apps/scheduling/deadletter.py +91 -0
- trueppm_api/apps/scheduling/finish_reading.py +198 -0
- trueppm_api/apps/scheduling/forecast_history_settings.py +215 -0
- trueppm_api/apps/scheduling/forecast_staleness.py +313 -0
- trueppm_api/apps/scheduling/graph_guard.py +263 -0
- trueppm_api/apps/scheduling/management/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/__init__.py +0 -0
- trueppm_api/apps/scheduling/management/commands/prune_forecast_snapshots.py +53 -0
- trueppm_api/apps/scheduling/mc_admission.py +181 -0
- trueppm_api/apps/scheduling/migrations/0001_failed_task.py +62 -0
- trueppm_api/apps/scheduling/migrations/0001_squashed_0007_projectforecastsnapshot.py +309 -0
- trueppm_api/apps/scheduling/migrations/0002_schedulerequest.py +78 -0
- trueppm_api/apps/scheduling/migrations/0003_add_schedule_request_reason.py +27 -0
- trueppm_api/apps/scheduling/migrations/0004_velocity_suggestion.py +94 -0
- trueppm_api/apps/scheduling/migrations/0005_montecarlorun.py +61 -0
- trueppm_api/apps/scheduling/migrations/0006_montecarlorun_distribution.py +17 -0
- trueppm_api/apps/scheduling/migrations/0007_projectforecastsnapshot.py +65 -0
- trueppm_api/apps/scheduling/migrations/0008_alter_schedulerequest_reason.py +28 -0
- trueppm_api/apps/scheduling/migrations/0008_folded_schedulerequest_reason.py +34 -0
- trueppm_api/apps/scheduling/migrations/0009_alter_schedulerequest_reason.py +29 -0
- trueppm_api/apps/scheduling/migrations/0010_failedtask_resolution_note_failedtask_resolved_at_and_more.py +43 -0
- trueppm_api/apps/scheduling/migrations/0010_squashed_0016_release_0_4.py +106 -0
- trueppm_api/apps/scheduling/migrations/0011_failedtask_project.py +26 -0
- trueppm_api/apps/scheduling/migrations/0012_montecarlorun_diagnostic.py +17 -0
- trueppm_api/apps/scheduling/migrations/0013_montecarlorun_status_date.py +17 -0
- trueppm_api/apps/scheduling/migrations/0014_montecarlorun_plan_version.py +17 -0
- trueppm_api/apps/scheduling/migrations/0015_projectforecastsnapshot_cpm_finish_at_day_start.py +17 -0
- trueppm_api/apps/scheduling/migrations/0016_montecarlorun_finish_readings.py +32 -0
- trueppm_api/apps/scheduling/migrations/__init__.py +0 -0
- trueppm_api/apps/scheduling/models.py +542 -0
- trueppm_api/apps/scheduling/receivers.py +160 -0
- trueppm_api/apps/scheduling/risk_premium.py +334 -0
- trueppm_api/apps/scheduling/serializers.py +723 -0
- trueppm_api/apps/scheduling/services.py +1251 -0
- trueppm_api/apps/scheduling/signals.py +56 -0
- trueppm_api/apps/scheduling/tasks.py +2248 -0
- trueppm_api/apps/scheduling/telemetry.py +80 -0
- trueppm_api/apps/scheduling/units.py +35 -0
- trueppm_api/apps/scheduling/urls.py +57 -0
- trueppm_api/apps/scheduling/views.py +2908 -0
- trueppm_api/apps/sso/__init__.py +0 -0
- trueppm_api/apps/sso/apps.py +19 -0
- trueppm_api/apps/sso/extensions.py +130 -0
- trueppm_api/apps/sso/management/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/__init__.py +0 -0
- trueppm_api/apps/sso/management/commands/seed_sso_keycloak.py +172 -0
- trueppm_api/apps/sso/migrations/0001_initial.py +119 -0
- trueppm_api/apps/sso/migrations/0002_remove_oidcprovider_workspace_ssoproviderpolicy_and_more.py +169 -0
- trueppm_api/apps/sso/migrations/__init__.py +0 -0
- trueppm_api/apps/sso/models.py +148 -0
- trueppm_api/apps/sso/serializers.py +446 -0
- trueppm_api/apps/sso/services.py +1473 -0
- trueppm_api/apps/sso/urls.py +47 -0
- trueppm_api/apps/sso/views.py +935 -0
- trueppm_api/apps/sync/__init__.py +0 -0
- trueppm_api/apps/sync/apps.py +15 -0
- trueppm_api/apps/sync/backfill.py +208 -0
- trueppm_api/apps/sync/broadcast.py +369 -0
- trueppm_api/apps/sync/conflict.py +262 -0
- trueppm_api/apps/sync/consumers.py +548 -0
- trueppm_api/apps/sync/migrations/0001_initial.py +59 -0
- trueppm_api/apps/sync/migrations/0001_squashed_0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +77 -0
- trueppm_api/apps/sync/migrations/0002_remove_syncbatch_syncbatch_project_client_batch_uniq_and_more.py +41 -0
- trueppm_api/apps/sync/migrations/0003_boardevent.py +46 -0
- trueppm_api/apps/sync/migrations/0003_squashed_0005_release_0_4.py +77 -0
- trueppm_api/apps/sync/migrations/0004_seed_sync_seq.py +24 -0
- trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
- trueppm_api/apps/sync/migrations/0006_boardevent_per_project_seq.py +77 -0
- trueppm_api/apps/sync/migrations/__init__.py +0 -0
- trueppm_api/apps/sync/models.py +272 -0
- trueppm_api/apps/sync/pagination.py +231 -0
- trueppm_api/apps/sync/sequence.py +488 -0
- trueppm_api/apps/sync/serializers.py +688 -0
- trueppm_api/apps/sync/tasks.py +260 -0
- trueppm_api/apps/sync/throttles.py +175 -0
- trueppm_api/apps/sync/upload.py +556 -0
- trueppm_api/apps/sync/urls.py +17 -0
- trueppm_api/apps/sync/views.py +957 -0
- trueppm_api/apps/sync/ws_auth.py +193 -0
- trueppm_api/apps/taskruns/__init__.py +0 -0
- trueppm_api/apps/taskruns/apps.py +11 -0
- trueppm_api/apps/taskruns/migrations/0001_initial.py +92 -0
- trueppm_api/apps/taskruns/migrations/__init__.py +0 -0
- trueppm_api/apps/taskruns/models.py +68 -0
- trueppm_api/apps/taskruns/serializers.py +92 -0
- trueppm_api/apps/taskruns/tasks.py +60 -0
- trueppm_api/apps/taskruns/tracker.py +286 -0
- trueppm_api/apps/taskruns/urls.py +46 -0
- trueppm_api/apps/taskruns/views.py +195 -0
- trueppm_api/apps/teams/__init__.py +8 -0
- trueppm_api/apps/teams/apps.py +16 -0
- trueppm_api/apps/teams/migrations/0001_initial.py +139 -0
- trueppm_api/apps/teams/migrations/0001_squashed_0002_default_teams.py +159 -0
- trueppm_api/apps/teams/migrations/0002_default_teams.py +62 -0
- trueppm_api/apps/teams/migrations/0003_team_sync_seq_teammembership_sync_seq.py +22 -0
- trueppm_api/apps/teams/migrations/0004_backfill_default_teams_on_upgrade.py +49 -0
- trueppm_api/apps/teams/migrations/__init__.py +0 -0
- trueppm_api/apps/teams/models.py +145 -0
- trueppm_api/apps/teams/permissions.py +149 -0
- trueppm_api/apps/teams/serializers.py +95 -0
- trueppm_api/apps/teams/services.py +440 -0
- trueppm_api/apps/teams/signals.py +61 -0
- trueppm_api/apps/teams/urls.py +34 -0
- trueppm_api/apps/teams/views.py +201 -0
- trueppm_api/apps/timetracking/__init__.py +0 -0
- trueppm_api/apps/timetracking/apps.py +9 -0
- trueppm_api/apps/timetracking/migrations/0001_initial.py +117 -0
- trueppm_api/apps/timetracking/migrations/0001_squashed_0004_release_0_4.py +167 -0
- trueppm_api/apps/timetracking/migrations/0002_timesheetsubmission.py +46 -0
- trueppm_api/apps/timetracking/migrations/0003_timeentry_deleted_at_timeentry_deleted_by.py +31 -0
- trueppm_api/apps/timetracking/migrations/0004_timeentry_sync_seq_and_more.py +24 -0
- trueppm_api/apps/timetracking/migrations/__init__.py +0 -0
- trueppm_api/apps/timetracking/models.py +178 -0
- trueppm_api/apps/timetracking/serializers.py +175 -0
- trueppm_api/apps/timetracking/services.py +211 -0
- trueppm_api/apps/timetracking/urls.py +47 -0
- trueppm_api/apps/timetracking/views.py +597 -0
- trueppm_api/apps/webhooks/__init__.py +0 -0
- trueppm_api/apps/webhooks/apps.py +8 -0
- trueppm_api/apps/webhooks/backfill.py +90 -0
- trueppm_api/apps/webhooks/dispatch.py +279 -0
- trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
- trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +249 -0
- trueppm_api/apps/webhooks/migrations/0002_alter_webhook_events.py +32 -0
- trueppm_api/apps/webhooks/migrations/0003_delivery_status_created_idx.py +17 -0
- trueppm_api/apps/webhooks/migrations/0004_webhook_program_alter_webhook_project_and_more.py +64 -0
- trueppm_api/apps/webhooks/migrations/0005_webhook_delivery_sequence_numbers.py +30 -0
- trueppm_api/apps/webhooks/migrations/0006_webhook_format_alter_webhook_events_and_more.py +61 -0
- trueppm_api/apps/webhooks/migrations/0007_sprint_lifecycle_events.py +63 -0
- trueppm_api/apps/webhooks/migrations/0008_risk_baseline_comment_events.py +73 -0
- trueppm_api/apps/webhooks/migrations/0009_encrypt_webhook_secret_and_failure_counters.py +100 -0
- trueppm_api/apps/webhooks/migrations/0010_alter_webhook_disabled_at.py +21 -0
- trueppm_api/apps/webhooks/migrations/0011_webhookeditor.py +48 -0
- trueppm_api/apps/webhooks/migrations/0012_alter_webhook_disabled_at.py +21 -0
- trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
- trueppm_api/apps/webhooks/models.py +437 -0
- trueppm_api/apps/webhooks/serializers.py +326 -0
- trueppm_api/apps/webhooks/tasks.py +680 -0
- trueppm_api/apps/webhooks/urls.py +22 -0
- trueppm_api/apps/webhooks/views.py +533 -0
- trueppm_api/apps/workflow_engine/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/apps.py +23 -0
- trueppm_api/apps/workflow_engine/migrations/0001_initial.py +230 -0
- trueppm_api/apps/workflow_engine/migrations/0001_squashed_0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +234 -0
- trueppm_api/apps/workflow_engine/migrations/0002_remove_workflowhistoryevent_workflow_history_lookup_idx.py +16 -0
- trueppm_api/apps/workflow_engine/migrations/0003_workflowoutboxrow_workflow_outbox_recovery_idx.py +21 -0
- trueppm_api/apps/workflow_engine/migrations/__init__.py +0 -0
- trueppm_api/apps/workflow_engine/models.py +265 -0
- trueppm_api/apps/workflow_engine/tasks.py +371 -0
- trueppm_api/apps/workspace/__init__.py +0 -0
- trueppm_api/apps/workspace/apps.py +10 -0
- trueppm_api/apps/workspace/backfill.py +111 -0
- trueppm_api/apps/workspace/export.py +254 -0
- trueppm_api/apps/workspace/migrations/0001_initial.py +326 -0
- trueppm_api/apps/workspace/migrations/0001_squashed_0014_workspacemembership_availability_effective_from_and_more.py +829 -0
- trueppm_api/apps/workspace/migrations/0002_remove_workspace_fiscal_year_start_and_more.py +85 -0
- trueppm_api/apps/workspace/migrations/0003_workspaceexportjob.py +73 -0
- trueppm_api/apps/workspace/migrations/0004_alter_workspaceinvite_status.py +27 -0
- trueppm_api/apps/workspace/migrations/0005_workspace_iteration_label_and_more.py +26 -0
- trueppm_api/apps/workspace/migrations/0006_alter_groupmembership_unique_together_and_more.py +45 -0
- trueppm_api/apps/workspace/migrations/0007_workspace_public_sharing_override_policy.py +21 -0
- trueppm_api/apps/workspace/migrations/0008_workspace_mc_history_attribution_audience_and_more.py +44 -0
- trueppm_api/apps/workspace/migrations/0009_workspace_methodology_and_more.py +186 -0
- trueppm_api/apps/workspace/migrations/0010_workspace_logo.py +38 -0
- trueppm_api/apps/workspace/migrations/0011_historicalworkspace_task_duration_change_percent_override_policy_and_more.py +56 -0
- trueppm_api/apps/workspace/migrations/0012_historicalworkspace_allowed_attachment_types_and_more.py +64 -0
- trueppm_api/apps/workspace/migrations/0013_auditevent.py +70 -0
- trueppm_api/apps/workspace/migrations/0014_workspacemembership_availability_effective_from_and_more.py +39 -0
- trueppm_api/apps/workspace/migrations/0015_squashed_0027_release_0_4.py +199 -0
- trueppm_api/apps/workspace/migrations/0015_trash_restore_1113.py +34 -0
- trueppm_api/apps/workspace/migrations/0016_historicalworkspace_calendar_and_more.py +55 -0
- trueppm_api/apps/workspace/migrations/0017_historicalworkspace_estimation_scale_and_more.py +38 -0
- trueppm_api/apps/workspace/migrations/0018_historicalworkspace_feedback_enabled_and_more.py +32 -0
- trueppm_api/apps/workspace/migrations/0019_historicalworkspace_mcp_enabled_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0020_viewer_ordinal_one.py +34 -0
- trueppm_api/apps/workspace/migrations/0021_group_sync_seq_groupmembership_sync_seq_and_more.py +27 -0
- trueppm_api/apps/workspace/migrations/0022_historicalworkspace_sprint_picker_ready_only_default_and_more.py +22 -0
- trueppm_api/apps/workspace/migrations/0023_alter_auditevent_event_type.py +32 -0
- trueppm_api/apps/workspace/migrations/0024_alter_auditevent_event_type.py +33 -0
- trueppm_api/apps/workspace/migrations/0025_alter_auditevent_event_type.py +36 -0
- trueppm_api/apps/workspace/migrations/0026_alter_auditevent_event_type.py +37 -0
- trueppm_api/apps/workspace/migrations/0027_alter_auditevent_event_type.py +42 -0
- trueppm_api/apps/workspace/migrations/__init__.py +0 -0
- trueppm_api/apps/workspace/models.py +857 -0
- trueppm_api/apps/workspace/permissions.py +187 -0
- trueppm_api/apps/workspace/serializers.py +590 -0
- trueppm_api/apps/workspace/services.py +967 -0
- trueppm_api/apps/workspace/signals.py +37 -0
- trueppm_api/apps/workspace/tasks.py +616 -0
- trueppm_api/apps/workspace/urls.py +113 -0
- trueppm_api/apps/workspace/views.py +1581 -0
- trueppm_api/asgi.py +49 -0
- trueppm_api/celery.py +40 -0
- trueppm_api/core/__init__.py +0 -0
- trueppm_api/core/admin_site.py +206 -0
- trueppm_api/core/auth_views.py +934 -0
- trueppm_api/core/constant_time.py +51 -0
- trueppm_api/core/csp.py +54 -0
- trueppm_api/core/db.py +87 -0
- trueppm_api/core/db_session.py +37 -0
- trueppm_api/core/demo_read_only.py +314 -0
- trueppm_api/core/exception_handlers.py +157 -0
- trueppm_api/core/export_downloads.py +56 -0
- trueppm_api/core/extension_providers.py +56 -0
- trueppm_api/core/extension_signals.py +147 -0
- trueppm_api/core/idempotent.py +260 -0
- trueppm_api/core/metadata.py +42 -0
- trueppm_api/core/middleware.py +51 -0
- trueppm_api/core/openapi.py +1221 -0
- trueppm_api/core/password_reset.py +513 -0
- trueppm_api/core/protect_conflict.py +100 -0
- trueppm_api/core/ratelimit.py +148 -0
- trueppm_api/core/redis_throttle.py +82 -0
- trueppm_api/core/refresh_cookie_policy.py +156 -0
- trueppm_api/core/request_body.py +86 -0
- trueppm_api/core/security_checks.py +1034 -0
- trueppm_api/core/storage_config.py +105 -0
- trueppm_api/core/text_decode.py +168 -0
- trueppm_api/core/throttling.py +514 -0
- trueppm_api/core/valkey.py +214 -0
- trueppm_api/core/valkey_cache.py +66 -0
- trueppm_api/core/valkey_checks.py +104 -0
- trueppm_api/core/valkey_config.py +39 -0
- trueppm_api/core/worker_broker_wait.py +149 -0
- trueppm_api/core/worker_heartbeat.py +134 -0
- trueppm_api/core/worker_selfheal.py +205 -0
- trueppm_api/fields.py +36 -0
- trueppm_api/permissions.py +30 -0
- trueppm_api/py.typed +0 -0
- trueppm_api/routing.py +11 -0
- trueppm_api/settings/__init__.py +0 -0
- trueppm_api/settings/base.py +2605 -0
- trueppm_api/settings/dev.py +296 -0
- trueppm_api/settings/prod.py +265 -0
- trueppm_api/urls.py +217 -0
- trueppm_api/workflows/__init__.py +38 -0
- trueppm_api/workflows/backends/__init__.py +6 -0
- trueppm_api/workflows/backends/default.py +297 -0
- trueppm_api/workflows/consumers/__init__.py +11 -0
- trueppm_api/workflows/consumers/requeue_failed_task.py +65 -0
- trueppm_api/workflows/interface.py +148 -0
- trueppm_api/workflows/registry.py +106 -0
- trueppm_api/workflows/services.py +90 -0
- trueppm_api/wsgi.py +11 -0
- trueppm_api-0.4.0.dist-info/METADATA +273 -0
- trueppm_api-0.4.0.dist-info/RECORD +799 -0
- trueppm_api-0.4.0.dist-info/WHEEL +4 -0
- trueppm_api-0.4.0.dist-info/licenses/LICENSE +201 -0
- trueppm_api-0.4.0.dist-info/licenses/NOTICE +7 -0
- trueppm_api-0.4.0.dist-info/licenses/NOTICES +104 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/GPL-3.0.txt +674 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/LGPL-3.0.txt +165 -0
- trueppm_api-0.4.0.dist-info/licenses/licenses/MPL-2.0.txt +373 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""OSS signal receivers for the scheduling app.
|
|
2
|
+
|
|
3
|
+
The default dead-letter alerting receiver (ADR-0084). When a Celery task is
|
|
4
|
+
permanently dead-lettered, OSS emits a single structured WARNING line that an
|
|
5
|
+
operator (or a log-based metrics aggregator) can alert on. Enterprise registers
|
|
6
|
+
*additional* receivers on the same signal for PagerDuty/Slack in its own
|
|
7
|
+
AppConfig.ready() — this module is never imported by enterprise and imports
|
|
8
|
+
nothing from it.
|
|
9
|
+
|
|
10
|
+
Also holds the start/success/retry structured-log receivers (#1917) that
|
|
11
|
+
complement the dead-letter alert above — each Celery task's full lifecycle
|
|
12
|
+
(started → succeeded, or started → retried → ... → dead-lettered) is now a
|
|
13
|
+
structured, greppable/aggregatable log line rather than the ad-hoc
|
|
14
|
+
``logger.info`` calls scattered across individual task bodies.
|
|
15
|
+
|
|
16
|
+
Wired by SchedulingConfig.ready() via ``from . import receivers``.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import logging
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from django.dispatch import receiver
|
|
25
|
+
|
|
26
|
+
from trueppm_api.apps.scheduling.signals import (
|
|
27
|
+
celery_task_permanently_failed,
|
|
28
|
+
celery_task_retried,
|
|
29
|
+
celery_task_started,
|
|
30
|
+
celery_task_succeeded,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@receiver(celery_task_permanently_failed)
|
|
37
|
+
def log_dead_letter_alert(
|
|
38
|
+
sender: Any,
|
|
39
|
+
task_id: str = "",
|
|
40
|
+
task_name: str = "",
|
|
41
|
+
exception: BaseException | None = None,
|
|
42
|
+
project_id: str | None = None,
|
|
43
|
+
**_kwargs: Any,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""Emit a WARNING alert line for a newly dead-lettered task.
|
|
46
|
+
|
|
47
|
+
Distinct from the ERROR line in ``record_failed_task`` (which records the
|
|
48
|
+
raw failure): this is the *alert*, carrying structured ``extra`` fields so
|
|
49
|
+
log pipelines can build the ``trueppm_task_dead_letter_count`` series by
|
|
50
|
+
``task_name`` without parsing the message. Broad ``except`` because an
|
|
51
|
+
alerting failure must never propagate back into the dead-letter path — the
|
|
52
|
+
signal is dispatched with ``send_robust`` for the same reason, so this is
|
|
53
|
+
belt-and-braces against a logging-config error masking a task failure.
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
logger.warning(
|
|
57
|
+
"dead-letter alert: task %s (%s) permanently failed: %s",
|
|
58
|
+
task_name,
|
|
59
|
+
task_id,
|
|
60
|
+
type(exception).__qualname__ if exception is not None else "unknown",
|
|
61
|
+
extra={
|
|
62
|
+
"task_name": task_name,
|
|
63
|
+
"task_id": task_id,
|
|
64
|
+
"exception_type": (
|
|
65
|
+
type(exception).__qualname__ if exception is not None else "unknown"
|
|
66
|
+
),
|
|
67
|
+
"project_id": project_id,
|
|
68
|
+
},
|
|
69
|
+
)
|
|
70
|
+
except Exception:
|
|
71
|
+
logger.exception("dead-letter alert receiver failed")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@receiver(celery_task_started)
|
|
75
|
+
def log_task_started(
|
|
76
|
+
sender: Any,
|
|
77
|
+
task_id: str = "",
|
|
78
|
+
task_name: str = "",
|
|
79
|
+
**_kwargs: Any,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""Emit a structured INFO line when a Celery task begins execution (#1917).
|
|
82
|
+
|
|
83
|
+
Bridged from the ``task_prerun`` framework signal in
|
|
84
|
+
``SchedulingConfig.ready()`` for every task in the process. Broad ``except``
|
|
85
|
+
(matching ``log_dead_letter_alert``): this is bridged via a plain (not
|
|
86
|
+
``send_robust``) Django signal fired synchronously inside the worker's task
|
|
87
|
+
execution path, so a logging-config error here must never surface as (or
|
|
88
|
+
interrupt) a task failure.
|
|
89
|
+
"""
|
|
90
|
+
try:
|
|
91
|
+
logger.info(
|
|
92
|
+
"task started: %s (%s)",
|
|
93
|
+
task_name,
|
|
94
|
+
task_id,
|
|
95
|
+
extra={"task_name": task_name, "task_id": task_id, "outcome": "started"},
|
|
96
|
+
)
|
|
97
|
+
except Exception:
|
|
98
|
+
logger.exception("task-started log receiver failed")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@receiver(celery_task_succeeded)
|
|
102
|
+
def log_task_succeeded(
|
|
103
|
+
sender: Any,
|
|
104
|
+
task_id: str = "",
|
|
105
|
+
task_name: str = "",
|
|
106
|
+
runtime_seconds: float = 0.0,
|
|
107
|
+
**_kwargs: Any,
|
|
108
|
+
) -> None:
|
|
109
|
+
"""Emit a structured INFO line when a Celery task completes successfully (#1917)."""
|
|
110
|
+
try:
|
|
111
|
+
logger.info(
|
|
112
|
+
"task succeeded: %s (%s) in %.3fs",
|
|
113
|
+
task_name,
|
|
114
|
+
task_id,
|
|
115
|
+
runtime_seconds,
|
|
116
|
+
extra={
|
|
117
|
+
"task_name": task_name,
|
|
118
|
+
"task_id": task_id,
|
|
119
|
+
"outcome": "succeeded",
|
|
120
|
+
"runtime_seconds": runtime_seconds,
|
|
121
|
+
},
|
|
122
|
+
)
|
|
123
|
+
except Exception:
|
|
124
|
+
logger.exception("task-succeeded log receiver failed")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@receiver(celery_task_retried)
|
|
128
|
+
def log_task_retried(
|
|
129
|
+
sender: Any,
|
|
130
|
+
task_id: str = "",
|
|
131
|
+
task_name: str = "",
|
|
132
|
+
attempt: int = 0,
|
|
133
|
+
exception: BaseException | None = None,
|
|
134
|
+
**_kwargs: Any,
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Emit a structured WARNING line when a Celery task is about to be retried (#1917).
|
|
137
|
+
|
|
138
|
+
Distinct from ``log_dead_letter_alert``: this fires on *every* retry attempt
|
|
139
|
+
(the task will run again), the dead-letter alert fires once, only on the
|
|
140
|
+
terminal transition after retries are exhausted.
|
|
141
|
+
"""
|
|
142
|
+
try:
|
|
143
|
+
logger.warning(
|
|
144
|
+
"task retry: %s (%s) attempt %s: %s",
|
|
145
|
+
task_name,
|
|
146
|
+
task_id,
|
|
147
|
+
attempt,
|
|
148
|
+
exception,
|
|
149
|
+
extra={
|
|
150
|
+
"task_name": task_name,
|
|
151
|
+
"task_id": task_id,
|
|
152
|
+
"outcome": "retried",
|
|
153
|
+
"attempt": attempt,
|
|
154
|
+
"exception_type": (
|
|
155
|
+
type(exception).__qualname__ if exception is not None else "unknown"
|
|
156
|
+
),
|
|
157
|
+
},
|
|
158
|
+
)
|
|
159
|
+
except Exception:
|
|
160
|
+
logger.exception("task-retried log receiver failed")
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"""The schedule risk premium — "added time" — as a first-class project fact (#2483).
|
|
2
|
+
|
|
3
|
+
The premium is the gap between the two finishes the platform already computes: the
|
|
4
|
+
deterministic CPM finish (what the plan says if nothing varies) and the P80
|
|
5
|
+
commitment date (the date 80% of simulations finished by). Its whole reason for
|
|
6
|
+
existing is that these two disagree, and the disagreement *is* the finding — so the
|
|
7
|
+
platform exposes the gap rather than blending the two into one number. A blend would
|
|
8
|
+
destroy the probability semantics of P80: you could no longer say "80% of runs
|
|
9
|
+
finished by here", and a date that cannot state what it means cannot be falsified.
|
|
10
|
+
|
|
11
|
+
The derivation itself is not new — :func:`delta_vs_cpm_days` has anchored the Monte
|
|
12
|
+
Carlo panel since #987. What this module adds is everything needed to carry that
|
|
13
|
+
number *off* the forecast payload and onto the project: a duration-normalized ratio
|
|
14
|
+
so two projects can be compared, a machine-readable state so no consumer re-decides
|
|
15
|
+
what the number means, and the provenance to say how stale it is.
|
|
16
|
+
|
|
17
|
+
Read together with :class:`~trueppm_api.apps.scheduling.models.MonteCarloRun`.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import datetime
|
|
23
|
+
from collections.abc import Callable, Mapping
|
|
24
|
+
from typing import Any, Literal, TypedDict
|
|
25
|
+
|
|
26
|
+
from trueppm_api.apps.scheduling.finish_reading import lazy_finish_shift_days
|
|
27
|
+
|
|
28
|
+
#: Returns the project's composed scheduler ``Calendar`` (or ``None``). Called only
|
|
29
|
+
#: when a start-of-day reading makes the calendar matter (#4204).
|
|
30
|
+
CalendarFor = Callable[[], Any | None]
|
|
31
|
+
|
|
32
|
+
# A run older than this reads as stale: its premium is reported, but marked, because
|
|
33
|
+
# the schedule it was computed against has had a week to move underneath it.
|
|
34
|
+
#
|
|
35
|
+
# This comment used to say the stronger trigger — "the schedule actually mutated since
|
|
36
|
+
# the run" — "needs a cheap per-project mutation counter that does not exist yet
|
|
37
|
+
# (#2483 open question 2)". Both halves were wrong by the time anyone read them: the
|
|
38
|
+
# counter arrived with ADR-0686 / #2491 as ``Project.last_sync_version``, and the
|
|
39
|
+
# pointer was misnumbered (#2483's open question 2 is band vocabulary). The mutation
|
|
40
|
+
# trigger now ships in :mod:`.forecast_staleness` (#3140).
|
|
41
|
+
#
|
|
42
|
+
# The two are deliberately NOT merged. This threshold keeps its own job — whether the
|
|
43
|
+
# added-time *number* is still worth reporting — and its ``stale`` occupies the same
|
|
44
|
+
# enum slot as ``premium``/``zero``/``negative``, so folding plan drift in here would
|
|
45
|
+
# cost the Overview card its premium classification. ``forecast_staleness`` imports this
|
|
46
|
+
# constant instead, so the two can never disagree about the age term while answering
|
|
47
|
+
# different questions.
|
|
48
|
+
STALE_AFTER_DAYS = 7
|
|
49
|
+
|
|
50
|
+
# The one reason code whose flat forecast is a genuine measured result rather than a
|
|
51
|
+
# missing one: every task is complete, so there is no remaining duration left to vary.
|
|
52
|
+
# Every *other* structurally-flat run means the simulation had nothing to measure —
|
|
53
|
+
# see :func:`_premium_state`.
|
|
54
|
+
_FORECAST_ALL_COMPLETE = "all_complete"
|
|
55
|
+
|
|
56
|
+
RiskPremiumState = Literal["not_run", "unmeasurable", "stale", "zero", "premium", "negative"]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class RiskPremium(TypedDict):
|
|
60
|
+
"""The added-time metric as it appears on a project payload."""
|
|
61
|
+
|
|
62
|
+
risk_premium_days: int | None
|
|
63
|
+
risk_premium_ratio: float | None
|
|
64
|
+
risk_premium_band: str | None
|
|
65
|
+
risk_premium_as_of: str | None
|
|
66
|
+
risk_premium_reason: str | None
|
|
67
|
+
risk_premium_state: RiskPremiumState
|
|
68
|
+
# The two endpoints the gap is measured between, carried from the same run as
|
|
69
|
+
# the gap itself. A signed day-count whose baseline is not on screen is an
|
|
70
|
+
# unverifiable delta (#2426), so any surface rendering the premium needs both
|
|
71
|
+
# dates — and taking them from a second source (the live forecast cache) would
|
|
72
|
+
# let the card's three numbers disagree with each other after a recompute.
|
|
73
|
+
risk_premium_cpm_finish: str | None
|
|
74
|
+
risk_premium_p80: str | None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def delta_vs_cpm_days(
|
|
78
|
+
percentile: datetime.date | None,
|
|
79
|
+
cpm_finish: datetime.date | None,
|
|
80
|
+
*,
|
|
81
|
+
percentile_at_day_start: bool | None = None,
|
|
82
|
+
cpm_finish_at_day_start: bool | None = None,
|
|
83
|
+
calendar_for: CalendarFor | None = None,
|
|
84
|
+
) -> int | None:
|
|
85
|
+
"""Signed delta of a percentile finish vs the deterministic CPM finish, in working time.
|
|
86
|
+
|
|
87
|
+
Positive means the probabilistic finish lands *later* than the deterministic
|
|
88
|
+
spine — the schedule risk pushes the date out (worse). ``None`` when either input
|
|
89
|
+
is missing. Server-owned so a headless/MCP client reads the risk premium directly
|
|
90
|
+
instead of re-subtracting dates (API-first, #987/#986).
|
|
91
|
+
|
|
92
|
+
Both dates are *shown* days (#4079), and a start-of-day milestone finish is shown
|
|
93
|
+
a weekend past the end of the Friday it equals in working time. So each is read
|
|
94
|
+
with its edge of the day — the engine's ``p80_at_day_start`` and the CPM finish's
|
|
95
|
+
reading — and the two are compared by
|
|
96
|
+
:func:`~.finish_reading.finish_shift_days` (#4204). The unit is still calendar
|
|
97
|
+
days. A reading of ``None`` (a run persisted before #4204) is unknown and read as
|
|
98
|
+
#4197 reads a legacy baseline: unmoved on the same day, the end of its day
|
|
99
|
+
otherwise.
|
|
100
|
+
"""
|
|
101
|
+
if percentile is None or cpm_finish is None:
|
|
102
|
+
return None
|
|
103
|
+
return lazy_finish_shift_days(
|
|
104
|
+
(cpm_finish, cpm_finish_at_day_start),
|
|
105
|
+
(percentile, percentile_at_day_start),
|
|
106
|
+
calendar_for,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _premium_state(
|
|
111
|
+
*,
|
|
112
|
+
days: int | None,
|
|
113
|
+
diagnostic: dict[str, Any] | None,
|
|
114
|
+
age_days: int | None,
|
|
115
|
+
) -> RiskPremiumState:
|
|
116
|
+
"""Classify one run into the state its presentation is allowed to use.
|
|
117
|
+
|
|
118
|
+
Evaluated in a fixed order, and the order is the safety property: ``unmeasurable``
|
|
119
|
+
is decided *before* the zero branch, so a structural zero can never fall through
|
|
120
|
+
into the good-news presentation.
|
|
121
|
+
|
|
122
|
+
That ordering exists because of a specific way this metric can lie. A project with
|
|
123
|
+
no three-point estimates simulates flat — every run returns the same date — so its
|
|
124
|
+
premium is exactly 0 days. Rendered as a number, "0 days of added time" tells a
|
|
125
|
+
completely unestimated project that it carries no schedule risk, which is not a
|
|
126
|
+
weaker claim than the truth but the *inverse* of it. The discriminator is whether
|
|
127
|
+
any task could have contributed duration variance at all: if none could, the
|
|
128
|
+
simulation did not measure a low risk, it measured nothing.
|
|
129
|
+
|
|
130
|
+
``all_complete`` is the one flat-with-no-variance run that is a real result — the
|
|
131
|
+
work is finished, so there is genuinely no remaining duration left to vary.
|
|
132
|
+
|
|
133
|
+
A missing ``diagnostic`` (runs recorded before #2483) is deliberately *not* treated
|
|
134
|
+
as unmeasurable: absence of a reason code is not evidence of a missing estimate, and
|
|
135
|
+
guessing would invent the same false verdict in the other direction. Those runs
|
|
136
|
+
report the measured state and let the band collapse.
|
|
137
|
+
"""
|
|
138
|
+
if days is None:
|
|
139
|
+
return "not_run"
|
|
140
|
+
|
|
141
|
+
if diagnostic is not None:
|
|
142
|
+
deterministic = bool(diagnostic.get("deterministic"))
|
|
143
|
+
with_variance = diagnostic.get("tasks_with_variance") or 0
|
|
144
|
+
reason = diagnostic.get("reason")
|
|
145
|
+
if deterministic and not with_variance and reason != _FORECAST_ALL_COMPLETE:
|
|
146
|
+
return "unmeasurable"
|
|
147
|
+
|
|
148
|
+
if age_days is not None and age_days > STALE_AFTER_DAYS:
|
|
149
|
+
return "stale"
|
|
150
|
+
if days > 0:
|
|
151
|
+
return "premium"
|
|
152
|
+
if days < 0:
|
|
153
|
+
return "negative"
|
|
154
|
+
return "zero"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _empty_premium() -> RiskPremium:
|
|
158
|
+
"""The all-null ``not_run`` premium — a project with nothing to report."""
|
|
159
|
+
return RiskPremium(
|
|
160
|
+
risk_premium_days=None,
|
|
161
|
+
risk_premium_ratio=None,
|
|
162
|
+
risk_premium_band=None,
|
|
163
|
+
risk_premium_as_of=None,
|
|
164
|
+
risk_premium_reason=None,
|
|
165
|
+
risk_premium_state="not_run",
|
|
166
|
+
risk_premium_cpm_finish=None,
|
|
167
|
+
risk_premium_p80=None,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def risk_premium_from_values(
|
|
172
|
+
*,
|
|
173
|
+
p80: datetime.date | None,
|
|
174
|
+
cpm_finish: datetime.date | None,
|
|
175
|
+
taken_at: datetime.datetime | None,
|
|
176
|
+
diagnostic: dict[str, Any] | None,
|
|
177
|
+
today: datetime.date,
|
|
178
|
+
p80_at_day_start: bool | None = None,
|
|
179
|
+
cpm_finish_at_day_start: bool | None = None,
|
|
180
|
+
calendar_for: CalendarFor | None = None,
|
|
181
|
+
) -> RiskPremium:
|
|
182
|
+
"""Derive the added-time metric from the four values a forecast run produces.
|
|
183
|
+
|
|
184
|
+
The single entry point to the state machine. Every caller — the project overview,
|
|
185
|
+
the live Monte Carlo run, the cached-forecast read — reaches ``_premium_state`` and
|
|
186
|
+
the ratio calculation only through here, so the platform has exactly one derivation
|
|
187
|
+
of what a premium of ``0`` means (ADR-0698).
|
|
188
|
+
|
|
189
|
+
Undefined is always ``None``, never ``0`` — the same discipline the per-task SPI
|
|
190
|
+
serializer follows. Three quantities can independently be undefined:
|
|
191
|
+
|
|
192
|
+
* **days** — needs both a P80 and a CPM finish. Measured in working time from
|
|
193
|
+
each date's edge-of-day reading (:func:`delta_vs_cpm_days`, #4204).
|
|
194
|
+
* **ratio** — ``days`` divided by the remaining CPM duration (today → CPM finish),
|
|
195
|
+
which is what makes the premium comparable across projects: 29 days on a
|
|
196
|
+
six-week project and 29 days on a three-year one are not the same finding.
|
|
197
|
+
Undefined once the CPM finish is in the past, because there is no remaining
|
|
198
|
+
duration to express the premium as a share of. This term is why the premium is
|
|
199
|
+
derived at response-build time and never frozen into a cache entry: ``today``
|
|
200
|
+
advances underneath a cached forecast, so a stored ratio starts describing a
|
|
201
|
+
remainder that no longer exists (ADR-0698 §2).
|
|
202
|
+
* **band** — the verdict. Deliberately always ``None`` today: threshold cut points
|
|
203
|
+
picked without evidence would be exactly the unfalsifiable tuning constant this
|
|
204
|
+
metric exists to avoid, so the band waits on the measured actual-vs-estimate
|
|
205
|
+
distributions from the calibration flywheel (#2299). ``days`` and ``ratio`` are
|
|
206
|
+
both fully true without it, and every consumer already renders a collapsed band.
|
|
207
|
+
"""
|
|
208
|
+
days = delta_vs_cpm_days(
|
|
209
|
+
p80,
|
|
210
|
+
cpm_finish,
|
|
211
|
+
percentile_at_day_start=p80_at_day_start,
|
|
212
|
+
cpm_finish_at_day_start=cpm_finish_at_day_start,
|
|
213
|
+
calendar_for=calendar_for,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
ratio: float | None = None
|
|
217
|
+
if days is not None and cpm_finish is not None:
|
|
218
|
+
remaining = (cpm_finish - today).days
|
|
219
|
+
if remaining > 0:
|
|
220
|
+
ratio = round(days / remaining, 3)
|
|
221
|
+
|
|
222
|
+
age_days = (today - taken_at.date()).days if taken_at is not None else None
|
|
223
|
+
state = _premium_state(days=days, diagnostic=diagnostic, age_days=age_days)
|
|
224
|
+
|
|
225
|
+
# The diagnostic is a JSONField / cache dict, so its `reason` is only a string by
|
|
226
|
+
# convention. Narrowed rather than trusted: a legacy row carrying a dict here would
|
|
227
|
+
# otherwise be serialized straight through and quietly contradict the documented
|
|
228
|
+
# `str | null` shape that the typed clients are generated against.
|
|
229
|
+
reason = (diagnostic or {}).get("reason")
|
|
230
|
+
|
|
231
|
+
return RiskPremium(
|
|
232
|
+
risk_premium_days=days,
|
|
233
|
+
risk_premium_ratio=ratio,
|
|
234
|
+
risk_premium_band=None,
|
|
235
|
+
risk_premium_as_of=taken_at.isoformat() if taken_at is not None else None,
|
|
236
|
+
# Carried even in measured states: the panel explains a flat-but-real forecast
|
|
237
|
+
# from the same code, so a consumer never has to fetch the run to caption it.
|
|
238
|
+
risk_premium_reason=reason if isinstance(reason, str) else None,
|
|
239
|
+
risk_premium_state=state,
|
|
240
|
+
risk_premium_cpm_finish=cpm_finish.isoformat() if cpm_finish is not None else None,
|
|
241
|
+
# Withheld in the unmeasurable state: a flat run's "P80" is the CPM date
|
|
242
|
+
# wearing a percentile's name, and offering it as a commitment would hand the
|
|
243
|
+
# reader a forecast to act on that the simulation never actually produced.
|
|
244
|
+
# The raw ``p80`` sits beside this on the forecast payload; that is not an
|
|
245
|
+
# inconsistency to "fix" — the withholding is a presentation control, and the
|
|
246
|
+
# client-side guard against a flat run reading as a commitment is structural.
|
|
247
|
+
risk_premium_p80=(p80.isoformat() if p80 is not None and state != "unmeasurable" else None),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def build_risk_premium(
|
|
252
|
+
run: Any | None, *, today: datetime.date, calendar_for: CalendarFor | None = None
|
|
253
|
+
) -> RiskPremium:
|
|
254
|
+
"""Derive the added-time metric from a project's most recent Monte Carlo run.
|
|
255
|
+
|
|
256
|
+
``run`` is a :class:`~trueppm_api.apps.scheduling.models.MonteCarloRun` or ``None``
|
|
257
|
+
when the project has never been simulated. Thin adapter over
|
|
258
|
+
:func:`risk_premium_from_values`, which owns the derivation. ``calendar_for``
|
|
259
|
+
supplies the project calendar the working-time comparison needs when the P80 or
|
|
260
|
+
CPM finish is a start-of-day reading (#4204).
|
|
261
|
+
"""
|
|
262
|
+
if run is None:
|
|
263
|
+
return _empty_premium()
|
|
264
|
+
return risk_premium_from_values(
|
|
265
|
+
p80=run.p80,
|
|
266
|
+
cpm_finish=run.cpm_finish,
|
|
267
|
+
taken_at=run.taken_at,
|
|
268
|
+
diagnostic=run.diagnostic if isinstance(run.diagnostic, dict) else None,
|
|
269
|
+
today=today,
|
|
270
|
+
p80_at_day_start=getattr(run, "p80_at_day_start", None),
|
|
271
|
+
cpm_finish_at_day_start=getattr(run, "cpm_finish_at_day_start", None),
|
|
272
|
+
calendar_for=calendar_for,
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def _parse_date(value: Any) -> datetime.date | None:
|
|
277
|
+
"""Best-effort ISO date parse; ``None`` for anything that is not one."""
|
|
278
|
+
if isinstance(value, datetime.datetime):
|
|
279
|
+
return value.date()
|
|
280
|
+
if isinstance(value, datetime.date):
|
|
281
|
+
return value
|
|
282
|
+
if not isinstance(value, str):
|
|
283
|
+
return None
|
|
284
|
+
try:
|
|
285
|
+
return datetime.date.fromisoformat(value)
|
|
286
|
+
except ValueError:
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _parse_datetime(value: Any) -> datetime.datetime | None:
|
|
291
|
+
"""Best-effort ISO datetime parse; ``None`` for anything that is not one."""
|
|
292
|
+
if isinstance(value, datetime.datetime):
|
|
293
|
+
return value
|
|
294
|
+
if not isinstance(value, str):
|
|
295
|
+
return None
|
|
296
|
+
try:
|
|
297
|
+
return datetime.datetime.fromisoformat(value)
|
|
298
|
+
except ValueError:
|
|
299
|
+
return None
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def _parse_reading(value: Any) -> bool | None:
|
|
303
|
+
"""An edge-of-day reading from a cache entry; ``None`` (unknown) unless a real bool."""
|
|
304
|
+
return value if isinstance(value, bool) else None
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def risk_premium_for_forecast_payload(
|
|
308
|
+
payload: Mapping[str, Any],
|
|
309
|
+
*,
|
|
310
|
+
today: datetime.date,
|
|
311
|
+
calendar_for: CalendarFor | None = None,
|
|
312
|
+
) -> RiskPremium:
|
|
313
|
+
"""Derive the premium from a cached Monte Carlo forecast dict.
|
|
314
|
+
|
|
315
|
+
The 24-hour ``mc_latest`` cache entry is written by the live-run path and read
|
|
316
|
+
back long after the fact, so the premium is computed *here*, on read, rather than
|
|
317
|
+
stored — see :func:`risk_premium_from_values` on why a frozen ``ratio`` goes wrong.
|
|
318
|
+
|
|
319
|
+
Absence is tolerated rather than trusted. A key that is missing, ``None`` or
|
|
320
|
+
unparseable is passed through as ``None``, so a legacy entry written before
|
|
321
|
+
``cpm_finish`` existed resolves to ``not_run`` — "we do not know" — instead of
|
|
322
|
+
raising or, worse, inventing a measured state from a partial payload.
|
|
323
|
+
"""
|
|
324
|
+
diagnostic = payload.get("forecast_diagnostic")
|
|
325
|
+
return risk_premium_from_values(
|
|
326
|
+
p80=_parse_date(payload.get("p80")),
|
|
327
|
+
cpm_finish=_parse_date(payload.get("cpm_finish")),
|
|
328
|
+
taken_at=_parse_datetime(payload.get("last_run_at")),
|
|
329
|
+
diagnostic=diagnostic if isinstance(diagnostic, dict) else None,
|
|
330
|
+
today=today,
|
|
331
|
+
p80_at_day_start=_parse_reading(payload.get("p80_at_day_start")),
|
|
332
|
+
cpm_finish_at_day_start=_parse_reading(payload.get("cpm_finish_at_day_start")),
|
|
333
|
+
calendar_for=calendar_for,
|
|
334
|
+
)
|