seed_local_proposals.py
python
sha256:94ef169c149a452bff7c604ded8b280b19bd477c2dabcb56972780b0b784c7aa
Merge 'fix/assignee-sigil-inline' into 'dev' — proposal: As…
Human
1 day ago
| 1 | """Seed local proposals with varied risk, type, state, merge conditions, and commits. |
| 2 | |
| 3 | Run once to populate the GUI with representative test fixtures: |
| 4 | |
| 5 | python3 scripts/seed_local_proposals.py |
| 6 | |
| 7 | Connects directly to the local Postgres instance on port 5434. |
| 8 | """ |
| 9 | from __future__ import annotations |
| 10 | |
| 11 | import hashlib |
| 12 | import json |
| 13 | import sys |
| 14 | from datetime import datetime, timedelta, timezone |
| 15 | |
| 16 | import psycopg2 |
| 17 | |
| 18 | DSN = "host=localhost port=5434 dbname=musehub user=musehub password=musehub" |
| 19 | |
| 20 | REPO_ID = "sha256:05e85038d2e0a48f33d9f0f9ad8802c8857e36d6a4bc72c7c97fec83207b8102" |
| 21 | |
| 22 | # ── Proposals ──────────────────────────────────────────────────────────────── |
| 23 | # merge_conditions spread across all 9 condition types; mix of pass/fail/unknown |
| 24 | PROPOSALS = [ |
| 25 | { |
| 26 | "proposal_id": "sha256:89cde8275f5e4b6248765f3e9c2a51cc0edefa6f54bed34771ac9f5c5de8a798", |
| 27 | "number": 1, |
| 28 | "title": "Cryptographic identity layer: Ed25519 key rotation, MSign auth v2, and SLIP-0010 HD derivation", |
| 29 | "proposal_type": "identity_transition", |
| 30 | "merge_strategy": "overlay", |
| 31 | "state": "open", |
| 32 | "from_branch": "feat/identity-v2", |
| 33 | "risk_score": 0.82, |
| 34 | "dimensional_risk": {"code": 0.82}, |
| 35 | "breakage_count": 3, |
| 36 | "test_gap_count": 7, |
| 37 | # Exercises: require_approvals (fail), max_risk_score (fail), |
| 38 | # require_no_breakage (fail), require_test_coverage (fail), |
| 39 | # require_signed_commits (fail — one unsigned commit), |
| 40 | # require_domains_approved (fail — missing identity domain), |
| 41 | # require_payment_settled (unknown) |
| 42 | "merge_conditions": { |
| 43 | "require_approvals": 2, |
| 44 | "max_risk_score": 0.7, |
| 45 | "require_signed_commits": True, |
| 46 | "require_no_breakage": True, |
| 47 | "require_test_coverage": True, |
| 48 | "require_domains_approved": ["code", "identity"], |
| 49 | "require_payment_settled": True, |
| 50 | }, |
| 51 | }, |
| 52 | { |
| 53 | "proposal_id": "sha256:d3642e390bfe558a23c04eda37a1d08964c63f49965e58b8b76e93c0301f23b2", |
| 54 | "number": 2, |
| 55 | "title": "Proposal type badges, 7-state lifecycle tabs, row redesign, and ghost object integrity fix", |
| 56 | "proposal_type": "state_merge", |
| 57 | "merge_strategy": "overlay", |
| 58 | "state": "in_review", |
| 59 | "from_branch": "task/proposal-models-v2", |
| 60 | "risk_score": 0.45, |
| 61 | "dimensional_risk": {"code": 0.45}, |
| 62 | "breakage_count": 0, |
| 63 | "test_gap_count": 4, |
| 64 | # Exercises: require_approvals (pass — 1 of 1), |
| 65 | # max_risk_score (pass — 0.45 ≤ 0.5), |
| 66 | # require_test_coverage (fail — gap=4), |
| 67 | # require_dependency_merged (fail — blocked by #1), |
| 68 | # max_agent_commit_ratio (pass — 1 of 4 = 25% ≤ 50%) |
| 69 | "merge_conditions": { |
| 70 | "require_approvals": 1, |
| 71 | "max_risk_score": 0.5, |
| 72 | "require_test_coverage": True, |
| 73 | "require_dependency_merged": True, |
| 74 | "max_agent_commit_ratio": 0.5, |
| 75 | }, |
| 76 | }, |
| 77 | { |
| 78 | "proposal_id": "sha256:71957a1fa4631f58e7b9259272bc80da8ec26e3b364e372bd5f1b2f1dfe8fe26", |
| 79 | "number": 3, |
| 80 | "title": "Increase push stream timeout to prevent drops on large repos with deep commit history", |
| 81 | "proposal_type": "canonical_release", |
| 82 | "merge_strategy": "replay", |
| 83 | "state": "approved", |
| 84 | "from_branch": "fix/push-timeout", |
| 85 | "risk_score": 0.18, |
| 86 | "dimensional_risk": {"code": 0.18}, |
| 87 | "breakage_count": 0, |
| 88 | "test_gap_count": 0, |
| 89 | # Exercises: require_approvals (pass — 2 of 2), |
| 90 | # max_risk_score (pass — 0.18 ≤ 0.3), |
| 91 | # require_no_breakage (pass), |
| 92 | # require_test_coverage (pass), |
| 93 | # require_dependency_merged (fail — still blocked by #2), |
| 94 | # max_agent_commit_ratio (pass — 3 of 5 = 60% ≤ 0.8) |
| 95 | "merge_conditions": { |
| 96 | "require_approvals": 2, |
| 97 | "max_risk_score": 0.3, |
| 98 | "require_no_breakage": True, |
| 99 | "require_test_coverage": True, |
| 100 | "require_dependency_merged": True, |
| 101 | "max_agent_commit_ratio": 0.8, |
| 102 | }, |
| 103 | }, |
| 104 | ] |
| 105 | |
| 106 | # Dependency edges: #2 blocked by #1, #3 blocked by #2 |
| 107 | DEPS = [ |
| 108 | (PROPOSALS[1]["proposal_id"], PROPOSALS[0]["proposal_id"]), |
| 109 | (PROPOSALS[2]["proposal_id"], PROPOSALS[1]["proposal_id"]), |
| 110 | ] |
| 111 | |
| 112 | # ── Commits to seed per proposal branch ────────────────────────────────────── |
| 113 | # Gives the gate real data for require_signed_commits and max_agent_commit_ratio. |
| 114 | def _commit_id(branch: str, n: int) -> str: |
| 115 | raw = f"{branch}:{n}".encode() |
| 116 | return "sha256:" + hashlib.sha256(raw).hexdigest() |
| 117 | |
| 118 | def _snap_id(branch: str, n: int) -> str: |
| 119 | raw = f"snap:{branch}:{n}".encode() |
| 120 | return "sha256:" + hashlib.sha256(raw).hexdigest() |
| 121 | |
| 122 | COMMITS: list[dict] = [] |
| 123 | now = datetime.now(tz=timezone.utc) |
| 124 | |
| 125 | # Proposal #1 — feat/identity-v2: 3 signed human + 1 unsigned human + 1 agent |
| 126 | for i, (signed, agent_id, model_id, msg) in enumerate([ |
| 127 | (True, "", "", "feat: add Ed25519 keygen"), |
| 128 | (True, "", "", "feat: SLIP-0010 HD derivation"), |
| 129 | (False, "", "", "wip: key rotation draft"), # unsigned → gate fails |
| 130 | (True, "claude-code", "claude-sonnet-4-6", "feat: MSign auth v2"), |
| 131 | (True, "", "", "test: identity key round-trip"), |
| 132 | ]): |
| 133 | COMMITS.append({ |
| 134 | "commit_id": _commit_id("feat/identity-v2", i), |
| 135 | "repo_id": REPO_ID, |
| 136 | "branch": "feat/identity-v2", |
| 137 | "message": msg, |
| 138 | "author": "gabriel", |
| 139 | "timestamp": now - timedelta(hours=10 - i), |
| 140 | "snapshot_id": _snap_id("feat/identity-v2", i), |
| 141 | "agent_id": agent_id, |
| 142 | "model_id": model_id, |
| 143 | "signature": "ed25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=" if signed else "", |
| 144 | }) |
| 145 | |
| 146 | # Proposal #2 — task/proposal-models-v2: 3 human signed + 1 agent signed |
| 147 | for i, (agent_id, model_id, msg) in enumerate([ |
| 148 | ("", "", "feat: proposal type badges"), |
| 149 | ("", "", "feat: 7-state lifecycle tabs"), |
| 150 | ("", "", "fix: ghost object integrity"), |
| 151 | ("claude-code", "claude-sonnet-4-6", "feat: row redesign"), |
| 152 | ]): |
| 153 | COMMITS.append({ |
| 154 | "commit_id": _commit_id("task/proposal-models-v2", i), |
| 155 | "repo_id": REPO_ID, |
| 156 | "branch": "task/proposal-models-v2", |
| 157 | "message": msg, |
| 158 | "author": "gabriel" if not agent_id else "claude-code", |
| 159 | "timestamp": now - timedelta(hours=6 - i), |
| 160 | "snapshot_id": _snap_id("task/proposal-models-v2", i), |
| 161 | "agent_id": agent_id, |
| 162 | "model_id": model_id, |
| 163 | "signature": "ed25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", |
| 164 | }) |
| 165 | |
| 166 | # Proposal #3 — fix/push-timeout: 2 human signed + 3 agent signed (60% agent ≤ 80%) |
| 167 | for i, (agent_id, model_id, msg) in enumerate([ |
| 168 | ("", "", "fix: increase push stream timeout"), |
| 169 | ("", "", "test: large-repo push timeout regression"), |
| 170 | ("claude-code", "claude-sonnet-4-6", "feat: configurable timeout per remote"), |
| 171 | ("claude-code", "claude-sonnet-4-6", "refactor: extract timeout config"), |
| 172 | ("claude-code", "claude-sonnet-4-6", "docs: push timeout configuration"), |
| 173 | ]): |
| 174 | COMMITS.append({ |
| 175 | "commit_id": _commit_id("fix/push-timeout", i), |
| 176 | "repo_id": REPO_ID, |
| 177 | "branch": "fix/push-timeout", |
| 178 | "message": msg, |
| 179 | "author": "gabriel" if not agent_id else "claude-code", |
| 180 | "timestamp": now - timedelta(hours=3 - i * 0.5), |
| 181 | "snapshot_id": _snap_id("fix/push-timeout", i), |
| 182 | "agent_id": agent_id, |
| 183 | "model_id": model_id, |
| 184 | "signature": "ed25519:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", |
| 185 | }) |
| 186 | |
| 187 | |
| 188 | def _dep_id(dependent: str, dependency: str) -> str: |
| 189 | raw = (dependent + dependency).encode() |
| 190 | return "sha256:" + hashlib.sha256(raw).hexdigest() |
| 191 | |
| 192 | |
| 193 | def main() -> None: |
| 194 | conn = psycopg2.connect(DSN) |
| 195 | conn.autocommit = False |
| 196 | cur = conn.cursor() |
| 197 | |
| 198 | # ── Update proposals ───────────────────────────────────────────────────── |
| 199 | for p in PROPOSALS: |
| 200 | cur.execute( |
| 201 | """ |
| 202 | UPDATE musehub_proposals |
| 203 | SET title = %s, |
| 204 | proposal_type = %s, |
| 205 | merge_strategy = %s, |
| 206 | state = %s, |
| 207 | from_branch = %s, |
| 208 | risk_score = %s, |
| 209 | dimensional_risk = %s, |
| 210 | breakage_count = %s, |
| 211 | test_gap_count = %s, |
| 212 | merge_conditions = %s, |
| 213 | updated_at = %s |
| 214 | WHERE proposal_id = %s |
| 215 | """, |
| 216 | ( |
| 217 | p["title"], |
| 218 | p["proposal_type"], |
| 219 | p["merge_strategy"], |
| 220 | p["state"], |
| 221 | p["from_branch"], |
| 222 | p["risk_score"], |
| 223 | json.dumps(p["dimensional_risk"]), |
| 224 | p["breakage_count"], |
| 225 | p["test_gap_count"], |
| 226 | json.dumps(p["merge_conditions"]), |
| 227 | datetime.now(tz=timezone.utc), |
| 228 | p["proposal_id"], |
| 229 | ), |
| 230 | ) |
| 231 | rows = cur.rowcount |
| 232 | conditions_list = ", ".join(p["merge_conditions"].keys()) |
| 233 | print(f" proposal #{p['number']}: {rows} row(s) → {p['state']} / risk={p['risk_score']} / conditions=[{conditions_list}]") |
| 234 | |
| 235 | # ── Upsert commits ─────────────────────────────────────────────────────── |
| 236 | for c in COMMITS: |
| 237 | cur.execute( |
| 238 | """ |
| 239 | INSERT INTO musehub_commits |
| 240 | (commit_id, repo_id, branch, parent_ids, message, author, timestamp, |
| 241 | snapshot_id, agent_id, model_id, signature, created_at) |
| 242 | VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) |
| 243 | ON CONFLICT (commit_id) DO UPDATE |
| 244 | SET agent_id = EXCLUDED.agent_id, |
| 245 | model_id = EXCLUDED.model_id, |
| 246 | signature = EXCLUDED.signature, |
| 247 | message = EXCLUDED.message |
| 248 | """, |
| 249 | ( |
| 250 | c["commit_id"], c["repo_id"], c["branch"], [], |
| 251 | c["message"], c["author"], c["timestamp"], |
| 252 | c["snapshot_id"], c["agent_id"], c["model_id"], |
| 253 | c["signature"], now, |
| 254 | ), |
| 255 | ) |
| 256 | print(f" commits: {len(COMMITS)} upserted") |
| 257 | |
| 258 | # ── Insert dependency edges ─────────────────────────────────────────────── |
| 259 | seed_now = datetime.now(tz=timezone.utc) |
| 260 | for dependent_id, dependency_id in DEPS: |
| 261 | dep_id = _dep_id(dependent_id, dependency_id) |
| 262 | cur.execute( |
| 263 | """ |
| 264 | INSERT INTO musehub_proposal_dependencies |
| 265 | (dep_id, dependent_proposal_id, dependency_proposal_id, created_at) |
| 266 | VALUES (%s, %s, %s, %s) |
| 267 | ON CONFLICT (dependent_proposal_id, dependency_proposal_id) DO NOTHING |
| 268 | """, |
| 269 | (dep_id, dependent_id, dependency_id, seed_now), |
| 270 | ) |
| 271 | dep_num = next(p["number"] for p in PROPOSALS if p["proposal_id"] == dependent_id) |
| 272 | dep_on_num = next(p["number"] for p in PROPOSALS if p["proposal_id"] == dependency_id) |
| 273 | print(f" dependency: #{dep_num} blocked by #{dep_on_num}") |
| 274 | |
| 275 | conn.commit() |
| 276 | cur.close() |
| 277 | conn.close() |
| 278 | print("\nDone. Refresh https://localhost:1337/gabriel/musehub/proposals") |
| 279 | |
| 280 | |
| 281 | if __name__ == "__main__": |
| 282 | main() |
File History
3 commits
sha256:94ef169c149a452bff7c604ded8b280b19bd477c2dabcb56972780b0b784c7aa
Merge 'fix/assignee-sigil-inline' into 'dev' — proposal: As…
Human
1 day ago
sha256:6b1949fc2797ca4c1936a637a4cbfec828ef56cf52398a2e74ca3c4f494e728f
fix: use wire_bytes not mpack_bytes_raw in compute_object_b…
Sonnet 4.6
patch
10 days ago
sha256:4aed3d8601c8dd3ed37074de35f11f4a9699a0a4b99d43727048fd3f8e6fd13d
chore: doc sweep, ignore wrangler build state, misc fixes
Sonnet 4.6
minor
⚠
12 days ago