wydcode 0.4.3

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.
Files changed (41) hide show
  1. package/LICENSE +100 -0
  2. package/NOTICE +5 -0
  3. package/README.md +434 -0
  4. package/SECURITY.md +64 -0
  5. package/SOCRA_SOURCE.md +36 -0
  6. package/TRADEMARKS.md +12 -0
  7. package/bin/wydcode.js +74 -0
  8. package/examples/behavior-preference-card.json +12 -0
  9. package/examples/exact-recurrence-card.json +11 -0
  10. package/examples/heldout-gene-evidence.json +6 -0
  11. package/examples/humaneval-ornith.md +29 -0
  12. package/examples/large_context_json_diagnostic.py +187 -0
  13. package/fixtures/failing-node-repo/package.json +9 -0
  14. package/fixtures/failing-node-repo/src/math.js +3 -0
  15. package/fixtures/failing-node-repo/test/math.test.js +8 -0
  16. package/package.json +55 -0
  17. package/pyproject.toml +24 -0
  18. package/socra_harness/__init__.py +3 -0
  19. package/socra_harness/attempts.py +76 -0
  20. package/socra_harness/central_traces.py +627 -0
  21. package/socra_harness/cli.py +265 -0
  22. package/socra_harness/eval/__init__.py +1 -0
  23. package/socra_harness/eval/humaneval.py +388 -0
  24. package/socra_harness/events.py +39 -0
  25. package/socra_harness/init.py +206 -0
  26. package/socra_harness/job/__init__.py +2 -0
  27. package/socra_harness/job/events.py +132 -0
  28. package/socra_harness/job/lock.py +90 -0
  29. package/socra_harness/job/manager.py +3785 -0
  30. package/socra_harness/job/planner.py +253 -0
  31. package/socra_harness/job/state.py +106 -0
  32. package/socra_harness/mumpix_trace_bridge.cjs +32 -0
  33. package/socra_harness/product.py +533 -0
  34. package/socra_harness/recurrence.py +263 -0
  35. package/socra_harness/scan/__init__.py +1 -0
  36. package/socra_harness/scan/repo.py +85 -0
  37. package/socra_harness/serve/__init__.py +1 -0
  38. package/socra_harness/serve/local_proxy.py +293 -0
  39. package/socra_harness/start.py +331 -0
  40. package/socra_harness/tui/__init__.py +1 -0
  41. package/socra_harness/tui/app.py +1114 -0
@@ -0,0 +1,263 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import posixpath
6
+ import re
7
+ from pathlib import Path, PurePosixPath
8
+ from typing import Any
9
+
10
+
11
+ IDENTIFIER_RE = re.compile(r"^[A-Za-z_$][A-Za-z0-9_$.#:\-/]*$")
12
+ SPACE_RE = re.compile(r"\s+")
13
+ LINE_COLUMN_RE = re.compile(r":\d+(?::\d+)?$")
14
+ FORBIDDEN_BEHAVIOR_MARKERS = ("```", "@@ ", "=>", "{", "}", ";")
15
+ MAX_BEHAVIOR_CHARS = 2400
16
+ SHA256_RE = re.compile(r"^[0-9a-f]{64}$")
17
+
18
+
19
+ def canonical_json(value: Any) -> str:
20
+ return json.dumps(value, ensure_ascii=True, sort_keys=True, separators=(",", ":"))
21
+
22
+
23
+ def sha256_json(value: Any) -> str:
24
+ return hashlib.sha256(canonical_json(value).encode("ascii")).hexdigest()
25
+
26
+
27
+ def normalize_repository(value: object) -> str:
28
+ text = str(value or "").strip()
29
+ text = re.sub(r"^(?:https?://|ssh://git@|git@)", "", text, flags=re.I)
30
+ text = text.replace(":", "/", 1) if text.lower().startswith("github.com:") else text
31
+ text = text.rstrip("/")
32
+ if text.endswith(".git"):
33
+ text = text[:-4]
34
+ text = text.lower()
35
+ match = re.fullmatch(r"github\.com/([^/]+)/([^/]+)", text)
36
+ if not match:
37
+ raise ValueError("repository_identity must be github.com/<owner>/<repo>")
38
+ return f"github.com/{match.group(1)}/{match.group(2)}"
39
+
40
+
41
+ def normalize_path(value: object) -> str:
42
+ text = str(value or "").strip().replace("\\", "/")
43
+ text = LINE_COLUMN_RE.sub("", text)
44
+ if not text or text.startswith("/") or re.match(r"^[A-Za-z]:/", text):
45
+ raise ValueError("owning_path must be a non-empty repository-relative path")
46
+ normalized = posixpath.normpath(text)
47
+ if normalized in (".", "..") or normalized.startswith("../"):
48
+ raise ValueError("owning_path escapes repository root")
49
+ if any(part in ("", ".", "..") for part in PurePosixPath(normalized).parts):
50
+ raise ValueError("owning_path is not canonical")
51
+ return normalized
52
+
53
+
54
+ def normalize_symbol(value: object) -> str:
55
+ text = str(value or "").strip()
56
+ if not text or not IDENTIFIER_RE.fullmatch(text):
57
+ raise ValueError("owning_symbol_or_api must be one exact identifier")
58
+ return text
59
+
60
+
61
+ def normalize_invariant_part(value: object, field: str) -> str:
62
+ text = SPACE_RE.sub(" ", str(value or "").strip().lower())
63
+ if not text:
64
+ raise ValueError(f"invariant.{field} is required")
65
+ if any(char in text for char in "\r\n\t"):
66
+ raise ValueError(f"invariant.{field} contains control whitespace")
67
+ return text
68
+
69
+
70
+ def compile_recurrence_card(card: object) -> dict[str, Any]:
71
+ if not isinstance(card, dict):
72
+ return {"status": "recurrence_key_unassignable", "reason": "card_not_object"}
73
+ card_id = str(card.get("card_id") or "").strip()
74
+ if not card_id:
75
+ return {"status": "recurrence_key_unassignable", "reason": "card_id_missing"}
76
+ try:
77
+ invariant = card.get("invariant")
78
+ if not isinstance(invariant, dict):
79
+ raise ValueError("invariant must be a structured object")
80
+ key = {
81
+ "canonical_repository_identity": normalize_repository(card.get("repository_identity")),
82
+ "repository_relative_owning_production_path": normalize_path(card.get("owning_path")),
83
+ "owning_production_symbol_or_exported_api": normalize_symbol(card.get("owning_symbol_or_api")),
84
+ "normalized_violated_invariant_signature": {
85
+ "error_or_assertion_class": normalize_invariant_part(
86
+ invariant.get("error_or_assertion_class"), "error_or_assertion_class"
87
+ ),
88
+ "operation": normalize_invariant_part(invariant.get("operation"), "operation"),
89
+ "expected_relation": normalize_invariant_part(
90
+ invariant.get("expected_relation"), "expected_relation"
91
+ ),
92
+ },
93
+ }
94
+ except ValueError as error:
95
+ return {"card_id": card_id, "status": "recurrence_key_unassignable", "reason": str(error)}
96
+ return {
97
+ "card_id": card_id,
98
+ "status": "assignable",
99
+ "recurrence_key": key,
100
+ "recurrence_key_sha256": sha256_json(key),
101
+ "compiler": "exact_recurrence_normalization_v1",
102
+ }
103
+
104
+
105
+ def load_recurrence_card(path: Path) -> dict[str, Any]:
106
+ result = compile_recurrence_card(json.loads(path.read_text(encoding="utf-8")))
107
+ if result.get("status") != "assignable":
108
+ raise ValueError(str(result.get("reason") or "recurrence_key_unassignable"))
109
+ return result
110
+
111
+
112
+ def validate_behavior_preference(value: object) -> dict[str, Any]:
113
+ if not isinstance(value, dict):
114
+ raise ValueError("behavior card must be a JSON object")
115
+ allowed = {"approach", "invariants_to_preserve", "checks_to_run", "known_nonmatches"}
116
+ if set(value) - allowed:
117
+ raise ValueError(f"behavior card has unknown fields: {sorted(set(value) - allowed)}")
118
+ approach = str(value.get("approach") or "").strip()
119
+ if not approach:
120
+ raise ValueError("behavior approach is required")
121
+ result: dict[str, Any] = {"approach": approach}
122
+ for field in ("invariants_to_preserve", "checks_to_run", "known_nonmatches"):
123
+ items = value.get(field)
124
+ if not isinstance(items, list) or not items or not all(isinstance(item, str) and item.strip() for item in items):
125
+ raise ValueError(f"behavior {field} must be a non-empty string list")
126
+ result[field] = [item.strip() for item in items]
127
+ strings = [approach, *result["invariants_to_preserve"], *result["checks_to_run"], *result["known_nonmatches"]]
128
+ for text in strings:
129
+ if "\n" in text or "\r" in text:
130
+ raise ValueError("behavior entries must be single-line prose")
131
+ if text.startswith(("+", "-")) or any(marker in text for marker in FORBIDDEN_BEHAVIOR_MARKERS):
132
+ raise ValueError("behavior card appears to contain source or patch text")
133
+ rendered = canonical_json(result)
134
+ if len(rendered) > MAX_BEHAVIOR_CHARS:
135
+ raise ValueError(f"behavior card exceeds {MAX_BEHAVIOR_CHARS} characters")
136
+ return result
137
+
138
+
139
+ def load_behavior_preference(path: Path) -> dict[str, Any]:
140
+ return validate_behavior_preference(json.loads(path.read_text(encoding="utf-8")))
141
+
142
+
143
+ def behavior_overlaps_patch(preference: dict[str, Any], patch_text: str) -> bool:
144
+ haystack = SPACE_RE.sub(" ", patch_text).lower()
145
+ strings = [
146
+ preference["approach"],
147
+ *preference["invariants_to_preserve"],
148
+ *preference["checks_to_run"],
149
+ *preference["known_nonmatches"],
150
+ ]
151
+ return any(len(text) >= 20 and SPACE_RE.sub(" ", text).lower() in haystack for text in strings)
152
+
153
+
154
+ def validate_gene_evidence(value: object) -> dict[str, Any]:
155
+ if not isinstance(value, dict):
156
+ raise ValueError("gene evidence must be a JSON object")
157
+ allowed = {"status", "probe_sha256", "hidden_feedback_used", "description"}
158
+ if set(value) - allowed:
159
+ raise ValueError(f"gene evidence has unknown fields: {sorted(set(value) - allowed)}")
160
+ if value.get("status") != "passed":
161
+ raise ValueError("gene evidence status must be passed")
162
+ probe_sha256 = str(value.get("probe_sha256") or "").lower()
163
+ if not SHA256_RE.fullmatch(probe_sha256):
164
+ raise ValueError("gene evidence probe_sha256 must be 64 lowercase hex characters")
165
+ if value.get("hidden_feedback_used") is not False:
166
+ raise ValueError("gene evidence hidden_feedback_used must be false")
167
+ description = str(value.get("description") or "").strip()
168
+ if len(description) > 500 or "\n" in description or "\r" in description:
169
+ raise ValueError("gene evidence description must be at most 500 single-line characters")
170
+ return {
171
+ "status": "passed",
172
+ "probe_sha256": probe_sha256,
173
+ "hidden_feedback_used": False,
174
+ "description": description,
175
+ }
176
+
177
+
178
+ def load_gene_evidence(path: Path) -> dict[str, Any]:
179
+ raw = path.read_bytes()
180
+ evidence = validate_gene_evidence(json.loads(raw.decode("utf-8")))
181
+ return {**evidence, "artifact_sha256": hashlib.sha256(raw).hexdigest()}
182
+
183
+
184
+ def task_instance_sha256(task: dict[str, Any]) -> str:
185
+ return sha256_json(
186
+ {
187
+ "description": task.get("description"),
188
+ "acceptance": task.get("acceptance") or [],
189
+ "declared_files": task.get("declared_files") or [],
190
+ }
191
+ )
192
+
193
+
194
+ def injection_budget_decision(
195
+ context_budget_tokens: int,
196
+ reserved_output_tokens: int,
197
+ base_input_tokens_estimate: int,
198
+ injection_tokens_estimate: int,
199
+ safety_margin_tokens: int = 256,
200
+ ) -> dict[str, Any]:
201
+ available = (
202
+ context_budget_tokens
203
+ - reserved_output_tokens
204
+ - base_input_tokens_estimate
205
+ - safety_margin_tokens
206
+ )
207
+ return {
208
+ "fits": available >= injection_tokens_estimate,
209
+ "available_injection_tokens": available,
210
+ "safety_margin_tokens": safety_margin_tokens,
211
+ }
212
+
213
+
214
+ def select_exact_behavior(
215
+ central_events: list[dict[str, Any]], project_scope_id: str, task: dict[str, Any]
216
+ ) -> dict[str, Any]:
217
+ recurrence = task.get("recurrence") if isinstance(task.get("recurrence"), dict) else {}
218
+ key_sha = str(recurrence.get("recurrence_key_sha256") or "")
219
+ target_key = recurrence.get("recurrence_key")
220
+ if recurrence.get("status") != "assignable" or not key_sha:
221
+ return {"status": "recurrence_key_unassignable", "fired": False}
222
+ target_instance = task_instance_sha256(task)
223
+ matches: list[dict[str, Any]] = []
224
+ exact_replays = 0
225
+ for event in central_events:
226
+ if event.get("type") != "validated_fix_promoted":
227
+ continue
228
+ payload = event.get("payload") if isinstance(event.get("payload"), dict) else {}
229
+ gene = payload.get("behavior_gene") if isinstance(payload.get("behavior_gene"), dict) else None
230
+ if not gene:
231
+ continue
232
+ if gene.get("project_scope_id") != project_scope_id or gene.get("recurrence_key_sha256") != key_sha:
233
+ continue
234
+ if gene.get("recurrence_key") != target_key:
235
+ continue
236
+ if gene.get("privacy", {}).get("contains_patch_or_source") is not False:
237
+ continue
238
+ try:
239
+ preference = validate_behavior_preference(gene.get("preference"))
240
+ except ValueError:
241
+ continue
242
+ if gene.get("preference_sha256") != sha256_json(preference):
243
+ continue
244
+ if gene.get("source_task_instance_sha256") == target_instance:
245
+ exact_replays += 1
246
+ continue
247
+ matches.append({"event": event, "gene": gene})
248
+ if len(matches) > 1:
249
+ return {"status": "recurrence_key_collision_abstain", "fired": False, "match_count": len(matches)}
250
+ if not matches:
251
+ return {
252
+ "status": "exact_instance_replay_abstain" if exact_replays else "exact_recurrence_miss",
253
+ "fired": False,
254
+ "match_count": 0,
255
+ }
256
+ selected = matches[0]
257
+ return {
258
+ "status": "exact_recurrence_match",
259
+ "fired": True,
260
+ "match_count": 1,
261
+ "source_central_event_sha256": selected["event"].get("event_sha256"),
262
+ "gene": selected["gene"],
263
+ }
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,85 @@
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ from collections import defaultdict
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from ..events import EventLog
10
+
11
+
12
+ SOURCE_EXTS = {
13
+ ".py", ".js", ".jsx", ".ts", ".tsx", ".swift", ".go", ".rs", ".java", ".kt", ".m", ".mm",
14
+ ".css", ".scss", ".json", ".yaml", ".yml", ".toml",
15
+ }
16
+ SKIP_PARTS = {"node_modules", ".git", "dist", "build", ".next", "DerivedData", "__pycache__", "vendor"}
17
+
18
+
19
+ def family_for(path: Path, text: str) -> str:
20
+ name = path.name.lower()
21
+ suffix = path.suffix.lower()
22
+ if suffix in {".tsx", ".jsx", ".swift"} and ("view" in name or "component" in text.lower() or "struct " in text):
23
+ return "ui_component"
24
+ if "route" in name or "/api/" in str(path).lower():
25
+ return "api_or_route_handler"
26
+ if suffix in {".json", ".yaml", ".yml", ".toml"}:
27
+ return "config"
28
+ if "test" in name or "spec" in name:
29
+ return "test"
30
+ return "source"
31
+
32
+
33
+ def shape_key(family: str, rel: str, text: str) -> str:
34
+ lines = [line.strip() for line in text.splitlines() if line.strip() and not line.strip().startswith("//")]
35
+ skeleton = "\n".join(lines[:80])
36
+ digest = hashlib.sha256((family + "\n" + skeleton).encode("utf-8", "ignore")).hexdigest()[:24]
37
+ return f"fsm-{digest}"
38
+
39
+
40
+ def scan_main(args: Any) -> int:
41
+ root = args.folder.resolve()
42
+ events = EventLog(args.event_log)
43
+ groups: dict[str, list[dict[str, Any]]] = defaultdict(list)
44
+ source_count = 0
45
+ for path in root.rglob("*"):
46
+ if not path.is_file():
47
+ continue
48
+ if any(part in SKIP_PARTS for part in path.parts):
49
+ continue
50
+ if path.suffix.lower() not in SOURCE_EXTS:
51
+ continue
52
+ try:
53
+ text = path.read_text(encoding="utf-8", errors="replace")
54
+ except OSError:
55
+ continue
56
+ source_count += 1
57
+ rel = str(path.relative_to(root))
58
+ family = family_for(path, text)
59
+ key = shape_key(family, rel, text)
60
+ groups[family].append({"path": rel, "shape_key": key, "bytes": len(text.encode("utf-8", "ignore"))})
61
+ candidates = []
62
+ for family, files in groups.items():
63
+ if len(files) < 2:
64
+ continue
65
+ total_bytes = sum(item["bytes"] for item in files)
66
+ candidates.append({
67
+ "family": family,
68
+ "file_count": len(files),
69
+ "score_estimate": len(files) * 10 + min(total_bytes // 1024, 100),
70
+ "evidence": "static_estimate",
71
+ "shape_keys": sorted({item["shape_key"] for item in files})[:8],
72
+ "samples": files[:8],
73
+ })
74
+ candidates.sort(key=lambda item: item["score_estimate"], reverse=True)
75
+ payload = {
76
+ "folder": str(root),
77
+ "source_files": source_count,
78
+ "candidate_count": len(candidates),
79
+ "candidates": candidates,
80
+ }
81
+ args.out.parent.mkdir(parents=True, exist_ok=True)
82
+ args.out.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n")
83
+ events.emit("scan_complete", folder=str(root), source_files=source_count, candidate_count=len(candidates))
84
+ print(json.dumps({"source_files": source_count, "candidate_count": len(candidates), "out": str(args.out)}, indent=2))
85
+ return 0
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,293 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ import signal
6
+ import subprocess
7
+ import threading
8
+ import time
9
+ import urllib.error
10
+ import urllib.request
11
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
12
+ from pathlib import Path
13
+ from typing import Any
14
+
15
+ from ..events import EventLog
16
+
17
+
18
+ LOOPBACK = {"127.0.0.1", "localhost", "::1"}
19
+
20
+ HARNESS_SYSTEM_PROMPT = """You are running behind Socra Harness.
21
+ For coding work, prefer direct, complete, editable code.
22
+ Do not include hidden reasoning.
23
+ When asked for code, return clean code or a concise patch-oriented answer.
24
+ Avoid Markdown fences unless the user explicitly asks for them."""
25
+
26
+
27
+ def post_json(url: str, payload: dict[str, Any], timeout: int = 600) -> tuple[int, dict[str, str], bytes]:
28
+ data = json.dumps(payload).encode("utf-8")
29
+ req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"}, method="POST")
30
+ try:
31
+ with urllib.request.urlopen(req, timeout=timeout) as res:
32
+ return res.status, dict(res.headers), res.read()
33
+ except urllib.error.HTTPError as exc:
34
+ return exc.code, dict(exc.headers), exc.read()
35
+
36
+
37
+ def get_bytes(url: str, timeout: int = 30) -> tuple[int, dict[str, str], bytes]:
38
+ req = urllib.request.Request(url, method="GET")
39
+ try:
40
+ with urllib.request.urlopen(req, timeout=timeout) as res:
41
+ return res.status, dict(res.headers), res.read()
42
+ except urllib.error.HTTPError as exc:
43
+ return exc.code, dict(exc.headers), exc.read()
44
+ except urllib.error.URLError as exc:
45
+ payload = {"error": {"code": 503, "message": str(exc), "type": "backend_unavailable"}}
46
+ return 503, {"Content-Type": "application/json"}, json.dumps(payload).encode("utf-8")
47
+
48
+
49
+ def split_reasoning_text(text: str) -> tuple[str, str]:
50
+ parts: list[str] = []
51
+
52
+ def collect(match: re.Match[str]) -> str:
53
+ parts.append(match.group(1).strip())
54
+ return ""
55
+
56
+ text = re.sub(r"(?is)<think>(.*?)</think>", collect, text)
57
+ text = re.sub(r"(?is)<reasoning>(.*?)</reasoning>", collect, text)
58
+ return text.strip(), "\n\n".join(part for part in parts if part)
59
+
60
+
61
+ def strip_reasoning_text(text: str) -> str:
62
+ cleaned, _reasoning = split_reasoning_text(text)
63
+ return cleaned
64
+
65
+
66
+ def clean_code_wrappers(text: str) -> tuple[str, str]:
67
+ stripped, reasoning = split_reasoning_text(text)
68
+ fence = re.fullmatch(r"\s*```(?:\w+)?\s*([\s\S]*?)```\s*", stripped)
69
+ if fence:
70
+ return fence.group(1).strip("\n"), reasoning
71
+ return stripped, reasoning
72
+
73
+
74
+ def apply_socra_response_harness(body: dict[str, Any]) -> tuple[dict[str, Any], bool]:
75
+ changed = False
76
+ for choice in body.get("choices", []):
77
+ message = choice.get("message")
78
+ if not isinstance(message, dict):
79
+ continue
80
+ content = message.get("content")
81
+ if isinstance(content, str):
82
+ cleaned, extracted_reasoning = clean_code_wrappers(content)
83
+ if cleaned != content:
84
+ message["content"] = cleaned
85
+ changed = True
86
+ if extracted_reasoning and not isinstance(message.get("reasoning_content"), str):
87
+ message["reasoning_content"] = extracted_reasoning
88
+ changed = True
89
+ reasoning = message.get("reasoning_content")
90
+ if isinstance(reasoning, str) and not reasoning.strip():
91
+ message.pop("reasoning_content", None)
92
+ changed = True
93
+ return body, changed
94
+
95
+
96
+ def apply_socra_request_harness(body: dict[str, Any], model_alias: str) -> tuple[dict[str, Any], bool]:
97
+ patched = dict(body)
98
+ patched["model"] = model_alias
99
+ messages = list(patched.get("messages") or [])
100
+ has_system = any(message.get("role") == "system" for message in messages if isinstance(message, dict))
101
+ if not has_system:
102
+ messages.insert(0, {"role": "system", "content": HARNESS_SYSTEM_PROMPT})
103
+ patched["messages"] = messages
104
+ return patched, patched != body
105
+
106
+
107
+ class SocraProxyHandler(BaseHTTPRequestHandler):
108
+ server: "SocraProxyServer"
109
+
110
+ def log_message(self, fmt: str, *args: Any) -> None:
111
+ return
112
+
113
+ def write_json(self, status: int, payload: dict[str, Any]) -> None:
114
+ data = json.dumps(payload).encode("utf-8")
115
+ self.send_response(status)
116
+ self.send_header("Content-Type", "application/json; charset=utf-8")
117
+ self.send_header("Content-Length", str(len(data)))
118
+ self.send_header("X-Socra-Harness", "active")
119
+ self.end_headers()
120
+ self.wfile.write(data)
121
+
122
+ def read_json(self) -> dict[str, Any]:
123
+ length = int(self.headers.get("Content-Length", "0"))
124
+ raw = self.rfile.read(length) if length else b"{}"
125
+ return json.loads(raw.decode("utf-8") or "{}")
126
+
127
+ def do_GET(self) -> None:
128
+ if self.path == "/health":
129
+ self.write_json(200, {"status": "ready", "backend": self.server.backend_url, "model": self.server.model_alias})
130
+ return
131
+ if self.path == "/runtime/stats":
132
+ self.write_json(200, self.server.metrics)
133
+ return
134
+ if self.path == "/v1/models":
135
+ status, _headers, data = get_bytes(f"{self.server.backend_url}/v1/models")
136
+ self.send_response(status)
137
+ self.send_header("Content-Type", "application/json; charset=utf-8")
138
+ self.send_header("X-Socra-Harness", "active")
139
+ self.end_headers()
140
+ self.wfile.write(data)
141
+ return
142
+ self.write_json(404, {"error": "not found"})
143
+
144
+ def do_POST(self) -> None:
145
+ if self.path != "/v1/chat/completions":
146
+ self.write_json(404, {"error": "not found"})
147
+ return
148
+ body = self.read_json()
149
+ stream = bool(body.get("stream"))
150
+ patched, request_changed = apply_socra_request_harness(body, self.server.model_alias)
151
+ self.server.metrics["chat_requests_total"] += 1
152
+ if request_changed:
153
+ self.server.metrics["request_harness_applied_total"] += 1
154
+ self.server.events.emit("chat_request", stream=stream, request_harness=request_changed)
155
+
156
+ if stream:
157
+ status, headers, data = post_json(f"{self.server.backend_url}/v1/chat/completions", patched)
158
+ self.send_response(status)
159
+ self.send_header("Content-Type", headers.get("Content-Type", "text/event-stream"))
160
+ self.send_header("X-Socra-Harness", "active")
161
+ self.send_header("X-Socra-Mode", "stream_passthrough")
162
+ self.end_headers()
163
+ self.wfile.write(data)
164
+ self.server.metrics["stream_passthrough_total"] += 1
165
+ return
166
+
167
+ status, _headers, data = post_json(f"{self.server.backend_url}/v1/chat/completions", patched)
168
+ try:
169
+ payload = json.loads(data.decode("utf-8"))
170
+ except json.JSONDecodeError:
171
+ self.send_response(status)
172
+ self.send_header("Content-Type", "text/plain; charset=utf-8")
173
+ self.send_header("X-Socra-Harness", "active")
174
+ self.end_headers()
175
+ self.wfile.write(data)
176
+ return
177
+ payload, response_changed = apply_socra_response_harness(payload)
178
+ if response_changed:
179
+ self.server.metrics["response_harness_applied_total"] += 1
180
+ self.server.events.emit("chat_response", status=status, response_harness=response_changed)
181
+ self.write_json(status, payload)
182
+
183
+
184
+ class SocraProxyServer(ThreadingHTTPServer):
185
+ def __init__(self, addr: tuple[str, int], backend_url: str, model_alias: str, events: EventLog):
186
+ super().__init__(addr, SocraProxyHandler)
187
+ self.backend_url = backend_url.rstrip("/")
188
+ self.model_alias = model_alias
189
+ self.events = events
190
+ self.metrics = {
191
+ "local_first_enforced": True,
192
+ "hosted_fallback_total": 0,
193
+ "external_code_requests_total": 0,
194
+ "chat_requests_total": 0,
195
+ "request_harness_applied_total": 0,
196
+ "response_harness_applied_total": 0,
197
+ "stream_passthrough_total": 0,
198
+ }
199
+
200
+
201
+ def wait_for_backend(url: str, timeout_seconds: int = 120) -> bool:
202
+ deadline = time.time() + timeout_seconds
203
+ while time.time() < deadline:
204
+ try:
205
+ status, _headers, _data = get_bytes(f"{url}/v1/models", timeout=5)
206
+ if status < 500:
207
+ return True
208
+ except Exception:
209
+ pass
210
+ time.sleep(1)
211
+ return False
212
+
213
+
214
+ def serve_main(args: Any) -> int:
215
+ if args.host not in LOOPBACK:
216
+ raise SystemExit("Socra Harness is local-first: --host must be loopback")
217
+ if args.backend_host not in LOOPBACK:
218
+ raise SystemExit("Socra Harness is local-first: --backend-host must be loopback")
219
+
220
+ events = EventLog(args.event_log)
221
+ state_dir = args.event_log.parent
222
+ state_dir.mkdir(parents=True, exist_ok=True)
223
+ model_alias = args.alias or Path(args.model).stem
224
+ backend_url = f"http://{args.backend_host}:{args.backend_port}"
225
+ frontend_url = f"http://{args.host}:{args.port}"
226
+
227
+ state = {
228
+ "model": str(args.model),
229
+ "model_alias": model_alias,
230
+ "llama_server": str(args.llama_server),
231
+ "host": args.host,
232
+ "port": args.port,
233
+ "endpoint": f"{frontend_url}/v1",
234
+ "backend_endpoint": f"{backend_url}/v1",
235
+ "local_first": True,
236
+ "hosted_fallback": False,
237
+ "harness": "socra_request_response",
238
+ }
239
+ (state_dir / "server-state.json").write_text(json.dumps(state, indent=2) + "\n")
240
+ events.emit("server_start", **state)
241
+
242
+ backend = None
243
+ if not getattr(args, "reuse_backend", False):
244
+ cmd = [
245
+ str(args.llama_server),
246
+ "-m",
247
+ str(args.model),
248
+ "--host",
249
+ args.backend_host,
250
+ "--port",
251
+ str(args.backend_port),
252
+ "--ctx-size",
253
+ str(args.ctx_size),
254
+ "--gpu-layers",
255
+ str(args.gpu_layers),
256
+ ]
257
+ print("Starting backend llama-server:")
258
+ print(" ".join(cmd))
259
+ backend = subprocess.Popen(cmd)
260
+ else:
261
+ print(f"Reusing existing backend llama-server at {backend_url}")
262
+
263
+ def stop_backend(*_: Any) -> None:
264
+ if backend is not None and backend.poll() is None:
265
+ backend.terminate()
266
+
267
+ signal.signal(signal.SIGINT, stop_backend)
268
+ signal.signal(signal.SIGTERM, stop_backend)
269
+
270
+ if not wait_for_backend(backend_url):
271
+ stop_backend()
272
+ raise SystemExit(f"backend did not become ready: {backend_url}")
273
+
274
+ print(f"Socra Harness endpoint: {frontend_url}/v1")
275
+ print("Use this endpoint for Codex/vibe coding tools. Press Ctrl+C to stop.")
276
+ server = SocraProxyServer((args.host, args.port), backend_url, model_alias, events)
277
+ try:
278
+ thread = threading.Thread(target=server.serve_forever, daemon=True)
279
+ thread.start()
280
+ if backend is None:
281
+ while True:
282
+ time.sleep(0.5)
283
+ while backend.poll() is None:
284
+ time.sleep(0.5)
285
+ except KeyboardInterrupt:
286
+ pass
287
+ finally:
288
+ server.shutdown()
289
+ stop_backend()
290
+ if backend is not None:
291
+ backend.wait(timeout=10)
292
+ events.emit("server_stop", model=model_alias)
293
+ return 0