code-coordinator 0.5.46__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- code_coordinator-0.5.46.dist-info/METADATA +625 -0
- code_coordinator-0.5.46.dist-info/RECORD +295 -0
- code_coordinator-0.5.46.dist-info/WHEEL +5 -0
- code_coordinator-0.5.46.dist-info/entry_points.txt +2 -0
- code_coordinator-0.5.46.dist-info/licenses/LICENSE +110 -0
- code_coordinator-0.5.46.dist-info/top_level.txt +1 -0
- coord/__init__.py +176 -0
- coord/_board_mapping.py +229 -0
- coord/acceptance.py +468 -0
- coord/acceptance_drivers.py +632 -0
- coord/agent.py +7517 -0
- coord/agent_app.py +1555 -0
- coord/agent_update.py +417 -0
- coord/agents/opencode/.gitignore +13 -0
- coord/agents/opencode/agents/work.md +129 -0
- coord/agents/opencode/routing.jsonc +49 -0
- coord/audit.py +301 -0
- coord/auto_loop.py +1440 -0
- coord/board_bool_guard.py +72 -0
- coord/board_service.py +141 -0
- coord/board_wire.py +309 -0
- coord/brain.py +581 -0
- coord/branch_model.py +214 -0
- coord/cargo_cache.py +258 -0
- coord/ci_github.py +386 -0
- coord/ci_store.py +560 -0
- coord/claim.py +353 -0
- coord/cli.py +454 -0
- coord/client.py +610 -0
- coord/commands/__init__.py +1 -0
- coord/commands/_common.py +329 -0
- coord/commands/acceptance.py +916 -0
- coord/commands/agent_ops.py +1339 -0
- coord/commands/audit.py +131 -0
- coord/commands/chat.py +320 -0
- coord/commands/dispatch.py +1780 -0
- coord/commands/dispatch_workers.py +4894 -0
- coord/commands/drive.py +616 -0
- coord/commands/drive_queue.py +1203 -0
- coord/commands/gate_a.py +217 -0
- coord/commands/gates.py +89 -0
- coord/commands/issues.py +681 -0
- coord/commands/lifecycle.py +513 -0
- coord/commands/merge.py +1900 -0
- coord/commands/milestone.py +2081 -0
- coord/commands/plan_followup.py +1243 -0
- coord/commands/plans.py +156 -0
- coord/commands/release.py +2232 -0
- coord/commands/report.py +341 -0
- coord/commands/review.py +1523 -0
- coord/commands/scorecard.py +252 -0
- coord/commands/sessions.py +1930 -0
- coord/commands/setup.py +576 -0
- coord/commands/status.py +2089 -0
- coord/commands/terminal.py +385 -0
- coord/commands/test_gate.py +775 -0
- coord/commands/tui.py +288 -0
- coord/comments.py +718 -0
- coord/config.py +3032 -0
- coord/conflict_fix.py +633 -0
- coord/dao.py +483 -0
- coord/dashboard/__init__.py +0 -0
- coord/dashboard/fixture.py +376 -0
- coord/dashboard/index.html +658 -0
- coord/dashboard/server.py +1894 -0
- coord/dashboard/terminal.py +382 -0
- coord/dashboard/webapp/.gitignore +9 -0
- coord/dashboard/webapp/components.json +17 -0
- coord/dashboard/webapp/dist/assets/Gallery-da3qNiIw.js +71 -0
- coord/dashboard/webapp/dist/assets/Terminal-9CEnUXvW.css +32 -0
- coord/dashboard/webapp/dist/assets/Terminal-skVFCxPU.js +63 -0
- coord/dashboard/webapp/dist/assets/index-DltfZR5f.js +184 -0
- coord/dashboard/webapp/dist/assets/index-Dq4kwTdw.css +1 -0
- coord/dashboard/webapp/dist/assets/workbox-window.prod.es5-BqEJf4Xk.js +2 -0
- coord/dashboard/webapp/dist/icons/icon-192.png +0 -0
- coord/dashboard/webapp/dist/icons/icon-512.png +0 -0
- coord/dashboard/webapp/dist/icons/icon.svg +5 -0
- coord/dashboard/webapp/dist/index.html +38 -0
- coord/dashboard/webapp/dist/manifest.webmanifest +1 -0
- coord/dashboard/webapp/dist/sw.js +1 -0
- coord/dashboard/webapp/dist/workbox-e4022e15.js +1 -0
- coord/dashboard/webapp/e2e/available-gates-terminal.spec.ts +75 -0
- coord/dashboard/webapp/e2e/deep-link.spec.ts +172 -0
- coord/dashboard/webapp/e2e/fixtureServer.ts +155 -0
- coord/dashboard/webapp/e2e/live-update-fixture.spec.ts +113 -0
- coord/dashboard/webapp/e2e/realtime.spec.ts +238 -0
- coord/dashboard/webapp/e2e/shell.spec.ts +309 -0
- coord/dashboard/webapp/e2e/smoke.spec.ts +191 -0
- coord/dashboard/webapp/e2e/terminal.spec.ts +420 -0
- coord/dashboard/webapp/e2e/theme.spec.ts +138 -0
- coord/dashboard/webapp/eslint.config.js +20 -0
- coord/dashboard/webapp/index.html +37 -0
- coord/dashboard/webapp/node_modules/flatted/python/flatted.py +144 -0
- coord/dashboard/webapp/package-lock.json +10584 -0
- coord/dashboard/webapp/package.json +63 -0
- coord/dashboard/webapp/playwright.acceptance.config.ts +166 -0
- coord/dashboard/webapp/playwright.config.ts +93 -0
- coord/dashboard/webapp/postcss.config.js +6 -0
- coord/dashboard/webapp/public/icons/icon-192.png +0 -0
- coord/dashboard/webapp/public/icons/icon-512.png +0 -0
- coord/dashboard/webapp/public/icons/icon.svg +5 -0
- coord/dashboard/webapp/src/App.tsx +140 -0
- coord/dashboard/webapp/src/api/client.ts +199 -0
- coord/dashboard/webapp/src/api/generated.ts +176 -0
- coord/dashboard/webapp/src/components/ConnectionBadge.tsx +52 -0
- coord/dashboard/webapp/src/components/Detail.tsx +800 -0
- coord/dashboard/webapp/src/components/Gallery.tsx +341 -0
- coord/dashboard/webapp/src/components/Home.tsx +435 -0
- coord/dashboard/webapp/src/components/MobileKeyBar.tsx +280 -0
- coord/dashboard/webapp/src/components/PanelHeader.tsx +59 -0
- coord/dashboard/webapp/src/components/PipelineCard.tsx +168 -0
- coord/dashboard/webapp/src/components/SessionCard.tsx +99 -0
- coord/dashboard/webapp/src/components/SessionDetail.tsx +140 -0
- coord/dashboard/webapp/src/components/SessionsList.tsx +81 -0
- coord/dashboard/webapp/src/components/Terminal.tsx +376 -0
- coord/dashboard/webapp/src/components/__tests__/ConnectionBadge.test.tsx +81 -0
- coord/dashboard/webapp/src/components/__tests__/Detail.test.tsx +680 -0
- coord/dashboard/webapp/src/components/__tests__/Gallery.test.tsx +83 -0
- coord/dashboard/webapp/src/components/__tests__/Home.test.tsx +271 -0
- coord/dashboard/webapp/src/components/__tests__/MobileKeyBar.test.tsx +197 -0
- coord/dashboard/webapp/src/components/__tests__/PipelineCard.test.tsx +143 -0
- coord/dashboard/webapp/src/components/__tests__/SessionCard.test.tsx +106 -0
- coord/dashboard/webapp/src/components/__tests__/Terminal.test.tsx +504 -0
- coord/dashboard/webapp/src/components/ui/badge.tsx +41 -0
- coord/dashboard/webapp/src/components/ui/button.tsx +54 -0
- coord/dashboard/webapp/src/components/ui/card.tsx +55 -0
- coord/dashboard/webapp/src/components/ui/dialog.tsx +99 -0
- coord/dashboard/webapp/src/components/ui/dropdown-menu.tsx +189 -0
- coord/dashboard/webapp/src/components/ui/empty-state.tsx +35 -0
- coord/dashboard/webapp/src/components/ui/sheet.tsx +123 -0
- coord/dashboard/webapp/src/components/ui/skeleton.tsx +9 -0
- coord/dashboard/webapp/src/components/ui/tabs.tsx +55 -0
- coord/dashboard/webapp/src/components/ui/theme-provider.tsx +78 -0
- coord/dashboard/webapp/src/components/ui/theme-toggle.tsx +20 -0
- coord/dashboard/webapp/src/components/ui/toast.tsx +123 -0
- coord/dashboard/webapp/src/components/ui/toaster.tsx +30 -0
- coord/dashboard/webapp/src/components/ui/tooltip.tsx +26 -0
- coord/dashboard/webapp/src/components/ui/use-toast.ts +134 -0
- coord/dashboard/webapp/src/index.css +210 -0
- coord/dashboard/webapp/src/lib/pipeline.ts +29 -0
- coord/dashboard/webapp/src/lib/utils.ts +6 -0
- coord/dashboard/webapp/src/main.tsx +46 -0
- coord/dashboard/webapp/src/realtime/RealtimeProvider.tsx +112 -0
- coord/dashboard/webapp/src/realtime/__tests__/RealtimeProvider.test.tsx +189 -0
- coord/dashboard/webapp/src/realtime/__tests__/connection.test.ts +255 -0
- coord/dashboard/webapp/src/realtime/connection.ts +227 -0
- coord/dashboard/webapp/src/realtime/events.ts +100 -0
- coord/dashboard/webapp/src/routes/__tests__/paths.test.ts +92 -0
- coord/dashboard/webapp/src/routes/paths.ts +92 -0
- coord/dashboard/webapp/src/shell/ActivityRail.tsx +335 -0
- coord/dashboard/webapp/src/shell/AppShell.tsx +276 -0
- coord/dashboard/webapp/src/shell/ComingSoon.tsx +33 -0
- coord/dashboard/webapp/src/shell/EmptyDetail.tsx +26 -0
- coord/dashboard/webapp/src/shell/RouteNotFound.tsx +33 -0
- coord/dashboard/webapp/src/shell/ShellLayout.tsx +147 -0
- coord/dashboard/webapp/src/shell/StatusBar.tsx +46 -0
- coord/dashboard/webapp/src/shell/__tests__/ShellLayout.test.tsx +520 -0
- coord/dashboard/webapp/src/shell/__tests__/shellState.test.ts +95 -0
- coord/dashboard/webapp/src/shell/__tests__/stubViewport.ts +40 -0
- coord/dashboard/webapp/src/shell/breakpoints.ts +87 -0
- coord/dashboard/webapp/src/shell/railItems.ts +105 -0
- coord/dashboard/webapp/src/shell/shellState.ts +174 -0
- coord/dashboard/webapp/src/shell/useRegionFocus.ts +95 -0
- coord/dashboard/webapp/src/test-setup.ts +41 -0
- coord/dashboard/webapp/src/vite-env.d.ts +2 -0
- coord/dashboard/webapp/tailwind.config.js +140 -0
- coord/dashboard/webapp/tsconfig.json +25 -0
- coord/dashboard/webapp/tsconfig.node.json +11 -0
- coord/dashboard/webapp/vite.config.ts +71 -0
- coord/db.py +1076 -0
- coord/dead_end.py +332 -0
- coord/deploy/README.md +33 -0
- coord/deploy/coord-agent.service +89 -0
- coord/deploy/coord-db-backup.service +60 -0
- coord/deploy/coord-db-backup.sh +74 -0
- coord/deploy/coord-db-backup.timer +18 -0
- coord/deploy/coord-drive-queue.service +117 -0
- coord/deploy/coord-drive-queue.timer +39 -0
- coord/deploy/coord-notify.service +48 -0
- coord/deploy/coord-notify.timer +24 -0
- coord/deploy/coord-release-propagate.service +83 -0
- coord/deploy/coord-release-propagate.timer +38 -0
- coord/deploy/coord-release-window.service +119 -0
- coord/deploy/coord-release-window.timer +36 -0
- coord/deploy/coord-serve.service +82 -0
- coord/deploy/coord-web-dist-build.service +43 -0
- coord/deploy/coord-web-dist-build.timer +36 -0
- coord/deploy/coord-web.service +125 -0
- coord/deploy_manifest.py +80 -0
- coord/deploy_units.py +384 -0
- coord/deps.py +115 -0
- coord/diagnose.py +1623 -0
- coord/dispatch.py +1009 -0
- coord/dist_name.py +123 -0
- coord/drive.py +3101 -0
- coord/drive_queue.py +2298 -0
- coord/drive_state.py +870 -0
- coord/events.py +381 -0
- coord/failure_class.py +914 -0
- coord/filelock.py +168 -0
- coord/fleet_config_health.py +300 -0
- coord/freshness.py +206 -0
- coord/gate_a.py +469 -0
- coord/gate_b.py +411 -0
- coord/gate_snapshot.py +385 -0
- coord/gates.py +582 -0
- coord/github_ops.py +1954 -0
- coord/goal.py +125 -0
- coord/graph_health.py +348 -0
- coord/health/__init__.py +69 -0
- coord/health/aggregate.py +129 -0
- coord/health/checks/__init__.py +13 -0
- coord/health/checks/agent_install.py +280 -0
- coord/health/checks/cargo_targets.py +171 -0
- coord/health/checks/claude_binary.py +65 -0
- coord/health/checks/deploy_lane_facts.py +458 -0
- coord/health/checks/disk.py +99 -0
- coord/health/checks/fleet_board.py +89 -0
- coord/health/checks/fleet_deploy_lanes.py +469 -0
- coord/health/checks/fleet_phantom.py +69 -0
- coord/health/checks/fleet_unit_drift.py +151 -0
- coord/health/checks/graph.py +192 -0
- coord/health/checks/plan_usage.py +88 -0
- coord/health/checks/repo_state.py +161 -0
- coord/health/checks/spawned_coord.py +465 -0
- coord/health/checks/timer_active.py +254 -0
- coord/health/checks/toolchain.py +547 -0
- coord/health/checks/unit_drift.py +648 -0
- coord/health/checks/unit_enablement.py +171 -0
- coord/health/checks/worktrees.py +96 -0
- coord/health/cli.py +121 -0
- coord/health/context.py +106 -0
- coord/health/fleet_snapshot.py +477 -0
- coord/health/models.py +250 -0
- coord/health/pypi.py +231 -0
- coord/health/registry.py +240 -0
- coord/health/render.py +82 -0
- coord/health/units.py +60 -0
- coord/hooks.py +106 -0
- coord/housekeeping.py +204 -0
- coord/interactive.py +4286 -0
- coord/issue_store.py +1496 -0
- coord/liveness_auditor.py +293 -0
- coord/machine_pause.py +755 -0
- coord/merge_queue.py +4681 -0
- coord/milestone_chat.py +600 -0
- coord/milestone_dispatch.py +943 -0
- coord/milestone_gate.py +709 -0
- coord/milestone_order.py +840 -0
- coord/mock_author.py +334 -0
- coord/models.py +891 -0
- coord/network.py +269 -0
- coord/new_issue_chat.py +229 -0
- coord/notify.py +3226 -0
- coord/openapi.py +404 -0
- coord/overlap_fence.py +133 -0
- coord/parentage.py +200 -0
- coord/parentage_github.py +58 -0
- coord/pipeline.py +481 -0
- coord/plan_parser.py +266 -0
- coord/plans.py +543 -0
- coord/platform_paths.py +43 -0
- coord/pr_body_lint.py +67 -0
- coord/prereqs.py +533 -0
- coord/progress.py +425 -0
- coord/providers/__init__.py +683 -0
- coord/providers/base.py +218 -0
- coord/providers/claude.py +284 -0
- coord/providers/claude_pty.py +610 -0
- coord/providers/opencode.py +896 -0
- coord/reconcile.py +2233 -0
- coord/refine_chat.py +485 -0
- coord/release_cordon.py +525 -0
- coord/release_propagate.py +1176 -0
- coord/release_verify.py +777 -0
- coord/release_window.py +322 -0
- coord/reports.py +1643 -0
- coord/revalidate.py +1101 -0
- coord/review.py +3317 -0
- coord/scorecard.py +484 -0
- coord/serve_app.py +7192 -0
- coord/skills/update-issue/SKILL.md +93 -0
- coord/smoke.py +1030 -0
- coord/split_work.py +210 -0
- coord/stage_projection.py +650 -0
- coord/state.py +5720 -0
- coord/test_author.py +1064 -0
- coord/test_chat.py +352 -0
- coord/test_orchestrator.py +494 -0
- coord/test_report.py +178 -0
- coord/tui_release.py +271 -0
- coord/usage.py +753 -0
- coord/usage_limits.py +358 -0
- coord/usage_rollup.py +709 -0
- coord/worker_events.py +954 -0
coord/_board_mapping.py
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"""Storage-neutral row → dataclass mapping for the board.
|
|
2
|
+
|
|
3
|
+
Extracted from :mod:`coord.state` (#584 portable control center) so that both
|
|
4
|
+
the local SQLite path (``coord.state``) and the networked daemon path
|
|
5
|
+
(``coord.dao`` / ``coord.serve_app`` serving the board, and ``coord.client``
|
|
6
|
+
reconstructing it from JSON) share **one** implementation — no Python-vs-Python
|
|
7
|
+
drift between the locally-built board and the daemon-served board.
|
|
8
|
+
|
|
9
|
+
The helpers are deliberately tolerant of two input shapes:
|
|
10
|
+
|
|
11
|
+
* a ``sqlite3.Row`` (or any dict-like) whose JSON columns are still raw strings
|
|
12
|
+
(the local SQLite path), and
|
|
13
|
+
* a plain ``dict`` decoded from the daemon's JSON ``/board`` payload, whose JSON
|
|
14
|
+
columns are already native lists/objects.
|
|
15
|
+
|
|
16
|
+
This is what lets ``row_to_assignment`` be reused verbatim on both sides.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
from typing import Any
|
|
23
|
+
|
|
24
|
+
from coord.models import WORK_LIKE_TYPES, Assignment, Board
|
|
25
|
+
|
|
26
|
+
_ACTIVE_STATUSES = ("running", "pending")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def json_loads(s: Any) -> Any:
|
|
30
|
+
"""Decode a JSON column.
|
|
31
|
+
|
|
32
|
+
Returns ``None`` for ``None``/malformed input. If *s* is already a decoded
|
|
33
|
+
value (not a string — e.g. a list/dict from the daemon's JSON payload) it is
|
|
34
|
+
returned unchanged.
|
|
35
|
+
"""
|
|
36
|
+
if s is None:
|
|
37
|
+
return None
|
|
38
|
+
if not isinstance(s, (str, bytes, bytearray)):
|
|
39
|
+
return s # already decoded (JSON API path)
|
|
40
|
+
try:
|
|
41
|
+
return json.loads(s)
|
|
42
|
+
except (json.JSONDecodeError, TypeError):
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def decode_smoke_tests(raw: object) -> list[str] | None:
|
|
47
|
+
"""#252: decode the ``smoke_tests`` column.
|
|
48
|
+
|
|
49
|
+
SQLite stores ``None`` (column missing / unset), ``"[]"`` (explicit "no
|
|
50
|
+
smoke tests — change internal") or ``'["item1", ...]'`` (bullets). Over the
|
|
51
|
+
daemon's JSON API the value arrives already decoded as a real list. Anything
|
|
52
|
+
malformed folds back to ``None`` so the TUI shows its graceful-degradation
|
|
53
|
+
placeholder instead of crashing.
|
|
54
|
+
"""
|
|
55
|
+
if raw is None:
|
|
56
|
+
return None
|
|
57
|
+
if isinstance(raw, list):
|
|
58
|
+
return [str(item) for item in raw] # already decoded (JSON API path)
|
|
59
|
+
if not raw:
|
|
60
|
+
return None
|
|
61
|
+
try:
|
|
62
|
+
value = json.loads(raw)
|
|
63
|
+
except (json.JSONDecodeError, TypeError):
|
|
64
|
+
return None
|
|
65
|
+
if not isinstance(value, list):
|
|
66
|
+
return None
|
|
67
|
+
return [str(item) for item in value]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def row_to_assignment(row: object) -> Assignment:
|
|
71
|
+
"""Convert a sqlite3.Row (or dict-like / decoded JSON dict) into an Assignment."""
|
|
72
|
+
d = dict(row)
|
|
73
|
+
return Assignment(
|
|
74
|
+
assignment_id=d.get("assignment_id"),
|
|
75
|
+
machine_name=d["machine_name"],
|
|
76
|
+
repo_name=d["repo_name"],
|
|
77
|
+
issue_number=d["issue_number"],
|
|
78
|
+
issue_title=d["issue_title"],
|
|
79
|
+
status=d.get("status", "running"),
|
|
80
|
+
type=d.get("type", "work"),
|
|
81
|
+
branch=d.get("branch"),
|
|
82
|
+
pr_url=d.get("pr_url"),
|
|
83
|
+
briefing=d.get("briefing") or "",
|
|
84
|
+
files_allowed=json_loads(d.get("files_allowed")) or [],
|
|
85
|
+
files_forbidden=json_loads(d.get("files_forbidden")) or [],
|
|
86
|
+
model=d.get("model"),
|
|
87
|
+
dispatched_at=d.get("dispatched_at"),
|
|
88
|
+
finished_at=d.get("finished_at"),
|
|
89
|
+
smoke_test=d.get("smoke_test"),
|
|
90
|
+
smoke_test_reason=d.get("smoke_test_reason"),
|
|
91
|
+
review_state=d.get("review_state"),
|
|
92
|
+
review_of_assignment_id=d.get("review_of_assignment_id"),
|
|
93
|
+
review_target=d.get("review_target"),
|
|
94
|
+
required_gates=json_loads(d.get("required_gates")) or [],
|
|
95
|
+
plan=json_loads(d.get("plan")),
|
|
96
|
+
unreachable_count=d.get("unreachable_count") or 0,
|
|
97
|
+
review_iteration=d.get("review_iteration") or 0,
|
|
98
|
+
review_posted_at=d.get("review_posted_at"),
|
|
99
|
+
test_state=d.get("test_state"),
|
|
100
|
+
test_reason=d.get("test_reason"),
|
|
101
|
+
# #1479: Test-gate staleness anchor; None for pre-1479 rows or where
|
|
102
|
+
# it couldn't be captured — the merge-queue gate treats that as "SHA
|
|
103
|
+
# tracking unavailable" and skips the staleness check (fail open).
|
|
104
|
+
test_head_sha=d.get("test_head_sha"),
|
|
105
|
+
test_patch_id=d.get("test_patch_id"),
|
|
106
|
+
test_base_sha=d.get("test_base_sha"),
|
|
107
|
+
# #1629: the toolchain that produced test_state; None for pre-1629
|
|
108
|
+
# rows or an unresolvable toolchain (renders as "unknown").
|
|
109
|
+
test_toolchain=d.get("test_toolchain"),
|
|
110
|
+
review_verdict=d.get("review_verdict"),
|
|
111
|
+
# #1456: coordinator-override audit trail; None when the reviewer's
|
|
112
|
+
# verdict stands (the normal case) and for pre-1456 rows.
|
|
113
|
+
review_verdict_original=d.get("review_verdict_original"),
|
|
114
|
+
review_verdict_override_reason=d.get("review_verdict_override_reason"),
|
|
115
|
+
# #821: commit-bound review gate; None for pre-821 rows.
|
|
116
|
+
review_head_sha=d.get("review_head_sha"),
|
|
117
|
+
# #1475: content-addressed patch-id alongside the SHA above; None
|
|
118
|
+
# for pre-1475 rows or where the patch-id couldn't be computed.
|
|
119
|
+
review_patch_id=d.get("review_patch_id"),
|
|
120
|
+
# #1476: scoped-re-review audit trail; False/None for rows predating
|
|
121
|
+
# this feature or ordinary (non-scoped) reviews.
|
|
122
|
+
review_scoped=bool(d.get("review_scoped") or False),
|
|
123
|
+
review_scope_base_sha=d.get("review_scope_base_sha"),
|
|
124
|
+
cost_usd=d.get("cost_usd"),
|
|
125
|
+
# #252: stored as JSON; absent column → None (not parsed yet).
|
|
126
|
+
smoke_tests=decode_smoke_tests(d.get("smoke_tests")),
|
|
127
|
+
# #324: resolved provider name; None for rows predating this feature.
|
|
128
|
+
provider_name=d.get("provider_name"),
|
|
129
|
+
# #546: token counts; absent column (pre-migration) or NULL → 0.
|
|
130
|
+
input_tokens=int(d.get("input_tokens") or 0),
|
|
131
|
+
output_tokens=int(d.get("output_tokens") or 0),
|
|
132
|
+
cache_creation_tokens=int(d.get("cache_creation_tokens") or 0),
|
|
133
|
+
cache_read_tokens=int(d.get("cache_read_tokens") or 0),
|
|
134
|
+
# #618: short launch-failure reason; None for successfully-launched rows.
|
|
135
|
+
failure_reason=d.get("failure_reason"),
|
|
136
|
+
# #944: Acceptance-gate verdict; None for rows predating the oracle loop
|
|
137
|
+
# or work that hasn't reached an `acceptance record` yet.
|
|
138
|
+
acceptance_state=d.get("acceptance_state"),
|
|
139
|
+
acceptance_reason=d.get("acceptance_reason"),
|
|
140
|
+
acceptance_sha=d.get("acceptance_sha"),
|
|
141
|
+
# #932: per-test counts; None for rows predating this column.
|
|
142
|
+
acceptance_total=d.get("acceptance_total"),
|
|
143
|
+
acceptance_passed=d.get("acceptance_passed"),
|
|
144
|
+
# #874: worker ### Summary prose; None when the worker emitted no block.
|
|
145
|
+
completion_summary=d.get("completion_summary"),
|
|
146
|
+
# #886 Phase 2: Milestone Outcome Audit structured verdict; None for
|
|
147
|
+
# non-audit assignments and for rows predating this feature.
|
|
148
|
+
audit_goals_json=d.get("audit_goals_json"),
|
|
149
|
+
audit_bottom_line=d.get("audit_bottom_line"),
|
|
150
|
+
audit_run_number=d.get("audit_run_number"),
|
|
151
|
+
# #1084: JIT test-author's per-member-issue correlation; None for
|
|
152
|
+
# Gate A / every other type and for rows predating this column.
|
|
153
|
+
for_issue_number=d.get("for_issue_number"),
|
|
154
|
+
# #1499: durable drive provenance; None for a hand `coord assign`
|
|
155
|
+
# and for rows predating this column.
|
|
156
|
+
driven_by=d.get("driven_by"),
|
|
157
|
+
# #1956: verdict provenance; None (→ treated as "agent") for every
|
|
158
|
+
# row predating this column and for a normally-parsed verdict.
|
|
159
|
+
verdict_source=d.get("verdict_source"),
|
|
160
|
+
verdict_source_reason=d.get("verdict_source_reason"),
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def assemble_board(
|
|
165
|
+
rows: list,
|
|
166
|
+
plans: dict[str, dict],
|
|
167
|
+
round_number: object,
|
|
168
|
+
) -> Board:
|
|
169
|
+
"""Build a :class:`Board` from assignment rows + a plan map (#749).
|
|
170
|
+
|
|
171
|
+
Storage-neutral core shared by ``coord.state._query_board`` (SQLite rows)
|
|
172
|
+
and ``coord.client.board_from_payload`` (daemon JSON rows) — the two used
|
|
173
|
+
to hand-roll the identical row→``Assignment``→active/completed bucketing
|
|
174
|
+
loop independently, which is exactly the "dual projection" duplication
|
|
175
|
+
#749 set out to collapse. Deliberately does NOT call
|
|
176
|
+
:func:`infer_review_state` — callers that need it (both of the above) run
|
|
177
|
+
it themselves against their own review rows, since the two paths fetch
|
|
178
|
+
those from different sources (a live cursor vs. the JSON payload).
|
|
179
|
+
"""
|
|
180
|
+
active: list[Assignment] = []
|
|
181
|
+
completed: list[Assignment] = []
|
|
182
|
+
for row in rows:
|
|
183
|
+
a = row_to_assignment(row)
|
|
184
|
+
if a.assignment_id and a.assignment_id in plans:
|
|
185
|
+
a.plan = plans[a.assignment_id]
|
|
186
|
+
(active if a.status in _ACTIVE_STATUSES else completed).append(a)
|
|
187
|
+
return Board(active=active, completed=completed, round_number=int(round_number or 0))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def infer_review_state(
|
|
191
|
+
board: Board,
|
|
192
|
+
review_rows: list,
|
|
193
|
+
notified_ids: set[str],
|
|
194
|
+
) -> None:
|
|
195
|
+
"""Set ``review_state`` on completed work-like assignments from their linked
|
|
196
|
+
reviews (#930: includes ``type="mock-author"`` — see
|
|
197
|
+
:data:`coord.models.WORK_LIKE_TYPES`).
|
|
198
|
+
|
|
199
|
+
Pure core of ``coord.state._infer_review_state``: takes the already-fetched
|
|
200
|
+
review rows (each a mapping with ``assignment_id`` /
|
|
201
|
+
``review_of_assignment_id`` / ``status``) and the set of notified assignment
|
|
202
|
+
ids, so it can run against either a live SQLite cursor's rows or rows
|
|
203
|
+
reconstructed from the daemon's JSON payload.
|
|
204
|
+
"""
|
|
205
|
+
review_status_for: dict[str, str] = {}
|
|
206
|
+
for row in review_rows:
|
|
207
|
+
review_status_for[row["review_of_assignment_id"]] = row["status"]
|
|
208
|
+
|
|
209
|
+
for a in board.completed:
|
|
210
|
+
if a.type not in WORK_LIKE_TYPES or a.assignment_id is None:
|
|
211
|
+
continue
|
|
212
|
+
if a.review_state is not None:
|
|
213
|
+
continue # explicitly set — don't override
|
|
214
|
+
review_aid = next(
|
|
215
|
+
(
|
|
216
|
+
r["assignment_id"]
|
|
217
|
+
for r in review_rows
|
|
218
|
+
if r["review_of_assignment_id"] == a.assignment_id
|
|
219
|
+
),
|
|
220
|
+
None,
|
|
221
|
+
)
|
|
222
|
+
if review_aid is None:
|
|
223
|
+
continue
|
|
224
|
+
if review_aid in notified_ids or review_status_for.get(
|
|
225
|
+
a.assignment_id, ""
|
|
226
|
+
) in ("done", "failed"):
|
|
227
|
+
a.review_state = "done"
|
|
228
|
+
else:
|
|
229
|
+
a.review_state = "dispatched"
|