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,61 @@
|
|
|
1
|
+
"""Canonical JSON seed data: validation, import, and export.
|
|
2
|
+
|
|
3
|
+
The seed format and its design rationale are specified in ADR-0109. This
|
|
4
|
+
subpackage owns the three consumers of that format:
|
|
5
|
+
|
|
6
|
+
- ``validation`` (#614) — ``validate_seed`` / ``inspect_seed`` and the bundled
|
|
7
|
+
JSON Schema. ``inspect_seed`` is the non-raising form backing the dry run
|
|
8
|
+
(#2418).
|
|
9
|
+
- ``importer`` (#615) — load a seed document into a workspace.
|
|
10
|
+
- ``exporter`` (#616) — serialize a live program back to the seed format.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from typing import TYPE_CHECKING
|
|
16
|
+
|
|
17
|
+
from trueppm_api.apps.projects.seed.validation import (
|
|
18
|
+
SUPPORTED_MAJORS,
|
|
19
|
+
SeedReport,
|
|
20
|
+
SeedValidationError,
|
|
21
|
+
inspect_seed,
|
|
22
|
+
validate_seed,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
if TYPE_CHECKING:
|
|
26
|
+
# Give type checkers the real callable signatures while runtime keeps the
|
|
27
|
+
# lazy ``__getattr__`` loading below (so importing ``validate_seed`` stays
|
|
28
|
+
# Django-free).
|
|
29
|
+
from trueppm_api.apps.projects.seed.exporter import export_program as export_program
|
|
30
|
+
from trueppm_api.apps.projects.seed.exporter import export_project as export_project
|
|
31
|
+
from trueppm_api.apps.projects.seed.importer import import_seed as import_seed
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def __getattr__(name: str) -> object:
|
|
35
|
+
# Lazily expose the importer/exporter so importing ``validate_seed`` does
|
|
36
|
+
# not pull in the Django ORM (validation is a pure function — ADR-0109).
|
|
37
|
+
if name == "import_seed":
|
|
38
|
+
from trueppm_api.apps.projects.seed.importer import import_seed
|
|
39
|
+
|
|
40
|
+
return import_seed
|
|
41
|
+
if name == "export_program":
|
|
42
|
+
from trueppm_api.apps.projects.seed.exporter import export_program
|
|
43
|
+
|
|
44
|
+
return export_program
|
|
45
|
+
if name == "export_project":
|
|
46
|
+
from trueppm_api.apps.projects.seed.exporter import export_project
|
|
47
|
+
|
|
48
|
+
return export_project
|
|
49
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
__all__ = [
|
|
53
|
+
"SUPPORTED_MAJORS",
|
|
54
|
+
"SeedReport",
|
|
55
|
+
"SeedValidationError",
|
|
56
|
+
"export_program",
|
|
57
|
+
"export_project",
|
|
58
|
+
"import_seed",
|
|
59
|
+
"inspect_seed",
|
|
60
|
+
"validate_seed",
|
|
61
|
+
]
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
"""The demo-only landing overlay applied after the sample import (#4050 Part B).
|
|
2
|
+
|
|
3
|
+
The hosted interactive demo (ADR-1197) seeds the Atlas Platform Launch sample and
|
|
4
|
+
lands a first-time visitor on **Migration Tooling**. That project is *deliberately*
|
|
5
|
+
unhealthy in the fixture — health overridden to ``AT_RISK``, a P80 nineteen days
|
|
6
|
+
past the commitment, a slipping dry run, an unconfirmed gate, a pile of unscheduled
|
|
7
|
+
rows — because it is a *teaching* fixture for a PM exploring a plan under pressure,
|
|
8
|
+
and several docs pages and #3095's coverage tests describe exactly that shape.
|
|
9
|
+
|
|
10
|
+
On a first visit it reads as a product that does not work.
|
|
11
|
+
|
|
12
|
+
So the fix is **not** to edit ``atlas-platform-launch.json``. Editing it would break
|
|
13
|
+
#3095's coverage tests (including the export/import round-trip), invalidate the docs
|
|
14
|
+
that describe the fixture, and take the teaching shape away from every *other*
|
|
15
|
+
consumer of the sample — the local demo compose file, `load_sample_project` on a
|
|
16
|
+
self-hosted install, the downloadable fixture. Instead the demo reset applies this
|
|
17
|
+
small overlay **after** ``import_seed`` and **before** a final Monte Carlo run, and
|
|
18
|
+
only on a deployment that is actually a read-only demo.
|
|
19
|
+
|
|
20
|
+
**What it changes, and why each one.** Every item is an *indicator a first-time
|
|
21
|
+
visitor reads as a fault*:
|
|
22
|
+
|
|
23
|
+
=========================== =========================================================
|
|
24
|
+
Seed indicator Overlay
|
|
25
|
+
=========================== =========================================================
|
|
26
|
+
Health ``AT_RISK`` Override cleared to ``AUTO`` — the chip reads "On track".
|
|
27
|
+
P80 after the commitment A final run lands P80 a few days AHEAD of the commitment.
|
|
28
|
+
"Edited since this run" Monte Carlo runs LAST, so the run outlives every edit.
|
|
29
|
+
Unconfirmed milestone "Migration complete" is confirmed (``edited_at`` stamped).
|
|
30
|
+
Dry-run slip Dry-run migration is 100% and complete.
|
|
31
|
+
Unscheduled pile Trimmed to at most two plausible post-cutover rows.
|
|
32
|
+
**Kept, deliberately** **Performance tuning** stays ~2 days behind plan.
|
|
33
|
+
=========================== =========================================================
|
|
34
|
+
|
|
35
|
+
**The one signal that stays is the point.** A plan with nothing wrong on it is not a
|
|
36
|
+
demo of a scheduling tool, it is a screenshot. Performance tuning sits on the
|
|
37
|
+
critical path at 40% against ~50% planned, with float to the commitment absorbing
|
|
38
|
+
it — a real project's ordinary Tuesday. It is also the task the landing hint asks
|
|
39
|
+
the visitor to drag, and the web resolves it by that schedule *position* rather than
|
|
40
|
+
by name, so this overlay and the hint cannot drift apart over a rename.
|
|
41
|
+
|
|
42
|
+
**Fixture-coupled on purpose, and loud about it.** The rows are resolved by name
|
|
43
|
+
within the landing project. That is a real coupling to ``atlas-platform-launch.json``
|
|
44
|
+
and it is why a missing row **raises** instead of being skipped: a half-applied
|
|
45
|
+
overlay is a demo that looks *partly* broken, with nothing in the job log saying so,
|
|
46
|
+
and the reset job's exit status is the only thing watching.
|
|
47
|
+
"""
|
|
48
|
+
|
|
49
|
+
from __future__ import annotations
|
|
50
|
+
|
|
51
|
+
import datetime as dt
|
|
52
|
+
from dataclasses import dataclass
|
|
53
|
+
from typing import TYPE_CHECKING, Any
|
|
54
|
+
|
|
55
|
+
from django.conf import settings
|
|
56
|
+
from django.db import transaction
|
|
57
|
+
from django.utils import timezone
|
|
58
|
+
|
|
59
|
+
from trueppm_api.apps.projects.models import Health, Program, Project, Task, TaskStatus
|
|
60
|
+
from trueppm_api.apps.scheduling.models import MonteCarloRun
|
|
61
|
+
|
|
62
|
+
if TYPE_CHECKING: # pragma: no cover - typing only
|
|
63
|
+
from collections.abc import Iterable
|
|
64
|
+
|
|
65
|
+
#: The project a first-time demo visitor lands on.
|
|
66
|
+
LANDING_PROJECT_NAME = "Migration Tooling"
|
|
67
|
+
|
|
68
|
+
#: The one indicator the overlay deliberately leaves standing (see the module docstring).
|
|
69
|
+
BEHIND_PLAN_TASK_NAME = "Performance tuning"
|
|
70
|
+
|
|
71
|
+
#: The gate a visitor should not be asked to confirm on their first screen.
|
|
72
|
+
CONFIRMED_MILESTONE_NAME = "Migration complete"
|
|
73
|
+
|
|
74
|
+
#: The in-flight task whose slip reads as "this plan is already failing".
|
|
75
|
+
DRY_RUN_TASK_NAME = "Dry-run migration"
|
|
76
|
+
|
|
77
|
+
#: How far behind its straight-line plan the kept signal sits, in percentage points.
|
|
78
|
+
#: The design's own framing — "40% complete against 50% planned" — held as a *gap*
|
|
79
|
+
#: rather than as a literal 40, because where today falls inside the task's span is a
|
|
80
|
+
#: function of the reset date and cannot be authored.
|
|
81
|
+
BEHIND_PLAN_GAP_POINTS = 10.0
|
|
82
|
+
|
|
83
|
+
#: Half the kept signal's span, in calendar days. Today sits in the middle of it, so
|
|
84
|
+
#: the straight-line expectation is exactly 50% and the progress the overlay writes is
|
|
85
|
+
#: exactly the design's 40% — the two numbers the mock puts on that bar.
|
|
86
|
+
KEPT_SIGNAL_HALF_SPAN_DAYS = 7
|
|
87
|
+
|
|
88
|
+
#: Working days the kept signal is declared to take. Two weeks of calendar span at a
|
|
89
|
+
#: five-day week; stated rather than derived so the duration chip and the bar agree.
|
|
90
|
+
KEPT_SIGNAL_DURATION_DAYS = 10
|
|
91
|
+
|
|
92
|
+
#: Days of headroom between the final P80 and the project's commitment date. Small on
|
|
93
|
+
#: purpose: a forecast comfortably early is as unrealistic as one comfortably late,
|
|
94
|
+
#: and the visitor is meant to read "on track", not "sandbagged".
|
|
95
|
+
P80_HEADROOM_DAYS = 4
|
|
96
|
+
|
|
97
|
+
#: The most unscheduled rows the landing project keeps. Two reads as a backlog; the
|
|
98
|
+
#: fixture's full set reads as work somebody lost.
|
|
99
|
+
MAX_UNSCHEDULED = 2
|
|
100
|
+
|
|
101
|
+
#: Simulation count recorded on the final run. Matches the fixture's own
|
|
102
|
+
#: ``forecast_history.mc_iterations`` so the demo's run history is self-consistent.
|
|
103
|
+
FINAL_RUN_SIMULATIONS = 2000
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class DemoOverlayRefused(RuntimeError):
|
|
107
|
+
"""The overlay was asked to run somewhere it must not.
|
|
108
|
+
|
|
109
|
+
Raised — rather than returning quietly — because every caller is a seed job
|
|
110
|
+
whose exit status is the only supervision the demo has. A silent no-op on a
|
|
111
|
+
deployment that *is* a demo would ship the unfixed landing; a silent success on
|
|
112
|
+
one that is *not* would rewrite a real project's health and milestones.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class DemoOverlayFixtureMismatch(RuntimeError):
|
|
117
|
+
"""A row the overlay is written against is not in the imported seed."""
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@dataclass(frozen=True)
|
|
121
|
+
class DemoLandingOverlayResult:
|
|
122
|
+
"""What the overlay did, for the caller to report and for tests to assert."""
|
|
123
|
+
|
|
124
|
+
project_id: str
|
|
125
|
+
#: The task left behind plan — the landing hint's target. Exposed so a caller can
|
|
126
|
+
#: log it, and so the acceptance test can name it without re-deriving the rule.
|
|
127
|
+
behind_plan_task_id: str
|
|
128
|
+
behind_plan_task_wbs_path: str
|
|
129
|
+
monte_carlo_run_id: str
|
|
130
|
+
p80: dt.date
|
|
131
|
+
commitment_finish: dt.date
|
|
132
|
+
unscheduled_removed: int
|
|
133
|
+
#: True when this run found every seed indicator already dealt with — the second
|
|
134
|
+
#: and every later nightly reset over an already-overlaid database. The kept
|
|
135
|
+
#: signal's window and the forecast row are re-asserted on every run regardless
|
|
136
|
+
#: (the CPM pass re-derives the first, and the second must stay newer than it), so
|
|
137
|
+
#: neither counts toward this.
|
|
138
|
+
was_noop: bool
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _landing_project(program: Program) -> Project:
|
|
142
|
+
project = Project.objects.filter(
|
|
143
|
+
program=program, name=LANDING_PROJECT_NAME, is_deleted=False
|
|
144
|
+
).first()
|
|
145
|
+
if project is None:
|
|
146
|
+
raise DemoOverlayFixtureMismatch(
|
|
147
|
+
f"The demo landing project {LANDING_PROJECT_NAME!r} is not in program "
|
|
148
|
+
f"{program.name!r}. The overlay is written against "
|
|
149
|
+
"atlas-platform-launch.json; if the fixture renamed it, update "
|
|
150
|
+
"LANDING_PROJECT_NAME rather than letting the overlay skip."
|
|
151
|
+
)
|
|
152
|
+
return project
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def landing_project_for_demo_visitor(user: Any) -> Project | None:
|
|
156
|
+
"""The demo's landing project for ``user``, or ``None`` if there isn't one (#4151).
|
|
157
|
+
|
|
158
|
+
Reuses this module's identification of the landing project by name
|
|
159
|
+
(:data:`LANDING_PROJECT_NAME`) rather than letting ``resolve_landing`` hardcode a
|
|
160
|
+
second copy of it — a duplicate name literal is exactly the drift this project's
|
|
161
|
+
memory warns about (two derivations of one fact).
|
|
162
|
+
|
|
163
|
+
Scoped to a project that is still **live** (not soft-deleted, not archived) and
|
|
164
|
+
**directly readable by `user`** (a live :class:`ProjectMembership`) — mirroring
|
|
165
|
+
``most_recent_project``'s own readability filter in ``profiles.services`` — rather
|
|
166
|
+
than trusting that "the overlay ran on some program" implies access. The overlay
|
|
167
|
+
could have been applied to a program this particular caller was never granted, and
|
|
168
|
+
a landing must never route to a project the visitor cannot open (RBAC).
|
|
169
|
+
|
|
170
|
+
One indexed query. Returns ``None`` (never raises) so ``resolve_landing`` can fall
|
|
171
|
+
through to the normal role policy — a missing or unreadable landing project is a
|
|
172
|
+
reason to fall back, not a 500 on the front door.
|
|
173
|
+
"""
|
|
174
|
+
return (
|
|
175
|
+
Project.objects.filter(
|
|
176
|
+
name=LANDING_PROJECT_NAME,
|
|
177
|
+
is_deleted=False,
|
|
178
|
+
is_archived=False,
|
|
179
|
+
memberships__user=user,
|
|
180
|
+
memberships__is_deleted=False,
|
|
181
|
+
)
|
|
182
|
+
.distinct()
|
|
183
|
+
.first()
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _live_tasks(project: Project) -> list[Task]:
|
|
188
|
+
return list(Task.objects.filter(project=project, is_deleted=False).order_by("wbs_path"))
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _summary_ids(tasks: Iterable[Task]) -> set[object]:
|
|
192
|
+
"""Ids of rows that have at least one live structural descendant.
|
|
193
|
+
|
|
194
|
+
``is_summary`` is derived, not stored (``resources.services.task_is_summary``
|
|
195
|
+
runs an ltree descendancy probe per task), so it cannot appear in a queryset
|
|
196
|
+
filter. Derived here from the ltree paths already in memory: the overlay loads
|
|
197
|
+
the project's two dozen rows once, and one pass over them answers the question
|
|
198
|
+
for all of them without a query each.
|
|
199
|
+
"""
|
|
200
|
+
paths = [str(t.wbs_path) for t in tasks if t.wbs_path]
|
|
201
|
+
out: set[object] = set()
|
|
202
|
+
for task in tasks:
|
|
203
|
+
path = str(task.wbs_path) if task.wbs_path else ""
|
|
204
|
+
if not path:
|
|
205
|
+
continue
|
|
206
|
+
if any(other.startswith(path + ".") for other in paths if other != path):
|
|
207
|
+
out.add(task.pk)
|
|
208
|
+
return out
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def _task(project: Project, name: str) -> Task:
|
|
212
|
+
task = Task.objects.filter(project=project, name=name, is_deleted=False).first()
|
|
213
|
+
if task is None:
|
|
214
|
+
raise DemoOverlayFixtureMismatch(
|
|
215
|
+
f"The demo overlay expected a task named {name!r} in {project.name!r} and "
|
|
216
|
+
"found none. See this module's docstring on why this raises."
|
|
217
|
+
)
|
|
218
|
+
return task
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _commitment_finish(project: Project, tasks: Iterable[Task]) -> dt.date:
|
|
222
|
+
"""The date the plan is measured against.
|
|
223
|
+
|
|
224
|
+
Taken from the latest finish among the project's scheduled rows rather than from
|
|
225
|
+
the fixture's ``forecast_history.commitment_finish`` literal: the seed re-anchors
|
|
226
|
+
every relative date to the import day (ADR-1175), so the literal is not a date at
|
|
227
|
+
all until the importer has resolved it, and re-resolving it here would be a second
|
|
228
|
+
implementation of the same rule (feedback: two derivations of one fact drift).
|
|
229
|
+
"""
|
|
230
|
+
finishes = [t.early_finish for t in tasks if t.early_finish is not None]
|
|
231
|
+
if not finishes:
|
|
232
|
+
raise DemoOverlayFixtureMismatch(
|
|
233
|
+
f"{project.name!r} has no scheduled task finish to measure a forecast "
|
|
234
|
+
"against; the seed import did not produce a usable schedule."
|
|
235
|
+
)
|
|
236
|
+
return max(finishes)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _schedule_program(program: Program) -> None:
|
|
240
|
+
"""Run the program-true CPM pass so the rows carry real dates.
|
|
241
|
+
|
|
242
|
+
Imported inside the function: ``scheduling.tasks`` imports the projects app's
|
|
243
|
+
models, so a module-level import here would close an import cycle at Django
|
|
244
|
+
start-up. This is the same entry point the program scheduler's own tests drive
|
|
245
|
+
(``_run_program_schedule``), rather than a second, overlay-only way of
|
|
246
|
+
scheduling — the demo must be looking at the schedule the product computes.
|
|
247
|
+
"""
|
|
248
|
+
from trueppm_api.apps.scheduling.tasks import _run_program_schedule
|
|
249
|
+
|
|
250
|
+
_run_program_schedule(str(program.id))
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _clear_health_override(project: Project) -> bool:
|
|
254
|
+
"""Drop the ``AT_RISK`` override. Returns whether anything changed."""
|
|
255
|
+
if project.health == Health.AUTO:
|
|
256
|
+
return False
|
|
257
|
+
# AUTO, not ON_TRACK. The issue says "override cleared", and that is the honest
|
|
258
|
+
# act: a PM override asserts a human judgment, and there is no human here. With
|
|
259
|
+
# the override gone the chip renders the computed state, which on this plan — one
|
|
260
|
+
# task modestly behind, float absorbing it — is "On track".
|
|
261
|
+
project.health = Health.AUTO
|
|
262
|
+
project.save(update_fields=["health"])
|
|
263
|
+
return True
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _confirm_milestone(project: Project) -> bool:
|
|
267
|
+
"""Mark the closing gate as looked-at.
|
|
268
|
+
|
|
269
|
+
"Unconfirmed" is not a field: it is ``TaskManager.untouched_seeded`` — a seeded
|
|
270
|
+
row no person has touched (``edited_at IS NULL``). So confirming it means giving
|
|
271
|
+
it an ``edited_at``, which an ordinary ``save()`` does, because ``Task.save``
|
|
272
|
+
treats a write as human unless it says otherwise (ADR-0786 §4). That default is
|
|
273
|
+
exactly right here: a visitor should see a gate somebody has agreed to.
|
|
274
|
+
"""
|
|
275
|
+
milestone = _task(project, CONFIRMED_MILESTONE_NAME)
|
|
276
|
+
if milestone.edited_at is not None:
|
|
277
|
+
return False
|
|
278
|
+
milestone.save(update_fields=["edited_at"])
|
|
279
|
+
return True
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _finish_dry_run(project: Project) -> bool:
|
|
283
|
+
"""Dry-run migration is done and on plan."""
|
|
284
|
+
task = _task(project, DRY_RUN_TASK_NAME)
|
|
285
|
+
if task.percent_complete >= 100.0 and task.status == TaskStatus.COMPLETE:
|
|
286
|
+
return False
|
|
287
|
+
task.percent_complete = 100.0
|
|
288
|
+
task.status = TaskStatus.COMPLETE
|
|
289
|
+
task.save(update_fields=["percent_complete", "status"])
|
|
290
|
+
return True
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def _place_the_kept_signal(project: Project) -> bool:
|
|
294
|
+
"""Put the kept signal in flight, straddling today, with a window we control.
|
|
295
|
+
|
|
296
|
+
The fixture starts Performance tuning at ``A+11`` — eleven days *after* the reset,
|
|
297
|
+
i.e. in the future — and a task that has not begun cannot be behind anything.
|
|
298
|
+
|
|
299
|
+
**The window is written directly rather than coaxed out of the engine, and that is
|
|
300
|
+
a deliberate call.** Two rounds of trying the other way say why: a `planned_start`
|
|
301
|
+
in the past is a *constraint*, and CPM still takes the max of it and the
|
|
302
|
+
predecessor-driven early start, so the task kept landing wherever the network put
|
|
303
|
+
it; and `scheduled_start` is derived from progress (ADR-0752), so the span moved
|
|
304
|
+
every time the percentage did. Both are correct engine behaviour and neither can
|
|
305
|
+
be steered into "today sits halfway through this bar", which is the one property
|
|
306
|
+
the landing needs. So the overlay states the span, and `_keep_one_behind_plan`
|
|
307
|
+
measures the percentage against the span it just stated — one direction of
|
|
308
|
+
derivation instead of a loop.
|
|
309
|
+
|
|
310
|
+
Nothing recomputes CPM afterwards, which is what makes that safe: these dates are
|
|
311
|
+
the ones the demo serves, and the deployment refuses every write that could
|
|
312
|
+
disturb them.
|
|
313
|
+
"""
|
|
314
|
+
task = _task(project, BEHIND_PLAN_TASK_NAME)
|
|
315
|
+
today = timezone.localdate()
|
|
316
|
+
started = today - dt.timedelta(days=KEPT_SIGNAL_HALF_SPAN_DAYS)
|
|
317
|
+
finishing = today + dt.timedelta(days=KEPT_SIGNAL_HALF_SPAN_DAYS)
|
|
318
|
+
if (
|
|
319
|
+
task.actual_start == started
|
|
320
|
+
and task.scheduled_start == started
|
|
321
|
+
and task.early_finish == finishing
|
|
322
|
+
and task.status == TaskStatus.IN_PROGRESS
|
|
323
|
+
):
|
|
324
|
+
return False
|
|
325
|
+
task.actual_start = started
|
|
326
|
+
task.planned_start = started
|
|
327
|
+
task.scheduled_start = started
|
|
328
|
+
task.early_start = started
|
|
329
|
+
task.early_finish = finishing
|
|
330
|
+
task.duration = KEPT_SIGNAL_DURATION_DAYS
|
|
331
|
+
task.status = TaskStatus.IN_PROGRESS
|
|
332
|
+
task.save(
|
|
333
|
+
update_fields=[
|
|
334
|
+
"actual_start",
|
|
335
|
+
"planned_start",
|
|
336
|
+
"scheduled_start",
|
|
337
|
+
"early_start",
|
|
338
|
+
"early_finish",
|
|
339
|
+
"duration",
|
|
340
|
+
"status",
|
|
341
|
+
]
|
|
342
|
+
)
|
|
343
|
+
return True
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _keep_one_behind_plan(project: Project) -> Task:
|
|
347
|
+
"""Leave exactly one realistic signal standing, and make sure it is the only one.
|
|
348
|
+
|
|
349
|
+
Two separate acts, and the **second** is the one that makes the acceptance
|
|
350
|
+
criterion true. Setting Performance tuning behind plan is easy; "exactly one
|
|
351
|
+
behind-plan task" is a statement about every *other* row, so each of them is
|
|
352
|
+
brought up to its own straight-line expectation rather than left wherever the
|
|
353
|
+
fixture put it.
|
|
354
|
+
|
|
355
|
+
Called after the CPM pass, and nothing recomputes CPM afterwards. That is
|
|
356
|
+
deliberate and it is what the ordering buys: progress consumes remaining duration
|
|
357
|
+
(ADR-0752), so re-running the engine here would move the very dates these
|
|
358
|
+
percentages were measured against — and, worse, would stamp ``recalculated_at``
|
|
359
|
+
after the forecast run and make the demo report its own forecast stale.
|
|
360
|
+
"""
|
|
361
|
+
today = timezone.localdate()
|
|
362
|
+
target = _task(project, BEHIND_PLAN_TASK_NAME)
|
|
363
|
+
expected = _expected_percent(target, today)
|
|
364
|
+
if expected is not None:
|
|
365
|
+
behind = round(expected - BEHIND_PLAN_GAP_POINTS, 1)
|
|
366
|
+
if target.percent_complete != behind:
|
|
367
|
+
target.percent_complete = behind
|
|
368
|
+
target.save(update_fields=["percent_complete"])
|
|
369
|
+
|
|
370
|
+
tasks = _live_tasks(project)
|
|
371
|
+
summaries = _summary_ids(tasks)
|
|
372
|
+
for task in tasks:
|
|
373
|
+
if task.pk == target.pk or task.pk in summaries or task.is_milestone:
|
|
374
|
+
continue
|
|
375
|
+
expected = _expected_percent(task, today)
|
|
376
|
+
if expected is None:
|
|
377
|
+
continue
|
|
378
|
+
if (task.percent_complete or 0.0) >= expected:
|
|
379
|
+
continue
|
|
380
|
+
task.percent_complete = expected
|
|
381
|
+
if expected >= 100.0:
|
|
382
|
+
task.status = TaskStatus.COMPLETE
|
|
383
|
+
elif expected > 0.0 and task.status == TaskStatus.NOT_STARTED:
|
|
384
|
+
task.status = TaskStatus.IN_PROGRESS
|
|
385
|
+
task.save(update_fields=["percent_complete", "status"])
|
|
386
|
+
return target
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _expected_percent(task: Task, today: dt.date) -> float | None:
|
|
390
|
+
"""Straight-line expected completion for ``task`` at ``today``.
|
|
391
|
+
|
|
392
|
+
Measured over the task's **span** — ``scheduled_start`` to ``early_finish``
|
|
393
|
+
(ADR-0752) — not over ``early_start``, which for an in-progress task names the
|
|
394
|
+
*remaining-work* window and therefore begins at the data date. Measuring against
|
|
395
|
+
that would report every started task as 0% expected, i.e. never behind, which is
|
|
396
|
+
the trap `project_2621_2623_remaining_duration_semantics` records. It is also the
|
|
397
|
+
window the canvas bar is drawn from and the one the web's hint-target picker
|
|
398
|
+
reads (``features/schedule/demoHintTarget.ts``), so all three agree by
|
|
399
|
+
construction rather than by coincidence.
|
|
400
|
+
"""
|
|
401
|
+
start = task.scheduled_start or task.early_start
|
|
402
|
+
finish = task.early_finish
|
|
403
|
+
if start is None or finish is None or finish <= start:
|
|
404
|
+
return None
|
|
405
|
+
if today <= start:
|
|
406
|
+
return 0.0
|
|
407
|
+
if today >= finish:
|
|
408
|
+
return 100.0
|
|
409
|
+
return round((today - start).days / (finish - start).days * 100.0, 1)
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _trim_unscheduled(project: Project) -> int:
|
|
413
|
+
"""Leave at most two unscheduled rows. Returns how many were removed."""
|
|
414
|
+
tasks = _live_tasks(project)
|
|
415
|
+
summaries = _summary_ids(tasks)
|
|
416
|
+
unscheduled = [
|
|
417
|
+
t
|
|
418
|
+
for t in tasks
|
|
419
|
+
if t.pk not in summaries and t.planned_start is None and t.early_start is None
|
|
420
|
+
]
|
|
421
|
+
surplus = unscheduled[MAX_UNSCHEDULED:]
|
|
422
|
+
for task in surplus:
|
|
423
|
+
task.soft_delete()
|
|
424
|
+
return len(surplus)
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
def _run_monte_carlo_last(
|
|
428
|
+
project: Project, *, commitment: dt.date, cpm_finish: dt.date
|
|
429
|
+
) -> MonteCarloRun:
|
|
430
|
+
"""Record the final forecast, after every other write.
|
|
431
|
+
|
|
432
|
+
**The ordering is the fix, not a detail.** "Edited since this run" is
|
|
433
|
+
``plan_version < plan_version_current`` or ``recalculated_at > taken_at``
|
|
434
|
+
(``scheduling/forecast_staleness.py``). A run recorded before the overlay's edits
|
|
435
|
+
is stale *by construction*, and the demo would carry a staleness warning that is
|
|
436
|
+
both true and entirely self-inflicted. So this is the last thing that happens, it
|
|
437
|
+
reads ``last_sync_version`` after the edits, and its ``taken_at`` (``auto_now_add``)
|
|
438
|
+
is therefore later than every one of them.
|
|
439
|
+
|
|
440
|
+
The percentiles are authored rather than simulated. Running the real engine here
|
|
441
|
+
would produce whatever the fixture's three-point estimates imply — which is the
|
|
442
|
+
A+86-vs-A+67 overshoot this overlay exists to remove — so simulating and then
|
|
443
|
+
overwriting the answer would be a more expensive way to write the same row while
|
|
444
|
+
pretending it was derived. The fixture's own backfilled history is synthesized the
|
|
445
|
+
same way and for the same reason (``forecast_backfill``, ADR-0211).
|
|
446
|
+
"""
|
|
447
|
+
p80 = commitment - dt.timedelta(days=P80_HEADROOM_DAYS)
|
|
448
|
+
return MonteCarloRun.objects.create(
|
|
449
|
+
project=project,
|
|
450
|
+
triggered_by=None,
|
|
451
|
+
p50=p80 - dt.timedelta(days=5),
|
|
452
|
+
p80=p80,
|
|
453
|
+
p95=p80 + dt.timedelta(days=6),
|
|
454
|
+
cpm_finish=cpm_finish,
|
|
455
|
+
n_simulations=FINAL_RUN_SIMULATIONS,
|
|
456
|
+
task_count=Task.objects.filter(project=project, is_deleted=False).count(),
|
|
457
|
+
status_date=timezone.localdate(),
|
|
458
|
+
# Read AFTER every edit above — this is what makes the run current rather
|
|
459
|
+
# than merely recent.
|
|
460
|
+
plan_version=Project.objects.values_list("last_sync_version", flat=True).get(pk=project.pk),
|
|
461
|
+
)
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
@transaction.atomic
|
|
465
|
+
def apply_demo_landing_overlay(program: Program) -> DemoLandingOverlayResult:
|
|
466
|
+
"""Apply the demo-only landing overlay to ``program``'s landing project.
|
|
467
|
+
|
|
468
|
+
Idempotent in the sense the nightly reset needs: a second call over an
|
|
469
|
+
already-overlaid database reaches the same state, and ``was_noop`` says that every
|
|
470
|
+
seed indicator was already dealt with. Two things are re-asserted on every run by
|
|
471
|
+
design — the kept signal's window (the CPM pass re-derives it each time) and the
|
|
472
|
+
forecast row (it has to stay newer than whatever this run wrote).
|
|
473
|
+
|
|
474
|
+
Raises:
|
|
475
|
+
DemoOverlayRefused: ``settings.DEMO_READ_ONLY`` is not on. The overlay
|
|
476
|
+
rewrites project health, task progress and milestone confirmation, and a
|
|
477
|
+
deployment people actually work in must never have that done to it by a
|
|
478
|
+
seed job.
|
|
479
|
+
DemoOverlayFixtureMismatch: the imported seed does not carry a row this
|
|
480
|
+
overlay is written against.
|
|
481
|
+
"""
|
|
482
|
+
if not settings.DEMO_READ_ONLY:
|
|
483
|
+
raise DemoOverlayRefused(
|
|
484
|
+
"The demo landing overlay refuses to run while TRUEPPM_DEMO_READ_ONLY is "
|
|
485
|
+
"off. It clears a project's health override, completes tasks, confirms a "
|
|
486
|
+
"milestone and soft-deletes unscheduled rows — none of which may happen "
|
|
487
|
+
"to a deployment people work in. See ADR-1197."
|
|
488
|
+
)
|
|
489
|
+
|
|
490
|
+
project = _landing_project(program)
|
|
491
|
+
|
|
492
|
+
# CPM FIRST, because every measurement below is against `early_start` /
|
|
493
|
+
# `early_finish`, and `import_seed` does not schedule — it writes
|
|
494
|
+
# `planned_start` + `duration` and leaves the engine to derive dates. Without
|
|
495
|
+
# this the overlay has no window to measure "behind plan" against, and the one
|
|
496
|
+
# signal it is supposed to leave standing would be left standing by accident.
|
|
497
|
+
_schedule_program(program)
|
|
498
|
+
|
|
499
|
+
changed = _clear_health_override(project)
|
|
500
|
+
changed |= _confirm_milestone(project)
|
|
501
|
+
changed |= _finish_dry_run(project)
|
|
502
|
+
removed = _trim_unscheduled(project)
|
|
503
|
+
changed |= removed > 0
|
|
504
|
+
|
|
505
|
+
# …and again, because completing the dry run, starting the kept signal and
|
|
506
|
+
# trimming the unscheduled pile all change the network. The percentages below are
|
|
507
|
+
# measured against THESE dates, and nothing recomputes after them — see
|
|
508
|
+
# `_keep_one_behind_plan`.
|
|
509
|
+
_schedule_program(program)
|
|
510
|
+
|
|
511
|
+
# After the last CPM pass, never before it: this writes the kept signal's dates
|
|
512
|
+
# outright, and a later engine run would take them back — which is also why it is
|
|
513
|
+
# NOT folded into `changed`. The CPM pass above re-derives that window on every
|
|
514
|
+
# run, so re-asserting it is what every reset does, not evidence that the previous
|
|
515
|
+
# reset left something undone. `was_noop` answers "were the seed's INDICATORS
|
|
516
|
+
# already dealt with", which is the question an operator reading the job log has.
|
|
517
|
+
_place_the_kept_signal(project)
|
|
518
|
+
target = _keep_one_behind_plan(project)
|
|
519
|
+
|
|
520
|
+
commitment = _commitment_finish(project, _live_tasks(project))
|
|
521
|
+
run = _run_monte_carlo_last(project, commitment=commitment, cpm_finish=commitment)
|
|
522
|
+
|
|
523
|
+
return DemoLandingOverlayResult(
|
|
524
|
+
project_id=str(project.pk),
|
|
525
|
+
behind_plan_task_id=str(target.pk),
|
|
526
|
+
behind_plan_task_wbs_path=str(target.wbs_path),
|
|
527
|
+
monte_carlo_run_id=str(run.pk),
|
|
528
|
+
p80=run.p80, # type: ignore[arg-type] # set unconditionally above
|
|
529
|
+
commitment_finish=commitment,
|
|
530
|
+
unscheduled_removed=removed,
|
|
531
|
+
was_noop=not changed,
|
|
532
|
+
)
|