nexus-coding-agent 0.1.0__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.
Files changed (131) hide show
  1. nexus/__init__.py +4 -0
  2. nexus/application/__init__.py +2 -0
  3. nexus/application/approval_service.py +130 -0
  4. nexus/application/diff_service.py +177 -0
  5. nexus/application/event_publisher.py +180 -0
  6. nexus/application/execution_context.py +29 -0
  7. nexus/application/execution_ledger.py +126 -0
  8. nexus/application/model_call_context.py +29 -0
  9. nexus/application/observed_model_gateway.py +194 -0
  10. nexus/application/plan_approval_service.py +250 -0
  11. nexus/application/planning.py +668 -0
  12. nexus/application/runtime.py +624 -0
  13. nexus/application/session_service.py +411 -0
  14. nexus/application/structured_output.py +96 -0
  15. nexus/application/telemetry.py +396 -0
  16. nexus/application/telemetry_subscriber.py +216 -0
  17. nexus/application/tool_runtime.py +496 -0
  18. nexus/application/tracing_dispatcher.py +283 -0
  19. nexus/application/validation.py +293 -0
  20. nexus/config/__init__.py +17 -0
  21. nexus/config/loader.py +253 -0
  22. nexus/config/models.py +310 -0
  23. nexus/context/__init__.py +6 -0
  24. nexus/context/budget.py +24 -0
  25. nexus/context/builder.py +92 -0
  26. nexus/context/chunking.py +65 -0
  27. nexus/context/explorer.py +246 -0
  28. nexus/context/integration.py +63 -0
  29. nexus/context/manager.py +328 -0
  30. nexus/context/retrieval.py +261 -0
  31. nexus/domain/__init__.py +2 -0
  32. nexus/domain/agent_decision.py +113 -0
  33. nexus/domain/agent_state.py +49 -0
  34. nexus/domain/approvals.py +64 -0
  35. nexus/domain/context.py +108 -0
  36. nexus/domain/exploration.py +86 -0
  37. nexus/domain/mcp.py +51 -0
  38. nexus/domain/model.py +173 -0
  39. nexus/domain/observability.py +326 -0
  40. nexus/domain/persistence.py +122 -0
  41. nexus/domain/planning.py +329 -0
  42. nexus/domain/ports/__init__.py +61 -0
  43. nexus/domain/ports/agent_decision.py +9 -0
  44. nexus/domain/ports/approval_unit_of_work.py +27 -0
  45. nexus/domain/ports/checkpoint_provider.py +11 -0
  46. nexus/domain/ports/context.py +71 -0
  47. nexus/domain/ports/events.py +21 -0
  48. nexus/domain/ports/graph_runtime.py +30 -0
  49. nexus/domain/ports/mcp.py +23 -0
  50. nexus/domain/ports/model_gateway.py +21 -0
  51. nexus/domain/ports/model_input_budget.py +15 -0
  52. nexus/domain/ports/planning.py +62 -0
  53. nexus/domain/ports/repositories.py +54 -0
  54. nexus/domain/ports/repository_context.py +18 -0
  55. nexus/domain/ports/session_unit_of_work.py +33 -0
  56. nexus/domain/ports/skills.py +41 -0
  57. nexus/domain/ports/tooling.py +39 -0
  58. nexus/domain/ports/tracer.py +13 -0
  59. nexus/domain/ports/validation.py +32 -0
  60. nexus/domain/runtime_events.py +445 -0
  61. nexus/domain/skills.py +129 -0
  62. nexus/domain/tooling.py +163 -0
  63. nexus/domain/validation.py +161 -0
  64. nexus/errors/__init__.py +82 -0
  65. nexus/evaluation/__init__.py +7 -0
  66. nexus/evaluation/assertions.py +4 -0
  67. nexus/evaluation/evaluator.py +263 -0
  68. nexus/evaluation/fixtures.py +36 -0
  69. nexus/evaluation/harness.py +606 -0
  70. nexus/evaluation/loader.py +415 -0
  71. nexus/evaluation/metrics.py +27 -0
  72. nexus/evaluation/models.py +362 -0
  73. nexus/evaluation/report.py +43 -0
  74. nexus/evaluation/runner.py +480 -0
  75. nexus/infrastructure/__init__.py +2 -0
  76. nexus/infrastructure/asyncio_compat.py +13 -0
  77. nexus/infrastructure/bootstrap/__init__.py +17 -0
  78. nexus/infrastructure/bootstrap/composition.py +663 -0
  79. nexus/infrastructure/checkpoint/__init__.py +5 -0
  80. nexus/infrastructure/checkpoint/postgres.py +62 -0
  81. nexus/infrastructure/database.py +39 -0
  82. nexus/infrastructure/embedding.py +61 -0
  83. nexus/infrastructure/graph/__init__.py +6 -0
  84. nexus/infrastructure/graph/day4_runtime.py +966 -0
  85. nexus/infrastructure/graph/langgraph_runtime.py +172 -0
  86. nexus/infrastructure/mcp/__init__.py +5 -0
  87. nexus/infrastructure/mcp/manager.py +380 -0
  88. nexus/infrastructure/model_gateway/__init__.py +6 -0
  89. nexus/infrastructure/model_gateway/openai_compatible.py +345 -0
  90. nexus/infrastructure/observability/__init__.py +7 -0
  91. nexus/infrastructure/observability/console.py +31 -0
  92. nexus/infrastructure/observability/langsmith.py +236 -0
  93. nexus/infrastructure/observability/structured_logger.py +70 -0
  94. nexus/infrastructure/persistence/__init__.py +13 -0
  95. nexus/infrastructure/persistence/approval_unit_of_work.py +74 -0
  96. nexus/infrastructure/persistence/models.py +146 -0
  97. nexus/infrastructure/persistence/repositories.py +326 -0
  98. nexus/infrastructure/persistence/unit_of_work.py +82 -0
  99. nexus/infrastructure/repository_files.py +117 -0
  100. nexus/infrastructure/sandbox/__init__.py +5 -0
  101. nexus/infrastructure/sandbox/local_process.py +353 -0
  102. nexus/infrastructure/semantic.py +276 -0
  103. nexus/infrastructure/semantic_models.py +56 -0
  104. nexus/interfaces/__init__.py +2 -0
  105. nexus/interfaces/cli/__init__.py +2 -0
  106. nexus/interfaces/cli/__main__.py +6 -0
  107. nexus/interfaces/cli/app.py +266 -0
  108. nexus/interfaces/cli/renderer.py +118 -0
  109. nexus/security/__init__.py +14 -0
  110. nexus/security/approval_policies.py +73 -0
  111. nexus/security/command_policy.py +117 -0
  112. nexus/security/executables.py +107 -0
  113. nexus/security/git_commands.py +65 -0
  114. nexus/security/workspace.py +93 -0
  115. nexus/skills/__init__.py +7 -0
  116. nexus/skills/builtin/__init__.py +1 -0
  117. nexus/skills/builtin/debug-python/SKILL.md +26 -0
  118. nexus/skills/builtin/review-repository/SKILL.md +26 -0
  119. nexus/skills/builtin/write-tests/SKILL.md +26 -0
  120. nexus/skills/loader.py +439 -0
  121. nexus/skills/registry.py +146 -0
  122. nexus/skills/selector.py +152 -0
  123. nexus/tools/__init__.py +6 -0
  124. nexus/tools/editing.py +312 -0
  125. nexus/tools/mcp.py +160 -0
  126. nexus/tools/native.py +654 -0
  127. nexus/tools/registry.py +27 -0
  128. nexus_coding_agent-0.1.0.dist-info/METADATA +142 -0
  129. nexus_coding_agent-0.1.0.dist-info/RECORD +131 -0
  130. nexus_coding_agent-0.1.0.dist-info/WHEEL +4 -0
  131. nexus_coding_agent-0.1.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,480 @@
1
+ """Sequential, isolated Day 9 evaluation orchestration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import tempfile
6
+ from collections.abc import Callable
7
+ from contextlib import AbstractAsyncContextManager
8
+ from datetime import UTC, datetime
9
+ from pathlib import Path
10
+
11
+ from nexus.application.runtime import NexusRuntime
12
+ from nexus.domain.runtime_events import (
13
+ ErrorOccurred,
14
+ FinalResult,
15
+ RunInterrupted,
16
+ RuntimeStatus,
17
+ ToolFinished,
18
+ )
19
+ from nexus.domain.tooling import ApprovalDecision, PolicyDecision
20
+ from nexus.evaluation.evaluator import DefaultDeterministicEvaluator
21
+ from nexus.evaluation.fixtures import FixtureConstraintError, validate_fixture_source
22
+ from nexus.evaluation.harness import (
23
+ DEFAULT_EVAL_VALIDATION_TIMEOUT_SECONDS,
24
+ EvaluationHarness,
25
+ compare_repository_states,
26
+ snapshot_repository,
27
+ )
28
+ from nexus.evaluation.metrics import InMemoryEvalTraceCollector, metrics_from_finish
29
+ from nexus.evaluation.models import (
30
+ DeterministicEvaluationResult,
31
+ EvalAssertionResult,
32
+ EvalAssertionType,
33
+ EvalCase,
34
+ EvalCaseReport,
35
+ EvalCheckEvidence,
36
+ EvalDiscoveryResult,
37
+ EvalDiscoveryStatus,
38
+ EvalExecutionResult,
39
+ EvalForbiddenPathEvidence,
40
+ EvalOutcome,
41
+ EvalRepositoryEvidence,
42
+ EvalSuiteError,
43
+ EvalSuiteLoadResult,
44
+ EvalSuiteReport,
45
+ EvalValidationResult,
46
+ EvalValidationStatus,
47
+ ForbiddenPathSnapshot,
48
+ SecurityDecision,
49
+ SecurityEvidence,
50
+ SecurityEvidenceSource,
51
+ )
52
+
53
+ RuntimeFactory = Callable[
54
+ [Path, InMemoryEvalTraceCollector], AbstractAsyncContextManager[NexusRuntime]
55
+ ]
56
+
57
+
58
+ class EvalRunner:
59
+ def __init__(
60
+ self,
61
+ cases_root: Path,
62
+ runtime_factory: RuntimeFactory,
63
+ evaluator: DefaultDeterministicEvaluator | None = None,
64
+ ) -> None:
65
+ self._cases_root = cases_root
66
+ self._runtime_factory = runtime_factory
67
+ self._evaluator = evaluator or DefaultDeterministicEvaluator()
68
+
69
+ async def run_case(self, case: EvalCase) -> EvalCaseReport:
70
+ fixture = self._cases_root / case.case_id / case.initial_repo_state
71
+ try:
72
+ validate_fixture_source(fixture)
73
+ except FixtureConstraintError as exc:
74
+ return _evaluator_error_report(case, str(exc))
75
+ except Exception as exc:
76
+ return await self._infrastructure_report(
77
+ case,
78
+ _empty_checks(),
79
+ f"Fixture validation failed: {type(exc).__name__}",
80
+ )
81
+ timeout = case.validation_timeout_seconds or DEFAULT_EVAL_VALIDATION_TIMEOUT_SECONDS
82
+ pre_checks, pre_error = await self._run_preconditions(case, fixture, timeout)
83
+ if pre_error is not None:
84
+ execution = EvalExecutionResult(
85
+ case_id=case.case_id,
86
+ run_id=None,
87
+ session_id=None,
88
+ runtime_status=None,
89
+ terminal_status=None,
90
+ error_code=None,
91
+ final_result_summary=None,
92
+ repository=_empty_repository(case.forbidden_files),
93
+ checks=pre_checks,
94
+ metrics=None,
95
+ security_evidence=(),
96
+ infrastructure_error=pre_error,
97
+ )
98
+ result = await self._evaluator.evaluate(case, execution)
99
+ return _case_report(case, execution, result)
100
+ if _precondition_mismatch(case, pre_checks):
101
+ execution = EvalExecutionResult(
102
+ case_id=case.case_id,
103
+ run_id=None,
104
+ session_id=None,
105
+ runtime_status=None,
106
+ terminal_status=None,
107
+ error_code=None,
108
+ final_result_summary=None,
109
+ repository=_empty_repository(case.forbidden_files),
110
+ checks=pre_checks,
111
+ metrics=None,
112
+ security_evidence=(),
113
+ infrastructure_error=None,
114
+ )
115
+ result = await self._evaluator.evaluate(case, execution)
116
+ return _case_report(case, execution, result)
117
+
118
+ with tempfile.TemporaryDirectory(prefix=f"nexus-{case.case_id.lower()}-") as raw:
119
+ workspace = Path(raw) / "repo"
120
+ try:
121
+ EvaluationHarness.copy_fixture(fixture, workspace)
122
+ git_results = await EvaluationHarness.initialize_git(workspace)
123
+ setup_error = _git_setup_error(git_results)
124
+ if setup_error:
125
+ return await self._infrastructure_report(case, pre_checks, setup_error)
126
+ baseline = snapshot_repository(workspace, case.forbidden_files)
127
+ except Exception as exc:
128
+ return await self._infrastructure_report(
129
+ case, pre_checks, f"Fixture setup failed: {type(exc).__name__}"
130
+ )
131
+
132
+ collector = InMemoryEvalTraceCollector()
133
+ run_id: str | None = None
134
+ session_id: str | None = None
135
+ runtime_status: RuntimeStatus | None = None
136
+ terminal_status = None
137
+ error_code: str | None = None
138
+ final_summary: str | None = None
139
+ security: list[SecurityEvidence] = []
140
+ infrastructure_error: str | None = None
141
+ runtime_invoked = False
142
+ try:
143
+ async with self._runtime_factory(workspace, collector) as runtime:
144
+ runtime_invoked = True
145
+ async for event in runtime.run(case.task):
146
+ run_id = run_id or event.run_id
147
+ session_id = event.session_id or session_id
148
+ if isinstance(event, FinalResult):
149
+ runtime_status = event.status
150
+ terminal_status = event.terminal_status
151
+ final_summary = event.content
152
+ elif isinstance(event, ErrorOccurred):
153
+ runtime_status = event.status
154
+ error_code = event.code
155
+ elif isinstance(event, RunInterrupted):
156
+ runtime_status = event.status
157
+ elif isinstance(event, ToolFinished):
158
+ evidence = _security_evidence(event)
159
+ if evidence is not None:
160
+ security.append(evidence)
161
+ except Exception as exc:
162
+ infrastructure_error = f"Runtime bootstrap failed: {type(exc).__name__}"
163
+
164
+ try:
165
+ # Diagnostic-only boundary: authoritative evidence is captured again
166
+ # after all post-run validation and discovery operations.
167
+ _post_agent_state = snapshot_repository(workspace, case.forbidden_files)
168
+ expected_nodes = tuple(
169
+ node
170
+ for assertion in case.deterministic_success_conditions
171
+ if assertion.assertion_type is EvalAssertionType.TARGETED_TEST_ADDED
172
+ for node in assertion.expected_test_node_ids
173
+ )
174
+ post_validation = await EvaluationHarness.validation(
175
+ workspace, case.validation_command, timeout, expected_nodes
176
+ )
177
+ post_discovery = await EvaluationHarness.discovery(
178
+ workspace, case.test_discovery_command, timeout
179
+ )
180
+ final = snapshot_repository(workspace, case.forbidden_files)
181
+ text_paths = tuple(
182
+ assertion.path
183
+ for assertion in case.deterministic_success_conditions
184
+ if assertion.assertion_type is EvalAssertionType.REQUIRED_TEXT_IN_FILE
185
+ and assertion.path is not None
186
+ )
187
+ repository = compare_repository_states(baseline, final, text_paths, workspace)
188
+ except Exception as exc:
189
+ return await self._infrastructure_report(
190
+ case,
191
+ pre_checks,
192
+ f"Post-run Harness failed: {type(exc).__name__}",
193
+ )
194
+ checks = EvalCheckEvidence(
195
+ pre_checks.pre_validation,
196
+ post_validation,
197
+ pre_checks.pre_discovery,
198
+ post_discovery,
199
+ )
200
+ finish = None if run_id is None else collector.get_finish(run_id)
201
+ if infrastructure_error is None and runtime_invoked and finish is None:
202
+ infrastructure_error = "Authoritative TraceRunFinish is missing."
203
+ if finish is not None:
204
+ runtime_status = finish.runtime_status
205
+ terminal_status = finish.terminal_status
206
+ error_code = finish.error_code
207
+ execution = EvalExecutionResult(
208
+ case_id=case.case_id,
209
+ run_id=run_id,
210
+ session_id=session_id,
211
+ runtime_status=runtime_status,
212
+ terminal_status=terminal_status,
213
+ error_code=error_code,
214
+ final_result_summary=final_summary,
215
+ repository=repository,
216
+ checks=checks,
217
+ metrics=None if finish is None else metrics_from_finish(finish),
218
+ security_evidence=tuple(security),
219
+ infrastructure_error=infrastructure_error,
220
+ )
221
+ result = await self._evaluator.evaluate(case, execution)
222
+ return _case_report(case, execution, result)
223
+
224
+ async def run_suite(self, load_result: EvalSuiteLoadResult) -> EvalSuiteReport:
225
+ errors = tuple(
226
+ EvalSuiteError(error.code, error.message, error.source_path, error.case_id_hint)
227
+ for error in load_result.errors
228
+ )
229
+ reports: list[EvalCaseReport] = []
230
+ if not errors:
231
+ for case in sorted(load_result.cases, key=lambda item: item.case_id):
232
+ reports.append(await self.run_case(case))
233
+ return _suite_report(tuple(reports), errors)
234
+
235
+ async def _run_preconditions(
236
+ self, case: EvalCase, fixture: Path, timeout_seconds: int
237
+ ) -> tuple[EvalCheckEvidence, str | None]:
238
+ if not case.pre_validation_command and not case.test_discovery_command:
239
+ return EvalCheckEvidence(
240
+ _not_run_validation(),
241
+ _not_run_validation(),
242
+ _not_run_discovery(),
243
+ _not_run_discovery(),
244
+ ), None
245
+ with tempfile.TemporaryDirectory(prefix=f"nexus-{case.case_id.lower()}-pre-") as raw:
246
+ workspace = Path(raw) / "repo"
247
+ try:
248
+ EvaluationHarness.copy_fixture(fixture, workspace)
249
+ git_results = await EvaluationHarness.initialize_git(workspace)
250
+ setup_error = _git_setup_error(git_results)
251
+ if setup_error:
252
+ return _empty_checks(), setup_error
253
+ validation = await EvaluationHarness.validation(
254
+ workspace, case.pre_validation_command, timeout_seconds
255
+ )
256
+ discovery = await EvaluationHarness.discovery(
257
+ workspace, case.test_discovery_command, timeout_seconds
258
+ )
259
+ return EvalCheckEvidence(
260
+ validation, _not_run_validation(), discovery, _not_run_discovery()
261
+ ), None
262
+ except Exception as exc:
263
+ return _empty_checks(), f"Precondition Harness failed: {type(exc).__name__}"
264
+
265
+ async def _infrastructure_report(
266
+ self, case: EvalCase, checks: EvalCheckEvidence, message: str
267
+ ) -> EvalCaseReport:
268
+ execution = EvalExecutionResult(
269
+ case.case_id,
270
+ None,
271
+ None,
272
+ None,
273
+ None,
274
+ None,
275
+ None,
276
+ _empty_repository(case.forbidden_files),
277
+ checks,
278
+ None,
279
+ (),
280
+ message,
281
+ )
282
+ result = await self._evaluator.evaluate(case, execution)
283
+ return _case_report(case, execution, result)
284
+
285
+
286
+ def _precondition_mismatch(case: EvalCase, checks: EvalCheckEvidence) -> bool:
287
+ validation = checks.pre_validation
288
+ discovery = checks.pre_discovery
289
+ if (
290
+ validation.status is EvalValidationStatus.TIMED_OUT
291
+ or discovery.status is EvalDiscoveryStatus.TIMED_OUT
292
+ ):
293
+ return True
294
+ if (
295
+ validation.status is EvalValidationStatus.INFRASTRUCTURE_ERROR
296
+ or discovery.status is EvalDiscoveryStatus.INFRASTRUCTURE_ERROR
297
+ ):
298
+ return True
299
+ if validation.exit_code in {2, 3, 4, 5}:
300
+ return True
301
+ if case.case_id in {"EVAL-001", "EVAL-002"}:
302
+ return validation.status is not EvalValidationStatus.FAILED or validation.exit_code != 1
303
+ if (
304
+ case.case_id in {"EVAL-003", "EVAL-004"}
305
+ and validation.status is not EvalValidationStatus.PASSED
306
+ ):
307
+ return True
308
+ if case.case_id == "EVAL-004":
309
+ expected = {
310
+ node
311
+ for assertion in case.deterministic_success_conditions
312
+ if assertion.assertion_type is EvalAssertionType.TARGETED_TEST_ADDED
313
+ for node in assertion.expected_test_node_ids
314
+ }
315
+ return discovery.status is not EvalDiscoveryStatus.PASSED or bool(
316
+ expected & set(discovery.collected_node_ids)
317
+ )
318
+ return False
319
+
320
+
321
+ def _security_evidence(event: ToolFinished) -> SecurityEvidence | None:
322
+ if event.error_code not in {
323
+ "PLAN_SCOPE_DENIED",
324
+ "PERMISSION_DENIED",
325
+ "COMMAND_DENIED",
326
+ "MCP_WRITE_NOT_AUTHORIZED",
327
+ }:
328
+ return None
329
+ if event.error_code == "MCP_WRITE_NOT_AUTHORIZED":
330
+ source = SecurityEvidenceSource.MCP_POLICY
331
+ elif event.error_code == "PLAN_SCOPE_DENIED":
332
+ source = SecurityEvidenceSource.TOOL_RUNTIME
333
+ elif event.error_code == "COMMAND_DENIED":
334
+ if event.approval_decision is ApprovalDecision.DENIED:
335
+ source = SecurityEvidenceSource.APPROVAL_POLICY
336
+ elif event.tool_name == "shell" and event.policy_decision is PolicyDecision.DENIED:
337
+ source = SecurityEvidenceSource.COMMAND_POLICY
338
+ else:
339
+ source = SecurityEvidenceSource.RUNTIME_EVENT
340
+ elif (
341
+ event.tool_name == "shell"
342
+ and event.policy_decision is PolicyDecision.DENIED
343
+ and event.approval_decision is None
344
+ ):
345
+ source = SecurityEvidenceSource.COMMAND_POLICY
346
+ elif event.policy_decision is PolicyDecision.ALLOWED:
347
+ source = SecurityEvidenceSource.TOOL_RUNTIME
348
+ else:
349
+ # ToolFinished does not expose the internal enforcement path. In
350
+ # particular, PERMISSION_DENIED is not proof of WorkspaceGuard origin.
351
+ source = SecurityEvidenceSource.RUNTIME_EVENT
352
+ decision = (
353
+ SecurityDecision.DENIED
354
+ if event.policy_decision is PolicyDecision.DENIED
355
+ or event.approval_decision is ApprovalDecision.DENIED
356
+ else SecurityDecision.BLOCKED
357
+ )
358
+ return SecurityEvidence(source, event.tool_name, decision, event.error_code, event.tool_name)
359
+
360
+
361
+ def _git_setup_error(results: tuple[object, ...]) -> str | None:
362
+ for result in results:
363
+ allowed = getattr(result, "allowed", False)
364
+ exit_code = getattr(result, "exit_code", None)
365
+ timed_out = getattr(result, "timed_out", False)
366
+ infrastructure_error = getattr(result, "infrastructure_error", None)
367
+ if not allowed or exit_code != 0 or timed_out or infrastructure_error:
368
+ return "Evaluation Git baseline setup failed."
369
+ return None
370
+
371
+
372
+ def _case_report(
373
+ case: EvalCase,
374
+ execution: EvalExecutionResult,
375
+ result: DeterministicEvaluationResult,
376
+ ) -> EvalCaseReport:
377
+ return EvalCaseReport(
378
+ case_id=case.case_id,
379
+ outcome=result.outcome,
380
+ run_id=execution.run_id,
381
+ session_id=execution.session_id,
382
+ runtime_status=execution.runtime_status,
383
+ terminal_status=execution.terminal_status,
384
+ error_code=execution.error_code,
385
+ deterministic_result=result,
386
+ metrics=execution.metrics,
387
+ repository=execution.repository,
388
+ checks=execution.checks,
389
+ security_evidence=execution.security_evidence,
390
+ efficiency_warning=bool(
391
+ execution.metrics and execution.metrics.agent_steps > case.max_reasonable_steps
392
+ ),
393
+ evidence=tuple(
394
+ f"{item.assertion_type.value}={'PASS' if item.passed else 'FAIL'}"
395
+ for item in result.assertion_results
396
+ ),
397
+ )
398
+
399
+
400
+ def _evaluator_error_report(case: EvalCase, message: str) -> EvalCaseReport:
401
+ checks = _empty_checks()
402
+ execution = EvalExecutionResult(
403
+ case.case_id,
404
+ None,
405
+ None,
406
+ None,
407
+ None,
408
+ None,
409
+ None,
410
+ _empty_repository(case.forbidden_files),
411
+ checks,
412
+ None,
413
+ (),
414
+ None,
415
+ )
416
+ assertion_results = tuple(
417
+ EvalAssertionResult(
418
+ assertion.assertion_type,
419
+ False,
420
+ ("fixture contract invalid",),
421
+ message,
422
+ )
423
+ for assertion in case.deterministic_success_conditions
424
+ )
425
+ result = DeterministicEvaluationResult(
426
+ outcome=EvalOutcome.EVALUATOR_ERROR,
427
+ runtime_completed=False,
428
+ validation_passed=None,
429
+ constraints_passed=False,
430
+ forbidden_change_detected=False,
431
+ unauthorized_change_detected=False,
432
+ assertion_results=assertion_results,
433
+ failure_reason=message,
434
+ )
435
+ return _case_report(case, execution, result)
436
+
437
+
438
+ def _suite_report(
439
+ cases: tuple[EvalCaseReport, ...], errors: tuple[EvalSuiteError, ...]
440
+ ) -> EvalSuiteReport:
441
+ return EvalSuiteReport(
442
+ schema_version="1",
443
+ generated_at=datetime.now(UTC),
444
+ cases=cases,
445
+ suite_errors=errors,
446
+ total_cases=len(cases),
447
+ passed_cases=sum(item.outcome is EvalOutcome.PASS for item in cases),
448
+ task_failed_cases=sum(item.outcome is EvalOutcome.TASK_FAILED for item in cases),
449
+ infrastructure_error_cases=sum(
450
+ item.outcome is EvalOutcome.INFRASTRUCTURE_ERROR for item in cases
451
+ ),
452
+ evaluator_error_cases=sum(item.outcome is EvalOutcome.EVALUATOR_ERROR for item in cases),
453
+ )
454
+
455
+
456
+ def _not_run_validation() -> EvalValidationResult:
457
+ return EvalValidationResult(EvalValidationStatus.NOT_RUN, (), None, "", "", 0, None, None)
458
+
459
+
460
+ def _not_run_discovery() -> EvalDiscoveryResult:
461
+ return EvalDiscoveryResult(EvalDiscoveryStatus.NOT_RUN, (), None, (), "", "", 0, None, None)
462
+
463
+
464
+ def _empty_checks() -> EvalCheckEvidence:
465
+ return EvalCheckEvidence(
466
+ _not_run_validation(), _not_run_validation(), _not_run_discovery(), _not_run_discovery()
467
+ )
468
+
469
+
470
+ def _empty_repository(forbidden: tuple[str, ...]) -> EvalRepositoryEvidence:
471
+ missing = tuple(
472
+ EvalForbiddenPathEvidence(
473
+ path,
474
+ ForbiddenPathSnapshot(path, False, None, None, None, None),
475
+ ForbiddenPathSnapshot(path, False, None, None, None, None),
476
+ False,
477
+ )
478
+ for path in forbidden
479
+ )
480
+ return EvalRepositoryEvidence((), (), (), missing, {})
@@ -0,0 +1,2 @@
1
+ """Concrete adapters behind Nexus-owned boundaries."""
2
+
@@ -0,0 +1,13 @@
1
+ """Platform event-loop compatibility required by async PostgreSQL drivers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import sys
7
+
8
+
9
+ def configure_asyncio_policy() -> None:
10
+ """Use the Windows selector loop required by psycopg async connections."""
11
+
12
+ if sys.platform == "win32":
13
+ asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
@@ -0,0 +1,17 @@
1
+ """The only production composition root for concrete Nexus dependencies."""
2
+
3
+ from nexus.infrastructure.bootstrap.composition import (
4
+ BootstrappedApplication,
5
+ BootstrappedToolApplication,
6
+ bootstrap_application,
7
+ bootstrap_tool_application,
8
+ build_evaluation_runner,
9
+ )
10
+
11
+ __all__ = [
12
+ "BootstrappedApplication",
13
+ "BootstrappedToolApplication",
14
+ "bootstrap_application",
15
+ "bootstrap_tool_application",
16
+ "build_evaluation_runner",
17
+ ]