engineering-platform 2.3.79__tar.gz → 2.3.80__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.79 → engineering_platform-2.3.80}/PKG-INFO +1 -1
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/pyproject.toml +1 -1
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/ENGINEERING_PLATFORM_CONFIG.json +1 -1
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/ENGINEERING_PLATFORM_VERSION.json +4 -4
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/dashboard.css +2 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/dashboard.js +167 -127
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/dashboard_locales.mjs +5 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_reporting.py +210 -63
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_timing.py +105 -31
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/platform_version.py +1 -1
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_usage.py +316 -63
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/server.py +444 -48
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/storage.py +258 -50
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/telemetry_contract.py +92 -42
- engineering_platform-2.3.80/src/engineering_platform/telemetry_export.py +495 -0
- engineering_platform-2.3.80/src/engineering_platform/telemetry_metrics.py +194 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/templates/workspace-config.json +1 -1
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform.egg-info/PKG-INFO +1 -1
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform.egg-info/SOURCES.txt +2 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/README.md +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/setup.cfg +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/__init__.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/__main__.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/agent_state.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/agent_trust.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/dashboard_status_store.mjs +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/dashboard_translation.mjs +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/operations-console/apple-touch-icon-dark.png +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/operations-console/apple-touch-icon-light.png +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/operations-console/icon-dark.png +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/operations-console/icon-light.png +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/operations-console/icon-transparent.png +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/assets/operations-console/manifest.webmanifest +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/capability_preflight.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/capability_review.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/central_data_transfer.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/central_database.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/central_store_migration.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/codex_capacity.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/codex_chat.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/codex_observability.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/component_lock.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/component_logging.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/console_presentation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/console_route_ownership.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/contracts/__init__.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/contracts/ep_consumer.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/contracts/models.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/contracts/projection.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/dashboard_browser_validation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/dashboard_state.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/dashboard_supervisor.swift +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/dashboard_translation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/dependabot_producer.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/development_profile.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/drift_diagnostics.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/emergency_recovery.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/engineering_memory.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/ep_consumer_credentials.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/evidence_projection.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_activity.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_context.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_errors.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_evidence.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_executor.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_finalization.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_host.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_host_evidence.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_lease.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_lifecycle.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_models.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_readiness.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_repository.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_timeout_policy.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/execution_transaction.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/external_producer_binding.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/file_inbox.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/forensic_attribution.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/forensic_attribution_v2.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/forensic_delta.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/golden_scenario.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/historical_dashboard_configuration.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/host_admin.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/host_preflight.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_relocation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_activation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_admission.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_backup.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_composition.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_executor.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_migration.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_operation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_plan.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/installation_update_preparation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/investigation_ledger.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/legacy_inbox_migration.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/legacy_installation_adoption.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/lifecycle_worker.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/live_status.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/local_api.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/local_api_keychain.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/local_repository_binding.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/managed_autonomy.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/managed_codex_runtime.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/operational_installation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/operational_installation_lock.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/operational_installation_record.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/owner_credential_recovery.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/parity_context.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/parity_lifecycle_dispatcher.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/platform_admin.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/platform_api.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/platform_bootstrap.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/platform_components.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/pr_check_repair.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/pr_evidence_backfill.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/producer.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/product_installation_readback.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/project_agent.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/project_agent_service.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/project_topology.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/prompt_history.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_context.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_context_benchmark.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_context_scope.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_interruption.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_process_identity.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_readiness.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/provider_recovery.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/providers.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/qualification.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/qualification_runtime.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/recommendation_handoff.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/reconciliation_adoption.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/release_operation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/report_analysis.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/repository_attachment.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/repository_handoff.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/resources.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/reviewer_evidence.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/revision_binding.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/schemas/producer-readback-v1.2.schema.json +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/schemas/producer-readback-v1.schema.json +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/schemas/repository-attachment.schema.json +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/server_console_services.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/server_relay.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/server_service.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/status_model.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/status_reconciliation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/submission_cli.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/submission_intake.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/submission_service.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/system_installation_topology.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/system_server_service.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/telemetry.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/terminal_evidence_reconciliation.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/validation_identity.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/validation_profile.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/version_preparation_delivery.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/workspace_preflight.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/worktree_provenance.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform/worktree_tooling.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform.egg-info/dependency_links.txt +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform.egg-info/entry_points.txt +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/src/engineering_platform.egg-info/top_level.txt +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/tests/test_adaptive_action_sizing_design.py +0 -0
- {engineering_platform-2.3.79 → engineering_platform-2.3.80}/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.80",
|
|
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.80",
|
|
10
10
|
"report_format": 2,
|
|
11
|
-
"runner_version": "2.3.
|
|
11
|
+
"runner_version": "2.3.80",
|
|
12
12
|
"status_model": 1,
|
|
13
13
|
"storage_schema": 45,
|
|
14
|
-
"watcher_version": "2.3.
|
|
14
|
+
"watcher_version": "2.3.80"
|
|
15
15
|
}
|
|
@@ -117,6 +117,7 @@ button:not(.theme-toggle):not(.section-state-toggle):hover:not(:disabled){backgr
|
|
|
117
117
|
#dashboardSplash{align-items:center;background:#101015;display:flex;inset:0;justify-content:center;padding:24px;position:fixed;text-align:center;transition:opacity .25s ease,visibility .25s ease;z-index:100}#dashboardSplash[hidden]{display:none}body.dashboard-ready #dashboardSplash{opacity:0;pointer-events:none;visibility:hidden}.dashboard-splash__content{align-items:center;display:flex;flex-direction:column;gap:12px;max-width:360px}.dashboard-splash__title{color:#f7f3ee;font:700 clamp(28px,8vw,42px)/1.1 system-ui;margin:0}.dashboard-splash__version{color:#b79aff;font:600 14px/1.3 system-ui;letter-spacing:.04em;text-transform:uppercase}.dashboard-splash__loading{color:#c8c4cc;font:14px system-ui}.dashboard-splash__spinner{animation:dashboard-splash-spin .85s linear infinite;border:3px solid #332a44;border-radius:50%;border-top-color:#b79aff;height:34px;width:34px}@keyframes dashboard-splash-spin{to{transform:rotate(360deg)}}
|
|
118
118
|
.dashboard-splash__icon{border-radius:18px;display:block;height:72px;width:72px}
|
|
119
119
|
#copyToast{align-items:center;background:var(--house-style-surface);border:1px solid var(--house-style);border-radius:999px;box-shadow:0 8px 24px #0009;box-sizing:border-box;color:var(--house-style-contrast);display:flex;font:600 13px system-ui;gap:8px;inset:auto;inset-block-end:max(20px,env(safe-area-inset-bottom));inset-inline-start:50%;margin:0;max-width:calc(100vw - 32px);opacity:0;padding:10px 15px;pointer-events:none;position:fixed;transform:translate(-50%,16px);transition:opacity .16s ease,transform .16s ease;z-index:110}#copyToast::before{content:attr(data-toast-glyph);font:700 17px/1 system-ui}#copyToast.copy-toast--visible{opacity:1;transform:translate(-50%,0)}
|
|
120
|
+
#copyToast[hidden]{display:none}
|
|
120
121
|
body{overflow-x:hidden}.dashboard-grid,.dashboard-grid>*{min-width:0}.telemetry,.platform-health{min-width:0}.telemetry-scroll{max-width:100%;-webkit-overflow-scrolling:touch}.platform-health__component{min-width:0}.platform-health__component-detail{overflow-wrap:anywhere}.dashboard-titlebar{align-items:center;background:#121217;box-shadow:0 10px 18px #121217;box-sizing:border-box;display:flex;gap:14px;justify-content:space-between;margin:0 0 18px;max-width:100%;padding:8px 16px 12px;position:sticky;top:0;width:100%;z-index:15}.dashboard-titlebar:has(+.dashboard-status-banner:not([hidden])){margin-bottom:0}.dashboard-status-banner{align-items:flex-start;box-sizing:border-box;display:flex;gap:8px;margin:0 0 18px;padding:10px 16px;position:sticky;top:0;width:100%;z-index:14}.dashboard-status-banner[hidden]{display:none}.dashboard-status-banner--usage-limit,.dashboard-status-banner--usage-warning,.dashboard-status-banner--usage-critical{box-shadow:0 10px 18px #121217;font:600 13px/1.45 system-ui}.dashboard-status-banner--usage-limit{background:color-mix(in srgb,var(--house-style) 24%,#241b16);border-bottom:1px solid var(--house-style);color:#fff0dc}.dashboard-status-banner--usage-limit strong{color:var(--house-style)}.dashboard-status-banner--usage-warning{background:#5b4316;border-bottom:1px solid #f4c34f;color:#fff4d6}.dashboard-status-banner--usage-warning strong{color:#ffd768}.dashboard-status-banner--usage-critical{background:#5b1d27;border-bottom:1px solid #ff6b7d;color:#ffe9ed}.dashboard-status-banner--usage-critical strong{color:#ff99a7}.dashboard-status-banner strong{flex:none}.dashboard-status-banner span{min-width:0}.dashboard-titlebar__brand{align-items:center;display:flex;flex:1 1 260px;gap:10px;min-width:0}.dashboard-titlebar h1{font-size:28px;line-height:1.1;margin:0;overflow-wrap:anywhere}.dashboard-titlebar__actions{align-items:center;display:flex;flex:none;gap:12px}.auto-refresh-toggle{align-items:center;color:#b9b6c0;cursor:pointer;display:flex;flex:none;font-size:12px;gap:7px;white-space:nowrap}.auto-refresh-toggle input{accent-color:#54d6a0;height:18px;margin:0;width:18px}.section-state-toggle{align-items:center;background:transparent;border:0;color:#b9b6c0;cursor:pointer;display:flex;font:12px system-ui;gap:7px;margin:0;min-height:44px;min-width:44px;padding:0;position:relative}.section-state-toggle::before{background:#4a4a55;border-radius:999px;content:"";height:24px;transition:background .18s ease;width:42px}.section-state-toggle::after{background:#f7f3ee;border-radius:50%;box-shadow:0 1px 3px #0008;content:"";height:18px;left:3px;position:absolute;top:13px;transform:translateX(0);transition:transform .18s ease;width:18px}.section-state-toggle[aria-checked="true"]::before{background:#8dc7ff}.section-state-toggle[aria-checked="true"]::after{transform:translateX(18px)}.section-state-toggle:focus-visible{box-shadow:none;outline:2px solid #8dc7ff;outline-offset:3px}@media (max-width:1400px){.dashboard-titlebar{align-items:flex-start;flex-wrap:wrap}.dashboard-titlebar__actions{flex:1 1 100%;flex-wrap:wrap;justify-content:flex-end}}@media (max-width:760px){.dashboard-titlebar__actions{justify-content:flex-start}}@media (max-width:620px){.dashboard-status-banner{align-items:stretch;flex-direction:column;margin-bottom:12px;padding:10px 14px}.dashboard-titlebar h1{font-size:25px}.auto-refresh-toggle span,.section-state-toggle__label{display:none}.dashboard-titlebar__actions{gap:8px}}html[data-theme="light"] .dashboard-status-banner--usage-limit{background:color-mix(in srgb,var(--house-style) 18%,#fff);color:#643a13}html[data-theme="light"] .dashboard-status-banner--usage-warning{background:#fff4d6;color:#654600}html[data-theme="light"] .dashboard-status-banner--usage-critical{background:#ffe8eb;color:#7d1726}
|
|
121
122
|
.dashboard-titlebar__brand{align-items:center;display:flex;gap:10px;min-width:0}.dashboard-app-icon{border-radius:9px;display:block;flex:none;height:32px;width:32px}@media (max-width:620px){.dashboard-app-icon{height:28px;width:28px}}
|
|
122
123
|
.inbox-queue{--category-color:#818cf8;background:#24242d;border:2px solid var(--category-color);border-radius:18px;box-shadow:0 5px 24px #0006;cursor:pointer;padding:14px}.inbox-queue>summary{border-bottom:1px solid var(--category-color);box-sizing:border-box;cursor:pointer;display:block;list-style:none;margin-bottom:8px;min-height:35px;padding:0 40px 10px 0;position:relative}.inbox-queue>summary::-webkit-details-marker{display:none}.inbox-queue>summary::before{color:var(--category-color);content:"▸ ";font-size:24px;line-height:1;margin:0;padding:0;position:absolute;right:0;top:0;vertical-align:-2px}.inbox-queue[open]>summary::before{content:"▾ "}.inbox-queue>summary>strong{color:var(--category-color);font-size:17px;font-weight:700;letter-spacing:.04em;line-height:1.25;text-transform:uppercase}.inbox-queue .category-description{color:#c9c7e2;font-size:14px;line-height:1.4;margin:12px 0}.inbox-queue .estimate-meta{color:#c9c7e2}.inbox-queue .queue-item{border-top-color:#48446f}
|
|
@@ -1329,3 +1330,4 @@ html[data-theme="light"] :is(.dashboard-status-banner--provider-auth_required .p
|
|
|
1329
1330
|
background-color:color-mix(in srgb,#b89025 14%,#fff)!important;
|
|
1330
1331
|
}
|
|
1331
1332
|
.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)}}
|
|
1333
|
+
.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}}
|
|
@@ -4355,16 +4355,23 @@ const executionTelemetryColumns = [
|
|
|
4355
4355
|
["blocked_count", "telemetry.blocked"], ["failed_count", "telemetry.failed"],
|
|
4356
4356
|
];
|
|
4357
4357
|
const EXECUTION_TELEMETRY_PAGE_SIZE = 7;
|
|
4358
|
-
let executionTelemetryRows = [], executionTelemetryPage = 1, executionTelemetrySort = { key: "date", direction: "desc" }
|
|
4358
|
+
let executionTelemetryRows = [], executionTelemetryPage = 1, executionTelemetrySort = { key: "date", direction: "desc" },
|
|
4359
|
+
executionTelemetryExportSnapshot = null;
|
|
4359
4360
|
function telemetryComparableValue(row, key) {
|
|
4360
4361
|
const value = row?.[key];
|
|
4361
|
-
return key === "date" ? String(value || "") : Number.isFinite(
|
|
4362
|
+
return key === "date" ? String(value || "") : typeof value === "number" && Number.isFinite(value) ? value : null;
|
|
4362
4363
|
}
|
|
4363
4364
|
function sortedExecutionTelemetryRows() {
|
|
4364
4365
|
const { key, direction } = executionTelemetrySort, multiplier = direction === "asc" ? 1 : -1;
|
|
4365
4366
|
return [...executionTelemetryRows].sort((left, right) => {
|
|
4366
4367
|
const leftValue = telemetryComparableValue(left, key), rightValue = telemetryComparableValue(right, key);
|
|
4367
|
-
|
|
4368
|
+
if (leftValue == null && rightValue == null) {
|
|
4369
|
+
const leftDate = String(left?.date || ""), rightDate = String(right?.date || "");
|
|
4370
|
+
return leftDate < rightDate ? -1 : leftDate > rightDate ? 1 : 0;
|
|
4371
|
+
}
|
|
4372
|
+
if (leftValue == null) return 1;
|
|
4373
|
+
if (rightValue == null) return -1;
|
|
4374
|
+
return typeof leftValue === "number" && typeof rightValue === "number"
|
|
4368
4375
|
? (leftValue - rightValue) * multiplier
|
|
4369
4376
|
: (leftValue < rightValue ? -1 : leftValue > rightValue ? 1 : 0) * multiplier;
|
|
4370
4377
|
});
|
|
@@ -4391,6 +4398,7 @@ function setExecutionTelemetrySort(key) {
|
|
|
4391
4398
|
? { key, direction: executionTelemetrySort.direction === "asc" ? "desc" : "asc" }
|
|
4392
4399
|
: { key, direction: key === "date" ? "desc" : "asc" };
|
|
4393
4400
|
executionTelemetryPage = 1;
|
|
4401
|
+
executionTelemetryExportSnapshot = null;
|
|
4394
4402
|
executionTelemetry(executionTelemetryRows);
|
|
4395
4403
|
}
|
|
4396
4404
|
function executionTelemetryText(rows = sortedExecutionTelemetryRows()) {
|
|
@@ -4402,15 +4410,74 @@ function executionTelemetryText(rows = sortedExecutionTelemetryRows()) {
|
|
|
4402
4410
|
]);
|
|
4403
4411
|
return [headings, ...values].map((line) => line.map((value) => String(value ?? "—").replaceAll("\t", " ").replaceAll("\n", " ")).join("\t")).join("\n");
|
|
4404
4412
|
}
|
|
4405
|
-
function
|
|
4413
|
+
function downloadTelemetryResponse(url, fallbackName) {
|
|
4414
|
+
// Start the server-owned response while the user activation is still live.
|
|
4415
|
+
// Fetching first and creating a Blob after a network await causes Chromium
|
|
4416
|
+
// to suppress the download on touch and other activation-gated surfaces.
|
|
4417
|
+
// Content-Disposition supplies the authoritative filename. A same-origin
|
|
4418
|
+
// hidden target keeps an HTTP error inspectable without navigating the
|
|
4419
|
+
// Console; successful attachment responses remain native downloads.
|
|
4420
|
+
let frame = $("telemetryExportDownloadTarget");
|
|
4421
|
+
if (!frame) {
|
|
4422
|
+
frame = document.createElement("iframe");
|
|
4423
|
+
frame.id = "telemetryExportDownloadTarget";
|
|
4424
|
+
frame.name = "telemetry-export-download-target";
|
|
4425
|
+
frame.hidden = true;
|
|
4426
|
+
frame.title = t("telemetry.export_download_target");
|
|
4427
|
+
document.body.append(frame);
|
|
4428
|
+
}
|
|
4429
|
+
const inspectFailure = () => {
|
|
4430
|
+
try {
|
|
4431
|
+
if (!frame.contentWindow || frame.contentWindow.location.href === "about:blank") return;
|
|
4432
|
+
const text = frame.contentDocument?.body?.textContent?.trim();
|
|
4433
|
+
if (text) showDashboardToast(t("telemetry.export_failed"), DASHBOARD_TOAST_GLYPHS.error);
|
|
4434
|
+
} catch {
|
|
4435
|
+
showDashboardToast(t("telemetry.export_failed"), DASHBOARD_TOAST_GLYPHS.error);
|
|
4436
|
+
}
|
|
4437
|
+
};
|
|
4438
|
+
if (!frame.dataset.failureListenerInstalled) {
|
|
4439
|
+
frame.dataset.failureListenerInstalled = "true";
|
|
4440
|
+
frame.addEventListener("load", inspectFailure);
|
|
4441
|
+
}
|
|
4442
|
+
const link = document.createElement("a");
|
|
4443
|
+
link.href = url; link.target = frame.name; link.hidden = true;
|
|
4444
|
+
link.setAttribute("aria-label", fallbackName);
|
|
4445
|
+
document.body.append(link); link.click(); link.remove();
|
|
4446
|
+
return Promise.resolve();
|
|
4447
|
+
}
|
|
4448
|
+
async function downloadExecutionTelemetry(format) {
|
|
4406
4449
|
if (!executionTelemetryRows.length) return;
|
|
4407
|
-
const
|
|
4408
|
-
const
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
4450
|
+
const markdown = format === "markdown", project = document.body.dataset.projectId || "";
|
|
4451
|
+
const parameters = new URLSearchParams({
|
|
4452
|
+
project, format: markdown ? "markdown" : "json", locale: dashboardLocale,
|
|
4453
|
+
sort: executionTelemetrySort.key, direction: executionTelemetrySort.direction,
|
|
4454
|
+
});
|
|
4455
|
+
const buttons = document.querySelectorAll("#executionTelemetry .telemetry-export");
|
|
4456
|
+
buttons.forEach((button) => button.disabled = true);
|
|
4457
|
+
try {
|
|
4458
|
+
const bindingParameters = new URLSearchParams(parameters);
|
|
4459
|
+
bindingParameters.delete("format");
|
|
4460
|
+
const binding = `/api/telemetry/export?${bindingParameters}`;
|
|
4461
|
+
if (!executionTelemetryExportSnapshot || executionTelemetryExportSnapshot.binding !== binding) {
|
|
4462
|
+
const prepareParameters = new URLSearchParams(parameters);
|
|
4463
|
+
prepareParameters.set("prepare", "1");
|
|
4464
|
+
prepareParameters.delete("format");
|
|
4465
|
+
const response = await fetch(`/api/telemetry/export?${prepareParameters}`, { cache: "no-store" });
|
|
4466
|
+
const prepared = await response.json().catch(() => ({}));
|
|
4467
|
+
if (!response.ok || typeof prepared.snapshot_id !== "string") throw new Error(t("telemetry.export_failed"));
|
|
4468
|
+
executionTelemetryExportSnapshot = { binding, id: prepared.snapshot_id };
|
|
4469
|
+
}
|
|
4470
|
+
parameters.set("snapshot_id", executionTelemetryExportSnapshot.id);
|
|
4471
|
+
await downloadTelemetryResponse(
|
|
4472
|
+
`/api/telemetry/export?${parameters}`,
|
|
4473
|
+
`telemetry-overview-${project || "project"}-utc.${markdown ? "md" : "json"}`,
|
|
4474
|
+
);
|
|
4475
|
+
void recordUserAction("telemetry_downloaded");
|
|
4476
|
+
} catch (error) {
|
|
4477
|
+
showDashboardToast(t("telemetry.export_failed"), DASHBOARD_TOAST_GLYPHS.error);
|
|
4478
|
+
} finally {
|
|
4479
|
+
buttons.forEach((button) => button.disabled = !executionTelemetryRows.length);
|
|
4480
|
+
}
|
|
4414
4481
|
}
|
|
4415
4482
|
async function copyExecutionTelemetry() {
|
|
4416
4483
|
if (!executionTelemetryRows.length) return;
|
|
@@ -4441,6 +4508,7 @@ async function clearExecutionTelemetry() {
|
|
|
4441
4508
|
}
|
|
4442
4509
|
}
|
|
4443
4510
|
function executionTelemetry(rows) {
|
|
4511
|
+
if (rows !== executionTelemetryRows) executionTelemetryExportSnapshot = null;
|
|
4444
4512
|
let panel = $("executionTelemetry"),
|
|
4445
4513
|
body = $("executionTelemetryRows"),
|
|
4446
4514
|
pagination = $("executionTelemetryPagination");
|
|
@@ -4458,7 +4526,8 @@ function executionTelemetry(rows) {
|
|
|
4458
4526
|
tableBody = document.createElement("tbody"),
|
|
4459
4527
|
navigation = document.createElement("nav"),
|
|
4460
4528
|
actions = document.createElement("div"),
|
|
4461
|
-
|
|
4529
|
+
downloadMarkdown = document.createElement("button"),
|
|
4530
|
+
downloadJson = document.createElement("button"),
|
|
4462
4531
|
copy = document.createElement("button"),
|
|
4463
4532
|
clear = document.createElement("button"),
|
|
4464
4533
|
retention = document.createElement("div"),
|
|
@@ -4518,7 +4587,8 @@ function executionTelemetry(rows) {
|
|
|
4518
4587
|
navigation.setAttribute("aria-label", t("telemetry.pagination_label"));
|
|
4519
4588
|
actions.className = "log-card-actions telemetry-actions";
|
|
4520
4589
|
for (const [button, className, glyph, label, handler] of [
|
|
4521
|
-
[
|
|
4590
|
+
[downloadMarkdown, "dashboard-action dashboard-action--download telemetry-export telemetry-export--markdown", "MD", "telemetry.download_overview_markdown", () => downloadExecutionTelemetry("markdown")],
|
|
4591
|
+
[downloadJson, "dashboard-action dashboard-action--download telemetry-export telemetry-export--json", "{}", "telemetry.download_overview_json", () => downloadExecutionTelemetry("json")],
|
|
4522
4592
|
[copy, "dashboard-action dashboard-action--copy telemetry-copy", "⧉", "telemetry.copy", copyExecutionTelemetry],
|
|
4523
4593
|
...(!CENTRAL_CONSOLE ? [[clear, "dashboard-action dashboard-action--destructive telemetry-clear", "⊠", "telemetry.clear_title", clearExecutionTelemetry]] : []),
|
|
4524
4594
|
]) {
|
|
@@ -4618,7 +4688,8 @@ function executionTelemetry(rows) {
|
|
|
4618
4688
|
}
|
|
4619
4689
|
updateExecutionTelemetrySortHeaders();
|
|
4620
4690
|
}
|
|
4621
|
-
let telemetryDetailTrigger = null, telemetryDetailPayload = null, telemetryDetailDate = null, telemetryDetailRequestId = 0
|
|
4691
|
+
let telemetryDetailTrigger = null, telemetryDetailPayload = null, telemetryDetailDate = null, telemetryDetailRequestId = 0,
|
|
4692
|
+
telemetryDetailSelection = { scope: "UTC_DAY_DETAIL", runId: null }, telemetryDetailExportSnapshot = null;
|
|
4622
4693
|
function telemetryMs(value) { return typeof value === "number" && value >= 0 ? telemetryDuration(value / 1000) : t("format.unavailable"); }
|
|
4623
4694
|
function telemetryNumber(value) {
|
|
4624
4695
|
return typeof value === "number" && Number.isFinite(value)
|
|
@@ -4638,9 +4709,8 @@ function telemetryMetricValue(metric) {
|
|
|
4638
4709
|
return `${telemetryNumber(metric.value)} · ${telemetryCoverage(metric)}`;
|
|
4639
4710
|
}
|
|
4640
4711
|
function telemetryPercent(value) {
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
? locale.number(percent, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + "%"
|
|
4712
|
+
return typeof value === "number" && Number.isFinite(value)
|
|
4713
|
+
? locale.number(value, { minimumFractionDigits: 1, maximumFractionDigits: 1 }) + "%"
|
|
4644
4714
|
: t("format.unavailable");
|
|
4645
4715
|
}
|
|
4646
4716
|
function telemetryMetric(label, value) {
|
|
@@ -4648,10 +4718,6 @@ function telemetryMetric(label, value) {
|
|
|
4648
4718
|
field.append(Object.assign(document.createElement("span"), { className: "label", textContent: label }), Object.assign(document.createElement("strong"), { textContent: telemetryMs(value) }));
|
|
4649
4719
|
return field;
|
|
4650
4720
|
}
|
|
4651
|
-
function telemetryRunMetric(value, phaseTelemetry) {
|
|
4652
|
-
if (typeof value === "number" && value >= 0) return telemetryMs(value);
|
|
4653
|
-
return phaseTelemetry === "RECORDED" ? t("telemetry.not_executed") : t("telemetry.not_recorded_short");
|
|
4654
|
-
}
|
|
4655
4721
|
function telemetryLabel(phase) { return t("telemetry.phase." + String(phase || "").toLowerCase(), {}, String(phase || t("format.unavailable"))); }
|
|
4656
4722
|
function telemetryDetailSortableTable(columns, rows, initialSort, appendRow) {
|
|
4657
4723
|
let sort = initialSort;
|
|
@@ -4715,100 +4781,42 @@ function setTelemetryDetailDownloads(payload, date) {
|
|
|
4715
4781
|
button.setAttribute("aria-label", t(label, { date: telemetryDate(date) }));
|
|
4716
4782
|
}
|
|
4717
4783
|
}
|
|
4718
|
-
function
|
|
4719
|
-
return String(value ?? t("format.unavailable")).replaceAll("|", "\\|").replaceAll(/[\r\n]+/g, " ").trim();
|
|
4720
|
-
}
|
|
4721
|
-
function telemetryMarkdownTable(headings, rows) {
|
|
4722
|
-
return [
|
|
4723
|
-
`| ${headings.map(telemetryMarkdownCell).join(" | ")} |`,
|
|
4724
|
-
`| ${headings.map(() => "---").join(" | ")} |`,
|
|
4725
|
-
...rows.map((row) => `| ${row.map(telemetryMarkdownCell).join(" | ")} |`),
|
|
4726
|
-
].join("\n");
|
|
4727
|
-
}
|
|
4728
|
-
function telemetryDetailMarkdown(detail, date) {
|
|
4729
|
-
const summary = detail?.summary || {}, phases = Array.isArray(detail?.inclusive_phases) ? detail.inclusive_phases : Array.isArray(detail?.phases) ? detail.phases : [];
|
|
4730
|
-
const exclusive = Array.isArray(detail?.exclusive_distribution) ? detail.exclusive_distribution : [];
|
|
4731
|
-
const runs = Array.isArray(detail?.runs) ? detail.runs : [], bottlenecks = detail?.bottlenecks || {};
|
|
4732
|
-
const usage = summary.usage || {};
|
|
4733
|
-
const summaryRows = [
|
|
4734
|
-
[t("telemetry.executions"), summary.executions ?? 0], [t("telemetry.complete"), summary.completed ?? 0],
|
|
4735
|
-
[t("telemetry.blocked"), summary.blocked ?? 0], [t("telemetry.failed"), summary.failed ?? 0],
|
|
4736
|
-
[t("telemetry.population"), `N=${summary.population ?? summary.executions ?? 0}`],
|
|
4737
|
-
[t("telemetry.elapsed"), telemetryMs(summary.total_wall_time?.average_ms)],
|
|
4738
|
-
[t("telemetry.provider_unique_coverage"), telemetryMs(summary.provider_unique_coverage?.average_ms)],
|
|
4739
|
-
[t("telemetry.provider_cumulative_process"), telemetryMs(summary.provider_cumulative_process?.average_ms)],
|
|
4740
|
-
[t("telemetry.external_wait"), telemetryMs(summary.external_wait?.average_ms)],
|
|
4741
|
-
[t("telemetry.unassigned"), telemetryMs(summary.unassigned?.average_ms)],
|
|
4742
|
-
[t("telemetry.observed_input"), telemetryMetricValue(usage.input_tokens)],
|
|
4743
|
-
[t("telemetry.observed_output"), telemetryMetricValue(usage.output_tokens)],
|
|
4744
|
-
[t("telemetry.cache_ratio"), telemetryPercent(summary.cache_ratio_percent)],
|
|
4745
|
-
[t("telemetry.contract_version"), detail?.contract_version || t("format.unavailable")],
|
|
4746
|
-
];
|
|
4747
|
-
const phaseRows = phases.map((phase) => [telemetryLabel(phase.phase), telemetryMs(phase.average_ms), telemetryMs(phase.median_ms), telemetryMs(phase.total_ms), telemetryPercent(phase.share_percent), phase.runs]);
|
|
4748
|
-
const exclusiveRows = exclusive.map((row) => [telemetryLabel(row.category), telemetryMs(row.duration_ms), telemetryPercent(row.share_percent)]);
|
|
4749
|
-
const runRows = runs.map((run) => [
|
|
4750
|
-
run.run_id, run.started_at ? locale.dateTime(new Date(run.started_at)) : t("format.unavailable"), translate(run.status),
|
|
4751
|
-
telemetryMs(run.total_duration_ms), telemetryRunMetric(run.provider_duration_ms, run.phase_telemetry),
|
|
4752
|
-
telemetryRunMetric(run.external_wait_ms, run.phase_telemetry), telemetryRunMetric(run.unassigned_ms, run.phase_telemetry),
|
|
4753
|
-
telemetryNumber(run.input_tokens), telemetryNumber(run.output_tokens), telemetryPercent(run.cache_ratio_percent),
|
|
4754
|
-
run.largest_phase ? telemetryLabel(run.largest_phase) : telemetryRunMetric(null, run.phase_telemetry), run.producer_type,
|
|
4755
|
-
run.repository, run.model,
|
|
4756
|
-
]);
|
|
4757
|
-
const bottleneckLines = [
|
|
4758
|
-
`${t("telemetry.longest_average_phase")}: ${bottlenecks.longest_average_phase ? telemetryLabel(bottlenecks.longest_average_phase.phase) : t("format.unavailable")}`,
|
|
4759
|
-
`${t("telemetry.largest_accumulated_phase")}: ${bottlenecks.largest_accumulated_phase ? telemetryLabel(bottlenecks.largest_accumulated_phase.phase) : t("format.unavailable")}`,
|
|
4760
|
-
`${t("telemetry.longest_individual_span")}: ${bottlenecks.longest_individual_span ? bottlenecks.longest_individual_span.label || telemetryLabel(bottlenecks.longest_individual_span.phase) : t("format.unavailable")}`,
|
|
4761
|
-
...(Array.isArray(bottlenecks.top_time_consumers) ? bottlenecks.top_time_consumers.map((item) => `${telemetryLabel(item.phase)} — ${telemetryPercent(item.share_percent)}`) : []),
|
|
4762
|
-
];
|
|
4763
|
-
const runDetails = [];
|
|
4764
|
-
for (const run of runs) {
|
|
4765
|
-
const snapshot = run.telemetry_snapshot || {}, attempt = snapshot.attempt || {}, chain = snapshot.chain || {};
|
|
4766
|
-
const invocations = Array.isArray(attempt.usage?.invocations) ? attempt.usage.invocations : [];
|
|
4767
|
-
runDetails.push(`## ${t("telemetry.scope_attempt")} — ${run.run_id}`, "",
|
|
4768
|
-
`${t("telemetry.measurement_coverage")}: ${attempt.timing?.coverage?.state || t("format.unavailable")}`, "",
|
|
4769
|
-
invocations.length ? telemetryMarkdownTable(
|
|
4770
|
-
[t("telemetry.phase"), t("telemetry.role"), t("telemetry.model"), t("telemetry.duration"), t("telemetry.input"), t("telemetry.cached_input"), t("telemetry.uncached_input"), t("telemetry.output"), t("telemetry.usage_coverage"), t("telemetry.invocation_id")],
|
|
4771
|
-
invocations.map((item) => [telemetryLabel(item.phase), item.role, `${item.model || t("format.unavailable")} (${item.model_provenance || t("format.unavailable")})`, telemetryMs(item.duration_ms), telemetryNumber(item.input_tokens), telemetryNumber(item.cached_input_tokens), telemetryNumber(item.uncached_input_tokens), telemetryNumber(item.output_tokens), item.usage_coverage, item.invocation_id]),
|
|
4772
|
-
) : t("format.unavailable"), "",
|
|
4773
|
-
`### ${t("telemetry.scope_chain")}`, "",
|
|
4774
|
-
telemetryMarkdownTable([t("table.details"), t("history.markdown_value")], [
|
|
4775
|
-
[t("telemetry.chain_coverage"), chain.coverage || t("format.unavailable")],
|
|
4776
|
-
[t("telemetry.chain_attempts"), chain.attempt_count ?? t("format.unavailable")],
|
|
4777
|
-
[t("telemetry.original_attempts"), chain.original_attempt_count ?? t("format.unavailable")],
|
|
4778
|
-
[t("telemetry.retries"), chain.retry_count ?? t("format.unavailable")],
|
|
4779
|
-
[t("telemetry.resumes"), chain.resume_count ?? t("format.unavailable")],
|
|
4780
|
-
[t("telemetry.chain_elapsed"), telemetryMs(chain.elapsed_ms)],
|
|
4781
|
-
[t("telemetry.chain_processing"), telemetryMs(chain.processing_time_ms)],
|
|
4782
|
-
[t("telemetry.inter_attempt_gaps"), telemetryMs(chain.inter_attempt_gap_ms)],
|
|
4783
|
-
[t("telemetry.outside_window"), chain.outside_selected_window_count ?? 0],
|
|
4784
|
-
]), "");
|
|
4785
|
-
}
|
|
4786
|
-
return [
|
|
4787
|
-
`# ${t("telemetry.detail_title", { date: telemetryDate(date) })}`, "", t("telemetry.detail_description"), "",
|
|
4788
|
-
`## ${t("telemetry.summary")}`, "", telemetryMarkdownTable([t("table.details"), t("history.markdown_value")], summaryRows), "",
|
|
4789
|
-
`## ${t("telemetry.inclusive_title")}`, "", t("telemetry.inclusive_help"), "", phaseRows.length ? telemetryMarkdownTable([t("telemetry.phase"), t("telemetry.average"), t("telemetry.median"), t("telemetry.accumulated"), t("telemetry.share"), t("telemetry.runs")], phaseRows) : t("telemetry.not_recorded"), "",
|
|
4790
|
-
`## ${t("telemetry.exclusive_title")}`, "", t("telemetry.exclusive_help"), "", exclusiveRows.length ? telemetryMarkdownTable([t("telemetry.category"), t("telemetry.duration"), t("telemetry.share")], exclusiveRows) : t("telemetry.not_recorded"), "",
|
|
4791
|
-
`## ${t("telemetry.bottlenecks")}`, "", ...bottleneckLines.map((line) => `- ${line}`), "",
|
|
4792
|
-
`## ${t("telemetry.runs")}`, "", runRows.length ? telemetryMarkdownTable([t("telemetry.run_id"), t("telemetry.start_time"), t("telemetry.status"), t("telemetry.duration"), t("telemetry.provider_unique_coverage"), t("telemetry.external_wait"), t("telemetry.unassigned"), t("telemetry.input"), t("telemetry.output"), t("telemetry.cache_ratio"), t("telemetry.largest_phase"), t("telemetry.producer_type"), t("telemetry.target_repository"), t("telemetry.model")], runRows) : t("format.unavailable"), "",
|
|
4793
|
-
...runDetails,
|
|
4794
|
-
].join("\n");
|
|
4795
|
-
}
|
|
4796
|
-
function downloadTelemetryDetail(format) {
|
|
4784
|
+
async function downloadTelemetryDetail(format) {
|
|
4797
4785
|
if (!telemetryDetailPayload || !telemetryDetailDate) return;
|
|
4798
|
-
const markdown = format === "markdown";
|
|
4799
|
-
const
|
|
4800
|
-
|
|
4801
|
-
:
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4786
|
+
const markdown = format === "markdown", project = document.body.dataset.projectId || "";
|
|
4787
|
+
const captured = { date: telemetryDetailDate, ...telemetryDetailSelection };
|
|
4788
|
+
const parameters = new URLSearchParams({
|
|
4789
|
+
project, format: markdown ? "markdown" : "json", locale: dashboardLocale,
|
|
4790
|
+
scope: captured.scope,
|
|
4791
|
+
});
|
|
4792
|
+
if (captured.runId) parameters.set("run_id", captured.runId);
|
|
4793
|
+
const buttons = [$('telemetryDetailDownloadMarkdown'), $('telemetryDetailDownloadJson')];
|
|
4794
|
+
buttons.forEach((button) => button.disabled = true);
|
|
4795
|
+
try {
|
|
4796
|
+
const binding = `${captured.date}:${captured.scope}:${captured.runId || ""}:${project}:${dashboardLocale}`;
|
|
4797
|
+
if (!telemetryDetailExportSnapshot || telemetryDetailExportSnapshot.binding !== binding) {
|
|
4798
|
+
const prepareParameters = new URLSearchParams(parameters);
|
|
4799
|
+
prepareParameters.set("prepare", "1");
|
|
4800
|
+
prepareParameters.delete("format");
|
|
4801
|
+
const response = await fetch(
|
|
4802
|
+
`/api/telemetry/${encodeURIComponent(captured.date)}/export?${prepareParameters}`,
|
|
4803
|
+
{ cache: "no-store" },
|
|
4804
|
+
);
|
|
4805
|
+
const prepared = await response.json().catch(() => ({}));
|
|
4806
|
+
if (!response.ok || typeof prepared.snapshot_id !== "string") throw new Error(t("telemetry.export_failed"));
|
|
4807
|
+
telemetryDetailExportSnapshot = { binding, id: prepared.snapshot_id };
|
|
4808
|
+
}
|
|
4809
|
+
parameters.set("snapshot_id", telemetryDetailExportSnapshot.id);
|
|
4810
|
+
await downloadTelemetryResponse(
|
|
4811
|
+
`/api/telemetry/${encodeURIComponent(captured.date)}/export?${parameters}`,
|
|
4812
|
+
`telemetry-detail-${project || "project"}-${captured.runId || captured.date}.${markdown ? "md" : "json"}`,
|
|
4813
|
+
);
|
|
4814
|
+
void recordUserAction(markdown ? "telemetry_detail_markdown_downloaded" : "telemetry_detail_json_downloaded");
|
|
4815
|
+
} catch (error) {
|
|
4816
|
+
showDashboardToast(t("telemetry.export_failed"), DASHBOARD_TOAST_GLYPHS.error);
|
|
4817
|
+
} finally {
|
|
4818
|
+
buttons.forEach((button) => button.disabled = false);
|
|
4819
|
+
}
|
|
4812
4820
|
}
|
|
4813
4821
|
function closeTelemetryDetail() { const modal = $("telemetryDetailModal"); if (modal.open) modal.close(); }
|
|
4814
4822
|
function telemetryDetailTableScroll(table, label) {
|
|
@@ -4825,6 +4833,8 @@ function openTelemetryDetail(date, trigger) {
|
|
|
4825
4833
|
void recordUserAction("telemetry_detail_opened");
|
|
4826
4834
|
const requestId = ++telemetryDetailRequestId;
|
|
4827
4835
|
telemetryDetailTrigger = trigger || document.activeElement;
|
|
4836
|
+
telemetryDetailSelection = { scope: "UTC_DAY_DETAIL", runId: null };
|
|
4837
|
+
telemetryDetailExportSnapshot = null;
|
|
4828
4838
|
const modal = $("telemetryDetailModal"), content = $("telemetryDetailContent");
|
|
4829
4839
|
$("telemetryDetailTitle").textContent = t("telemetry.detail_title", { date: telemetryDate(date) });
|
|
4830
4840
|
$("telemetryDetailDescription").textContent = t("telemetry.detail_description");
|
|
@@ -4847,7 +4857,7 @@ function telemetryTextField(label, value, title) {
|
|
|
4847
4857
|
if (title) { strong.title = title; strong.tabIndex = 0; }
|
|
4848
4858
|
field.append(name, strong); return field;
|
|
4849
4859
|
}
|
|
4850
|
-
function renderCanonicalRunDetail(run, host) {
|
|
4860
|
+
function renderCanonicalRunDetail(run, host, selectForExport = false) {
|
|
4851
4861
|
host.replaceChildren();
|
|
4852
4862
|
const snapshot = run?.telemetry_snapshot || {}, attempt = snapshot.attempt || {}, chain = snapshot.chain || {};
|
|
4853
4863
|
const timing = attempt.timing || {}, usage = attempt.usage || {}, invocations = Array.isArray(usage.invocations) ? usage.invocations : [];
|
|
@@ -4856,11 +4866,15 @@ function renderCanonicalRunDetail(run, host) {
|
|
|
4856
4866
|
const attemptButton = Object.assign(document.createElement("button"), { type: "button", textContent: t("telemetry.scope_attempt") });
|
|
4857
4867
|
const chainButton = Object.assign(document.createElement("button"), { type: "button", textContent: t("telemetry.scope_chain") });
|
|
4858
4868
|
attemptButton.setAttribute("role", "tab"); chainButton.setAttribute("role", "tab");
|
|
4859
|
-
const select = (showChain) => {
|
|
4869
|
+
const select = (showChain, updateExportSelection = selectForExport) => {
|
|
4860
4870
|
attemptPanel.hidden = showChain; chainPanel.hidden = !showChain;
|
|
4861
4871
|
attemptButton.setAttribute("aria-selected", String(!showChain)); chainButton.setAttribute("aria-selected", String(showChain));
|
|
4872
|
+
if (updateExportSelection) telemetryDetailSelection = {
|
|
4873
|
+
scope: showChain ? "EXECUTION_CHAIN" : "EP_RUN_ATTEMPT", runId: run.run_id,
|
|
4874
|
+
};
|
|
4875
|
+
if (updateExportSelection) telemetryDetailExportSnapshot = null;
|
|
4862
4876
|
};
|
|
4863
|
-
attemptButton.addEventListener("click", () => select(false)); chainButton.addEventListener("click", () => select(true));
|
|
4877
|
+
attemptButton.addEventListener("click", () => select(false, true)); chainButton.addEventListener("click", () => select(true, true));
|
|
4864
4878
|
switcher.append(attemptButton, chainButton); select(false); host.append(switcher);
|
|
4865
4879
|
|
|
4866
4880
|
const attemptGrid = document.createElement("div"); attemptGrid.className = "technical-grid";
|
|
@@ -4889,37 +4903,57 @@ function renderCanonicalRunDetail(run, host) {
|
|
|
4889
4903
|
if (timeline.length) {
|
|
4890
4904
|
const byId = new Map(timeline.map((span) => [span.phase_id, span]));
|
|
4891
4905
|
const depth = (span) => { let value = 0, parent = span.parent_phase_id, seen = new Set(); while (parent && byId.has(parent) && !seen.has(parent)) { seen.add(parent); value += 1; parent = byId.get(parent).parent_phase_id; } return value; };
|
|
4906
|
+
const axisDuration = timing.timeline_axis?.duration_ms;
|
|
4907
|
+
const axis = document.createElement("div"); axis.className = "telemetry-timeline-axis";
|
|
4908
|
+
axis.append(
|
|
4909
|
+
Object.assign(document.createElement("span"), { textContent: telemetryMs(0) }),
|
|
4910
|
+
Object.assign(document.createElement("span"), { textContent: telemetryMs(axisDuration) }),
|
|
4911
|
+
);
|
|
4912
|
+
timelineSection.append(axis);
|
|
4892
4913
|
const list = document.createElement("ol"); list.className = "telemetry-timeline";
|
|
4893
4914
|
timeline.forEach((span) => {
|
|
4894
4915
|
const item = document.createElement("li"); item.style.setProperty("--timeline-depth", String(depth(span)));
|
|
4895
|
-
|
|
4896
|
-
|
|
4916
|
+
const label = document.createElement("div"); label.className = "telemetry-timeline__label";
|
|
4917
|
+
label.textContent = `${telemetryLabel(span.phase_name)} · ${telemetryMs(span.duration_ms)} · ${translate(span.outcome)} · ${span.measurement_basis || t("format.unavailable")}`;
|
|
4918
|
+
const track = document.createElement("div"); track.className = "telemetry-timeline__track";
|
|
4919
|
+
const bar = document.createElement("span"); bar.className = "telemetry-timeline__bar";
|
|
4920
|
+
if (typeof axisDuration === "number" && axisDuration > 0 && typeof span.relative_start_ms === "number" && typeof span.relative_end_ms === "number") {
|
|
4921
|
+
bar.style.left = `${Math.max(0, Math.min(100, span.relative_start_ms * 100 / axisDuration))}%`;
|
|
4922
|
+
bar.style.width = `${Math.max(.25, Math.min(100, (span.relative_end_ms - span.relative_start_ms) * 100 / axisDuration))}%`;
|
|
4923
|
+
} else bar.classList.add("telemetry-timeline__bar--unpositioned");
|
|
4924
|
+
bar.title = `${span.phase_id || t("format.unavailable")} · ${span.started_at || t("format.unavailable")} — ${span.completed_at || t("format.unavailable")}`;
|
|
4925
|
+
bar.tabIndex = 0; track.append(bar);
|
|
4926
|
+
const identity = document.createElement("code"); identity.className = "telemetry-timeline__identity";
|
|
4927
|
+
identity.textContent = `${span.phase_id || t("format.unavailable")}${span.parent_phase_id ? ` ← ${span.parent_phase_id}` : ""}`;
|
|
4928
|
+
item.append(label, track, identity); list.append(item);
|
|
4897
4929
|
});
|
|
4898
4930
|
timelineSection.append(list);
|
|
4899
|
-
if (timing.timeline_truncated) timelineSection.append(Object.assign(document.createElement("p"), { className: "telemetry-note", textContent: t("telemetry.
|
|
4931
|
+
if (timing.timeline_truncated) timelineSection.append(Object.assign(document.createElement("p"), { className: "telemetry-note", textContent: t("telemetry.timeline_truncated_full_export", { shown: timeline.length, total: timing.timeline_observation_count }) }));
|
|
4900
4932
|
} else timelineSection.append(Object.assign(document.createElement("p"), { textContent: t("telemetry.not_recorded") }));
|
|
4901
4933
|
attemptPanel.append(timelineSection);
|
|
4902
4934
|
|
|
4903
4935
|
const invocationSection = document.createElement("section");
|
|
4904
|
-
invocationSection.append(Object.assign(document.createElement("h4"), { textContent: `${t("telemetry.invocations")} (${invocations.length})` }));
|
|
4936
|
+
invocationSection.append(Object.assign(document.createElement("h4"), { textContent: `${t("telemetry.invocations")} (${usage.invocation_observation_count ?? invocations.length})` }));
|
|
4905
4937
|
if (invocations.length) {
|
|
4906
4938
|
const columns = [
|
|
4907
4939
|
["phase", "telemetry.phase"], ["role", "telemetry.role"], ["model", "telemetry.model"], ["duration_ms", "telemetry.duration", "desc"],
|
|
4908
4940
|
["input_tokens", "telemetry.input", "desc"], ["cached_input_tokens", "telemetry.cached_input"], ["uncached_input_tokens", "telemetry.uncached_input"],
|
|
4909
|
-
["output_tokens", "telemetry.output"], ["usage_coverage", "telemetry.usage_coverage"], ["invocation_id", "telemetry.invocation_id"], ["retry_ordinal", "telemetry.retry_identity"],
|
|
4910
|
-
].map(([key, label, defaultDirection]) => ({ key, label, defaultDirection, value: (item) => key === "phase" ? telemetryLabel(item.phase) : Number.isFinite(
|
|
4941
|
+
["output_tokens", "telemetry.output"], ["usage_coverage", "telemetry.usage_coverage"], ["timing_correlation", "telemetry.timing_correlation"], ["invocation_id", "telemetry.invocation_id"], ["retry_ordinal", "telemetry.retry_identity"],
|
|
4942
|
+
].map(([key, label, defaultDirection]) => ({ key, label, defaultDirection, value: (item) => key === "phase" ? telemetryLabel(item.phase) : typeof item[key] === "number" && Number.isFinite(item[key]) ? item[key] : String(item[key] || "") }));
|
|
4911
4943
|
const table = telemetryDetailSortableTable(columns, invocations, { key: "input_tokens", direction: "desc" }, (item, body) => {
|
|
4912
4944
|
const row = document.createElement("tr");
|
|
4913
4945
|
const model = item.model ? `${item.model} (${item.model_provenance || t("format.unavailable")})` : t("format.unavailable");
|
|
4914
|
-
[telemetryLabel(item.phase), item.role || t("format.unavailable"), model, telemetryMs(item.duration_ms), telemetryNumber(item.input_tokens), telemetryNumber(item.cached_input_tokens), telemetryNumber(item.uncached_input_tokens), telemetryNumber(item.output_tokens), item.usage_coverage || t("format.unavailable"), item.invocation_id || t("format.unavailable"), item.retry_ordinal ?? t("format.unavailable")]
|
|
4946
|
+
[telemetryLabel(item.phase), item.role || t("format.unavailable"), model, telemetryMs(item.duration_ms), telemetryNumber(item.input_tokens), telemetryNumber(item.cached_input_tokens), telemetryNumber(item.uncached_input_tokens), telemetryNumber(item.output_tokens), item.usage_coverage || t("format.unavailable"), item.timing_correlation || t("format.unavailable"), item.invocation_id || t("format.unavailable"), item.retry_ordinal ?? t("format.unavailable")]
|
|
4915
4947
|
.forEach((value) => row.append(Object.assign(document.createElement("td"), { textContent: String(value) })));
|
|
4916
4948
|
body.append(row);
|
|
4917
4949
|
});
|
|
4918
4950
|
invocationSection.append(telemetryDetailTableScroll(table, t("telemetry.invocations")));
|
|
4951
|
+
if (usage.invocation_table_truncated) invocationSection.append(Object.assign(document.createElement("p"), { className: "telemetry-note", textContent: t("telemetry.invocations_truncated_full_export", { shown: invocations.length, total: usage.invocation_observation_count }) }));
|
|
4919
4952
|
} else invocationSection.append(Object.assign(document.createElement("p"), { textContent: t("telemetry.not_recorded") }));
|
|
4920
4953
|
attemptPanel.append(invocationSection);
|
|
4921
4954
|
|
|
4922
4955
|
const chainGrid = document.createElement("div"); chainGrid.className = "technical-grid";
|
|
4956
|
+
const chainMetric = (name) => chain.usage_metrics?.[name];
|
|
4923
4957
|
chainGrid.append(
|
|
4924
4958
|
telemetryTextField(t("telemetry.chain_coverage"), chain.coverage, Array.isArray(chain.reasons) ? chain.reasons.join("; ") : chain.reason),
|
|
4925
4959
|
telemetryTextField(t("telemetry.chain_attempts"), chain.attempt_count),
|
|
@@ -4931,6 +4965,12 @@ function renderCanonicalRunDetail(run, host) {
|
|
|
4931
4965
|
telemetryTextField(t("telemetry.inter_attempt_gaps"), telemetryMs(chain.inter_attempt_gap_ms)),
|
|
4932
4966
|
telemetryTextField(t("telemetry.outside_window"), chain.outside_selected_window_count ?? 0),
|
|
4933
4967
|
telemetryTextField(t("telemetry.mission_scope"), chain.mission_scope_label || t("format.unavailable")),
|
|
4968
|
+
telemetryTextField(t("telemetry.invocations"), chain.provider_invocation_count ?? t("format.unavailable")),
|
|
4969
|
+
telemetryTextField(t("telemetry.observed_input"), telemetryMetricValue(chainMetric("input_tokens")), chainMetric("input_tokens")?.missing_reason),
|
|
4970
|
+
telemetryTextField(t("telemetry.cached_input"), telemetryMetricValue(chainMetric("cached_input_tokens")), chainMetric("cached_input_tokens")?.missing_reason),
|
|
4971
|
+
telemetryTextField(t("telemetry.uncached_input"), telemetryMetricValue(chainMetric("uncached_input_tokens")), chainMetric("uncached_input_tokens")?.missing_reason),
|
|
4972
|
+
telemetryTextField(t("telemetry.observed_output"), telemetryMetricValue(chainMetric("output_tokens")), chainMetric("output_tokens")?.missing_reason),
|
|
4973
|
+
telemetryTextField(t("telemetry.cache_ratio"), telemetryPercent(chain.cache_ratio_percent), telemetryCoverage(chain.cache_ratio_population)),
|
|
4934
4974
|
);
|
|
4935
4975
|
chainPanel.append(chainGrid);
|
|
4936
4976
|
const chainRuns = Array.isArray(chain.runs) ? chain.runs : [];
|
|
@@ -4975,7 +5015,7 @@ function renderTelemetryDetail(detail, content) {
|
|
|
4975
5015
|
: [categoryKey, "duration_ms", "share_percent"];
|
|
4976
5016
|
const table = telemetryDetailSortableTable(columns.map((label, index) => ({
|
|
4977
5017
|
key: columnKeys[index], label,
|
|
4978
|
-
value: (item) => index === 0 ? telemetryLabel(item[categoryKey]) : Number(item[columnKeys[index]])
|
|
5018
|
+
value: (item) => index === 0 ? telemetryLabel(item[categoryKey]) : typeof item[columnKeys[index]] === "number" && Number.isFinite(item[columnKeys[index]]) ? item[columnKeys[index]] : null,
|
|
4979
5019
|
})), values, { key: categoryKey, direction: "asc" }, (item, body) => {
|
|
4980
5020
|
const row = document.createElement("tr"), category = telemetryLabel(item[categoryKey]);
|
|
4981
5021
|
const rendered = durationKey === "total_ms"
|
|
@@ -5012,11 +5052,11 @@ function renderTelemetryDetail(detail, content) {
|
|
|
5012
5052
|
["provider_duration_ms", "telemetry.provider_unique_coverage"], ["external_wait_ms", "telemetry.external_wait"], ["unassigned_ms", "telemetry.unassigned"],
|
|
5013
5053
|
["input_tokens", "telemetry.input"], ["output_tokens", "telemetry.output"], ["cache_ratio_percent", "telemetry.cache_ratio"], ["largest_phase", "telemetry.largest_phase"],
|
|
5014
5054
|
["model", "telemetry.model"],
|
|
5015
|
-
].map(([key, label, defaultDirection]) => ({ key, label, defaultDirection, value: (run) => key === "largest_phase" ? telemetryLabel(run[key]) : key === "started_at" ? Date.parse(run[key]) ||
|
|
5055
|
+
].map(([key, label, defaultDirection]) => ({ key, label, defaultDirection, value: (run) => key === "largest_phase" ? telemetryLabel(run[key]) : key === "started_at" ? Date.parse(run[key]) || null : typeof run[key] === "number" && Number.isFinite(run[key]) ? run[key] : String(run[key] || "") }));
|
|
5016
5056
|
const runTable = telemetryDetailSortableTable(runColumns, runs, { key: "started_at", direction: "desc" }, (run, runBody) => {
|
|
5017
5057
|
const row = document.createElement("tr"), id = document.createElement("button"); row.className = "telemetry-row"; row.tabIndex = 0; row.setAttribute("role", "button");
|
|
5018
5058
|
row.setAttribute("aria-label", String(run.run_id || t("format.unavailable"))); id.type = "button"; id.className = "telemetry-run-link"; id.textContent = run.run_id;
|
|
5019
|
-
const selectRun = () => { runBody.querySelectorAll('.telemetry-row[data-selected="true"]').forEach((candidate) => { candidate.dataset.selected = "false"; }); row.dataset.selected = "true"; renderCanonicalRunDetail(run, runDetailHost); };
|
|
5059
|
+
const selectRun = () => { runBody.querySelectorAll('.telemetry-row[data-selected="true"]').forEach((candidate) => { candidate.dataset.selected = "false"; }); row.dataset.selected = "true"; renderCanonicalRunDetail(run, runDetailHost, true); };
|
|
5020
5060
|
row.addEventListener("click", selectRun); row.addEventListener("keydown", (event) => { if (event.key === "Enter" || event.key === " ") { event.preventDefault(); selectRun(); } });
|
|
5021
5061
|
id.addEventListener("click", (event) => { event.stopPropagation(); selectRun(); openPromptHistoryDetail({ run_id: run.run_id, title: run.run_id }); });
|
|
5022
5062
|
[id, run.started_at ? locale.dateTime(new Date(run.started_at)) : t("format.unavailable"), translate(run.status), telemetryMs(run.total_duration_ms), telemetryMs(run.provider_duration_ms), telemetryMs(run.external_wait_ms), telemetryMs(run.unassigned_ms), telemetryNumber(run.input_tokens), telemetryNumber(run.output_tokens), telemetryPercent(run.cache_ratio_percent), run.largest_phase ? telemetryLabel(run.largest_phase) : t("format.unavailable"), run.model || t("format.unavailable")].forEach((value) => { const cell = document.createElement("td"); if (value instanceof Element) cell.append(value); else cell.textContent = String(value); row.append(cell); });
|
|
@@ -3150,6 +3150,11 @@ Object.assign(DASHBOARD_MESSAGES.es, {
|
|
|
3150
3150
|
"log_event.terminal_report_corrected":"Informe final corregido", "log_event.active_run_lease_reconciled":"Arrendamiento de ejecución activa conciliado", "log_event.detached_runner_job_missing":"Falta la tarea de ejecución desconectada", "log_event.inbox_scan":"Bandeja de entrada analizada", "log_event.active_transaction_queue_refreshed":"Cola de ejecución activa actualizada",
|
|
3151
3151
|
"log_event.inbox_log_unavailable":"Registro del monitor de bandeja de entrada no disponible", "log_event.dashboard_log_unavailable":"Registro del panel de estado no disponible"
|
|
3152
3152
|
});
|
|
3153
|
+
Object.assign(DASHBOARD_MESSAGES.en, {"telemetry.download_overview_markdown":"Download complete overview as Markdown","telemetry.download_overview_json":"Download complete overview as JSON","telemetry.export_failed":"The telemetry export could not be created. Try again.","telemetry.export_download_target":"Telemetry export download response","telemetry.timeline_truncated_full_export":"Showing {shown} of {total} spans. The complete detail export contains all spans.","telemetry.invocations_truncated_full_export":"Showing {shown} of {total} invocations. The complete detail export contains all invocations.","telemetry.timing_correlation":"Timing correlation"});
|
|
3154
|
+
Object.assign(DASHBOARD_MESSAGES.nl, {"telemetry.download_overview_markdown":"Volledig overzicht als Markdown downloaden","telemetry.download_overview_json":"Volledig overzicht als JSON downloaden","telemetry.export_failed":"De telemetrie-export kon niet worden gemaakt. Probeer opnieuw.","telemetry.export_download_target":"Downloadrespons voor telemetrie-export","telemetry.timeline_truncated_full_export":"{shown} van {total} spans worden getoond. De volledige detailexport bevat alle spans.","telemetry.invocations_truncated_full_export":"{shown} van {total} invocations worden getoond. De volledige detailexport bevat alle invocations.","telemetry.timing_correlation":"Timingkoppeling"});
|
|
3155
|
+
Object.assign(DASHBOARD_MESSAGES.de, {"telemetry.download_overview_markdown":"Vollständige Übersicht als Markdown herunterladen","telemetry.download_overview_json":"Vollständige Übersicht als JSON herunterladen","telemetry.export_failed":"Der Telemetrieexport konnte nicht erstellt werden. Versuchen Sie es erneut.","telemetry.export_download_target":"Downloadantwort des Telemetrieexports","telemetry.timeline_truncated_full_export":"{shown} von {total} Zeitspannen werden angezeigt. Der vollständige Detailexport enthält alle Zeitspannen.","telemetry.invocations_truncated_full_export":"{shown} von {total} Aufrufen werden angezeigt. Der vollständige Detailexport enthält alle Aufrufe.","telemetry.timing_correlation":"Zeitkorrelation"});
|
|
3156
|
+
Object.assign(DASHBOARD_MESSAGES.fr, {"telemetry.download_overview_markdown":"Télécharger la vue complète en Markdown","telemetry.download_overview_json":"Télécharger la vue complète en JSON","telemetry.export_failed":"L’export de télémétrie n’a pas pu être créé. Réessayez.","telemetry.export_download_target":"Réponse de téléchargement de l’export de télémétrie","telemetry.timeline_truncated_full_export":"{shown} intervalles sur {total} sont affichés. L’export détaillé complet contient tous les intervalles.","telemetry.invocations_truncated_full_export":"{shown} invocations sur {total} sont affichées. L’export détaillé complet contient toutes les invocations.","telemetry.timing_correlation":"Corrélation temporelle"});
|
|
3157
|
+
Object.assign(DASHBOARD_MESSAGES.es, {"telemetry.download_overview_markdown":"Descargar el resumen completo como Markdown","telemetry.download_overview_json":"Descargar el resumen completo como JSON","telemetry.export_failed":"No se pudo crear la exportación de telemetría. Inténtalo de nuevo.","telemetry.export_download_target":"Respuesta de descarga de la exportación de telemetría","telemetry.timeline_truncated_full_export":"Se muestran {shown} de {total} tramos. La exportación detallada completa contiene todos los tramos.","telemetry.invocations_truncated_full_export":"Se muestran {shown} de {total} invocaciones. La exportación detallada completa contiene todas las invocaciones.","telemetry.timing_correlation":"Correlación temporal"});
|
|
3153
3158
|
Object.assign(DASHBOARD_MESSAGES.en, {
|
|
3154
3159
|
"action.recover": "Recover",
|
|
3155
3160
|
"preflight.sync": "Preflight failed: {reason}\nRecovery: {recovery}",
|