Skip to content

Commit 76829ae

Browse files
Merge remote-tracking branch 'upstream/main' into dev
2 parents cb511a1 + 7426ede commit 76829ae

49 files changed

Lines changed: 22101 additions & 145 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.omx/cc2/board.json

Lines changed: 14886 additions & 0 deletions
Large diffs are not rendered by default.

.omx/cc2/board.md

Lines changed: 842 additions & 0 deletions
Large diffs are not rendered by default.

.omx/cc2/issue-parity-intake.json

Lines changed: 429 additions & 0 deletions
Large diffs are not rendered by default.

.omx/cc2/issue-parity-intake.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# CC2 Issue / Parity Intake Mapping
2+
3+
Generated by `worker-2` for team task 3 (`G001 issue/parity intake mapping`). This is a board-integration fragment for Stream 0; it intentionally does **not** mutate `.omx/ultragoal`.
4+
5+
## Covered local issue clusters
6+
7+
| Issue | Theme | Bucket | Lifecycle | Board anchor |
8+
|---:|---|---|---|---|
9+
| #3007 | security/path-scope | `alpha_blocker` | `active` | Policy engine + green-ness contract |
10+
| #3020 | provider/model-routing | `beta_adoption` | `open` | Provider routing/model source status |
11+
| #3006 | windows/install | `beta_adoption` | `open` | Immediate backlog / install readiness |
12+
| #3005 | provider/response-shape | `beta_adoption` | `open` | Failure taxonomy / provider diagnostics |
13+
| #3004 | ide/acp | `ga_ecosystem` | `deferred_with_rationale` | Plugin/MCP lifecycle maturity |
14+
| #3003 | session-hygiene/gitignore | `beta_adoption` | `open` | Green-ness / recovery hygiene |
15+
| #2997 | docs/license | `beta_adoption` | `open` | Adoption docs/license readiness |
16+
| #3023 | repo-hygiene/anti-slop | `beta_adoption` | `open` | Immediate backlog / PR quality gate |
17+
| #3028 | docs/navigation-context | `beta_adoption` | `open` | Human UX leaks into claw workflows |
18+
| #3029 | install/distribution | `beta_adoption` | `open` | Cross-platform release quickstart |
19+
| #3030 | provider/setup-profiles | `beta_adoption` | `open` | Boot preflight / structured session control |
20+
| #3031 | session-recovery/context-window | `beta_adoption` | `open` | Recovery recipes / compaction event |
21+
| #3032 | provider/diagnostics-docs | `beta_adoption` | `open` | Failure taxonomy |
22+
| #3033 | engine-api/control-plane | `ga_ecosystem` | `deferred_with_rationale` | Structured session control API |
23+
| #3034 | sdlc/evidence-handoff | `post_2_0_research` | `deferred_with_rationale` | Event/report/task contract input |
24+
| #3035 | session-resume/discoverability | `beta_adoption` | `open` | Recovery recipes / session enumeration |
25+
| #3036 | provider/local-docs | `beta_adoption` | `open` | Provider setup and diagnostics docs |
26+
| #3037 | docs/product-positioning | `beta_adoption` | `open` | Goal / definition of clawable |
27+
| #3038 | plugin-marketplace/ecosystem | `ga_ecosystem` | `deferred_with_rationale` | Plugin/MCP lifecycle maturity |
28+
29+
## Parity intake rows
30+
31+
| Row | Source | Bucket | Lifecycle | Adaptation rule |
32+
|---|---|---|---|---|
33+
| `CC2-PARITY-OPENCODE-PLUGIN-ECOSYSTEM` | opencode repo + #3038 | `ga_ecosystem` | `deferred_with_rationale` | Inventory Claw extension points before marketplace work. |
34+
| `CC2-PARITY-OPENCODE-PERMISSION-PRESETS` | opencode #27464 | `beta_adoption` | `open` | Permission preset UX must not bypass Claw path-scope policy. |
35+
| `CC2-PARITY-OPENCODE-CUSTOM-PROVIDER-PARAMS` | opencode #27462 + #3030/#3032 | `beta_adoption` | `open` | Custom provider params need schema validation, redaction, and provenance. |
36+
| `CC2-PARITY-OPENCODE-TODOWRITE-AUTOCOMPLETE` | opencode #27453 | `ga_ecosystem` | `deferred_with_rationale` | Auto-complete task UX follows typed task lifecycle/evidence gates. |
37+
| `CC2-PARITY-OPENCODE-WINDOWS-DISTRIBUTION` | opencode #27476/#27459/#27470 + #3006/#3029 | `beta_adoption` | `open` | Use external pain as release-matrix and diagnostics evidence. |
38+
| `CC2-PARITY-CODEX-GRANULAR-PERMISSIONS` | Codex #22595 + docs | `alpha_blocker` | `active` | Adapt granular permissions only through Claw policy engine and approval tokens. |
39+
| `CC2-PARITY-CODEX-SESSION-RECOVERY` | Codex #22619/#22597/#22593 + #3035 | `beta_adoption` | `open` | Session discovery/recovery must avoid storage amplification. |
40+
| `CC2-PARITY-CODEX-PROXY-NETWORK` | Codex #22623 + #3032 | `beta_adoption` | `open` | Provider diagnostics should expose proxy behavior. |
41+
| `CC2-PARITY-CODEX-CLI-AGENT-FLAG` | Codex #22615 | `ga_ecosystem` | `deferred_with_rationale` | CLI agent mode waits for typed task/session control contracts. |
42+
43+
Validation command:
44+
45+
```bash
46+
python3 .omx/cc2/validate_issue_parity_intake.py
47+
```

.omx/cc2/render_board_md.py

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
#!/usr/bin/env python3
2+
"""Render the Claw Code 2.0 canonical board JSON as a human-readable Markdown board."""
3+
from __future__ import annotations
4+
5+
import argparse
6+
import json
7+
import sys
8+
from collections import Counter, defaultdict
9+
from pathlib import Path
10+
from typing import Any
11+
12+
STATUS_DESCRIPTIONS = {
13+
"context": "Context-only heading or evidence anchor; not an implementation work item.",
14+
"active": "Current Claw Code 2.0 implementation surface that should remain visible on the board.",
15+
"open": "Actionable unresolved work that needs implementation or acceptance evidence.",
16+
"done_verify": "Marked as done upstream but retained for verification against current CC2 behavior.",
17+
"stale_done": "Historically completed or merged work that may be stale and needs freshness checks before relying on it.",
18+
"superseded": "Replaced by a newer item; keep as traceability context only.",
19+
"deferred_with_rationale": "Intentionally deferred; rationale must be present in the board item.",
20+
"rejected_not_claw": "Excluded because it is not Claw Code product work.",
21+
}
22+
23+
BUCKET_DESCRIPTIONS = {
24+
"alpha_blocker": "Must be resolved before alpha-quality autonomous coding lanes are dependable.",
25+
"beta_adoption": "Important for broader dogfood/adoption once alpha blockers are controlled.",
26+
"ga_ecosystem": "Required for mature plugin/MCP/provider ecosystem behavior.",
27+
"2.x_intake": "Post-2.0 intake or follow-up candidate retained for sequencing.",
28+
"post_2_0_research": "Research-oriented item not required for the CC2 board cut.",
29+
"context": "Non-actionable roadmap context.",
30+
"rejected_not_claw": "Explicit non-Claw rejection bucket.",
31+
}
32+
33+
LANE_TITLES = {
34+
"stream_0_governance": "Stream 0 — Governance, intake, and cross-cutting roadmap triage",
35+
"stream_1_worker_boot_session_control": "Stream 1 — Worker boot and session control",
36+
"stream_2_event_reporting_contracts": "Stream 2 — Event/reporting contracts",
37+
"stream_3_branch_test_recovery": "Stream 3 — Branch/test recovery",
38+
"stream_4_claws_first_execution": "Stream 4 — Claws-first task execution",
39+
"stream_5_plugin_mcp_lifecycle": "Stream 5 — Plugin/MCP lifecycle",
40+
"adoption_overlay": "Adoption overlay — user-visible parity and release polish",
41+
"parity_overlay": "Parity overlay — opencode/codex comparison context",
42+
}
43+
44+
REQUIRED_ITEM_FIELDS = [
45+
"id",
46+
"title",
47+
"source_anchor",
48+
"source_type",
49+
"release_bucket",
50+
"lifecycle_status",
51+
"dependencies",
52+
"verification_required",
53+
"deferral_rationale",
54+
]
55+
56+
57+
def load_board(path: Path) -> dict[str, Any]:
58+
with path.open() as f:
59+
board = json.load(f)
60+
if not isinstance(board, dict):
61+
raise ValueError("board JSON root must be an object")
62+
items = board.get("items")
63+
if not isinstance(items, list):
64+
raise ValueError("board JSON must contain an items array")
65+
return board
66+
67+
68+
def validate_board(board: dict[str, Any]) -> list[str]:
69+
errors: list[str] = []
70+
coverage = board.get("coverage", {})
71+
if coverage.get("unmapped_roadmap_heading_lines"):
72+
errors.append(f"unmapped roadmap heading lines: {coverage['unmapped_roadmap_heading_lines']}")
73+
if coverage.get("roadmap_headings_mapped") != coverage.get("roadmap_headings_total"):
74+
errors.append("roadmap heading coverage is incomplete")
75+
if coverage.get("roadmap_actions_mapped") != coverage.get("roadmap_actions_total"):
76+
errors.append("roadmap ordered-action coverage is incomplete")
77+
78+
allowed_status = set(board.get("generation_policy", {}).get("status_values", []))
79+
allowed_buckets = set(board.get("generation_policy", {}).get("release_buckets", []))
80+
seen_ids: set[str] = set()
81+
for index, item in enumerate(board["items"], 1):
82+
for field in REQUIRED_ITEM_FIELDS:
83+
if field not in item:
84+
errors.append(f"item {index} missing required field {field}")
85+
item_id = item.get("id")
86+
if item_id in seen_ids:
87+
errors.append(f"duplicate item id {item_id}")
88+
seen_ids.add(item_id)
89+
status = item.get("lifecycle_status")
90+
bucket = item.get("release_bucket")
91+
if allowed_status and status not in allowed_status:
92+
errors.append(f"{item_id} has unknown lifecycle_status {status!r}")
93+
if allowed_buckets and bucket not in allowed_buckets:
94+
errors.append(f"{item_id} has unknown release_bucket {bucket!r}")
95+
if status == "deferred_with_rationale" and not str(item.get("deferral_rationale", "")).strip():
96+
errors.append(f"{item_id} is deferred without deferral_rationale")
97+
return errors
98+
99+
100+
def table(headers: list[str], rows: list[list[Any]]) -> list[str]:
101+
out = ["| " + " | ".join(headers) + " |", "| " + " | ".join("---" for _ in headers) + " |"]
102+
for row in rows:
103+
out.append("| " + " | ".join(str(cell) for cell in row) + " |")
104+
return out
105+
106+
107+
def fmt_list(value: Any) -> str:
108+
if not value:
109+
return "none"
110+
if isinstance(value, list):
111+
return ", ".join(f"`{v}`" for v in value) if value else "none"
112+
return f"`{value}`"
113+
114+
115+
def render(board: dict[str, Any]) -> str:
116+
items: list[dict[str, Any]] = board["items"]
117+
summary = board.get("summary", {})
118+
coverage = board.get("coverage", {})
119+
sources = board.get("sources", {})
120+
policy = board.get("generation_policy", {})
121+
by_lane = Counter(item.get("owner_lane", "unassigned") for item in items)
122+
by_status = Counter(item.get("lifecycle_status", "unknown") for item in items)
123+
by_bucket = Counter(item.get("release_bucket", "unknown") for item in items)
124+
by_source = Counter(item.get("source_type", "unknown") for item in items)
125+
126+
lines: list[str] = []
127+
lines.append("# Claw Code 2.0 Canonical Board")
128+
lines.append("")
129+
lines.append(f"Generated from board schema: `{board.get('generated_at', 'unknown')}`")
130+
lines.append(f"Schema version: `{board.get('schema_version', 'unknown')}`")
131+
lines.append("Ultragoal mutation policy: `.omx/ultragoal` is leader-owned and was not modified by this rendering task.")
132+
lines.append("")
133+
134+
lines.append("## Evidence Freeze")
135+
lines.append("")
136+
roadmap = sources.get("roadmap", {})
137+
research = sources.get("research", {})
138+
plan = sources.get("approved_plan", {})
139+
lines.extend(table(["Source", "Frozen evidence"], [
140+
["Roadmap", f"`{roadmap.get('path', 'ROADMAP.md')}` sha256 prefix `{roadmap.get('sha256_prefix', 'unknown')}`; {roadmap.get('heading_count', '?')} headings; {roadmap.get('ordered_action_count', '?')} ordered actions"],
141+
["Approved plan", f"`{plan.get('path', '.omx/plans/claw-code-2-0-adaptive-plan.md')}` sha256 prefix `{plan.get('sha256_prefix', 'unknown')}`"],
142+
["Research bundle", f"root `{research.get('root', '.omx/research')}`; latest open issues {research.get('claw_open_latest_count', '?')}; issue corpus {research.get('claw_issues_count', '?')}; codex/opencode clone metadata included"],
143+
]))
144+
lines.append("")
145+
146+
lines.append("## Roadmap Coverage Summary")
147+
lines.append("")
148+
heading_total = coverage.get("roadmap_headings_total", 0)
149+
heading_mapped = coverage.get("roadmap_headings_mapped", 0)
150+
action_total = coverage.get("roadmap_actions_total", 0)
151+
action_mapped = coverage.get("roadmap_actions_mapped", 0)
152+
lines.extend(table(["Coverage gate", "Mapped", "Total", "Status"], [
153+
["ROADMAP headings", heading_mapped, heading_total, "PASS" if heading_mapped == heading_total and not coverage.get("unmapped_roadmap_heading_lines") else "FAIL"],
154+
["ROADMAP ordered actions", action_mapped, action_total, "PASS" if action_mapped == action_total else "FAIL"],
155+
["Duplicate heading lines", len(coverage.get("duplicate_roadmap_heading_lines", [])), 0, "PASS" if not coverage.get("duplicate_roadmap_heading_lines") else "WARN"],
156+
]))
157+
lines.append("")
158+
lines.append(f"Total canonical board items: **{len(items)}**")
159+
lines.append("")
160+
161+
lines.append("## Lifecycle Enum Reference")
162+
lines.append("")
163+
status_rows = []
164+
for status in policy.get("status_values", sorted(by_status)):
165+
status_rows.append([f"`{status}`", by_status.get(status, 0), STATUS_DESCRIPTIONS.get(status, "Board-defined lifecycle status.")])
166+
lines.extend(table(["Lifecycle", "Count", "Meaning"], status_rows))
167+
lines.append("")
168+
169+
lines.append("## Release Bucket Reference")
170+
lines.append("")
171+
bucket_rows = []
172+
for bucket in policy.get("release_buckets", sorted(by_bucket)):
173+
bucket_rows.append([f"`{bucket}`", by_bucket.get(bucket, 0), BUCKET_DESCRIPTIONS.get(bucket, "Board-defined release bucket.")])
174+
lines.extend(table(["Bucket", "Count", "Meaning"], bucket_rows))
175+
lines.append("")
176+
177+
lines.append("## Stream Summaries")
178+
lines.append("")
179+
lane_rows = []
180+
for lane, count in sorted(by_lane.items()):
181+
lane_items = [item for item in items if item.get("owner_lane") == lane]
182+
lane_status = Counter(item.get("lifecycle_status") for item in lane_items)
183+
open_like = lane_status.get("active", 0) + lane_status.get("open", 0) + lane_status.get("done_verify", 0)
184+
lane_rows.append([
185+
LANE_TITLES.get(lane, lane),
186+
count,
187+
open_like,
188+
", ".join(f"`{k}` {v}" for k, v in sorted(lane_status.items())),
189+
])
190+
lines.extend(table(["Stream / lane", "Items", "Active+open+verify", "Lifecycle mix"], lane_rows))
191+
lines.append("")
192+
193+
lines.append("## Source-Type Mix")
194+
lines.append("")
195+
lines.extend(table(["Source type", "Items"], [[f"`{k}`", v] for k, v in sorted(by_source.items())]))
196+
lines.append("")
197+
198+
lines.append("## Board Items by Stream")
199+
lines.append("")
200+
for lane in sorted(by_lane):
201+
lane_items = [item for item in items if item.get("owner_lane") == lane]
202+
lines.append(f"### {LANE_TITLES.get(lane, lane)}")
203+
lines.append("")
204+
lines.extend(table(
205+
["ID", "Title", "Source", "Bucket", "Lifecycle", "Verification", "Dependencies", "Deferral"],
206+
[[
207+
f"`{item.get('id')}`",
208+
str(item.get("title", "")).replace("|", "\\|"),
209+
f"`{item.get('source_anchor')}` / `{item.get('source_type')}`",
210+
f"`{item.get('release_bucket')}`",
211+
f"`{item.get('lifecycle_status')}`",
212+
f"`{item.get('verification_required')}`",
213+
fmt_list(item.get("dependencies")),
214+
str(item.get("deferral_rationale") or "—").replace("|", "\\|"),
215+
] for item in lane_items]
216+
))
217+
lines.append("")
218+
219+
return "\n".join(lines).rstrip() + "\n"
220+
221+
222+
def main() -> int:
223+
parser = argparse.ArgumentParser(description=__doc__)
224+
parser.add_argument("board_json", type=Path)
225+
parser.add_argument("board_md", type=Path)
226+
parser.add_argument("--check", action="store_true", help="fail if board_md is not up to date")
227+
args = parser.parse_args()
228+
229+
board = load_board(args.board_json)
230+
errors = validate_board(board)
231+
if errors:
232+
for error in errors:
233+
print(f"ERROR: {error}", file=sys.stderr)
234+
return 1
235+
rendered = render(board)
236+
if args.check:
237+
existing = args.board_md.read_text() if args.board_md.exists() else ""
238+
if existing != rendered:
239+
print(f"ERROR: {args.board_md} is not up to date", file=sys.stderr)
240+
return 1
241+
print(f"PASS: {args.board_md} is up to date and roadmap coverage is complete")
242+
return 0
243+
args.board_md.parent.mkdir(parents=True, exist_ok=True)
244+
args.board_md.write_text(rendered)
245+
print(f"wrote {args.board_md}")
246+
return 0
247+
248+
249+
if __name__ == "__main__":
250+
raise SystemExit(main())
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env python3
2+
"""Validate the worker-2 CC2 issue/parity intake fragment."""
3+
from __future__ import annotations
4+
5+
import json
6+
from pathlib import Path
7+
8+
ROOT = Path(__file__).resolve().parents[2]
9+
INTAKE = ROOT / ".omx" / "cc2" / "issue-parity-intake.json"
10+
REQUIRED_ISSUES = set(range(3028, 3039)) | {3007, 3006, 3020, 3005, 3003, 2997, 3023, 3004}
11+
ALLOWED_STATUS = {
12+
"context",
13+
"active",
14+
"open",
15+
"done_verify",
16+
"stale_done",
17+
"superseded",
18+
"deferred_with_rationale",
19+
"rejected_not_claw",
20+
}
21+
ALLOWED_BUCKETS = {"alpha_blocker", "beta_adoption", "ga_ecosystem", "post_2_0_research"}
22+
23+
24+
def require(condition: bool, message: str) -> None:
25+
if not condition:
26+
raise SystemExit(f"FAIL: {message}")
27+
28+
29+
def main() -> None:
30+
data = json.loads(INTAKE.read_text())
31+
issue_rows = data.get("issue_clusters", [])
32+
parity_rows = data.get("parity_rows", [])
33+
34+
seen = {row.get("source_number") for row in issue_rows}
35+
missing = sorted(REQUIRED_ISSUES - seen)
36+
extra = sorted(seen - REQUIRED_ISSUES)
37+
require(not missing, f"missing required issue rows: {missing}")
38+
require(not extra, f"unexpected issue rows in scoped intake: {extra}")
39+
require(len(issue_rows) == len(REQUIRED_ISSUES), "duplicate or missing issue row count")
40+
41+
ids = [row.get("id") for row in issue_rows + parity_rows]
42+
require(len(ids) == len(set(ids)), "duplicate ids present")
43+
44+
for row in issue_rows + parity_rows:
45+
row_id = row.get("id")
46+
for field in ["source_anchor", "source_type", "release_bucket", "lifecycle_status", "dependencies", "verification_required"]:
47+
require(row.get(field) not in (None, "", []), f"{row_id} missing {field}")
48+
require(row["release_bucket"] in ALLOWED_BUCKETS, f"{row_id} invalid release_bucket {row['release_bucket']}")
49+
require(row["lifecycle_status"] in ALLOWED_STATUS, f"{row_id} invalid lifecycle_status {row['lifecycle_status']}")
50+
if row["lifecycle_status"] == "deferred_with_rationale":
51+
require(row.get("deferral_rationale"), f"{row_id} deferred without rationale")
52+
53+
require(len(parity_rows) >= data["coverage"]["parity_rows_expected_minimum"], "not enough parity rows")
54+
print(f"PASS issue/parity intake: {len(issue_rows)} issue rows, {len(parity_rows)} parity rows")
55+
56+
57+
if __name__ == "__main__":
58+
main()
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"session_id": "b035f648d5b549aa836ea01f6727ec62",
3+
"messages": [
4+
"review MCP tool"
5+
],
6+
"input_tokens": 3,
7+
"output_tokens": 13
8+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"session_id": "b234acb1eb8c486e80544ddc7e13e6d8",
3+
"messages": [
4+
"review MCP tool",
5+
"review MCP tool"
6+
],
7+
"input_tokens": 6,
8+
"output_tokens": 32
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"session_id": "b67e062748f04e10ac5770df9285e4bd",
3+
"messages": [
4+
"review MCP tool",
5+
"review MCP tool"
6+
],
7+
"input_tokens": 6,
8+
"output_tokens": 32
9+
}

0 commit comments

Comments
 (0)