优化流程
This commit is contained in:
@@ -153,6 +153,7 @@ class ProfileCadRuntime:
|
||||
fragment,
|
||||
selector_tokens=allowed_selectors,
|
||||
reference_tokens=list(reference_tokens),
|
||||
root_xy_datum=not bool((base_cdsl or {}).get("features")),
|
||||
)
|
||||
if errors:
|
||||
raise RuntimeAdapterError(
|
||||
@@ -262,6 +263,73 @@ class ProfileCadRuntime:
|
||||
except Exception as error:
|
||||
raise RuntimeAdapterError(f"RUNTIME_EXECUTION_FAILURE: {error}") from error
|
||||
|
||||
def rebuild_best_effort(
|
||||
self,
|
||||
cdsl: dict[str, Any],
|
||||
output_dir: str,
|
||||
task_id: str,
|
||||
revision_id: str,
|
||||
) -> tuple[dict[str, Any], list[dict[str, Any]]]:
|
||||
"""Build independent feature prefixes without discarding prior geometry.
|
||||
|
||||
A full CDSL document can contain several features even though the
|
||||
action protocol normally appends one at a time. Engine validation is
|
||||
all-or-nothing, so replay features in source order and retain each
|
||||
executable feature. A failed feature is reported as a diagnostic;
|
||||
it does not erase already executable geometry or prevent later,
|
||||
independent features from being tried.
|
||||
"""
|
||||
features = cdsl.get("features") if isinstance(cdsl.get("features"), list) else []
|
||||
accepted: list[dict[str, Any]] = []
|
||||
accepted_ids: set[str] = set()
|
||||
failures: list[dict[str, Any]] = []
|
||||
latest: dict[str, Any] | None = None
|
||||
for index, feature in enumerate(features):
|
||||
if not isinstance(feature, dict):
|
||||
failures.append({"feature_index": index, "feature_id": "", "message": "Feature must be an object."})
|
||||
continue
|
||||
feature_id = str(feature.get("id") or f"feature_{index + 1:03d}")
|
||||
dependencies = [str(value) for value in feature.get("depends_on") or () if isinstance(value, str)]
|
||||
unavailable = [value for value in dependencies if value not in accepted_ids]
|
||||
if unavailable:
|
||||
failures.append({
|
||||
"feature_index": index,
|
||||
"feature_id": feature_id,
|
||||
"message": "Feature was skipped because an earlier dependency did not execute.",
|
||||
"dependencies": unavailable,
|
||||
})
|
||||
continue
|
||||
candidate = self._feature_subset(cdsl, [*accepted, feature])
|
||||
try:
|
||||
latest = self.rebuild(candidate, output_dir, task_id, revision_id)
|
||||
except Exception as error:
|
||||
failures.append({"feature_index": index, "feature_id": feature_id, "message": str(error)[:1000]})
|
||||
continue
|
||||
accepted.append(deepcopy(feature))
|
||||
accepted_ids.add(feature_id)
|
||||
if not accepted:
|
||||
if failures:
|
||||
raise RuntimeAdapterError(str(failures[0].get("message") or "RUNTIME_EXECUTION_FAILURE: no feature could be rebuilt"))
|
||||
raise RuntimeAdapterError("RUNTIME_EXECUTION_FAILURE: CDSL document has no executable features")
|
||||
# A failed later attempt may have left partial files in the stage.
|
||||
# Rebuild the retained feature set once so all published artifacts are
|
||||
# guaranteed to describe the same successful checkpoint.
|
||||
latest = self.rebuild(self._feature_subset(cdsl, accepted), output_dir, task_id, revision_id)
|
||||
return {**latest, "executed_feature_ids": sorted(accepted_ids)}, failures
|
||||
|
||||
@staticmethod
|
||||
def _feature_subset(cdsl: dict[str, Any], features: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
document = deepcopy(cdsl)
|
||||
document["features"] = deepcopy(features)
|
||||
geometry = document.get("geometry") if isinstance(document.get("geometry"), dict) else {}
|
||||
sketches = geometry.get("sketches") if isinstance(geometry.get("sketches"), list) else []
|
||||
sketch_ids = {str(feature.get("sketch_id") or "") for feature in features}
|
||||
document["geometry"] = {
|
||||
**geometry,
|
||||
"sketches": [deepcopy(sketch) for sketch in sketches if isinstance(sketch, dict) and str(sketch.get("id") or "") in sketch_ids],
|
||||
}
|
||||
return document
|
||||
|
||||
def _semantic_preflight(self, fragment: dict[str, Any], contract: dict[str, Any], selector_tokens: dict[str, dict[str, Any]], base_cdsl: dict[str, Any] | None, *, require_through: bool) -> None:
|
||||
if fragment.get("feature", {}).get("atomic_id") != contract.get("atomic_id"):
|
||||
raise RuntimeAdapterError("RUNTIME_PRECONDITION_FAILED: atomic_id does not match active contract")
|
||||
|
||||
@@ -19,6 +19,7 @@ class SqliteTaskRepository:
|
||||
self.database_path = database_path
|
||||
self.database_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
self._lock = RLock()
|
||||
self.protocol_reset = False
|
||||
self._initialize()
|
||||
|
||||
@contextmanager
|
||||
@@ -34,11 +35,27 @@ class SqliteTaskRepository:
|
||||
|
||||
def _initialize(self) -> None:
|
||||
with self._lock, self._connection() as connection:
|
||||
# Protocol 3.1 intentionally has no migration path from the
|
||||
# structured-only / review-loop task model. Deployment starts with
|
||||
# an empty task database, as those tasks do not have immutable
|
||||
# Markdown source artifacts to compile from.
|
||||
existing = connection.execute("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'tasks'").fetchone()
|
||||
if existing is not None and "'3.1'" not in str(existing[0] or ""):
|
||||
self.protocol_reset = True
|
||||
connection.executescript("""
|
||||
DROP TABLE IF EXISTS outbox;
|
||||
DROP TABLE IF EXISTS tool_audits;
|
||||
DROP TABLE IF EXISTS usage_records;
|
||||
DROP TABLE IF EXISTS invocations;
|
||||
DROP TABLE IF EXISTS ledger;
|
||||
DROP TABLE IF EXISTS model_capabilities;
|
||||
DROP TABLE IF EXISTS tasks;
|
||||
""")
|
||||
connection.executescript(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS tasks (
|
||||
task_id TEXT PRIMARY KEY,
|
||||
protocol_version TEXT NOT NULL CHECK(protocol_version = '3.0'),
|
||||
protocol_version TEXT NOT NULL CHECK(protocol_version = '3.1'),
|
||||
request TEXT NOT NULL,
|
||||
phase TEXT NOT NULL,
|
||||
state_version INTEGER NOT NULL,
|
||||
@@ -50,6 +67,9 @@ class SqliteTaskRepository:
|
||||
last_error TEXT,
|
||||
retry_from_phase TEXT NOT NULL DEFAULT '',
|
||||
requirements_spec_path TEXT NOT NULL DEFAULT '',
|
||||
requirements_document_path TEXT NOT NULL DEFAULT '',
|
||||
completion_target_path TEXT NOT NULL DEFAULT '',
|
||||
modeling_plan_path TEXT NOT NULL DEFAULT '',
|
||||
clarification_path TEXT NOT NULL DEFAULT '',
|
||||
requirements_contract_path TEXT NOT NULL DEFAULT '',
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -104,8 +124,8 @@ class SqliteTaskRepository:
|
||||
def create_task(self, task_id: str, request: str) -> TaskState:
|
||||
with self._lock, self._connection() as connection:
|
||||
connection.execute(
|
||||
"INSERT OR IGNORE INTO tasks(task_id, protocol_version, request, phase, state_version) VALUES (?, '3.0', ?, ?, 0)",
|
||||
(task_id, request, TaskPhase.DRAFTING_REQUIREMENTS.value),
|
||||
"INSERT OR IGNORE INTO tasks(task_id, protocol_version, request, phase, state_version) VALUES (?, '3.1', ?, ?, 0)",
|
||||
(task_id, request, TaskPhase.DRAFTING_REQUIREMENTS_DOCUMENT.value),
|
||||
)
|
||||
state = self.get_state(task_id)
|
||||
if state is None:
|
||||
@@ -130,7 +150,7 @@ class SqliteTaskRepository:
|
||||
for item in events
|
||||
if item.get("event") == "accepted" and isinstance(item.get("revision_id"), str)
|
||||
]
|
||||
frozen = next((item for item in reversed(events) if item.get("event") == "requirements_contract_frozen"), {})
|
||||
frozen = next((item for item in reversed(events) if item.get("event") == "requirements_compiled"), {})
|
||||
verification_warnings = [
|
||||
str(item) for item in frozen.get("verification_warnings") or () if str(item)
|
||||
] if isinstance(frozen, dict) else []
|
||||
@@ -141,12 +161,13 @@ class SqliteTaskRepository:
|
||||
"no_progress_limit",
|
||||
"candidate_runtime_execution_failure", "candidate_recovery_runtime_execution_failure",
|
||||
"failed_author_format", "runtime_contract_invalid",
|
||||
"completed_best_effort",
|
||||
}
|
||||
), {}) if state.phase in {TaskPhase.FAILED, TaskPhase.WAITING_RETRY, TaskPhase.WAITING_FOR_USER} else {}
|
||||
), {}) if state.phase in {TaskPhase.COMPLETED, TaskPhase.FAILED, TaskPhase.WAITING_RETRY, TaskPhase.WAITING_FOR_USER} else {}
|
||||
questions = [str(item) for item in status_event.get("questions") or () if str(item)] if isinstance(status_event, dict) else []
|
||||
issues = [str(item) for item in status_event.get("issues") or () if str(item)] if isinstance(status_event, dict) else []
|
||||
return {
|
||||
"schema_version": "3.0",
|
||||
"schema_version": "3.1",
|
||||
"task_id": state.task_id,
|
||||
"phase": state.phase.value,
|
||||
"lifecycle": self._lifecycle(state.phase),
|
||||
@@ -160,10 +181,13 @@ class SqliteTaskRepository:
|
||||
"last_error": state.last_error.value if state.last_error else "",
|
||||
"retry_from_phase": state.retry_from_phase.value if state.retry_from_phase else "",
|
||||
"requirements_spec_path": state.requirements_spec_path,
|
||||
"requirements_document_path": state.requirements_document_path,
|
||||
"completion_target_path": state.completion_target_path,
|
||||
"modeling_plan_path": state.modeling_plan_path,
|
||||
"clarification_path": state.clarification_path,
|
||||
"requirements_contract_path": state.requirements_contract_path,
|
||||
"verification_status": (
|
||||
"completed_with_risks" if state.phase == TaskPhase.COMPLETED and verification_warnings
|
||||
"completed_with_risks" if state.phase == TaskPhase.COMPLETED and (verification_warnings or state.last_error == ErrorCode.BEST_EFFORT_COMPLETED)
|
||||
else "verified" if state.phase == TaskPhase.COMPLETED
|
||||
else "pending"
|
||||
),
|
||||
@@ -219,7 +243,7 @@ class SqliteTaskRepository:
|
||||
cursor = connection.execute(
|
||||
"""UPDATE tasks SET phase = ?, state_version = ?, active_revision = ?, pending_action_json = ?,
|
||||
candidate_id = ?, candidate_stage_id = ?, repair_required = ?, last_error = ?, retry_from_phase = ?, requirements_spec_path = ?,
|
||||
clarification_path = ?, requirements_contract_path = ?, updated_at = CURRENT_TIMESTAMP
|
||||
requirements_document_path = ?, completion_target_path = ?, modeling_plan_path = ?, clarification_path = ?, requirements_contract_path = ?, updated_at = CURRENT_TIMESTAMP
|
||||
WHERE task_id = ? AND state_version = ?""",
|
||||
(
|
||||
state.phase.value, state.version, state.active_revision,
|
||||
@@ -227,6 +251,7 @@ class SqliteTaskRepository:
|
||||
state.candidate_id, state.candidate_stage_id,
|
||||
int(state.repair_required), state.last_error.value if state.last_error else None,
|
||||
state.retry_from_phase.value if state.retry_from_phase else "", state.requirements_spec_path,
|
||||
state.requirements_document_path, state.completion_target_path, state.modeling_plan_path,
|
||||
state.clarification_path, state.requirements_contract_path,
|
||||
state.task_id, previous_version,
|
||||
),
|
||||
@@ -377,6 +402,9 @@ class SqliteTaskRepository:
|
||||
last_error=ErrorCode(str(row["last_error"])) if row["last_error"] else None,
|
||||
retry_from_phase=TaskPhase(str(row["retry_from_phase"])) if row["retry_from_phase"] else None,
|
||||
requirements_spec_path=str(row["requirements_spec_path"] or ""),
|
||||
requirements_document_path=str(row["requirements_document_path"] or ""),
|
||||
completion_target_path=str(row["completion_target_path"] or ""),
|
||||
modeling_plan_path=str(row["modeling_plan_path"] or ""),
|
||||
clarification_path=str(row["clarification_path"] or ""),
|
||||
requirements_contract_path=str(row["requirements_contract_path"] or ""),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user