engineering-platform 2.3.93__tar.gz → 2.3.95__tar.gz
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.
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/PKG-INFO +1 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/pyproject.toml +1 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/agent_state.py +33 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/dashboard.css +4 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/dashboard.js +127 -47
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/dashboard_locales.mjs +10 -5
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/capability_review.py +104 -3
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/dashboard_state.py +8 -7
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_executor.py +64 -20
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_host.py +82 -33
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_reporting.py +18 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/live_status.py +11 -11
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/platform_version.py +1 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/qualification_runtime.py +15 -2
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/templates/workspace-config.json +1 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform.egg-info/PKG-INFO +1 -1
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/README.md +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/setup.cfg +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/__init__.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/__main__.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/agent_trust.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/assurance_scope.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/capability_preflight.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/central_data_transfer.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/central_database.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/central_operational_reset.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/central_store_migration.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/codex_capacity.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/codex_chat.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/codex_observability.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/component_lock.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/component_logging.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/console_presentation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/console_route_ownership.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/contracts/__init__.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/contracts/ep_consumer.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/contracts/models.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/contracts/projection.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/dashboard_browser_validation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/dashboard_supervisor.swift +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/dashboard_translation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/dependabot_producer.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/development_profile.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/drift_diagnostics.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/emergency_recovery.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/engineering_memory.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/ep_consumer_credentials.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/evidence_projection.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_activity.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_context.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_errors.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_evidence.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_finalization.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_host_evidence.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_lease.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_lifecycle.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_models.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_readiness.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_repository.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_timeout_policy.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_timing.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/execution_transaction.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/external_producer_binding.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/file_inbox.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/forensic_attribution.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/forensic_attribution_v2.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/forensic_delta.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/golden_scenario.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/host_admin.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/host_preflight.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_relocation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_activation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_admission.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_backup.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_composition.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_executor.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_migration.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_operation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_plan.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/installation_update_preparation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/investigation_ledger.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/legacy_inbox_migration.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/legacy_installation_adoption.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/lifecycle_worker.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/local_api.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/local_api_keychain.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/local_repository_binding.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/managed_autonomy.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/managed_codex_runtime.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/managed_workspace_readiness.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/merge_delegation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/operational_installation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/operational_installation_lock.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/operational_installation_record.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/owner_credential_recovery.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/parity_context.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/platform_admin.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/platform_api.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/platform_bootstrap.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/platform_components.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/pr_check_repair.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/pr_evidence_backfill.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/producer.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/product_installation_readback.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/project_agent.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/project_agent_service.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/project_topology.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/prompt_history.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_context.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_context_benchmark.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_context_scope.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_interruption.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_process_identity.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_readiness.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_recovery.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/provider_usage.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/providers.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/qualification.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/recommendation_handoff.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/reconciliation_adoption.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/release_operation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/report_analysis.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/repository_attachment.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/repository_handoff.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/resources.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/reviewer_evidence.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/revision_binding.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/schemas/producer-readback-v1.3.schema.json +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/server.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/server_console_services.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/server_relay.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/server_service.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/status_model.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/status_reconciliation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/storage.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/submission_cli.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/submission_intake.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/submission_service.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/system_installation_topology.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/system_server_service.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/telemetry.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/telemetry_contract.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/telemetry_export.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/telemetry_metrics.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/validation_identity.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/validation_profile.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/version_preparation_delivery.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/workspace_preflight.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/worktree_provenance.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/worktree_tooling.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform.egg-info/SOURCES.txt +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform.egg-info/entry_points.txt +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform.egg-info/top_level.txt +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/tests/test_adaptive_action_sizing_design.py +0 -0
- {engineering_platform-2.3.93 → engineering_platform-2.3.95}/tests/test_role_task_model_policy_design.py +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"bootstrap_contract": "2026.12",
|
|
3
3
|
"checkpoint_format": 1,
|
|
4
|
-
"dashboard_version": "2.3.
|
|
4
|
+
"dashboard_version": "2.3.95",
|
|
5
5
|
"handoff_protocol": 1,
|
|
6
6
|
"memory_format": 2,
|
|
7
7
|
"minimum_codex_cli": "0.146.0",
|
|
8
8
|
"inbox_protocol": 1,
|
|
9
|
-
"platform_version": "2.3.
|
|
9
|
+
"platform_version": "2.3.95",
|
|
10
10
|
"report_format": 2,
|
|
11
|
-
"runner_version": "2.3.
|
|
11
|
+
"runner_version": "2.3.95",
|
|
12
12
|
"status_model": 1,
|
|
13
13
|
"storage_schema": 45,
|
|
14
|
-
"watcher_version": "2.3.
|
|
14
|
+
"watcher_version": "2.3.95"
|
|
15
15
|
}
|
{engineering_platform-2.3.93 → engineering_platform-2.3.95}/src/engineering_platform/agent_state.py
RENAMED
|
@@ -458,13 +458,16 @@ class TransactionState:
|
|
|
458
458
|
raise StateError("checkpoint assurance profile is invalid")
|
|
459
459
|
review_fields = {"reviewer", "status", "candidate_sha", "profile_digest", "invocation_id", "findings"}
|
|
460
460
|
current_review_fields = review_fields | {"contract_version", "started_at", "completed_at"}
|
|
461
|
+
integral_review_fields = current_review_fields | {"coverage", "finding_dispositions"}
|
|
461
462
|
finding_fields = {"id", "fingerprint", "category", "criterion", "observation", "severity", "confidence", "blocking", "disposition"}
|
|
462
463
|
current_finding_fields = finding_fields | {"evidence_ref"}
|
|
464
|
+
coverage_fields = {"surface", "status", "evidence_ref"}
|
|
465
|
+
finding_disposition_fields = {"finding_id", "disposition", "evidence_ref"}
|
|
463
466
|
if (
|
|
464
467
|
not isinstance(state.assurance_reviews, tuple)
|
|
465
468
|
or len(state.assurance_reviews) > 16
|
|
466
469
|
or any(
|
|
467
|
-
not isinstance(review, dict) or set(review) not in (review_fields, current_review_fields)
|
|
470
|
+
not isinstance(review, dict) or set(review) not in (review_fields, current_review_fields, integral_review_fields)
|
|
468
471
|
or review.get("reviewer") not in {"quality", "security"}
|
|
469
472
|
or review.get("status") not in {"PASS", "FAIL", "UNRESOLVED"}
|
|
470
473
|
or not isinstance(review.get("candidate_sha"), str) or not re.fullmatch(r"[0-9a-f]{40}", review["candidate_sha"])
|
|
@@ -486,6 +489,35 @@ class TransactionState:
|
|
|
486
489
|
or not isinstance(review.get("started_at"), str)
|
|
487
490
|
or not isinstance(review.get("completed_at"), str)
|
|
488
491
|
))
|
|
492
|
+
or (set(review) == integral_review_fields and (
|
|
493
|
+
review.get("contract_version") != "2.0"
|
|
494
|
+
or not isinstance(review.get("started_at"), str)
|
|
495
|
+
or not isinstance(review.get("completed_at"), str)
|
|
496
|
+
or not isinstance(review.get("coverage"), list)
|
|
497
|
+
or not 1 <= len(review["coverage"]) <= 16
|
|
498
|
+
or any(
|
|
499
|
+
not isinstance(item, dict) or set(item) != coverage_fields
|
|
500
|
+
or item.get("status") not in {"REVIEWED", "NOT_APPLICABLE"}
|
|
501
|
+
or any(
|
|
502
|
+
not isinstance(value, str) or not value or len(value) > 240
|
|
503
|
+
or value != redact_diagnostic(value, limit=240)
|
|
504
|
+
for value in item.values()
|
|
505
|
+
)
|
|
506
|
+
for item in review["coverage"]
|
|
507
|
+
)
|
|
508
|
+
or not isinstance(review.get("finding_dispositions"), list)
|
|
509
|
+
or len(review["finding_dispositions"]) > 64
|
|
510
|
+
or any(
|
|
511
|
+
not isinstance(item, dict) or set(item) != finding_disposition_fields
|
|
512
|
+
or item.get("disposition") not in {"RESOLVED", "OPEN"}
|
|
513
|
+
or any(
|
|
514
|
+
not isinstance(value, str) or not value or len(value) > 240
|
|
515
|
+
or value != redact_diagnostic(value, limit=240)
|
|
516
|
+
for value in item.values()
|
|
517
|
+
)
|
|
518
|
+
for item in review["finding_dispositions"]
|
|
519
|
+
)
|
|
520
|
+
))
|
|
489
521
|
for review in state.assurance_reviews
|
|
490
522
|
)
|
|
491
523
|
):
|
|
@@ -280,6 +280,8 @@ html[data-theme="light"] :is(#rateLimitReset,#codexCliUpdate){background:#e8fff5
|
|
|
280
280
|
.prompt-detail-provider-review{display:grid;gap:18px;grid-column:1/-1;grid-template-columns:minmax(0,1fr) minmax(320px,.78fr)}@media (max-width:760px){.prompt-detail-provider-review{grid-template-columns:1fr}}
|
|
281
281
|
.prompt-detail-provider-review-stack{display:grid;gap:18px;grid-column:1/-1}.prompt-detail-provider-review>.prompt-detail-card{align-self:stretch;box-sizing:border-box}.prompt-detail-card--commit-timeline{display:flex;flex-direction:column;min-height:0}.prompt-detail-commit-timeline__list{align-content:start;display:grid;flex:1;gap:10px;list-style:none;margin:0;max-height:none;min-height:0;overflow:auto;padding:0 8px 0 0;scrollbar-gutter:stable}.prompt-detail-commit-timeline__item{border-top:1px solid color-mix(in srgb,var(--category-color) 38%,transparent);display:grid;gap:3px;padding-top:10px}.prompt-detail-commit-timeline__item:first-child{border-top:0;padding-top:0}.prompt-detail-commit-timeline__meta{color:var(--dashboard-modal-muted);font-size:12px;line-height:1.35}.prompt-detail-commit-timeline__item code{font-size:12px;overflow-wrap:normal;white-space:nowrap}.prompt-detail-commit-timeline__item>span{font-size:13px;line-height:1.4;overflow-wrap:anywhere}
|
|
282
282
|
.prompt-detail-card--evidence pre,.prompt-detail-card--reviewers pre,.prompt-detail-card--assurance-reviews pre{font-family:inherit}
|
|
283
|
+
.reviewer-agent__status--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313;font:800 14px/1 system-ui;height:16px;width:16px}
|
|
284
|
+
.prompt-detail-reviewer{border-top:1px solid color-mix(in srgb,var(--category-color) 45%,transparent);display:grid;gap:7px;padding-top:14px}.prompt-detail-reviewer:first-of-type{border-top:0;padding-top:0}.prompt-detail-reviewer h4{color:var(--category-color);font-size:16px;margin:0 0 4px}.prompt-detail-reviewer>.field{margin:2px 0 0}.prompt-detail-reviewer__status{align-items:center;display:inline-flex;gap:8px}.prompt-detail-reviewer__status-icon{align-items:center;border-radius:50%;display:inline-flex;flex:0 0 18px;font:800 12px/1 system-ui;height:18px;justify-content:center}.prompt-detail-reviewer__status-icon--completed{background:#51d88a;box-shadow:0 0 8px #51d88a66;color:#11261d}.prompt-detail-reviewer__status-icon--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313}.prompt-detail-reviewer__status-icon--neutral{background:#9a9aa3;color:#202027}
|
|
283
285
|
.prompt-detail-commit-timeline__phase{border-top:1px solid color-mix(in srgb,var(--category-color) 52%,transparent);list-style:none;padding:13px 0 0}.prompt-detail-commit-timeline__phase:first-child{border-top:0;padding-top:0}.prompt-detail-commit-timeline__phase h4{color:var(--category-color);font-size:12px;letter-spacing:.04em;margin:0 0 9px;text-transform:uppercase}.prompt-detail-commit-timeline__phase-entries{display:grid;gap:10px;list-style:none;margin:0;padding:0 0 2px}.prompt-detail-commit-timeline__phase-entries .prompt-detail-commit-timeline__item{border-top:0;padding-top:0}
|
|
284
286
|
.prompt-detail-commit-timeline__phase{--commit-kind-color:#8dc7ff;border-left:3px solid var(--commit-kind-color);padding-left:10px}.prompt-detail-commit-timeline__phase--implementation{--commit-kind-color:#65c5d9}.prompt-detail-commit-timeline__phase--validation{--commit-kind-color:#65d9a3}.prompt-detail-commit-timeline__phase--quality{--commit-kind-color:#c29aff}.prompt-detail-commit-timeline__phase--repair{--commit-kind-color:#f4c34f}.prompt-detail-commit-timeline__phase--finalization{--commit-kind-color:#ff99a7}.prompt-detail-commit-timeline__phase--implementation_merge,.prompt-detail-commit-timeline__phase--finalization_merge,.prompt-detail-commit-timeline__phase--reconciliation_merge{--commit-kind-color:#f3d36a}.prompt-detail-commit-timeline__phase--reconciliation{--commit-kind-color:#73d6b0}.prompt-detail-commit-timeline__phase h4{align-items:center;color:var(--commit-kind-color);display:flex;gap:7px}.prompt-detail-commit-timeline__kind{border:1px solid currentColor;border-radius:999px;font-size:10px;line-height:1;padding:4px 6px}.prompt-detail-commit-timeline__phase-name{color:var(--dashboard-modal-muted);font-size:11px;font-weight:500;letter-spacing:0;text-transform:none;white-space:nowrap}
|
|
285
287
|
|
|
@@ -1335,3 +1337,5 @@ html[data-theme="light"] :is(.dashboard-status-banner--provider-auth_required .p
|
|
|
1335
1337
|
}
|
|
1336
1338
|
.telemetry-note{color:var(--dashboard-muted,#b9b6c0);font-size:12px;line-height:1.45;margin:0 0 10px}.telemetry-run-detail{border-top:1px solid color-mix(in srgb,var(--category-color,#fb7185) 45%,transparent);display:grid;gap:16px;margin-top:16px;padding-top:16px}.telemetry-run-detail h4{color:var(--category-color,#fb7185);font-size:14px;margin:14px 0 8px}.telemetry-scope-switcher{display:flex;flex-wrap:wrap;gap:8px}.telemetry-scope-switcher button{background:var(--dashboard-expanded-content-surface,#24242d);border:1px solid color-mix(in srgb,var(--category-color,#fb7185) 72%,transparent);border-radius:7px;color:inherit;cursor:pointer;font:400 12px/1.2 system-ui;min-height:32px;padding:5px 9px}.telemetry-scope-switcher button:hover{background:color-mix(in srgb,var(--category-color,#fb7185) 14%,var(--dashboard-expanded-content-surface,#24242d));border-color:var(--category-color,#fb7185)}.telemetry-scope-switcher button[aria-selected="true"]{background:color-mix(in srgb,var(--category-color,#fb7185) 24%,var(--dashboard-expanded-content-surface,#24242d));border-color:var(--category-color,#fb7185);box-shadow:inset 3px 0 0 var(--category-color,#fb7185)}.telemetry-scope-switcher button:focus:not(:focus-visible){box-shadow:none!important;outline:0!important}.telemetry-scope-switcher button[aria-selected="true"]:focus:not(:focus-visible){box-shadow:inset 3px 0 0 var(--category-color,#fb7185)!important}.telemetry-timeline{display:grid;gap:5px;list-style:none;margin:0;padding:0}.telemetry-timeline li{border-left:2px solid color-mix(in srgb,var(--category-color,#fb7185) 60%,transparent);margin-left:calc(var(--timeline-depth,0) * 14px);padding:6px 8px;word-break:break-word}@media(max-width:620px){.telemetry-detail-modal__content .technical-grid{grid-template-columns:minmax(0,1fr)}.telemetry-scope-switcher{position:sticky;top:0;background:var(--dashboard-expanded-content-surface,#24242d);padding-block:6px;z-index:2}.telemetry-timeline li{margin-left:min(calc(var(--timeline-depth,0) * 9px),45px)}}
|
|
1337
1339
|
.telemetry-timeline-axis{color:var(--dashboard-muted,#b9b6c0);display:flex;font:11px ui-monospace,monospace;justify-content:space-between;margin:4px 8px}.telemetry-timeline__label{font-size:12px;line-height:1.35}.telemetry-timeline__track{background:color-mix(in srgb,var(--category-color,#fb7185) 10%,transparent);border:1px solid color-mix(in srgb,var(--category-color,#fb7185) 24%,transparent);border-radius:4px;height:14px;margin:5px 0;overflow:hidden;position:relative}.telemetry-timeline__bar{background:var(--category-color,#fb7185);border-radius:3px;display:block;height:100%;min-width:2px;position:absolute}.telemetry-timeline__bar:focus-visible{outline:3px solid var(--house-style);outline-offset:2px}.telemetry-timeline__bar--unpositioned{background:repeating-linear-gradient(135deg,var(--category-color,#fb7185) 0 4px,transparent 4px 8px);inset:0;width:100%}.telemetry-timeline__identity{color:var(--dashboard-muted,#b9b6c0);display:block;font-size:10px;overflow-wrap:anywhere}.telemetry-export{min-width:38px}@media(max-width:620px){.telemetry-timeline-axis{margin-inline:0}.telemetry-timeline__identity{font-size:9px}.telemetry-actions{flex-wrap:wrap}}
|
|
1340
|
+
/* Status markers inside lifecycle assurance evidence mirror the main status language. */
|
|
1341
|
+
.lifecycle-detail-modal__assurance-heading{align-items:center;display:inline-flex;gap:8px}.lifecycle-detail-modal__assurance-status{align-items:center;border-radius:50%;display:inline-flex;flex:0 0 18px;font:800 12px/1 system-ui;height:18px;justify-content:center;width:18px!important}.lifecycle-detail-modal__assurance-status--passed{background:#51d88a;box-shadow:0 0 8px #51d88a66;color:#11261d!important}.lifecycle-detail-modal__assurance-status--failed{background:#ff6b6b;box-shadow:0 0 8px #ff6b6b66;color:#351313!important}.lifecycle-detail-modal__assurance-status--neutral{background:#9a9aa3;color:#202027!important}
|
|
@@ -148,6 +148,24 @@ function reviewerCapabilityLabel(value, fallback = t("format.not_available")) {
|
|
|
148
148
|
const raw = String(value || "").trim();
|
|
149
149
|
return raw ? enumLabel(raw.toUpperCase(), raw) : fallback;
|
|
150
150
|
}
|
|
151
|
+
function reviewerStatusPresentation(reviewer) {
|
|
152
|
+
const rawStatus = String(reviewer?.status || "completed").toLowerCase();
|
|
153
|
+
const failed = rawStatus === "failed", completed = ["completed", "uitgevoerd"].includes(rawStatus);
|
|
154
|
+
const label = document.createElement("span"), row = document.createElement("span"),
|
|
155
|
+
indicator = document.createElement("span"), text = document.createElement("span");
|
|
156
|
+
label.className = "label";
|
|
157
|
+
label.textContent = t("detail.prompt_status");
|
|
158
|
+
row.className = "prompt-detail-reviewer__status";
|
|
159
|
+
indicator.className = "prompt-detail-reviewer__status-icon prompt-detail-reviewer__status-icon--"
|
|
160
|
+
+ (failed ? "failed" : completed ? "completed" : "neutral");
|
|
161
|
+
indicator.setAttribute("aria-hidden", "true");
|
|
162
|
+
indicator.textContent = failed ? "×" : completed ? "✓" : "•";
|
|
163
|
+
text.className = "prompt-detail-reviewer__status-text";
|
|
164
|
+
text.textContent = reviewerCapabilityLabel(reviewer?.capability || "ENGINEERING")
|
|
165
|
+
+ " · " + reviewerStatusLabel(rawStatus);
|
|
166
|
+
row.append(indicator, text);
|
|
167
|
+
return { label, row };
|
|
168
|
+
}
|
|
151
169
|
function driftPresentationValue(field, drift = {}) {
|
|
152
170
|
const value = String(drift?.[field] || "").trim();
|
|
153
171
|
if (!value) return t("format.not_available");
|
|
@@ -831,12 +849,12 @@ function reviewerPresentationState(status = {}) {
|
|
|
831
849
|
}
|
|
832
850
|
function activeReviewerAgents(items, executionStatus = {}) {
|
|
833
851
|
const reviewActive = String(executionStatus?.current_phase || "").toUpperCase() === "CAPABILITY_REVIEW";
|
|
834
|
-
// A later phase may retain
|
|
835
|
-
//
|
|
836
|
-
//
|
|
837
|
-
const
|
|
838
|
-
&& items.every((agent) => String(agent?.status || "").toLowerCase()
|
|
839
|
-
const agents = (reviewActive ||
|
|
852
|
+
// A later phase may retain a wholly terminal review as compact historical
|
|
853
|
+
// evidence. Running or incomplete projections stay phase-scoped so they can
|
|
854
|
+
// never look like live reviewer work.
|
|
855
|
+
const terminalReview = Array.isArray(items) && items.length > 0
|
|
856
|
+
&& items.every((agent) => ["completed", "failed"].includes(String(agent?.status || "").toLowerCase()));
|
|
857
|
+
const agents = (reviewActive || terminalReview) && Array.isArray(items) ? items : [];
|
|
840
858
|
let card = $("activeReviewerAgents");
|
|
841
859
|
if (!card) {
|
|
842
860
|
card = document.createElement("section");
|
|
@@ -871,19 +889,23 @@ function activeReviewerAgents(items, executionStatus = {}) {
|
|
|
871
889
|
indicator = document.createElement("span"), rawStatus = String(agent?.status || "").toLowerCase(),
|
|
872
890
|
status = rawStatus === "running" && presentation !== "active" ? presentation : rawStatus;
|
|
873
891
|
const isRunning = status === "running";
|
|
874
|
-
const isCompleted = ["completed", "uitgevoerd"].includes(status);
|
|
892
|
+
const isCompleted = ["completed", "uitgevoerd"].includes(status), isFailed = status === "failed";
|
|
875
893
|
row.className = "reviewer-agent";
|
|
876
894
|
header.className = "reviewer-agent__header";
|
|
877
895
|
name.className = "reviewer-agent__name";
|
|
878
896
|
meta.className = "reviewer-agent__meta";
|
|
879
897
|
name.textContent = reviewerLabel(agent.reviewer);
|
|
880
898
|
meta.textContent = `${reviewerCapabilityLabel(agent.capability || "ENGINEERING")} · ${reviewerStatusLabel(status || "selected")}`;
|
|
881
|
-
if (isRunning || isCompleted) {
|
|
882
|
-
|
|
899
|
+
if (isRunning || isCompleted || isFailed) {
|
|
900
|
+
const tone = isRunning ? "running" : isFailed ? "failed" : "completed";
|
|
901
|
+
indicator.className = `reviewer-agent__status reviewer-agent__status--${tone}`;
|
|
883
902
|
indicator.setAttribute("role", "status");
|
|
884
|
-
indicator.setAttribute("aria-label", isRunning
|
|
903
|
+
indicator.setAttribute("aria-label", isRunning
|
|
904
|
+
? t("ui.reviewer_status_running")
|
|
905
|
+
: isFailed ? reviewerStatusLabel("failed") : t("ui.reviewer_status_completed"));
|
|
885
906
|
indicator.setAttribute("title", indicator.getAttribute("aria-label"));
|
|
886
907
|
if (isCompleted) indicator.textContent = "✓";
|
|
908
|
+
if (isFailed) indicator.textContent = "×";
|
|
887
909
|
}
|
|
888
910
|
header.append(name, indicator);
|
|
889
911
|
row.append(header, meta);
|
|
@@ -2143,12 +2165,31 @@ function lifecycleAssuranceEvidence(step) {
|
|
|
2143
2165
|
for (const review of reviews) {
|
|
2144
2166
|
if (!review || typeof review !== "object") continue;
|
|
2145
2167
|
const findings = Array.isArray(review.findings) ? review.findings : [];
|
|
2146
|
-
const item = document.createElement("li")
|
|
2147
|
-
|
|
2148
|
-
|
|
2168
|
+
const item = document.createElement("li"), heading = document.createElement("strong"),
|
|
2169
|
+
statusIcon = document.createElement("span"), status = String(review.status || "UNRESOLVED"),
|
|
2170
|
+
normalizedStatus = status.toUpperCase();
|
|
2171
|
+
const role = String(review.reviewer || "");
|
|
2172
|
+
const passed = normalizedStatus === "PASS", failed = ["FAIL", "FAILED", "UNRESOLVED"].includes(normalizedStatus);
|
|
2173
|
+
heading.className = "lifecycle-detail-modal__assurance-heading";
|
|
2174
|
+
statusIcon.className = "lifecycle-detail-modal__assurance-status lifecycle-detail-modal__assurance-status--"
|
|
2175
|
+
+ (passed ? "passed" : failed ? "failed" : "neutral");
|
|
2176
|
+
statusIcon.setAttribute("aria-hidden", "true");
|
|
2177
|
+
statusIcon.textContent = passed ? "✓" : failed ? "×" : "•";
|
|
2178
|
+
heading.append(statusIcon, Object.assign(document.createElement("span"), {
|
|
2179
|
+
textContent: `${reviewerLabel(role, role)} · ${assuranceStatusLabel(status, status)}`,
|
|
2180
|
+
}));
|
|
2181
|
+
item.append(heading);
|
|
2149
2182
|
const summary = findings.map((finding) => String(finding?.observation || "").trim()).filter(Boolean).join("; ");
|
|
2150
2183
|
const summaryElement = Object.assign(document.createElement("span"), { textContent: summary || t("lifecycle.assurance_no_findings") });
|
|
2151
2184
|
item.append(summaryElement);
|
|
2185
|
+
const coverage = Array.isArray(review.coverage) ? review.coverage : [];
|
|
2186
|
+
const dispositions = Array.isArray(review.finding_dispositions) ? review.finding_dispositions : [];
|
|
2187
|
+
if (coverage.length || dispositions.length) item.append(Object.assign(document.createElement("span"), {
|
|
2188
|
+
className: "estimate-meta",
|
|
2189
|
+
textContent: t("lifecycle.assurance_integral_evidence", {
|
|
2190
|
+
coverage: coverage.length, dispositions: dispositions.length,
|
|
2191
|
+
}),
|
|
2192
|
+
}));
|
|
2152
2193
|
if (summary) dynamicRows.push({ source: summary, element: summaryElement });
|
|
2153
2194
|
list.append(item);
|
|
2154
2195
|
}
|
|
@@ -2169,10 +2210,9 @@ function lifecycleCapabilityEvidence(step) {
|
|
|
2169
2210
|
list.className = "lifecycle-detail-modal__phase-list";
|
|
2170
2211
|
for (const reviewer of reviewers) {
|
|
2171
2212
|
if (!reviewer || typeof reviewer !== "object") continue;
|
|
2172
|
-
const item = document.createElement("li")
|
|
2213
|
+
const item = document.createElement("li"), heading = document.createElement("strong"),
|
|
2214
|
+
status = reviewerStatusPresentation(reviewer);
|
|
2173
2215
|
const details = [
|
|
2174
|
-
reviewerCapabilityLabel(reviewer.capability || "ENGINEERING"),
|
|
2175
|
-
reviewerStatusLabel(reviewer.status || "completed"),
|
|
2176
2216
|
reviewer.selected_because
|
|
2177
2217
|
? t("detail.selected_because") + ": " + String(reviewer.selected_because)
|
|
2178
2218
|
: null,
|
|
@@ -2186,34 +2226,57 @@ function lifecycleCapabilityEvidence(step) {
|
|
|
2186
2226
|
? t("detail.rejected_recommendations") + ": " + reviewer.rejected_recommendations
|
|
2187
2227
|
: null,
|
|
2188
2228
|
].filter(Boolean);
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
textContent: details.join("\n"),
|
|
2195
|
-
}),
|
|
2196
|
-
);
|
|
2229
|
+
heading.textContent = reviewerLabel(reviewer.reviewer, t("detail.specialist_review"));
|
|
2230
|
+
item.append(heading, status.label, status.row);
|
|
2231
|
+
if (details.length) item.append(Object.assign(document.createElement("span"), {
|
|
2232
|
+
textContent: details.join("\n"),
|
|
2233
|
+
}));
|
|
2197
2234
|
list.append(item);
|
|
2198
2235
|
}
|
|
2199
2236
|
if (!list.childElementCount) return null;
|
|
2200
2237
|
section.append(list);
|
|
2201
2238
|
return section;
|
|
2202
2239
|
}
|
|
2203
|
-
function
|
|
2204
|
-
const
|
|
2240
|
+
function lifecyclePullRequestField(label, pullRequest, repository) {
|
|
2241
|
+
const field = lifecycleDetailField(label, `#${pullRequest}`);
|
|
2242
|
+
const repositoryIdentity = String(repository || "").trim();
|
|
2243
|
+
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repositoryIdentity)) return field;
|
|
2244
|
+
const link = document.createElement("a");
|
|
2245
|
+
link.className = "prompt-detail-pr-link";
|
|
2246
|
+
link.href = `https://github.com/${repositoryIdentity.split("/").map(encodeURIComponent).join("/")}/pull/${pullRequest}`;
|
|
2247
|
+
link.target = "_blank";
|
|
2248
|
+
link.rel = "noopener noreferrer";
|
|
2249
|
+
link.textContent = `#${pullRequest} ↗`;
|
|
2250
|
+
link.setAttribute("aria-label", `${label} #${pullRequest}`);
|
|
2251
|
+
field.lastElementChild.replaceWith(link);
|
|
2252
|
+
return field;
|
|
2253
|
+
}
|
|
2254
|
+
function lifecycleDeliveryEvidence(step) {
|
|
2255
|
+
const evidence = step?.delivery_evidence || step?.implementation_evidence;
|
|
2205
2256
|
if (!evidence || typeof evidence !== "object") return null;
|
|
2257
|
+
const role = String(evidence.role || "implementation").toLowerCase();
|
|
2258
|
+
const titles = {
|
|
2259
|
+
implementation: "lifecycle.detail_implementation_evidence",
|
|
2260
|
+
finalization: "lifecycle.detail_finalization_evidence",
|
|
2261
|
+
reconciliation: "lifecycle.detail_reconciliation_evidence",
|
|
2262
|
+
};
|
|
2263
|
+
const pullRequestLabels = {
|
|
2264
|
+
implementation: "detail.implementation_pull_request",
|
|
2265
|
+
finalization: "detail.finalization_pull_request",
|
|
2266
|
+
reconciliation: "detail.reconciliation_pull_request",
|
|
2267
|
+
};
|
|
2206
2268
|
const fields = [];
|
|
2207
2269
|
if (evidence.branch) fields.push(lifecycleDetailField(t("workspace.current_branch"), String(evidence.branch)));
|
|
2208
2270
|
if (evidence.candidate_sha) fields.push(lifecycleDetailField(t("detail.candidate_sha"), String(evidence.candidate_sha)));
|
|
2209
2271
|
if (Number.isInteger(evidence.pull_request) && evidence.pull_request > 0) {
|
|
2210
|
-
|
|
2272
|
+
const label = t(pullRequestLabels[role] || pullRequestLabels.implementation);
|
|
2273
|
+
fields.push(lifecyclePullRequestField(label, evidence.pull_request, evidence.repository));
|
|
2211
2274
|
}
|
|
2212
2275
|
if (!fields.length) return null;
|
|
2213
2276
|
const section = document.createElement("section");
|
|
2214
2277
|
section.className = "lifecycle-detail-modal__implementation-evidence";
|
|
2215
2278
|
section.append(
|
|
2216
|
-
Object.assign(document.createElement("h3"), { textContent: t(
|
|
2279
|
+
Object.assign(document.createElement("h3"), { textContent: t(titles[role] || titles.implementation) }),
|
|
2217
2280
|
Object.assign(document.createElement("div"), { className: "technical-grid" }),
|
|
2218
2281
|
);
|
|
2219
2282
|
section.lastElementChild.append(...fields);
|
|
@@ -2346,8 +2409,8 @@ function openLifecycleDetail(step, trigger, { presentationOnly = false } = {}) {
|
|
|
2346
2409
|
if (capabilityEvidence) content.append(capabilityEvidence);
|
|
2347
2410
|
const assuranceEvidence = lifecycleAssuranceEvidence(step);
|
|
2348
2411
|
if (assuranceEvidence) content.append(assuranceEvidence);
|
|
2349
|
-
const
|
|
2350
|
-
if (
|
|
2412
|
+
const deliveryEvidence = lifecycleDeliveryEvidence(step);
|
|
2413
|
+
if (deliveryEvidence) content.append(deliveryEvidence);
|
|
2351
2414
|
const repairEvidence = lifecycleRepairEvidence(step);
|
|
2352
2415
|
if (repairEvidence) content.append(repairEvidence);
|
|
2353
2416
|
if (!modal.open) modal.showModal();
|
|
@@ -2364,15 +2427,24 @@ function lifecycleStepWithEvidence(step, context = {}) {
|
|
|
2364
2427
|
: Array.isArray(context.reviewers) ? context.reviewers : [];
|
|
2365
2428
|
if (reviewers.length) enriched.reviewer_evidence = reviewers;
|
|
2366
2429
|
}
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2430
|
+
const deliverySteps = {
|
|
2431
|
+
EXECUTE_AGENT: { role: "implementation", candidate: "implementation_candidate_sha", branch: "implementation_branch", pullRequest: "implementation_pr" },
|
|
2432
|
+
FINALIZE_AGENT: { role: "finalization", candidate: "finalization_candidate_sha", branch: "finalization_branch", pullRequest: "finalization_pr" },
|
|
2433
|
+
RECONCILE_AGENT: { role: "reconciliation", candidate: "reconciliation_candidate_sha", branch: "reconciliation_branch", pullRequest: "reconciliation_pr" },
|
|
2434
|
+
};
|
|
2435
|
+
const delivery = deliverySteps[id];
|
|
2436
|
+
if (delivery) {
|
|
2437
|
+
const candidate = String(context[delivery.candidate] || "").trim();
|
|
2438
|
+
const branch = String(context[delivery.branch] || "").trim();
|
|
2439
|
+
const pullRequest = Number(context[delivery.pullRequest]);
|
|
2440
|
+
const repository = String(context.github_repository || context.target_repository || "").trim();
|
|
2371
2441
|
const evidence = {};
|
|
2442
|
+
evidence.role = delivery.role;
|
|
2372
2443
|
if (/^[0-9a-f]{40}$/.test(candidate)) evidence.candidate_sha = candidate;
|
|
2373
2444
|
if (branch) evidence.branch = branch;
|
|
2374
2445
|
if (Number.isInteger(pullRequest) && pullRequest > 0) evidence.pull_request = pullRequest;
|
|
2375
|
-
if (
|
|
2446
|
+
if (/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)) evidence.repository = repository;
|
|
2447
|
+
if (Object.keys(evidence).length > 1) enriched.delivery_evidence = evidence;
|
|
2376
2448
|
}
|
|
2377
2449
|
return enriched;
|
|
2378
2450
|
}
|
|
@@ -8543,19 +8615,27 @@ function promptDetailRecommendationHandoff(handoff) {
|
|
|
8543
8615
|
}
|
|
8544
8616
|
function promptDetailReviewersSection(reviewers, { wide = true } = {}) {
|
|
8545
8617
|
if (!reviewers.length) return null;
|
|
8546
|
-
const fields = reviewers.map((reviewer) =>
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8618
|
+
const fields = reviewers.map((reviewer) => {
|
|
8619
|
+
const field = document.createElement("article"), heading = document.createElement("h4"),
|
|
8620
|
+
status = reviewerStatusPresentation(reviewer);
|
|
8621
|
+
field.className = "field prompt-detail-reviewer";
|
|
8622
|
+
heading.textContent = reviewerLabel(reviewer.reviewer, t("detail.specialist_review"));
|
|
8623
|
+
field.append(
|
|
8624
|
+
heading,
|
|
8625
|
+
status.label,
|
|
8626
|
+
status.row,
|
|
8627
|
+
detailField(
|
|
8628
|
+
t("detail.selected_because"),
|
|
8555
8629
|
String(reviewer.selected_because || t("detail.not_recorded")),
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8630
|
+
true,
|
|
8631
|
+
),
|
|
8632
|
+
detailField(
|
|
8633
|
+
t("detail.accepted_recommendations"),
|
|
8634
|
+
String(Number(reviewer.accepted_recommendations) || 0),
|
|
8635
|
+
),
|
|
8636
|
+
);
|
|
8637
|
+
return field;
|
|
8638
|
+
});
|
|
8559
8639
|
return promptDetailCard(t("detail.specialist_reviews"), fields, wide, "prompt-detail-card--reviewers");
|
|
8560
8640
|
}
|
|
8561
8641
|
function promptDetailAssuranceReviewsSection(reviews) {
|
|
@@ -4273,8 +4273,13 @@ Object.assign(DASHBOARD_MESSAGES.es, {
|
|
|
4273
4273
|
// A repair step can be entered before a pull request exists and shares its
|
|
4274
4274
|
// bounded budget across local validation, assurance, hosted checks and
|
|
4275
4275
|
// finalization. Keep the flow label generic; detail evidence names the cause.
|
|
4276
|
-
Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.step.repair_agent":"Repair round","lifecycle.detail_repair_evidence":"Completed repair rounds","lifecycle.detail_implementation_evidence":"Implementation result","lifecycle.detail_validation_pass":"Validation pass {iteration}","detail.initial_observation":"Initial observation","detail.rejected_recommendations":"Rejected recommendations"});
|
|
4277
|
-
Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.step.repair_agent":"Herstelronde","lifecycle.detail_repair_evidence":"Uitgevoerde herstelrondes","lifecycle.detail_implementation_evidence":"Implementatieresultaat","lifecycle.detail_validation_pass":"Validatiepass {iteration}","detail.initial_observation":"Initiële bevinding","detail.rejected_recommendations":"Afgewezen aanbevelingen"});
|
|
4278
|
-
Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.step.repair_agent":"Reparaturrunde","lifecycle.detail_repair_evidence":"Abgeschlossene Reparaturrunden","lifecycle.detail_implementation_evidence":"Implementierungsergebnis","lifecycle.detail_validation_pass":"Validierungsdurchlauf {iteration}","detail.initial_observation":"Erste Beobachtung","detail.rejected_recommendations":"Abgelehnte Empfehlungen"});
|
|
4279
|
-
Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.step.repair_agent":"Cycle de réparation","lifecycle.detail_repair_evidence":"Cycles de réparation terminés","lifecycle.detail_implementation_evidence":"Résultat de l’implémentation","lifecycle.detail_validation_pass":"Passe de validation {iteration}","detail.initial_observation":"Observation initiale","detail.rejected_recommendations":"Recommandations rejetées"});
|
|
4280
|
-
Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.step.repair_agent":"Ronda de reparación","lifecycle.detail_repair_evidence":"Rondas de reparación completadas","lifecycle.detail_implementation_evidence":"Resultado de la implementación","lifecycle.detail_validation_pass":"Pasada de validación {iteration}","detail.initial_observation":"Observación inicial","detail.rejected_recommendations":"Recomendaciones rechazadas"});
|
|
4276
|
+
Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.step.repair_agent":"Repair round","lifecycle.detail_repair_evidence":"Completed repair rounds","lifecycle.detail_implementation_evidence":"Implementation result","lifecycle.detail_finalization_evidence":"Finalization result","lifecycle.detail_reconciliation_evidence":"Reconciliation result","lifecycle.detail_validation_pass":"Validation pass {iteration}","detail.initial_observation":"Initial observation","detail.rejected_recommendations":"Rejected recommendations"});
|
|
4277
|
+
Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.step.repair_agent":"Herstelronde","lifecycle.detail_repair_evidence":"Uitgevoerde herstelrondes","lifecycle.detail_implementation_evidence":"Implementatieresultaat","lifecycle.detail_finalization_evidence":"Finalisatieresultaat","lifecycle.detail_reconciliation_evidence":"Reconciliatieresultaat","lifecycle.detail_validation_pass":"Validatiepass {iteration}","detail.initial_observation":"Initiële bevinding","detail.rejected_recommendations":"Afgewezen aanbevelingen"});
|
|
4278
|
+
Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.step.repair_agent":"Reparaturrunde","lifecycle.detail_repair_evidence":"Abgeschlossene Reparaturrunden","lifecycle.detail_implementation_evidence":"Implementierungsergebnis","lifecycle.detail_finalization_evidence":"Finalisierungsergebnis","lifecycle.detail_reconciliation_evidence":"Abstimmungsergebnis","lifecycle.detail_validation_pass":"Validierungsdurchlauf {iteration}","detail.initial_observation":"Erste Beobachtung","detail.rejected_recommendations":"Abgelehnte Empfehlungen"});
|
|
4279
|
+
Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.step.repair_agent":"Cycle de réparation","lifecycle.detail_repair_evidence":"Cycles de réparation terminés","lifecycle.detail_implementation_evidence":"Résultat de l’implémentation","lifecycle.detail_finalization_evidence":"Résultat de la finalisation","lifecycle.detail_reconciliation_evidence":"Résultat de la réconciliation","lifecycle.detail_validation_pass":"Passe de validation {iteration}","detail.initial_observation":"Observation initiale","detail.rejected_recommendations":"Recommandations rejetées"});
|
|
4280
|
+
Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.step.repair_agent":"Ronda de reparación","lifecycle.detail_repair_evidence":"Rondas de reparación completadas","lifecycle.detail_implementation_evidence":"Resultado de la implementación","lifecycle.detail_finalization_evidence":"Resultado de la finalización","lifecycle.detail_reconciliation_evidence":"Resultado de la conciliación","lifecycle.detail_validation_pass":"Pasada de validación {iteration}","detail.initial_observation":"Observación inicial","detail.rejected_recommendations":"Recomendaciones rechazadas"});
|
|
4281
|
+
Object.assign(DASHBOARD_MESSAGES.en, {"lifecycle.assurance_integral_evidence":"Impact surfaces reviewed: {coverage} · Prior findings reassessed: {dispositions}"});
|
|
4282
|
+
Object.assign(DASHBOARD_MESSAGES.nl, {"lifecycle.assurance_integral_evidence":"Impactvlakken beoordeeld: {coverage} · Eerdere bevindingen herbeoordeeld: {dispositions}"});
|
|
4283
|
+
Object.assign(DASHBOARD_MESSAGES.de, {"lifecycle.assurance_integral_evidence":"Geprüfte Auswirkungsbereiche: {coverage} · Frühere Befunde erneut bewertet: {dispositions}"});
|
|
4284
|
+
Object.assign(DASHBOARD_MESSAGES.fr, {"lifecycle.assurance_integral_evidence":"Surfaces d’impact examinées : {coverage} · Constats antérieurs réévalués : {dispositions}"});
|
|
4285
|
+
Object.assign(DASHBOARD_MESSAGES.es, {"lifecycle.assurance_integral_evidence":"Superficies de impacto revisadas: {coverage} · Hallazgos anteriores reevaluados: {dispositions}"});
|
|
@@ -44,10 +44,47 @@ REVIEWER_LABELS = {
|
|
|
44
44
|
"documentation": "Documentation Reviewer",
|
|
45
45
|
"finalization": "Finalization Reviewer",
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
ADVISORY_REVIEW_OUTPUT_CONTRACT_VERSION = "1.0"
|
|
48
|
+
MANDATORY_REVIEW_OUTPUT_CONTRACT_VERSION = "2.0"
|
|
48
49
|
MANDATORY_FINDING_FIELDS = frozenset({
|
|
49
50
|
"id", "observation", "category", "criterion", "severity", "confidence", "evidence_ref",
|
|
50
51
|
})
|
|
52
|
+
MANDATORY_COVERAGE_FIELDS = frozenset({"surface", "status", "evidence_ref"})
|
|
53
|
+
MANDATORY_DISPOSITION_FIELDS = frozenset({"finding_id", "disposition", "evidence_ref"})
|
|
54
|
+
MANDATORY_COVERAGE_SURFACES = {
|
|
55
|
+
"IMPLEMENTATION": {
|
|
56
|
+
"quality": (
|
|
57
|
+
"approved_criteria", "full_candidate_diff", "callers_and_consumers",
|
|
58
|
+
"service_lifecycle", "maintenance_recovery_cleanup", "persistence_concurrency",
|
|
59
|
+
"transport_schema_compatibility", "regression_validation",
|
|
60
|
+
),
|
|
61
|
+
"security": (
|
|
62
|
+
"approved_criteria", "full_candidate_diff", "trust_authentication",
|
|
63
|
+
"data_integrity_concurrency", "maintenance_recovery_cleanup",
|
|
64
|
+
"failure_redaction", "availability_resource_bounds", "security_validation",
|
|
65
|
+
),
|
|
66
|
+
},
|
|
67
|
+
"FINALIZATION": {
|
|
68
|
+
"quality": (
|
|
69
|
+
"delivery_role_scope", "full_candidate_diff", "record_consistency",
|
|
70
|
+
"lifecycle_state_claims", "regression_validation",
|
|
71
|
+
),
|
|
72
|
+
"security": (
|
|
73
|
+
"delivery_role_scope", "full_candidate_diff", "authority_scope",
|
|
74
|
+
"sensitive_data", "lifecycle_state_claims", "security_validation",
|
|
75
|
+
),
|
|
76
|
+
},
|
|
77
|
+
"RECONCILIATION": {
|
|
78
|
+
"quality": (
|
|
79
|
+
"delivery_role_scope", "full_candidate_diff", "record_consistency",
|
|
80
|
+
"lifecycle_state_claims", "regression_validation",
|
|
81
|
+
),
|
|
82
|
+
"security": (
|
|
83
|
+
"delivery_role_scope", "full_candidate_diff", "authority_scope",
|
|
84
|
+
"sensitive_data", "lifecycle_state_claims", "security_validation",
|
|
85
|
+
),
|
|
86
|
+
},
|
|
87
|
+
}
|
|
51
88
|
PRODUCT_MATCHERS = {
|
|
52
89
|
"apple_platform": (("apps/apple/", "engineering-platform-app", "swiftui", "watchos", "macos", "ios"), "Apple platform capability"),
|
|
53
90
|
"windows_platform": (("apps/windows/", "engineering-platform-windows", "maui", "windows packaging"), "Windows platform capability"),
|
|
@@ -77,13 +114,15 @@ class ReviewerResult:
|
|
|
77
114
|
# In-process deterministic/test adapters construct this typed result only
|
|
78
115
|
# after choosing the mandatory contract. Raw provider JSON is still
|
|
79
116
|
# required to carry this field by ``CodexCliClient.review``.
|
|
80
|
-
contract_version: str | None =
|
|
117
|
+
contract_version: str | None = ADVISORY_REVIEW_OUTPUT_CONTRACT_VERSION
|
|
81
118
|
failed: bool = False
|
|
82
119
|
usage: dict[str, object] = field(default_factory=dict)
|
|
83
120
|
runtime_metadata: dict[str, object] = field(default_factory=dict)
|
|
84
121
|
churn: dict[str, object] = field(default_factory=dict)
|
|
85
122
|
duration_seconds: float | None = None
|
|
86
123
|
usage_snapshots: tuple[dict[str, int], ...] = ()
|
|
124
|
+
coverage: tuple[dict[str, str], ...] = ()
|
|
125
|
+
finding_dispositions: tuple[dict[str, str], ...] = ()
|
|
87
126
|
|
|
88
127
|
|
|
89
128
|
class ReviewerClient(Protocol):
|
|
@@ -164,6 +203,8 @@ def run_reviews(
|
|
|
164
203
|
result.churn,
|
|
165
204
|
result.duration_seconds,
|
|
166
205
|
result.usage_snapshots,
|
|
206
|
+
tuple(dict(item) for item in result.coverage if isinstance(item, dict)),
|
|
207
|
+
tuple(dict(item) for item in result.finding_dispositions if isinstance(item, dict)),
|
|
167
208
|
)
|
|
168
209
|
except Exception: # Reviewer failure is advisory and cannot block the transaction.
|
|
169
210
|
result = ReviewerResult(selection.reviewer, "Reviewer failed; primary review continues.", failed=True)
|
|
@@ -192,7 +233,8 @@ def mandatory_findings(result: ReviewerResult) -> tuple[dict[str, str], ...] | N
|
|
|
192
233
|
"""Return validated mandatory output, never advice-shaped pseudo-evidence."""
|
|
193
234
|
if result.failed or result.contract_version != MANDATORY_REVIEW_OUTPUT_CONTRACT_VERSION:
|
|
194
235
|
return None
|
|
195
|
-
if
|
|
236
|
+
finding_limit = 12 if result.reviewer in {"quality", "security"} else 64
|
|
237
|
+
if not isinstance(result.findings, tuple) or len(result.findings) > finding_limit:
|
|
196
238
|
return None
|
|
197
239
|
normalized: list[dict[str, str]] = []
|
|
198
240
|
seen: set[str] = set()
|
|
@@ -210,6 +252,65 @@ def mandatory_findings(result: ReviewerResult) -> tuple[dict[str, str], ...] | N
|
|
|
210
252
|
return tuple(normalized)
|
|
211
253
|
|
|
212
254
|
|
|
255
|
+
def mandatory_coverage_surfaces(reviewer: str, delivery_role: str) -> tuple[str, ...]:
|
|
256
|
+
"""Return the host-owned complete impact checklist for one assurance role."""
|
|
257
|
+
return MANDATORY_COVERAGE_SURFACES.get(delivery_role, {}).get(reviewer, ())
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def mandatory_assessment(
|
|
261
|
+
result: ReviewerResult,
|
|
262
|
+
*,
|
|
263
|
+
delivery_role: str,
|
|
264
|
+
prior_finding_ids: tuple[str, ...],
|
|
265
|
+
) -> tuple[tuple[dict[str, str], ...], tuple[dict[str, str], ...], tuple[dict[str, str], ...]] | None:
|
|
266
|
+
"""Validate complete impact coverage and explicit prior-finding closure.
|
|
267
|
+
|
|
268
|
+
A syntactically valid list of findings is insufficient for mandatory
|
|
269
|
+
assurance. Each reviewer must cover every host-owned impact surface and
|
|
270
|
+
explicitly reassess every still-open finding previously raised by that
|
|
271
|
+
same independent role.
|
|
272
|
+
"""
|
|
273
|
+
findings = mandatory_findings(result)
|
|
274
|
+
required_surfaces = mandatory_coverage_surfaces(result.reviewer, delivery_role)
|
|
275
|
+
if findings is None or not required_surfaces:
|
|
276
|
+
return None
|
|
277
|
+
coverage = result.coverage
|
|
278
|
+
dispositions = result.finding_dispositions
|
|
279
|
+
if (
|
|
280
|
+
not isinstance(coverage, tuple)
|
|
281
|
+
or len(coverage) != len(required_surfaces)
|
|
282
|
+
or any(not isinstance(item, dict) or set(item) != MANDATORY_COVERAGE_FIELDS for item in coverage)
|
|
283
|
+
or any(
|
|
284
|
+
item["surface"] not in required_surfaces
|
|
285
|
+
or item["status"] not in {"REVIEWED", "NOT_APPLICABLE"}
|
|
286
|
+
or not isinstance(item["evidence_ref"], str) or not item["evidence_ref"].strip()
|
|
287
|
+
or len(item["evidence_ref"]) > 240
|
|
288
|
+
for item in coverage
|
|
289
|
+
)
|
|
290
|
+
or {item["surface"] for item in coverage} != set(required_surfaces)
|
|
291
|
+
):
|
|
292
|
+
return None
|
|
293
|
+
if (
|
|
294
|
+
not isinstance(dispositions, tuple)
|
|
295
|
+
or len(dispositions) != len(prior_finding_ids)
|
|
296
|
+
or any(not isinstance(item, dict) or set(item) != MANDATORY_DISPOSITION_FIELDS for item in dispositions)
|
|
297
|
+
or any(
|
|
298
|
+
item["finding_id"] not in prior_finding_ids
|
|
299
|
+
or item["disposition"] not in {"RESOLVED", "OPEN"}
|
|
300
|
+
or not isinstance(item["evidence_ref"], str) or not item["evidence_ref"].strip()
|
|
301
|
+
or len(item["evidence_ref"]) > 240
|
|
302
|
+
for item in dispositions
|
|
303
|
+
)
|
|
304
|
+
or {item["finding_id"] for item in dispositions} != set(prior_finding_ids)
|
|
305
|
+
):
|
|
306
|
+
return None
|
|
307
|
+
return (
|
|
308
|
+
findings,
|
|
309
|
+
tuple({key: redact_diagnostic(value, limit=240) for key, value in item.items()} for item in coverage),
|
|
310
|
+
tuple({key: redact_diagnostic(value, limit=240) for key, value in item.items()} for item in dispositions),
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
|
|
213
314
|
def records_for_storage(selections: tuple[ReviewerSelection, ...], results: tuple[ReviewerResult, ...]) -> tuple[dict[str, object], ...]:
|
|
214
315
|
by_reviewer = {result.reviewer: result for result in results}
|
|
215
316
|
records: list[dict[str, object]] = []
|
|
@@ -29,14 +29,15 @@ RunJsonReader = Callable[[Path, str | None], bytes]
|
|
|
29
29
|
TERMINAL_PHASES = frozenset({"COMPLETE", "BLOCKED", "FAILED"})
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
def
|
|
33
|
-
"""Expose
|
|
32
|
+
def _terminal_reviewer_agents(value: object) -> list[dict[str, object]]:
|
|
33
|
+
"""Expose a wholly terminal review beyond its live phase."""
|
|
34
34
|
if not isinstance(value, list):
|
|
35
35
|
return []
|
|
36
36
|
reviewers = [item for item in value if isinstance(item, dict)]
|
|
37
37
|
if not reviewers or len(reviewers) != len(value):
|
|
38
38
|
return []
|
|
39
|
-
|
|
39
|
+
terminal = {"completed", "failed"}
|
|
40
|
+
return reviewers if all(item.get("status") in terminal for item in reviewers) else []
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
def _run_workspace_preflight(root: Path, run_id: object) -> dict[str, object]:
|
|
@@ -417,13 +418,13 @@ def status(root: Path) -> bytes:
|
|
|
417
418
|
"candidate_sha": live.get("candidate_sha"),
|
|
418
419
|
"repair_iteration": live.get("repair_iteration"),
|
|
419
420
|
"workspace_preflight": run_workspace_preflight,
|
|
420
|
-
# Only a wholly
|
|
421
|
-
#
|
|
422
|
-
#
|
|
421
|
+
# Only a wholly terminal specialist review survives its live
|
|
422
|
+
# phase as historical evidence for this active run. A running
|
|
423
|
+
# or malformed reviewer projection remains hidden.
|
|
423
424
|
"reviewer_agents": (
|
|
424
425
|
live.get("reviewer_agents", [])
|
|
425
426
|
if live.get("phase") == "CAPABILITY_REVIEW"
|
|
426
|
-
else
|
|
427
|
+
else _terminal_reviewer_agents(live.get("reviewer_agents"))
|
|
427
428
|
),
|
|
428
429
|
"runtime_metadata": live.get("runtime_metadata", {}),
|
|
429
430
|
"workspace_progress": live.get("workspace_progress"),
|