trueppm-api 0.4.0b2__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 +14 -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 +164 -0
- trueppm_api/apps/access/management/commands/migrate_locked.py +96 -0
- trueppm_api/apps/access/management/commands/revoke_api_tokens.py +209 -0
- trueppm_api/apps/access/migrations/0001_initial.py +61 -0
- trueppm_api/apps/access/migrations/0001_squashed_0012_programmembership_role_title.py +167 -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_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 +132 -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/models.py +588 -0
- trueppm_api/apps/access/permissions.py +2837 -0
- trueppm_api/apps/access/serializers.py +946 -0
- trueppm_api/apps/access/services.py +667 -0
- trueppm_api/apps/access/signals.py +103 -0
- trueppm_api/apps/access/tasks.py +50 -0
- trueppm_api/apps/access/throttles.py +95 -0
- trueppm_api/apps/access/urls.py +191 -0
- trueppm_api/apps/access/views.py +1931 -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/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 +108 -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/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 +418 -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 +177 -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 +837 -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 +403 -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_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/__init__.py +0 -0
- trueppm_api/apps/integrations/models.py +622 -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 +519 -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 +731 -0
- trueppm_api/apps/integrations/throttles.py +165 -0
- trueppm_api/apps/integrations/urls.py +77 -0
- trueppm_api/apps/integrations/views.py +1106 -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 +277 -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 +500 -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 +1231 -0
- trueppm_api/apps/msproject/serializers.py +136 -0
- trueppm_api/apps/msproject/services.py +58 -0
- trueppm_api/apps/msproject/tasks.py +436 -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 +447 -0
- trueppm_api/apps/notifications/email_backend.py +330 -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 +294 -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_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 +1197 -0
- trueppm_api/apps/notifications/receivers.py +155 -0
- trueppm_api/apps/notifications/schema_migrations.py +56 -0
- trueppm_api/apps/notifications/serializers.py +961 -0
- trueppm_api/apps/notifications/services.py +1451 -0
- trueppm_api/apps/notifications/tasks.py +711 -0
- trueppm_api/apps/notifications/throttles.py +98 -0
- trueppm_api/apps/notifications/urls.py +97 -0
- trueppm_api/apps/notifications/views.py +904 -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 +551 -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 +969 -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 +523 -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_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 +466 -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 +449 -0
- trueppm_api/apps/projects/backfill.py +287 -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 +204 -0
- trueppm_api/apps/projects/config_notice.py +1325 -0
- trueppm_api/apps/projects/custom_field_values.py +266 -0
- trueppm_api/apps/projects/decisions_services.py +93 -0
- trueppm_api/apps/projects/decisions_views.py +94 -0
- trueppm_api/apps/projects/estimation_scale.py +126 -0
- trueppm_api/apps/projects/export_bundle.py +353 -0
- trueppm_api/apps/projects/fixtures/seeds/atlas-platform-launch.json +4256 -0
- trueppm_api/apps/projects/fixtures/seeds/aurora-mobile-app.json +2000 -0
- trueppm_api/apps/projects/fixtures/seeds/bayside-civic-center.json +1825 -0
- trueppm_api/apps/projects/fixtures/seeds/ga-launch.json +1905 -0
- trueppm_api/apps/projects/fixtures/seeds/helios-crm-replacement.json +1409 -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/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 +247 -0
- trueppm_api/apps/projects/management/commands/seed_capacity.py +405 -0
- trueppm_api/apps/projects/management/commands/seed_integration_fixtures.py +178 -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/migrations/0001_initial.py +208 -0
- trueppm_api/apps/projects/migrations/0001_squashed_0094_project_decisions_policy.py +5595 -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 +44 -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 +61 -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 +62 -0
- trueppm_api/apps/projects/migrations/0106_boardsavedview_schema_version.py +20 -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/__init__.py +0 -0
- trueppm_api/apps/projects/models.py +8946 -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 +575 -0
- trueppm_api/apps/projects/program_schedule.py +745 -0
- trueppm_api/apps/projects/program_views.py +3220 -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 +493 -0
- trueppm_api/apps/projects/schemas/seed_v2.json +892 -0
- trueppm_api/apps/projects/seed/__init__.py +61 -0
- trueppm_api/apps/projects/seed/exporter.py +1644 -0
- trueppm_api/apps/projects/seed/forecast_backfill.py +247 -0
- trueppm_api/apps/projects/seed/importer.py +2390 -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 +126 -0
- trueppm_api/apps/projects/seed/replay.py +1691 -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 +1149 -0
- trueppm_api/apps/projects/serializers.py +12310 -0
- trueppm_api/apps/projects/services.py +6966 -0
- trueppm_api/apps/projects/share_serializers.py +132 -0
- trueppm_api/apps/projects/share_services.py +325 -0
- trueppm_api/apps/projects/share_views.py +374 -0
- trueppm_api/apps/projects/sharing_settings.py +187 -0
- trueppm_api/apps/projects/signal_privacy_services.py +909 -0
- trueppm_api/apps/projects/signal_privacy_views.py +476 -0
- trueppm_api/apps/projects/signals.py +132 -0
- trueppm_api/apps/projects/slip_conflict.py +266 -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 +1152 -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 +1917 -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 +258 -0
- trueppm_api/apps/projects/template_views.py +799 -0
- trueppm_api/apps/projects/throttles.py +311 -0
- trueppm_api/apps/projects/urls.py +1011 -0
- trueppm_api/apps/projects/utilization.py +885 -0
- trueppm_api/apps/projects/views.py +20572 -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/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 +1749 -0
- trueppm_api/apps/scheduling/__init__.py +0 -0
- trueppm_api/apps/scheduling/apps.py +153 -0
- trueppm_api/apps/scheduling/calendars.py +119 -0
- trueppm_api/apps/scheduling/deadletter.py +91 -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/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/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/__init__.py +0 -0
- trueppm_api/apps/scheduling/models.py +516 -0
- trueppm_api/apps/scheduling/receivers.py +160 -0
- trueppm_api/apps/scheduling/risk_premium.py +283 -0
- trueppm_api/apps/scheduling/serializers.py +564 -0
- trueppm_api/apps/scheduling/services.py +1182 -0
- trueppm_api/apps/scheduling/signals.py +56 -0
- trueppm_api/apps/scheduling/tasks.py +1984 -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 +2564 -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 +437 -0
- trueppm_api/apps/sso/services.py +1385 -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 +320 -0
- trueppm_api/apps/sync/conflict.py +262 -0
- trueppm_api/apps/sync/consumers.py +471 -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/0004_seed_sync_seq.py +24 -0
- trueppm_api/apps/sync/migrations/0005_program_sync_sequence.py +35 -0
- trueppm_api/apps/sync/migrations/__init__.py +0 -0
- trueppm_api/apps/sync/models.py +225 -0
- trueppm_api/apps/sync/pagination.py +231 -0
- trueppm_api/apps/sync/sequence.py +371 -0
- trueppm_api/apps/sync/serializers.py +687 -0
- trueppm_api/apps/sync/tasks.py +260 -0
- trueppm_api/apps/sync/throttles.py +175 -0
- trueppm_api/apps/sync/upload.py +501 -0
- trueppm_api/apps/sync/urls.py +17 -0
- trueppm_api/apps/sync/views.py +930 -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 +142 -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/__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 +434 -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/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 +117 -0
- trueppm_api/apps/timetracking/urls.py +47 -0
- trueppm_api/apps/timetracking/views.py +526 -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 +144 -0
- trueppm_api/apps/webhooks/migrations/0001_initial.py +146 -0
- trueppm_api/apps/webhooks/migrations/0001_squashed_0007_sprint_lifecycle_events.py +243 -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 +90 -0
- trueppm_api/apps/webhooks/migrations/__init__.py +0 -0
- trueppm_api/apps/webhooks/models.py +372 -0
- trueppm_api/apps/webhooks/serializers.py +318 -0
- trueppm_api/apps/webhooks/tasks.py +663 -0
- trueppm_api/apps/webhooks/urls.py +22 -0
- trueppm_api/apps/webhooks/views.py +383 -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 +368 -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 +242 -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_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 +919 -0
- trueppm_api/apps/workspace/signals.py +37 -0
- trueppm_api/apps/workspace/tasks.py +555 -0
- trueppm_api/apps/workspace/urls.py +113 -0
- trueppm_api/apps/workspace/views.py +1502 -0
- trueppm_api/asgi.py +42 -0
- trueppm_api/celery.py +31 -0
- trueppm_api/core/__init__.py +0 -0
- trueppm_api/core/admin_site.py +206 -0
- trueppm_api/core/auth_views.py +916 -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/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 +949 -0
- trueppm_api/core/password_reset.py +500 -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 +884 -0
- trueppm_api/core/storage_config.py +105 -0
- trueppm_api/core/text_decode.py +168 -0
- trueppm_api/core/throttling.py +344 -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/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 +2455 -0
- trueppm_api/settings/dev.py +273 -0
- trueppm_api/settings/prod.py +228 -0
- trueppm_api/urls.py +153 -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.0b2.dist-info/METADATA +70 -0
- trueppm_api-0.4.0b2.dist-info/RECORD +759 -0
- trueppm_api-0.4.0b2.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
"""Agent-action audit models — the OSS hash-chained audit substrate (ADR-0112 RC1/RC2, #1805).
|
|
2
|
+
|
|
3
|
+
Every MCP/agent decision (a read, or a refusal) is recorded as one append-only
|
|
4
|
+
``AgentAction`` row. The rows form a **per-instance, hash-chained** log: each row
|
|
5
|
+
stores a monotonic ``sequence`` and ``record_hash = sha256(prev_hash ‖ canonical(record))``
|
|
6
|
+
where ``prev_hash`` is the predecessor row's ``record_hash``. A team can therefore
|
|
7
|
+
detect whether its own log was altered on its own instance via
|
|
8
|
+
``manage.py audit_verify`` — the OSS integrity self-check (the audit-log analog of the
|
|
9
|
+
answer-stamp hash). Org-scale compliance *evidence* (external notarization, a
|
|
10
|
+
cryptographic signature over the chain, retention policy, cross-instance trail) is the
|
|
11
|
+
Enterprise value-add (#146); this OSS log detects local tampering, it does not notarize.
|
|
12
|
+
|
|
13
|
+
RC2: the ``sequence`` and chain are **per-instance / per-workspace**, not per-tenant —
|
|
14
|
+
TruePPM is single-tenant/self-hosted. The chain head is a single row
|
|
15
|
+
(``AgentActionChainHead``); ``record_agent_action`` serializes appends with a
|
|
16
|
+
``select_for_update`` on it, so the chain is strictly gap-free and ordered.
|
|
17
|
+
|
|
18
|
+
Both models are plain ``models.Model`` (not ``VersionedModel``): append-only audit rows
|
|
19
|
+
are never synced to mobile and immutability makes ``server_version`` unnecessary — the
|
|
20
|
+
same rationale as ``ApiTokenAuditEntry`` and the ADR-0176 sprint-outcome snapshots.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import hashlib
|
|
26
|
+
import uuid
|
|
27
|
+
|
|
28
|
+
from django.conf import settings
|
|
29
|
+
from django.db import models
|
|
30
|
+
from django.db.models import Q
|
|
31
|
+
|
|
32
|
+
#: Schema version of the ``AgentAction`` record + the canonical hash input. Bumped only
|
|
33
|
+
#: on a breaking change to the chained field set or the canonicalization (which would be
|
|
34
|
+
#: a chain-format break). Enterprise receivers branch on this (ADR-0112 contract).
|
|
35
|
+
AGENT_ACTION_SCHEMA_VERSION = 1
|
|
36
|
+
|
|
37
|
+
#: The genesis ``prev_hash`` for the first row in a fresh chain. A fixed, versioned
|
|
38
|
+
#: domain-separated constant so the chain root is deterministic and reproducible across
|
|
39
|
+
#: instances (it is not secret — it anchors the chain, it does not authenticate it).
|
|
40
|
+
GENESIS_PREV_HASH = hashlib.sha256(b"trueppm/agents/agent-action/genesis/v1").hexdigest()
|
|
41
|
+
|
|
42
|
+
#: ``actor_token_prefix`` of a row the bundled-sample loader wrote (#3603). No real
|
|
43
|
+
#: token prefix can equal it: real prefixes are 8 hex chars, this is 6 non-hex ones.
|
|
44
|
+
SAMPLE_TOKEN_PREFIX = "sample"
|
|
45
|
+
|
|
46
|
+
#: Leading text of a sample row's ``summary``. Both markers are hashed fields, so a
|
|
47
|
+
#: sample row cannot be relabeled as real evidence without failing ``audit_verify``.
|
|
48
|
+
SAMPLE_SUMMARY_PREFIX = "[Sample data] "
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class AgentActorKind(models.TextChoices):
|
|
52
|
+
"""What kind of actor performed the action.
|
|
53
|
+
|
|
54
|
+
Phase 0 (#1805) only ever records ``MCP_TOKEN`` — a personal ``mcp:read`` API
|
|
55
|
+
token acting on the MCP read surface. The fuller first-class agent-actor kinds
|
|
56
|
+
arrive with #1063 (0.5); the field exists now so the vocabulary is stable.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
MCP_TOKEN = "mcp_token", "MCP token"
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class AgentActionVerdict(models.TextChoices):
|
|
63
|
+
"""The decision outcome recorded for the action (ADR-0112 RC1)."""
|
|
64
|
+
|
|
65
|
+
ALLOWED = "allowed", "Allowed"
|
|
66
|
+
REFUSED = "refused", "Refused"
|
|
67
|
+
REQUIRES_APPROVAL = "requires_approval", "Requires approval"
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class AgentActionRefusalReason(models.TextChoices):
|
|
71
|
+
"""Why a ``REFUSED`` action was refused (ADR-0112 RC1).
|
|
72
|
+
|
|
73
|
+
``IDENTITY`` — no/invalid actor (a revoked or expired token was presented).
|
|
74
|
+
``POLICY`` — actor known, but a capability/permission (or, later, an approval)
|
|
75
|
+
was denied. Recorded from day one so the log answers *why* a decision went the
|
|
76
|
+
way it did, not merely *that* it did.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
IDENTITY = "identity", "Identity"
|
|
80
|
+
POLICY = "policy", "Policy"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class RefusalConstraint(models.TextChoices):
|
|
84
|
+
"""Which constraint fired for a refusal (ADR-0421, #1850).
|
|
85
|
+
|
|
86
|
+
A **finer** axis than ``AgentActionRefusalReason`` (identity|policy): the coarse
|
|
87
|
+
reason answers *which layer* refused, this answers *which specific guard*. Recorded
|
|
88
|
+
on the non-hashed ``AgentActionRefusalDetail`` side-car so it is queryable for
|
|
89
|
+
engineering triage ("show me every ``graph_validation`` refusal") without touching
|
|
90
|
+
the hash-chained record. The vocabulary is forward-compatible by addition — the two
|
|
91
|
+
``*_scope``/``*_identity`` codes have live producers today; the remaining four are
|
|
92
|
+
reserved for the 0.6 gated-write producers (ADR-0362 §7) so those slot in with no
|
|
93
|
+
schema change.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
CAPABILITY_SCOPE = "capability_scope", "Capability scope"
|
|
97
|
+
TOKEN_IDENTITY = "token_identity", "Token identity"
|
|
98
|
+
# Reserved for the 0.6 gated-write surface (ADR-0362 §4 refusal-engine v1); no
|
|
99
|
+
# producer emits these yet — the enum reserves the codes so they slot in later.
|
|
100
|
+
GRAPH_VALIDATION = "graph_validation", "Graph validation"
|
|
101
|
+
SPRINT_SOVEREIGNTY = "sprint_sovereignty", "Sprint sovereignty"
|
|
102
|
+
ROLLUP_LOCK = "rollup_lock", "Rollup lock"
|
|
103
|
+
ENGINE_REFEREE = "engine_referee", "Engine referee"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class AgentActionChainHead(models.Model):
|
|
107
|
+
"""Singleton head of the per-instance hash chain (ADR-0112 RC2).
|
|
108
|
+
|
|
109
|
+
Holds the last allocated ``sequence`` and the last row's ``record_hash`` so a new
|
|
110
|
+
append reads the predecessor link under a single ``select_for_update`` lock. The row
|
|
111
|
+
is seeded (id=1, sequence=0, hash=genesis) by the initial migration so the service
|
|
112
|
+
can ``select_for_update().get(pk=1)`` without a create race on the first request.
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
id = models.PositiveSmallIntegerField(primary_key=True, default=1, editable=False)
|
|
116
|
+
last_sequence = models.BigIntegerField(
|
|
117
|
+
default=0,
|
|
118
|
+
help_text="Highest sequence allocated so far (0 before the first record).",
|
|
119
|
+
)
|
|
120
|
+
last_record_hash = models.CharField(
|
|
121
|
+
max_length=64,
|
|
122
|
+
default=GENESIS_PREV_HASH,
|
|
123
|
+
help_text="record_hash of the most recent AgentAction — the next row's prev_hash.",
|
|
124
|
+
)
|
|
125
|
+
updated_at = models.DateTimeField(auto_now=True)
|
|
126
|
+
|
|
127
|
+
class Meta:
|
|
128
|
+
db_table = "agents_agent_action_chain_head"
|
|
129
|
+
constraints = [
|
|
130
|
+
# Enforce the singleton at the DB level: only id=1 may exist.
|
|
131
|
+
models.CheckConstraint(
|
|
132
|
+
condition=Q(id=1),
|
|
133
|
+
name="agent_action_chain_head_singleton",
|
|
134
|
+
),
|
|
135
|
+
]
|
|
136
|
+
|
|
137
|
+
def __str__(self) -> str:
|
|
138
|
+
return f"AgentActionChainHead(seq={self.last_sequence})"
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class AgentAction(models.Model):
|
|
142
|
+
"""One append-only, hash-chained record of an MCP/agent decision (ADR-0112 RC1, #1805).
|
|
143
|
+
|
|
144
|
+
Never updated in place. Rows are removed only by chain-aware pruning (``audit_prune``,
|
|
145
|
+
ADR-0361), which deletes a contiguous oldest-prefix and writes an
|
|
146
|
+
``AgentActionCheckpoint`` so ``audit_verify`` re-anchors and the surviving tail still
|
|
147
|
+
verifies; a delete *without* that checkpoint still surfaces as a break. ``token_prefix``
|
|
148
|
+
and the denormalized identity fields are preserved after the parent token/user is deleted
|
|
149
|
+
(the FKs are SET_NULL) so a row stays identifiable and its hash stays valid.
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
153
|
+
schema_version = models.PositiveSmallIntegerField(
|
|
154
|
+
default=AGENT_ACTION_SCHEMA_VERSION,
|
|
155
|
+
help_text="AGENT_ACTION_SCHEMA_VERSION at write time (part of the hashed record).",
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# --- actor + human principal ------------------------------------------------
|
|
159
|
+
actor_kind = models.CharField(max_length=16, choices=AgentActorKind.choices)
|
|
160
|
+
actor_token = models.ForeignKey(
|
|
161
|
+
"projects.ApiToken",
|
|
162
|
+
on_delete=models.SET_NULL,
|
|
163
|
+
null=True,
|
|
164
|
+
blank=True,
|
|
165
|
+
related_name="agent_actions",
|
|
166
|
+
help_text="The API token that acted. SET_NULL — a deleted token leaves its "
|
|
167
|
+
"audit trail behind (identified by actor_token_prefix).",
|
|
168
|
+
)
|
|
169
|
+
actor_token_prefix = models.CharField(
|
|
170
|
+
max_length=8,
|
|
171
|
+
db_index=True,
|
|
172
|
+
help_text="First 8 hex chars of the acting token — denormalized, never the "
|
|
173
|
+
"token material. Preserved after token deletion.",
|
|
174
|
+
)
|
|
175
|
+
principal = models.ForeignKey(
|
|
176
|
+
settings.AUTH_USER_MODEL,
|
|
177
|
+
on_delete=models.SET_NULL,
|
|
178
|
+
null=True,
|
|
179
|
+
blank=True,
|
|
180
|
+
related_name="agent_actions_as_principal",
|
|
181
|
+
help_text="The human on whose behalf the actor acted (the token owner). "
|
|
182
|
+
"SET_NULL so the row survives account deletion.",
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
# --- what was attempted -----------------------------------------------------
|
|
186
|
+
action = models.CharField(
|
|
187
|
+
max_length=128,
|
|
188
|
+
help_text="Stable operation identifier (e.g. the MCP tool / view name).",
|
|
189
|
+
)
|
|
190
|
+
method = models.CharField(max_length=8, help_text="HTTP method (GET, POST, …).")
|
|
191
|
+
object_type = models.CharField(max_length=64, blank=True, default="")
|
|
192
|
+
object_id = models.CharField(max_length=64, blank=True, default="")
|
|
193
|
+
project = models.ForeignKey(
|
|
194
|
+
"projects.Project",
|
|
195
|
+
on_delete=models.SET_NULL,
|
|
196
|
+
null=True,
|
|
197
|
+
blank=True,
|
|
198
|
+
related_name="agent_actions",
|
|
199
|
+
help_text="The project in scope, when resolvable from the request.",
|
|
200
|
+
)
|
|
201
|
+
capability_used = models.CharField(
|
|
202
|
+
max_length=64,
|
|
203
|
+
blank=True,
|
|
204
|
+
default="",
|
|
205
|
+
help_text="The scope/capability that authorized (or was checked for) the "
|
|
206
|
+
"action, e.g. 'mcp:read'.",
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
# --- verdict ----------------------------------------------------------------
|
|
210
|
+
verdict = models.CharField(max_length=20, choices=AgentActionVerdict.choices)
|
|
211
|
+
refusal_reason = models.CharField(
|
|
212
|
+
max_length=16,
|
|
213
|
+
choices=AgentActionRefusalReason.choices,
|
|
214
|
+
blank=True,
|
|
215
|
+
default="",
|
|
216
|
+
help_text="Set (identity|policy) when verdict=refused; empty otherwise.",
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# --- reproducibility anchor (ADR-0112 §2 / #1065) ---------------------------
|
|
220
|
+
payload_hash = models.CharField(
|
|
221
|
+
max_length=64,
|
|
222
|
+
help_text="sha256 over the canonicalized operation payload (method, path, "
|
|
223
|
+
"sorted query, body shape) — the reproducibility anchor for the request.",
|
|
224
|
+
)
|
|
225
|
+
engine_version = models.CharField(
|
|
226
|
+
max_length=64,
|
|
227
|
+
help_text="trueppm-scheduler version at decision time (the answer-stamp engine anchor).",
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
# --- chain link -------------------------------------------------------------
|
|
231
|
+
sequence = models.BigIntegerField(
|
|
232
|
+
unique=True,
|
|
233
|
+
help_text="Per-instance monotonic sequence (RC2). Gap-free and strictly "
|
|
234
|
+
"increasing; a gap or reorder is a tamper signal.",
|
|
235
|
+
)
|
|
236
|
+
prev_hash = models.CharField(
|
|
237
|
+
max_length=64,
|
|
238
|
+
help_text="record_hash of the predecessor row (GENESIS_PREV_HASH for the first).",
|
|
239
|
+
)
|
|
240
|
+
record_hash = models.CharField(
|
|
241
|
+
max_length=64,
|
|
242
|
+
unique=True,
|
|
243
|
+
help_text="sha256(prev_hash ‖ canonical(record)) — the chain link. Recomputed "
|
|
244
|
+
"and checked by `manage.py audit_verify`.",
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
summary = models.TextField(blank=True, default="", help_text="Human-readable, team-facing.")
|
|
248
|
+
source_ip = models.GenericIPAddressField(null=True, blank=True)
|
|
249
|
+
occurred_at = models.DateTimeField(
|
|
250
|
+
db_index=True,
|
|
251
|
+
help_text="Set explicitly at write time (NOT auto_now_add) because its exact "
|
|
252
|
+
"value is part of the hashed record.",
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
class Meta:
|
|
256
|
+
db_table = "agents_agent_action"
|
|
257
|
+
ordering = ["sequence"]
|
|
258
|
+
indexes = [
|
|
259
|
+
models.Index(fields=["project", "-occurred_at"], name="agent_action_proj_idx"),
|
|
260
|
+
models.Index(fields=["principal", "-occurred_at"], name="agent_action_princ_idx"),
|
|
261
|
+
]
|
|
262
|
+
|
|
263
|
+
def __str__(self) -> str:
|
|
264
|
+
return f"AgentAction(#{self.sequence} {self.action} {self.verdict})"
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
class AgentActionCheckpoint(models.Model):
|
|
268
|
+
"""Immutable re-anchor written when the oldest ``AgentAction`` rows are pruned (ADR-0361).
|
|
269
|
+
|
|
270
|
+
Chain-aware pruning (``manage.py audit_prune``) deletes a contiguous **prefix** of the
|
|
271
|
+
oldest rows. Because ``audit_verify`` recomputes each row's ``record_hash`` from its
|
|
272
|
+
predecessor's, deleting that predecessor would break verification of the first surviving
|
|
273
|
+
row. This checkpoint stores exactly what the verifier re-seeds from: the ``record_hash``
|
|
274
|
+
of the last-deleted row (the surviving tail's ``prev_hash``) and the sequence at which
|
|
275
|
+
the retained chain resumes.
|
|
276
|
+
|
|
277
|
+
One row is written per prune that actually deletes rows; ``audit_verify`` seeds from the
|
|
278
|
+
**latest** checkpoint (highest ``pruned_through_sequence``). It is append-only — an
|
|
279
|
+
integrity-continuity artifact that keeps the OSS self-check passing across a legitimate
|
|
280
|
+
prune, **not** compliance evidence. Signing, notarizing, or hash-chaining the checkpoints
|
|
281
|
+
for an external auditor is the Enterprise value-add (ADR-0112 §3, #146), not built here.
|
|
282
|
+
"""
|
|
283
|
+
|
|
284
|
+
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
|
285
|
+
pruned_through_sequence = models.BigIntegerField(
|
|
286
|
+
unique=True,
|
|
287
|
+
help_text="Highest AgentAction.sequence deleted by this prune; the retained chain "
|
|
288
|
+
"resumes at pruned_through_sequence + 1.",
|
|
289
|
+
)
|
|
290
|
+
pruned_through_hash = models.CharField(
|
|
291
|
+
max_length=64,
|
|
292
|
+
help_text="record_hash of the last-deleted row — the prev_hash the first surviving "
|
|
293
|
+
"row points at, and the seed audit_verify re-anchors from.",
|
|
294
|
+
)
|
|
295
|
+
first_retained_sequence = models.BigIntegerField(
|
|
296
|
+
help_text="Sequence of the lowest surviving row (pruned_through_sequence + 1); "
|
|
297
|
+
"audit_verify asserts the retained chain starts here.",
|
|
298
|
+
)
|
|
299
|
+
pruned_count = models.BigIntegerField(help_text="Number of rows deleted by this prune.")
|
|
300
|
+
pruned_by = models.ForeignKey(
|
|
301
|
+
settings.AUTH_USER_MODEL,
|
|
302
|
+
on_delete=models.SET_NULL,
|
|
303
|
+
null=True,
|
|
304
|
+
blank=True,
|
|
305
|
+
related_name="agent_action_prunes",
|
|
306
|
+
help_text="The user who ran the prune, when known. SET_NULL so the row survives "
|
|
307
|
+
"account deletion.",
|
|
308
|
+
)
|
|
309
|
+
created_at = models.DateTimeField(help_text="When the prune ran (set at write time).")
|
|
310
|
+
|
|
311
|
+
class Meta:
|
|
312
|
+
db_table = "agents_agent_action_checkpoint"
|
|
313
|
+
ordering = ["pruned_through_sequence"]
|
|
314
|
+
|
|
315
|
+
def __str__(self) -> str:
|
|
316
|
+
return (
|
|
317
|
+
f"AgentActionCheckpoint(through={self.pruned_through_sequence}, "
|
|
318
|
+
f"count={self.pruned_count})"
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
class AgentActionRefusalDetail(models.Model):
|
|
323
|
+
"""Non-hashed 1:1 telemetry side-car for a refused ``AgentAction`` (ADR-0421, #1850).
|
|
324
|
+
|
|
325
|
+
Records *which constraint fired* and the *projected impact* of a refusal so the
|
|
326
|
+
refusal moment (ADR-0362 §4) is queryable for engineering triage and demo capture.
|
|
327
|
+
It lives **outside** the hash-chained record on purpose: ``canonical_fields`` and
|
|
328
|
+
``audit_verify`` never see it, so ``AGENT_ACTION_SCHEMA_VERSION`` stays 1 and the
|
|
329
|
+
chain is byte-for-byte unchanged. The load-bearing decision (``verdict`` +
|
|
330
|
+
``refusal_reason``) remains tamper-evident on the chain; this finer explanation is
|
|
331
|
+
telemetry, not the audited decision. Making the ``constraint`` code tamper-evident is
|
|
332
|
+
a deliberate ``schema_version=2`` graduation for *when real producers exist* (0.6),
|
|
333
|
+
not a speculative bump now (ADR-0421 Consequences).
|
|
334
|
+
|
|
335
|
+
``on_delete=CASCADE`` is intended: a chain-aware prune (ADR-0361) that deletes an
|
|
336
|
+
``AgentAction`` takes its explanatory detail with it — the detail is worthless
|
|
337
|
+
without its row, and being unhashed, cascading it never affects ``audit_verify``.
|
|
338
|
+
"""
|
|
339
|
+
|
|
340
|
+
action = models.OneToOneField(
|
|
341
|
+
AgentAction,
|
|
342
|
+
on_delete=models.CASCADE,
|
|
343
|
+
primary_key=True,
|
|
344
|
+
related_name="refusal_detail",
|
|
345
|
+
help_text="The refused AgentAction this detail explains (1:1, PK).",
|
|
346
|
+
)
|
|
347
|
+
constraint = models.CharField(
|
|
348
|
+
max_length=32,
|
|
349
|
+
choices=RefusalConstraint.choices,
|
|
350
|
+
help_text="Which specific guard fired — a finer axis than the chain's "
|
|
351
|
+
"refusal_reason (identity|policy).",
|
|
352
|
+
)
|
|
353
|
+
projected_impact = models.JSONField(
|
|
354
|
+
default=dict,
|
|
355
|
+
blank=True,
|
|
356
|
+
help_text="Structured projected schedule impact of the refused write. Empty {} "
|
|
357
|
+
"for the current MCP-scope/identity producers (no schedule impact); the 0.6 "
|
|
358
|
+
"gated-write producers populate {affected_task_count, slip_days, "
|
|
359
|
+
"critical_path_delta_days, affected_task_ids}.",
|
|
360
|
+
)
|
|
361
|
+
|
|
362
|
+
class Meta:
|
|
363
|
+
db_table = "agents_agent_action_refusal_detail"
|
|
364
|
+
indexes = [
|
|
365
|
+
# Powers the ?constraint= triage filter ("show me every graph_validation
|
|
366
|
+
# refusal") without a full scan of the side-car.
|
|
367
|
+
models.Index(fields=["constraint"], name="agent_refusal_constraint_idx"),
|
|
368
|
+
]
|
|
369
|
+
|
|
370
|
+
def __str__(self) -> str:
|
|
371
|
+
return f"AgentActionRefusalDetail({self.constraint} for {self.action_id})"
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""Carry the refusal taxonomy to the caller that triggered it (ADR-0809, #2689).
|
|
2
|
+
|
|
3
|
+
The API models a genuine two-axis refusal taxonomy — ``AgentActionRefusalReason``
|
|
4
|
+
(identity | policy) and ``RefusalConstraint`` (which specific guard fired) — and
|
|
5
|
+
records it, hash-chained, on every refused agent call. None of it reached the
|
|
6
|
+
caller. An agent operator saw DRF's constant ``PermissionDenied.default_detail``
|
|
7
|
+
and had to make a *second*, separate call to ``GET /agent-actions/?constraint=…``
|
|
8
|
+
to learn why. "Computed, not guessed" names **refuse** as one of its four parts;
|
|
9
|
+
a system that fails without saying why is the worst outcome for the persona 0.4
|
|
10
|
+
is sold on.
|
|
11
|
+
|
|
12
|
+
Three design points, each load-bearing:
|
|
13
|
+
|
|
14
|
+
**The guards still return ``False``.** They are fail-closed by construction and
|
|
15
|
+
that is not worth trading for a richer body. Instead a denying guard *marks* the
|
|
16
|
+
request with the taxonomy, and this module's envelope is attached centrally by
|
|
17
|
+
:mod:`trueppm_api.core.exception_handlers`. A guard that forgets to mark still
|
|
18
|
+
denies — it simply denies with the generic detail, which is exactly the
|
|
19
|
+
pre-existing behavior.
|
|
20
|
+
|
|
21
|
+
**Disclosure is an allow-list, not a pass-through.** A constraint code is only
|
|
22
|
+
serialized if it is in :data:`DISCLOSABLE_CONSTRAINTS`. The two live producers
|
|
23
|
+
(``TOKEN_IDENTITY``, ``CAPABILITY_SCOPE``) describe the *caller's own token* and
|
|
24
|
+
disclose nothing about resources. The four reserved schedule constraints
|
|
25
|
+
(``GRAPH_VALIDATION``, ``SPRINT_SOVEREIGNTY``, ``ROLLUP_LOCK``,
|
|
26
|
+
``ENGINE_REFEREE``) describe the *plan*, and a constraint naming a task the caller
|
|
27
|
+
may not read is an information leak. They have no producer today; when 0.6 wires
|
|
28
|
+
them, adding each to the allow-list is a deliberate disclosure decision rather
|
|
29
|
+
than something that happens by default.
|
|
30
|
+
|
|
31
|
+
**Only token callers get the envelope.** A human JWT/session 403 is unchanged, so
|
|
32
|
+
this is not a contract change for the web client — the refusal envelope exists for
|
|
33
|
+
the agent surface that has no other channel.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from __future__ import annotations
|
|
37
|
+
|
|
38
|
+
from typing import Any
|
|
39
|
+
|
|
40
|
+
from trueppm_api.apps.agents.models import (
|
|
41
|
+
AgentActionRefusalReason,
|
|
42
|
+
AgentActionVerdict,
|
|
43
|
+
RefusalConstraint,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
#: Request attribute carrying ``(reason, constraint)`` from the guard that denied.
|
|
47
|
+
#: Underscore-prefixed to match the existing ``_mcp_scope_filtered`` convention for
|
|
48
|
+
#: request-local markers set by a permission class and read after the fact.
|
|
49
|
+
REFUSAL_MARKER = "_trueppm_refusal"
|
|
50
|
+
|
|
51
|
+
#: Constraint codes safe to return to a caller that was just denied.
|
|
52
|
+
#:
|
|
53
|
+
#: Both members describe the caller's own credential, so disclosing them tells the
|
|
54
|
+
#: caller nothing they did not already supply. Every other member of
|
|
55
|
+
#: ``RefusalConstraint`` describes the *schedule*, and is deliberately absent:
|
|
56
|
+
#: naming ``sprint_sovereignty`` on a sprint the caller cannot read would leak the
|
|
57
|
+
#: existence and state of that sprint. Adding one here is a disclosure decision.
|
|
58
|
+
DISCLOSABLE_CONSTRAINTS: frozenset[str] = frozenset(
|
|
59
|
+
{
|
|
60
|
+
RefusalConstraint.TOKEN_IDENTITY,
|
|
61
|
+
RefusalConstraint.CAPABILITY_SCOPE,
|
|
62
|
+
}
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def mark_refusal(request: Any, reason: str, constraint: str = "") -> None:
|
|
67
|
+
"""Record on *request* why this call is being refused.
|
|
68
|
+
|
|
69
|
+
Called by a guard immediately before it returns ``False`` (or raises). Marking
|
|
70
|
+
is advisory: an unmarked refusal still refuses, it just carries no taxonomy.
|
|
71
|
+
The first mark wins — the guards are ANDed and evaluated in order, so the
|
|
72
|
+
first one to deny is the one that actually decided.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
if getattr(request, REFUSAL_MARKER, None) is None:
|
|
76
|
+
setattr(request, REFUSAL_MARKER, (reason, constraint))
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def refusal_marks(request: Any) -> tuple[str, str] | None:
|
|
80
|
+
"""Return ``(reason, constraint)`` marked on *request*, or ``None``."""
|
|
81
|
+
|
|
82
|
+
marks = getattr(request, REFUSAL_MARKER, None)
|
|
83
|
+
if isinstance(marks, tuple) and len(marks) == 2:
|
|
84
|
+
return marks
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def build_refusal_payload(reason: str, constraint: str = "") -> dict[str, str]:
|
|
89
|
+
"""The wire form of a refusal: verdict, reason, and (if disclosable) constraint.
|
|
90
|
+
|
|
91
|
+
``verdict`` is included even though it is constant for a refusal, so a client
|
|
92
|
+
can branch on one field across the whole taxonomy rather than inferring the
|
|
93
|
+
verdict from the presence of the envelope — and so the wire shape lines up with
|
|
94
|
+
the ``AgentAction`` record it describes.
|
|
95
|
+
"""
|
|
96
|
+
|
|
97
|
+
payload = {
|
|
98
|
+
"verdict": str(AgentActionVerdict.REFUSED),
|
|
99
|
+
"reason": str(reason or AgentActionRefusalReason.POLICY),
|
|
100
|
+
}
|
|
101
|
+
if constraint and constraint in DISCLOSABLE_CONSTRAINTS:
|
|
102
|
+
payload["constraint"] = str(constraint)
|
|
103
|
+
return payload
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Read-only serializer for the team-readable agent-action log (ADR-0112 §1.3)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from drf_spectacular.utils import extend_schema_field
|
|
6
|
+
from rest_framework import serializers
|
|
7
|
+
|
|
8
|
+
from trueppm_api.apps.agents.models import (
|
|
9
|
+
AgentAction,
|
|
10
|
+
AgentActionRefusalDetail,
|
|
11
|
+
AgentActionRefusalReason,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AgentActionRefusalDetailSerializer(serializers.ModelSerializer[AgentActionRefusalDetail]):
|
|
16
|
+
"""The non-hashed refusal telemetry attached to a refused action (ADR-0421, #1850)."""
|
|
17
|
+
|
|
18
|
+
class Meta:
|
|
19
|
+
model = AgentActionRefusalDetail
|
|
20
|
+
fields = ["constraint", "projected_impact"]
|
|
21
|
+
read_only_fields = fields
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AgentActionSerializer(serializers.ModelSerializer[AgentAction]):
|
|
25
|
+
"""Team-facing view of one audited agent action.
|
|
26
|
+
|
|
27
|
+
Read-only — ``AgentAction`` rows are append-only and never mutated through the API.
|
|
28
|
+
Exposes the chain fields (``sequence``, ``record_hash``) for transparency; they are
|
|
29
|
+
integrity anchors, not secrets. Never exposes token material — only the 8-char
|
|
30
|
+
``actor_token_prefix``. ``refusal_detail`` is the non-hashed side-car telemetry
|
|
31
|
+
(constraint that fired + projected impact); ``null`` for allowed actions and for
|
|
32
|
+
refusals recorded before a constraint was wired.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
# Declared explicitly (like refusal_detail below) rather than left to
|
|
36
|
+
# ModelSerializer's auto-build from Meta.read_only_fields: DRF's
|
|
37
|
+
# include_extra_kwargs() strips allow_blank from any field once
|
|
38
|
+
# read_only_fields forces read_only=True, so the auto-built field never
|
|
39
|
+
# tells drf-spectacular that "" is a real, expected value — and the
|
|
40
|
+
# published AgentActionRefusalReasonEnum schema silently disagreed with
|
|
41
|
+
# every allowed-verdict row (schemathesis, job #16501510109 / #3811). An
|
|
42
|
+
# explicitly-declared field bypasses that stripping entirely.
|
|
43
|
+
refusal_reason = serializers.ChoiceField(
|
|
44
|
+
choices=AgentActionRefusalReason.choices,
|
|
45
|
+
allow_blank=True,
|
|
46
|
+
read_only=True,
|
|
47
|
+
help_text="Set (identity|policy) when verdict=refused; empty otherwise.",
|
|
48
|
+
)
|
|
49
|
+
refusal_detail = serializers.SerializerMethodField()
|
|
50
|
+
|
|
51
|
+
class Meta:
|
|
52
|
+
model = AgentAction
|
|
53
|
+
fields = [
|
|
54
|
+
"id",
|
|
55
|
+
"schema_version",
|
|
56
|
+
"sequence",
|
|
57
|
+
"actor_kind",
|
|
58
|
+
"actor_token_prefix",
|
|
59
|
+
"principal",
|
|
60
|
+
"action",
|
|
61
|
+
"method",
|
|
62
|
+
"object_type",
|
|
63
|
+
"object_id",
|
|
64
|
+
"project",
|
|
65
|
+
"capability_used",
|
|
66
|
+
"verdict",
|
|
67
|
+
"refusal_reason",
|
|
68
|
+
"refusal_detail",
|
|
69
|
+
"engine_version",
|
|
70
|
+
"payload_hash",
|
|
71
|
+
"record_hash",
|
|
72
|
+
"summary",
|
|
73
|
+
"occurred_at",
|
|
74
|
+
]
|
|
75
|
+
read_only_fields = fields
|
|
76
|
+
|
|
77
|
+
@extend_schema_field(AgentActionRefusalDetailSerializer(allow_null=True))
|
|
78
|
+
def get_refusal_detail(self, obj: AgentAction) -> dict[str, object] | None:
|
|
79
|
+
# Reverse OneToOne: absent for allowed actions (and constraint-less refusals).
|
|
80
|
+
# Accessing a missing reverse o2o raises, so catch rather than getattr-default.
|
|
81
|
+
try:
|
|
82
|
+
detail = obj.refusal_detail
|
|
83
|
+
except AgentActionRefusalDetail.DoesNotExist:
|
|
84
|
+
return None
|
|
85
|
+
return AgentActionRefusalDetailSerializer(detail).data
|