millforge 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 (116) hide show
  1. millforge/__init__.py +1174 -0
  2. millforge/_forge/LICENSE +21 -0
  3. millforge/_forge/PROVENANCE.json +295 -0
  4. millforge/_forge/UPDATE_POLICY.md +24 -0
  5. millforge/_forge/__init__.py +14 -0
  6. millforge/_forge/adapter.py +2232 -0
  7. millforge/_forge/base_runner.py +121 -0
  8. millforge/_forge/clients/__init__.py +10 -0
  9. millforge/_forge/clients/base.py +200 -0
  10. millforge/_forge/context/__init__.py +23 -0
  11. millforge/_forge/context/manager.py +178 -0
  12. millforge/_forge/context/strategies.py +335 -0
  13. millforge/_forge/core/__init__.py +16 -0
  14. millforge/_forge/core/inference.py +433 -0
  15. millforge/_forge/core/messages.py +119 -0
  16. millforge/_forge/core/runner.py +479 -0
  17. millforge/_forge/core/steps.py +108 -0
  18. millforge/_forge/core/workflow.py +400 -0
  19. millforge/_forge/errors.py +222 -0
  20. millforge/_forge/guardrails/__init__.py +21 -0
  21. millforge/_forge/guardrails/error_tracker.py +71 -0
  22. millforge/_forge/guardrails/guardrails.py +194 -0
  23. millforge/_forge/guardrails/nudge.py +47 -0
  24. millforge/_forge/guardrails/response_validator.py +119 -0
  25. millforge/_forge/guardrails/step_enforcer.py +183 -0
  26. millforge/_forge/prompts/__init__.py +16 -0
  27. millforge/_forge/prompts/nudges.py +95 -0
  28. millforge/_forge/prompts/templates.py +285 -0
  29. millforge/_version.py +3 -0
  30. millforge/artifacts.py +570 -0
  31. millforge/base/__init__.py +97 -0
  32. millforge/base/composition.py +402 -0
  33. millforge/base/context.py +285 -0
  34. millforge/base/harness.py +138 -0
  35. millforge/base/identity.py +465 -0
  36. millforge/base/options.py +34 -0
  37. millforge/base/platform.py +17 -0
  38. millforge/base/prompt.py +317 -0
  39. millforge/base/runner.py +546 -0
  40. millforge/compiled_plan.py +970 -0
  41. millforge/compiler/__init__.py +231 -0
  42. millforge/compiler/artifact_validation.py +257 -0
  43. millforge/compiler/canonicalization.py +169 -0
  44. millforge/compiler/capabilities.py +66 -0
  45. millforge/compiler/catalogs.py +500 -0
  46. millforge/compiler/diagnostics.py +491 -0
  47. millforge/compiler/graph.py +678 -0
  48. millforge/compiler/lowering.py +198 -0
  49. millforge/compiler/output.py +692 -0
  50. millforge/compiler/parsing.py +1424 -0
  51. millforge/compiler/requests.py +1180 -0
  52. millforge/compiler/schema_validation.py +272 -0
  53. millforge/compiler/semantic.py +490 -0
  54. millforge/compiler/service.py +448 -0
  55. millforge/compiler/source.py +375 -0
  56. millforge/compiler/validators.py +184 -0
  57. millforge/connectors/__init__.py +95 -0
  58. millforge/connectors/admission.py +801 -0
  59. millforge/connectors/broker.py +202 -0
  60. millforge/connectors/contracts.py +1159 -0
  61. millforge/connectors/diagnostics.py +189 -0
  62. millforge/connectors/fake.py +66 -0
  63. millforge/connectors/runtime.py +236 -0
  64. millforge/contracts.py +2860 -0
  65. millforge/custom_tools/__init__.py +67 -0
  66. millforge/custom_tools/compiler.py +724 -0
  67. millforge/custom_tools/contracts.py +1093 -0
  68. millforge/custom_tools/diagnostics.py +205 -0
  69. millforge/eval_artifacts.py +952 -0
  70. millforge/eval_boundary.py +2435 -0
  71. millforge/eval_fixtures/__init__.py +1 -0
  72. millforge/eval_fixtures/default_pack/__init__.py +1 -0
  73. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.bug_diagnosis.traceback.v1.json +52 -0
  74. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.direct_edit.import_sort.v1.json +52 -0
  75. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.evidence_discipline.no_source_change.v1.json +51 -0
  76. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.false_closure.visible_green.v1.json +52 -0
  77. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.multi_file.api_contract.v1.json +54 -0
  78. millforge/eval_fixtures/default_pack/fixtures/fixture.08a.recovery.malformed_artifact.v1.json +54 -0
  79. millforge/eval_fixtures/default_pack/manifest.json +12 -0
  80. millforge/eval_modes.py +1282 -0
  81. millforge/eval_presets.py +1398 -0
  82. millforge/eval_reports.py +2517 -0
  83. millforge/eval_suite.py +2429 -0
  84. millforge/eval_trials.py +2632 -0
  85. millforge/eval_workflow.py +794 -0
  86. millforge/exceptions.py +122 -0
  87. millforge/model_backend.py +2098 -0
  88. millforge/protocols.py +340 -0
  89. millforge/py.typed +0 -0
  90. millforge/runtime.py +1791 -0
  91. millforge/testing/__init__.py +1089 -0
  92. millforge/tools/__init__.py +83 -0
  93. millforge/tools/builtin_runtime.py +1339 -0
  94. millforge/tools/builtins.py +773 -0
  95. millforge/tools/execution.py +1545 -0
  96. millforge/tools/path_policy.py +155 -0
  97. millforge/tools/pi_compat/PI_LICENSE +21 -0
  98. millforge/tools/pi_compat/PROVENANCE.json +55 -0
  99. millforge/tools/pi_compat/UPDATE_POLICY.md +36 -0
  100. millforge/tools/pi_compat/__init__.py +34 -0
  101. millforge/tools/pi_compat/contracts.py +49 -0
  102. millforge/tools/pi_compat/editing.py +390 -0
  103. millforge/tools/pi_compat/mutations.py +57 -0
  104. millforge/tools/pi_compat/operations.py +401 -0
  105. millforge/tools/pi_compat/paths.py +155 -0
  106. millforge/tools/pi_compat/process.py +1375 -0
  107. millforge/tools/pi_compat/search.py +738 -0
  108. millforge/tools/pi_compat/truncation.py +267 -0
  109. millforge/tools/pi_compat_catalog.py +396 -0
  110. millforge/tools/pi_compat_runtime.py +460 -0
  111. millforge/tools/registry.py +553 -0
  112. millforge/tools/results.py +533 -0
  113. millforge-0.1.0.dist-info/METADATA +844 -0
  114. millforge-0.1.0.dist-info/RECORD +116 -0
  115. millforge-0.1.0.dist-info/WHEEL +4 -0
  116. millforge-0.1.0.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,692 @@
1
+ """Atomic compiler output publication helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import errno
6
+ import hashlib
7
+ import os
8
+ import secrets
9
+ import stat
10
+ from dataclasses import dataclass
11
+ from pathlib import Path, PurePosixPath
12
+ from urllib.parse import quote
13
+
14
+ from millforge.compiled_plan import CompiledHarnessPlan, canonical_compiled_plan_bytes
15
+ from millforge.compiled_plan import canonical_json_serialize
16
+ from millforge.compiler.diagnostics import (
17
+ CompilerDiagnostic,
18
+ CompilerPhase,
19
+ DiagnosticField,
20
+ DiagnosticSeverity,
21
+ )
22
+ from millforge.compiler.requests import (
23
+ CompileStatus,
24
+ DiagnosticReportState,
25
+ HarnessCompileRequest,
26
+ HarnessCompileResult,
27
+ PlanCommitCertainty,
28
+ )
29
+ from millforge.compiler.validators import validate_utf8_size
30
+ from millforge.compiler.validators import validate_sha256
31
+
32
+ MAX_COMPILED_PLAN_OUTPUT_BYTES = 1024 * 1024
33
+ _HARNESS_ID_FILENAME_SAFE = (
34
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-"
35
+ )
36
+
37
+
38
+ @dataclass(frozen=True)
39
+ class _AdmittedOutputDir:
40
+ """Exact admitted output-directory handle used for anchored writes."""
41
+
42
+ path: Path
43
+ fd: int
44
+
45
+
46
+ def request_identity_sha256(request: HarnessCompileRequest) -> str:
47
+ """Hash the request identity fields that affect output addressing."""
48
+ payload = {
49
+ "request_id": request.request_id,
50
+ "source_path": request.source_path,
51
+ "source_format": request.source_format,
52
+ "expected_harness_id": request.expected_harness_id,
53
+ "stage_kind_id": request.stage_kind_id,
54
+ }
55
+ return hashlib.sha256(canonical_json_serialize(payload).encode("utf-8")).hexdigest()
56
+
57
+
58
+ def compiled_plan_output_path(
59
+ request: HarnessCompileRequest, plan: CompiledHarnessPlan
60
+ ) -> str:
61
+ """Return the safe relative content-addressed compiled-plan output path."""
62
+ return _join_output_path(
63
+ request.output_dir,
64
+ (
65
+ f"{_safe_harness_identity(plan.harness_id)}@{plan.harness_version}."
66
+ f"{plan.compiled_sha256}.compiled.json"
67
+ ),
68
+ )
69
+
70
+
71
+ def diagnostics_output_path(
72
+ request: HarnessCompileRequest,
73
+ *,
74
+ harness_id: str | None = None,
75
+ harness_version: int | None = None,
76
+ source_document_sha256: str | None = None,
77
+ compiled_sha256: str | None = None,
78
+ ) -> str:
79
+ """Return the safe relative request-addressed diagnostics output path."""
80
+ request_hash = request_identity_sha256(request)
81
+ if compiled_sha256 is not None:
82
+ digest = validate_sha256(compiled_sha256, "compiled_sha256")
83
+ prefix = _harness_identity_prefix(
84
+ harness_id=harness_id,
85
+ harness_version=harness_version,
86
+ )
87
+ filename = f"{prefix}.{digest}.request-{request_hash}.diagnostics.json"
88
+ elif source_document_sha256 is not None:
89
+ digest = validate_sha256(source_document_sha256, "source_document_sha256")
90
+ prefix = _harness_identity_prefix(
91
+ harness_id=harness_id,
92
+ harness_version=harness_version,
93
+ )
94
+ filename = f"{prefix}.{digest}.request-{request_hash}.diagnostics.json"
95
+ else:
96
+ filename = f"request-{request_hash}.diagnostics.json"
97
+ return _join_output_path(
98
+ request.output_dir,
99
+ filename,
100
+ )
101
+
102
+
103
+ def persist_compile_outputs(
104
+ *,
105
+ request: HarnessCompileRequest,
106
+ plan: CompiledHarnessPlan,
107
+ diagnostics: tuple[CompilerDiagnostic, ...] = (),
108
+ source_document_sha256: str | None = None,
109
+ ) -> HarnessCompileResult:
110
+ """Persist prepared diagnostics, publish a compiled plan, then commit diagnostics."""
111
+ request_hash = request_identity_sha256(request)
112
+ output_dir = _admit_output_dir(request, request_hash=request_hash)
113
+ if isinstance(output_dir, HarnessCompileResult):
114
+ return output_dir
115
+
116
+ plan_relpath = compiled_plan_output_path(request, plan)
117
+ diagnostics_relpath = diagnostics_output_path(
118
+ request,
119
+ harness_id=plan.harness_id,
120
+ harness_version=plan.harness_version,
121
+ source_document_sha256=source_document_sha256,
122
+ compiled_sha256=plan.compiled_sha256,
123
+ )
124
+ plan_name = Path(plan_relpath).name
125
+ diagnostics_name = Path(diagnostics_relpath).name
126
+
127
+ try:
128
+ if not _admitted_output_dir_matches(output_dir):
129
+ return _failed_output_result(
130
+ request=request,
131
+ request_hash=request_hash,
132
+ code="MF-O001",
133
+ message="Output directory could not be confirmed after admission.",
134
+ source_document_sha256=source_document_sha256,
135
+ diagnostics=diagnostics,
136
+ )
137
+
138
+ prepared_result = HarnessCompileResult(
139
+ request_id=request.request_id,
140
+ status=CompileStatus.PREPARED,
141
+ plan_commit_certainty=PlanCommitCertainty.ABSENT,
142
+ diagnostic_report_state=DiagnosticReportState.PREPARED,
143
+ source_document_sha256=source_document_sha256,
144
+ source_sha256=plan.source_sha256,
145
+ request_identity_sha256=request_hash,
146
+ harness_id=plan.harness_id,
147
+ diagnostics_path=diagnostics_relpath,
148
+ diagnostics=diagnostics,
149
+ )
150
+ prepared_error = _write_diagnostics_report(
151
+ output_dir=output_dir, filename=diagnostics_name, result=prepared_result
152
+ )
153
+ if prepared_error is not None:
154
+ return _failed_output_result(
155
+ request=request,
156
+ plan=plan,
157
+ request_hash=request_hash,
158
+ code="MF-O002",
159
+ message="Prepared diagnostics report could not be written.",
160
+ source_document_sha256=source_document_sha256,
161
+ diagnostics=diagnostics,
162
+ fields=prepared_error,
163
+ )
164
+
165
+ plan_bytes = canonical_compiled_plan_bytes(plan)
166
+ if len(plan_bytes) > MAX_COMPILED_PLAN_OUTPUT_BYTES:
167
+ return _failed_output_result(
168
+ request=request,
169
+ plan=plan,
170
+ request_hash=request_hash,
171
+ code="MF-O003",
172
+ message="Compiled plan exceeds the output size limit.",
173
+ source_document_sha256=source_document_sha256,
174
+ diagnostics=diagnostics,
175
+ diagnostics_path=diagnostics_relpath,
176
+ diagnostic_report_state=DiagnosticReportState.PREPARED,
177
+ fields=(_field("compiled_plan_size", len(plan_bytes)),),
178
+ )
179
+
180
+ publish = _publish_content_addressed_file(
181
+ output_dir=output_dir, destination_name=plan_name, data=plan_bytes
182
+ )
183
+ if publish.result == _PublishResult.CONFLICT:
184
+ return _failed_output_result(
185
+ request=request,
186
+ plan=plan,
187
+ request_hash=request_hash,
188
+ code="MF-O004",
189
+ message="Compiled plan destination already contains different bytes.",
190
+ source_document_sha256=source_document_sha256,
191
+ diagnostics=diagnostics,
192
+ diagnostics_path=diagnostics_relpath,
193
+ diagnostic_report_state=DiagnosticReportState.PREPARED,
194
+ plan_certainty=PlanCommitCertainty.ABSENT,
195
+ cleanup_error=publish.cleanup_error,
196
+ )
197
+ if publish.error is not None:
198
+ return _failed_output_result(
199
+ request=request,
200
+ plan=plan,
201
+ request_hash=request_hash,
202
+ code="MF-O003",
203
+ message="Compiled plan temporary file could not be written.",
204
+ source_document_sha256=source_document_sha256,
205
+ diagnostics=diagnostics,
206
+ diagnostics_path=diagnostics_relpath,
207
+ diagnostic_report_state=DiagnosticReportState.PREPARED,
208
+ fields=publish.error,
209
+ cleanup_error=publish.cleanup_error,
210
+ )
211
+ if publish.cleanup_error is not None:
212
+ return _failed_output_result(
213
+ request=request,
214
+ plan=plan,
215
+ request_hash=request_hash,
216
+ code="MF-O005",
217
+ message="Compiled plan temporary file could not be cleaned up.",
218
+ source_document_sha256=source_document_sha256,
219
+ diagnostics=diagnostics,
220
+ diagnostics_path=diagnostics_relpath,
221
+ diagnostic_report_state=DiagnosticReportState.PREPARED,
222
+ plan_relpath=plan_relpath,
223
+ plan_certainty=PlanCommitCertainty.UNKNOWN,
224
+ fields=publish.cleanup_error,
225
+ )
226
+
227
+ if not _destination_matches(
228
+ output_dir=output_dir, destination_name=plan_name, data=plan_bytes
229
+ ) or not _fsync_directory(output_dir.fd):
230
+ durability_result = _failed_output_result(
231
+ request=request,
232
+ plan=plan,
233
+ request_hash=request_hash,
234
+ code="MF-O003",
235
+ message="Compiled plan publication durability could not be confirmed.",
236
+ source_document_sha256=source_document_sha256,
237
+ diagnostics=diagnostics,
238
+ diagnostics_path=diagnostics_relpath,
239
+ diagnostic_report_state=DiagnosticReportState.COMMITTED,
240
+ plan_relpath=plan_relpath,
241
+ plan_certainty=PlanCommitCertainty.UNKNOWN,
242
+ )
243
+ commit_error = _write_diagnostics_report(
244
+ output_dir=output_dir,
245
+ filename=diagnostics_name,
246
+ result=durability_result,
247
+ )
248
+ if commit_error is None:
249
+ return durability_result
250
+ return HarnessCompileResult(
251
+ request_id=request.request_id,
252
+ status=CompileStatus.FAILED,
253
+ plan_commit_certainty=PlanCommitCertainty.UNKNOWN,
254
+ diagnostic_report_state=DiagnosticReportState.UNKNOWN,
255
+ failure_phase=CompilerPhase.OUTPUT,
256
+ source_document_sha256=source_document_sha256,
257
+ source_sha256=plan.source_sha256,
258
+ request_identity_sha256=request_hash,
259
+ harness_id=plan.harness_id,
260
+ compiled_plan_path=plan_relpath,
261
+ compiled_sha256=plan.compiled_sha256,
262
+ diagnostics_path=diagnostics_relpath,
263
+ diagnostics=(
264
+ *durability_result.diagnostics,
265
+ _output_diagnostic(
266
+ code="MF-O002",
267
+ message="Committed diagnostics report could not be written.",
268
+ fields=commit_error,
269
+ ),
270
+ ),
271
+ )
272
+
273
+ committed_result = HarnessCompileResult(
274
+ request_id=request.request_id,
275
+ status=CompileStatus.COMMITTED,
276
+ plan_commit_certainty=PlanCommitCertainty.COMMITTED,
277
+ diagnostic_report_state=DiagnosticReportState.COMMITTED,
278
+ source_document_sha256=source_document_sha256,
279
+ source_sha256=plan.source_sha256,
280
+ request_identity_sha256=request_hash,
281
+ harness_id=plan.harness_id,
282
+ compiled_plan_path=plan_relpath,
283
+ compiled_sha256=plan.compiled_sha256,
284
+ diagnostics_path=diagnostics_relpath,
285
+ diagnostics=diagnostics,
286
+ )
287
+ commit_error = _write_diagnostics_report(
288
+ output_dir=output_dir,
289
+ filename=diagnostics_name,
290
+ result=committed_result,
291
+ )
292
+ if commit_error is None:
293
+ return committed_result
294
+ return HarnessCompileResult(
295
+ request_id=request.request_id,
296
+ status=CompileStatus.PREPARED,
297
+ plan_commit_certainty=PlanCommitCertainty.COMMITTED,
298
+ diagnostic_report_state=DiagnosticReportState.UNKNOWN,
299
+ source_document_sha256=source_document_sha256,
300
+ source_sha256=plan.source_sha256,
301
+ request_identity_sha256=request_hash,
302
+ harness_id=plan.harness_id,
303
+ compiled_plan_path=plan_relpath,
304
+ compiled_sha256=plan.compiled_sha256,
305
+ diagnostics_path=diagnostics_relpath,
306
+ diagnostics=(
307
+ *diagnostics,
308
+ _output_diagnostic(
309
+ code="MF-O002",
310
+ message="Committed diagnostics report could not be written.",
311
+ fields=commit_error,
312
+ ),
313
+ ),
314
+ )
315
+ finally:
316
+ _close_output_dir(output_dir)
317
+
318
+
319
+ class _PublishResult:
320
+ PUBLISHED = "published"
321
+ REUSED = "reused"
322
+ CONFLICT = "conflict"
323
+
324
+
325
+ @dataclass(frozen=True)
326
+ class _PublishOutcome:
327
+ result: str | None = None
328
+ error: tuple[DiagnosticField, ...] | None = None
329
+ cleanup_error: tuple[DiagnosticField, ...] | None = None
330
+
331
+
332
+ def _publish_content_addressed_file(
333
+ *,
334
+ output_dir: _AdmittedOutputDir,
335
+ destination_name: str,
336
+ data: bytes,
337
+ ) -> _PublishOutcome:
338
+ temp_name = _temporary_path(destination_name)
339
+ result: str | None = None
340
+ error: tuple[DiagnosticField, ...] | None = None
341
+ try:
342
+ _write_exclusive_temp(output_dir.fd, temp_name, data)
343
+ try:
344
+ os.link(
345
+ temp_name,
346
+ destination_name,
347
+ src_dir_fd=output_dir.fd,
348
+ dst_dir_fd=output_dir.fd,
349
+ )
350
+ except FileExistsError:
351
+ result = (
352
+ _PublishResult.REUSED
353
+ if _destination_matches(
354
+ output_dir=output_dir, destination_name=destination_name, data=data
355
+ )
356
+ else _PublishResult.CONFLICT
357
+ )
358
+ except OSError as exc:
359
+ if exc.errno == errno.EEXIST:
360
+ result = (
361
+ _PublishResult.REUSED
362
+ if _destination_matches(
363
+ output_dir=output_dir,
364
+ destination_name=destination_name,
365
+ data=data,
366
+ )
367
+ else _PublishResult.CONFLICT
368
+ )
369
+ else:
370
+ error = (_field("errno", exc.errno or errno.EIO),)
371
+ else:
372
+ result = _PublishResult.PUBLISHED
373
+ except FileExistsError as exc:
374
+ return _PublishOutcome(error=(_field("errno", exc.errno or errno.EEXIST),))
375
+ except OSError as exc:
376
+ error = (_field("errno", exc.errno or errno.EIO),)
377
+ cleanup_error = _unlink_if_present(output_dir=output_dir, filename=temp_name)
378
+ return _PublishOutcome(result=result, error=error, cleanup_error=cleanup_error)
379
+
380
+
381
+ def _write_diagnostics_report(
382
+ *,
383
+ output_dir: _AdmittedOutputDir,
384
+ filename: str,
385
+ result: HarnessCompileResult,
386
+ ) -> tuple[DiagnosticField, ...] | None:
387
+ data = canonical_json_serialize(result.model_dump(mode="json")).encode("utf-8")
388
+ temp_name = _temporary_path(filename)
389
+ try:
390
+ _write_exclusive_temp(output_dir.fd, temp_name, data)
391
+ os.replace(
392
+ temp_name,
393
+ filename,
394
+ src_dir_fd=output_dir.fd,
395
+ dst_dir_fd=output_dir.fd,
396
+ )
397
+ if not _fsync_directory(output_dir.fd):
398
+ raise OSError(errno.EIO, os.strerror(errno.EIO))
399
+ except FileExistsError as exc:
400
+ return (_field("errno", exc.errno or errno.EEXIST),)
401
+ except OSError as exc:
402
+ _unlink_if_present(output_dir=output_dir, filename=temp_name)
403
+ return (_field("errno", exc.errno or errno.EIO),)
404
+ return None
405
+
406
+
407
+ def _write_exclusive_temp(directory_fd: int, filename: str, data: bytes) -> None:
408
+ flags = os.O_WRONLY | os.O_CREAT | os.O_EXCL
409
+ if hasattr(os, "O_NOFOLLOW"):
410
+ flags |= os.O_NOFOLLOW
411
+ fd = os.open(filename, flags, 0o600, dir_fd=directory_fd)
412
+ with os.fdopen(fd, "wb") as handle:
413
+ handle.write(data)
414
+ handle.flush()
415
+ os.fsync(handle.fileno())
416
+
417
+
418
+ def _admit_output_dir(
419
+ request: HarnessCompileRequest,
420
+ *,
421
+ request_hash: str | None = None,
422
+ ) -> _AdmittedOutputDir | HarnessCompileResult:
423
+ root = Path(request.output_root)
424
+ output_parts = _relative_posix_parts(request.output_dir)
425
+ if output_parts is None:
426
+ return _failed_output_result(
427
+ request=request,
428
+ code="MF-O001",
429
+ message="Output directory must stay within output_root.",
430
+ request_hash=request_hash,
431
+ )
432
+ try:
433
+ root_resolved = root.resolve(strict=True)
434
+ if not stat.S_ISDIR(root_resolved.lstat().st_mode):
435
+ raise NotADirectoryError(request.output_root)
436
+ candidate = root_resolved.joinpath(*output_parts)
437
+ parent = candidate.parent.resolve(strict=True)
438
+ if not _is_relative_to(parent, root_resolved):
439
+ raise PermissionError(request.output_dir)
440
+ resolved = parent.joinpath(candidate.name)
441
+ before = resolved.lstat()
442
+ if stat.S_ISLNK(before.st_mode) or not stat.S_ISDIR(before.st_mode):
443
+ raise NotADirectoryError(request.output_dir)
444
+ resolved = resolved.resolve(strict=True)
445
+ if not _is_relative_to(resolved, root_resolved):
446
+ raise PermissionError(request.output_dir)
447
+ if (
448
+ os.open not in os.supports_dir_fd
449
+ or os.link not in os.supports_dir_fd
450
+ or os.unlink not in os.supports_dir_fd
451
+ or not hasattr(os, "O_DIRECTORY")
452
+ or not hasattr(os, "O_NOFOLLOW")
453
+ ):
454
+ raise OSError(
455
+ errno.EOPNOTSUPP, "anchored output-directory operations unavailable"
456
+ )
457
+ flags = os.O_RDONLY | os.O_DIRECTORY
458
+ flags |= os.O_NOFOLLOW
459
+ fd = os.open(resolved, flags)
460
+ try:
461
+ opened = os.fstat(fd)
462
+ current = resolved.lstat()
463
+ if (
464
+ opened.st_dev != current.st_dev
465
+ or opened.st_ino != current.st_ino
466
+ or not stat.S_ISDIR(opened.st_mode)
467
+ or not stat.S_ISDIR(current.st_mode)
468
+ ):
469
+ raise PermissionError(request.output_dir)
470
+ except Exception:
471
+ os.close(fd)
472
+ raise
473
+ return _AdmittedOutputDir(path=resolved, fd=fd)
474
+ except OSError as exc:
475
+ return _failed_output_result(
476
+ request=request,
477
+ code="MF-O001",
478
+ message="Output directory could not be admitted for diagnostics.",
479
+ request_hash=request_hash,
480
+ fields=(_field("errno", exc.errno or errno.EIO),),
481
+ )
482
+
483
+
484
+ def _failed_output_result(
485
+ *,
486
+ request: HarnessCompileRequest,
487
+ code: str,
488
+ message: str,
489
+ plan: CompiledHarnessPlan | None = None,
490
+ request_hash: str | None = None,
491
+ source_document_sha256: str | None = None,
492
+ diagnostics: tuple[CompilerDiagnostic, ...] = (),
493
+ diagnostics_path: str | None = None,
494
+ diagnostic_report_state: DiagnosticReportState = DiagnosticReportState.ABSENT,
495
+ plan_relpath: str | None = None,
496
+ plan_certainty: PlanCommitCertainty = PlanCommitCertainty.ABSENT,
497
+ fields: tuple[DiagnosticField, ...] = (),
498
+ cleanup_error: tuple[DiagnosticField, ...] | None = None,
499
+ ) -> HarnessCompileResult:
500
+ cleanup_diagnostics = (
501
+ (
502
+ _output_diagnostic(
503
+ code="MF-O005",
504
+ message="Compiled plan temporary file could not be cleaned up.",
505
+ fields=cleanup_error,
506
+ ),
507
+ )
508
+ if cleanup_error is not None
509
+ else ()
510
+ )
511
+ return HarnessCompileResult(
512
+ request_id=request.request_id,
513
+ status=CompileStatus.FAILED,
514
+ plan_commit_certainty=plan_certainty,
515
+ diagnostic_report_state=diagnostic_report_state,
516
+ failure_phase=CompilerPhase.OUTPUT,
517
+ source_document_sha256=source_document_sha256,
518
+ source_sha256=None if plan is None else plan.source_sha256,
519
+ request_identity_sha256=request_hash,
520
+ harness_id=None if plan is None else plan.harness_id,
521
+ compiled_plan_path=plan_relpath,
522
+ compiled_sha256=(
523
+ None
524
+ if plan is None or plan_certainty == PlanCommitCertainty.ABSENT
525
+ else plan.compiled_sha256
526
+ ),
527
+ diagnostics_path=diagnostics_path,
528
+ diagnostics=(
529
+ *diagnostics,
530
+ _output_diagnostic(code=code, message=message, fields=fields),
531
+ *cleanup_diagnostics,
532
+ ),
533
+ )
534
+
535
+
536
+ def _output_diagnostic(
537
+ *,
538
+ code: str,
539
+ message: str,
540
+ fields: tuple[DiagnosticField, ...] = (),
541
+ ) -> CompilerDiagnostic:
542
+ return CompilerDiagnostic(
543
+ code=code,
544
+ severity=DiagnosticSeverity.ERROR,
545
+ phase=CompilerPhase.OUTPUT,
546
+ message=message,
547
+ fields=fields,
548
+ )
549
+
550
+
551
+ def _field(key: str, value: str | int | float | bool) -> DiagnosticField:
552
+ return DiagnosticField(key=key, value=value)
553
+
554
+
555
+ def _destination_matches(
556
+ *,
557
+ output_dir: _AdmittedOutputDir,
558
+ destination_name: str,
559
+ data: bytes,
560
+ ) -> bool:
561
+ try:
562
+ flags = os.O_RDONLY
563
+ if hasattr(os, "O_NOFOLLOW"):
564
+ flags |= os.O_NOFOLLOW
565
+ fd = os.open(destination_name, flags, dir_fd=output_dir.fd)
566
+ except OSError:
567
+ return False
568
+ try:
569
+ with os.fdopen(fd, "rb") as handle:
570
+ return handle.read() == data
571
+ except OSError:
572
+ return False
573
+
574
+
575
+ def _fsync_directory(directory: Path | int) -> bool:
576
+ if isinstance(directory, int):
577
+ try:
578
+ os.fsync(directory)
579
+ except OSError:
580
+ return False
581
+ return True
582
+ if not hasattr(os, "O_DIRECTORY"):
583
+ return True
584
+ try:
585
+ fd = os.open(directory, os.O_RDONLY | os.O_DIRECTORY)
586
+ except OSError:
587
+ return False
588
+ try:
589
+ os.fsync(fd)
590
+ except OSError:
591
+ return False
592
+ finally:
593
+ os.close(fd)
594
+ return True
595
+
596
+
597
+ def _temporary_path(destination_name: str) -> str:
598
+ return f".{destination_name}.{secrets.token_hex(8)}.tmp"
599
+
600
+
601
+ def _unlink_if_present(
602
+ *, output_dir: _AdmittedOutputDir, filename: str
603
+ ) -> tuple[DiagnosticField, ...] | None:
604
+ try:
605
+ os.unlink(filename, dir_fd=output_dir.fd)
606
+ except FileNotFoundError:
607
+ return None
608
+ except OSError as exc:
609
+ return (_field("errno", exc.errno or errno.EIO),)
610
+ return None
611
+
612
+
613
+ def _join_output_path(output_dir: str, filename: str) -> str:
614
+ value = f"{PurePosixPath(output_dir).as_posix().rstrip('/')}/{filename}"
615
+ return validate_utf8_size(value, "output path", 1024)
616
+
617
+
618
+ def _safe_harness_identity(value: str) -> str:
619
+ return validate_utf8_size(
620
+ quote(value, safe=_HARNESS_ID_FILENAME_SAFE),
621
+ "harness identity",
622
+ 320,
623
+ )
624
+
625
+
626
+ def _harness_identity_prefix(
627
+ *,
628
+ harness_id: str | None,
629
+ harness_version: int | None,
630
+ ) -> str:
631
+ if harness_id is None or harness_version is None:
632
+ raise ValueError("harness diagnostics paths require identity and version")
633
+ if harness_version <= 0:
634
+ raise ValueError("harness_version must be positive")
635
+ return f"{_safe_harness_identity(harness_id)}@{harness_version}"
636
+
637
+
638
+ def _relative_posix_parts(value: str) -> tuple[str, ...] | None:
639
+ path = PurePosixPath(value)
640
+ if path.is_absolute() or value.startswith("/") or "\\" in value:
641
+ return None
642
+ parts = path.parts
643
+ if not parts or any(_is_forbidden_path_part(part) for part in parts):
644
+ return None
645
+ return parts
646
+
647
+
648
+ def _is_forbidden_path_part(part: str) -> bool:
649
+ reserved_names = {
650
+ "con",
651
+ "prn",
652
+ "aux",
653
+ "nul",
654
+ *(f"com{index}" for index in range(1, 10)),
655
+ *(f"lpt{index}" for index in range(1, 10)),
656
+ }
657
+ stem = part.split(".", 1)[0].casefold()
658
+ return (
659
+ part in {"", ".", ".."}
660
+ or ":" in part
661
+ or "\x00" in part
662
+ or stem in reserved_names
663
+ )
664
+
665
+
666
+ def _is_relative_to(path: Path, root: Path) -> bool:
667
+ try:
668
+ path.relative_to(root)
669
+ return True
670
+ except ValueError:
671
+ return False
672
+
673
+
674
+ def _admitted_output_dir_matches(output_dir: _AdmittedOutputDir) -> bool:
675
+ try:
676
+ current = output_dir.path.lstat()
677
+ admitted = os.fstat(output_dir.fd)
678
+ except OSError:
679
+ return False
680
+ return (
681
+ stat.S_ISDIR(current.st_mode)
682
+ and stat.S_ISDIR(admitted.st_mode)
683
+ and current.st_dev == admitted.st_dev
684
+ and current.st_ino == admitted.st_ino
685
+ )
686
+
687
+
688
+ def _close_output_dir(output_dir: _AdmittedOutputDir) -> None:
689
+ try:
690
+ os.close(output_dir.fd)
691
+ except OSError:
692
+ return