devflow-engine 1.2.1__py3-none-any.whl → 1.2.3__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.
- devflow_engine/errors/error_solver_dag.py +61 -8
- {devflow_engine-1.2.1.dist-info → devflow_engine-1.2.3.dist-info}/METADATA +1 -1
- {devflow_engine-1.2.1.dist-info → devflow_engine-1.2.3.dist-info}/RECORD +5 -5
- {devflow_engine-1.2.1.dist-info → devflow_engine-1.2.3.dist-info}/WHEEL +1 -1
- {devflow_engine-1.2.1.dist-info → devflow_engine-1.2.3.dist-info}/entry_points.txt +0 -0
|
@@ -151,6 +151,34 @@ def _proof_candidate(verification: dict[str, Any] | None) -> dict[str, Any]:
|
|
|
151
151
|
return {}
|
|
152
152
|
|
|
153
153
|
|
|
154
|
+
def _observation_fix_proof(context: dict[str, Any]) -> dict[str, Any]:
|
|
155
|
+
build_observability = context.get("BuildObservability")
|
|
156
|
+
if not isinstance(build_observability, dict):
|
|
157
|
+
return {}
|
|
158
|
+
output = build_observability.get("output")
|
|
159
|
+
if not isinstance(output, dict):
|
|
160
|
+
return {}
|
|
161
|
+
observation = output.get("observation")
|
|
162
|
+
if not isinstance(observation, dict):
|
|
163
|
+
return {}
|
|
164
|
+
proof = observation.get("fix_proof")
|
|
165
|
+
return proof if isinstance(proof, dict) else {}
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _verification_with_observed_fix_proof(
|
|
169
|
+
verification: dict[str, Any] | None,
|
|
170
|
+
context: dict[str, Any],
|
|
171
|
+
) -> dict[str, Any] | None:
|
|
172
|
+
if _proof_candidate(verification):
|
|
173
|
+
return verification
|
|
174
|
+
observed_proof = _observation_fix_proof(context)
|
|
175
|
+
if not observed_proof:
|
|
176
|
+
return verification
|
|
177
|
+
merged = dict(verification or {})
|
|
178
|
+
merged["fix_proof"] = observed_proof
|
|
179
|
+
return merged
|
|
180
|
+
|
|
181
|
+
|
|
154
182
|
def _resolve_artifact_path(repo_root: Path, artifact_path: Any) -> Path | None:
|
|
155
183
|
raw = str(artifact_path or "").strip()
|
|
156
184
|
if not raw:
|
|
@@ -216,7 +244,23 @@ def _validate_ui_fix_proof(
|
|
|
216
244
|
return True, normalized, None
|
|
217
245
|
|
|
218
246
|
|
|
219
|
-
def
|
|
247
|
+
def _artifact_under_observability_sandbox(artifact: str, *, error_task_id: str) -> bool:
|
|
248
|
+
normalized = artifact.replace("\\", "/").strip()
|
|
249
|
+
allowed_prefixes = (
|
|
250
|
+
f".devflow/observability/{error_task_id}/",
|
|
251
|
+
".devflow/observability/<id>/",
|
|
252
|
+
)
|
|
253
|
+
if any(normalized.startswith(prefix) for prefix in allowed_prefixes):
|
|
254
|
+
return True
|
|
255
|
+
marker = f"/.devflow/observability/{error_task_id}/"
|
|
256
|
+
return marker in normalized
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _validate_ui_observability_repro(
|
|
260
|
+
observation: dict[str, Any],
|
|
261
|
+
*,
|
|
262
|
+
error_task_id: str,
|
|
263
|
+
) -> tuple[bool, str | None]:
|
|
220
264
|
artifact = str(observation.get("repro_artifact_path") or "").strip()
|
|
221
265
|
command = str(observation.get("repro_run_command") or "").strip()
|
|
222
266
|
output = str(observation.get("repro_output") or "").strip()
|
|
@@ -228,6 +272,8 @@ def _validate_ui_observability_repro(observation: dict[str, Any]) -> tuple[bool,
|
|
|
228
272
|
return False, "ui_observability_missing_playwright_repro_artifact"
|
|
229
273
|
if "playwright" not in command.lower():
|
|
230
274
|
return False, "ui_observability_requires_playwright_repro_command"
|
|
275
|
+
if not _artifact_under_observability_sandbox(artifact, error_task_id=error_task_id):
|
|
276
|
+
return False, "ui_observability_repro_artifact_outside_sandbox"
|
|
231
277
|
if not output:
|
|
232
278
|
return False, "ui_observability_missing_repro_output"
|
|
233
279
|
if not isinstance(oracles, list) or not any(str(o or "").strip() for o in oracles):
|
|
@@ -848,7 +894,10 @@ class BuildObservabilityNode(Node):
|
|
|
848
894
|
else {}
|
|
849
895
|
)
|
|
850
896
|
if observed_flag and _ui_proof_required({"runtimeContext": user_report_context_for_ui}):
|
|
851
|
-
ui_repro_ok, ui_repro_failure_reason = _validate_ui_observability_repro(
|
|
897
|
+
ui_repro_ok, ui_repro_failure_reason = _validate_ui_observability_repro(
|
|
898
|
+
observation,
|
|
899
|
+
error_task_id=error_task_id,
|
|
900
|
+
)
|
|
852
901
|
|
|
853
902
|
# Split deferred questions via LLM classifier (v1.1.22).
|
|
854
903
|
# An injectable hook is used when present so tests can
|
|
@@ -1138,6 +1187,10 @@ class ResolveNode(Node):
|
|
|
1138
1187
|
error_task_id = task_context.event.error_task_id
|
|
1139
1188
|
|
|
1140
1189
|
verification = task_context.metadata.get("verification")
|
|
1190
|
+
effective_verification = _verification_with_observed_fix_proof(
|
|
1191
|
+
verification if isinstance(verification, dict) else None,
|
|
1192
|
+
context,
|
|
1193
|
+
)
|
|
1141
1194
|
# Red-before-fix invariant: ResolveNode refuses to mark resolved
|
|
1142
1195
|
# unless BuildObservability persisted observable=True at intake.
|
|
1143
1196
|
# Closes the "already-green-at-intake" leak — a green-gate True with
|
|
@@ -1147,14 +1200,14 @@ class ResolveNode(Node):
|
|
|
1147
1200
|
if isinstance(bo, dict):
|
|
1148
1201
|
bo_out = bo.get("output") if isinstance(bo.get("output"), dict) else {}
|
|
1149
1202
|
observation_was_red = bool(bo_out.get("observable"))
|
|
1150
|
-
green_gate = bool((
|
|
1203
|
+
green_gate = bool((effective_verification or {}).get("green_gate"))
|
|
1151
1204
|
proof_verified = True
|
|
1152
1205
|
fix_proof: dict[str, Any] | None = None
|
|
1153
1206
|
proof_failure_reason: str | None = None
|
|
1154
1207
|
if _ui_proof_required(context):
|
|
1155
1208
|
proof_verified, fix_proof, proof_failure_reason = _validate_ui_fix_proof(
|
|
1156
1209
|
repo_root=persistor.repo_root,
|
|
1157
|
-
verification=
|
|
1210
|
+
verification=effective_verification if isinstance(effective_verification, dict) else None,
|
|
1158
1211
|
)
|
|
1159
1212
|
verified = green_gate and observation_was_red and proof_verified
|
|
1160
1213
|
runtime_context = context.get("runtimeContext") if isinstance(context.get("runtimeContext"), dict) else None
|
|
@@ -1165,13 +1218,13 @@ class ResolveNode(Node):
|
|
|
1165
1218
|
fingerprint = runtime_context.get("fingerprint") or current_record.get("fingerprint")
|
|
1166
1219
|
title = context.get("metadata", {}).get("title") if isinstance(context.get("metadata"), dict) else None
|
|
1167
1220
|
|
|
1168
|
-
resolve_output: dict[str, Any] = {"verification":
|
|
1221
|
+
resolve_output: dict[str, Any] = {"verification": effective_verification, "verified": verified}
|
|
1169
1222
|
if proof_failure_reason:
|
|
1170
1223
|
resolve_output["proof_failure_reason"] = proof_failure_reason
|
|
1171
1224
|
if fix_proof:
|
|
1172
1225
|
resolve_output["fix_proof"] = fix_proof
|
|
1173
1226
|
persistor.persist(context=context, node_name="Resolve", output=resolve_output)
|
|
1174
|
-
self.save_output(ResolveNode.OutputType(verified=verified, verification=
|
|
1227
|
+
self.save_output(ResolveNode.OutputType(verified=verified, verification=effective_verification))
|
|
1175
1228
|
|
|
1176
1229
|
if verified:
|
|
1177
1230
|
if fix_proof:
|
|
@@ -1185,7 +1238,7 @@ class ResolveNode(Node):
|
|
|
1185
1238
|
persistor.repo_root,
|
|
1186
1239
|
error_task_id=error_task_id,
|
|
1187
1240
|
title=str(title) if title is not None else None,
|
|
1188
|
-
verification=
|
|
1241
|
+
verification=effective_verification if isinstance(effective_verification, dict) else None,
|
|
1189
1242
|
)
|
|
1190
1243
|
task_context.metadata["commit_result"] = commit_result
|
|
1191
1244
|
# v1.1.19: persist resolution_commit_sha + portal_token so the
|
|
@@ -1228,7 +1281,7 @@ class ResolveNode(Node):
|
|
|
1228
1281
|
outcome=str(task_context.metadata.get("outcome") or "in_progress"),
|
|
1229
1282
|
title=str(title) if title is not None else None,
|
|
1230
1283
|
fingerprint=str(fingerprint) if fingerprint is not None else None,
|
|
1231
|
-
verification=
|
|
1284
|
+
verification=effective_verification if isinstance(effective_verification, dict) else None,
|
|
1232
1285
|
reason=str(task_context.metadata.get("reason")) if task_context.metadata.get("reason") else None,
|
|
1233
1286
|
context_path=persistor.context_path,
|
|
1234
1287
|
runtime_context=runtime_context,
|
|
@@ -32,7 +32,7 @@ devflow_engine/devin2/agent_definition.py,sha256=pCp915tojwPlepRpvjlU1DoPuT_anxR
|
|
|
32
32
|
devflow_engine/devin2/pi_runner.py,sha256=xRl-qA3RgMFgiR5fnG6fTwwL95PMk6zVdRdFa-fXy2E,7466
|
|
33
33
|
devflow_engine/error/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
34
34
|
devflow_engine/error/remediation.py,sha256=Z4LJQzZPzb7_6tea_XtasDvFYQiEdpkFlyxoCEO1I2k,548
|
|
35
|
-
devflow_engine/errors/error_solver_dag.py,sha256=
|
|
35
|
+
devflow_engine/errors/error_solver_dag.py,sha256=GZXVqssgqUgoqRqA5r7_fnz7noZVKD-g3NS5r0ShBms,60195
|
|
36
36
|
devflow_engine/errors/question_classifier.py,sha256=oBJ29hszG--TUna62BQHnNmi6hPwf-wEE8eGLmgS624,9729
|
|
37
37
|
devflow_engine/errors/repo_quality_judge.py,sha256=LVBaXN6AsID-x8qb-IriQKYY1c9AMMRNo-tWMeiuMaA,9962
|
|
38
38
|
devflow_engine/errors/runtime_observability.py,sha256=Do93Ah3vxLEocYtC0JpnRIRQN6uNAOkYjBz0pmOqg5g,29719
|
|
@@ -382,7 +382,7 @@ devflow_engine/prompts/source_doc_mutation/source_doc_enrichment_coherence/promp
|
|
|
382
382
|
devflow_engine/prompts/source_doc_mutation/user_workflows/prompt.md,sha256=2Bv-EkZwzxtPSsDGdw9YuuuzT1c_2R9c6HPSMdP-MD0,406
|
|
383
383
|
devflow_engine/prompts/source_scope/doctrine/prompt.md,sha256=AJk1gfePTdaBSw5DHvCr7Sigsk2orGaRVNZ3Dj3NdcQ,837
|
|
384
384
|
devflow_engine/prompts/ui_grounding/doctrine/prompt.md,sha256=0L5y-QjjquPABqxAHZNPkcjyHMZQSDRVncNDQa2app0,409
|
|
385
|
-
devflow_engine-1.2.
|
|
386
|
-
devflow_engine-1.2.
|
|
387
|
-
devflow_engine-1.2.
|
|
388
|
-
devflow_engine-1.2.
|
|
385
|
+
devflow_engine-1.2.3.dist-info/METADATA,sha256=spmTNfOipkpqYWkJx_uOVJjLtfYG_ZZ9PBs6aOWSjDM,7755
|
|
386
|
+
devflow_engine-1.2.3.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
387
|
+
devflow_engine-1.2.3.dist-info/entry_points.txt,sha256=U5Pw4y4v4u4xcRS5DbXfemBg0RKp74kMxcnEoL0MACY,99
|
|
388
|
+
devflow_engine-1.2.3.dist-info/RECORD,,
|
|
File without changes
|