fix: chain T029a profile migrations

This commit is contained in:
2026-09-29 20:52:39 +03:00
parent 1b6edaf701
commit 1a3d3958ea
3 changed files with 12 additions and 1 deletions

View File

@@ -6,7 +6,7 @@ from alembic import op
import sqlalchemy as sa
revision = "0028_durable_test_pack_profiles"
down_revision = "0027_schedule_baseline"
down_revision = "0028_profile_eligibility_receipt"
branch_labels = None
depends_on = None

View File

@@ -291,6 +291,8 @@ def create_initial(db: Session, *, intent, user_id: str, owner_username: str | N
"""Create the initial chain; caller commits workspace and transaction together."""
# T029f: the MCP bootstrap accepts ONLY server-issued stored handles. The legacy
# caller-composed `compile:{run_id}:{digest}` string and raw DraftArtifact path are rejected.
if intent.selected_environment_id not in intent.allowed_environment_ids:
raise ValueError("SELECTED_ENVIRONMENT_NOT_ALLOWED")
if db.get(DraftPackHandle, intent.draft_pack_id) is None:
raise ValueError("HANDLE_NOT_FOUND")
compiled = db.get(CompiledScenarioHandle, intent.compiled_handle_id)
@@ -303,6 +305,7 @@ def create_initial(db: Session, *, intent, user_id: str, owner_username: str | N
user_id=user_id, owner_username=owner_username,
expected_environment_id=intent.selected_environment_id,
expected_case_ids=list(intent.selected_case_ids),
require_receipt=True,
)
entry.name = intent.title
entry.description = intent.objective

View File

@@ -45,6 +45,8 @@ HANDLE_CONSUMED = "HANDLE_CONSUMED"
HANDLE_BYTES_MISSING = "HANDLE_BYTES_MISSING"
HANDLE_VALIDATION_MISSING = "HANDLE_VALIDATION_MISSING"
HANDLE_VALIDATION_INVALID = "HANDLE_VALIDATION_INVALID"
HANDLE_RECEIPT_MISSING = "HANDLE_RECEIPT_MISSING"
HANDLE_RECEIPT_MISMATCH = "HANDLE_RECEIPT_MISMATCH"
# #region ScenarioGraph.Handles.BlobStore [C:4] [TYPE Class] [SEMANTICS scenario,handles,storage,canonical]
@@ -347,6 +349,7 @@ def verify_handle_chain(
dashboard_id: int,
expected_environment_id: str | None = None,
expected_case_ids: list[str] | None = None,
require_receipt: bool = False,
) -> dict[str, Any]:
# SELECT ... FOR UPDATE serializes concurrent consumers on the handle rows, so two
# create/save transactions can never both observe an unconsumed handle and double-consume.
@@ -377,6 +380,11 @@ def verify_handle_chain(
raise ValueError(HANDLE_CONSUMED)
if pack.compiled_handle_id != compiled.handle_id:
raise ValueError(HANDLE_CROSS_BINDING)
if require_receipt:
if not compiled.agent_run_id or not pack.agent_run_id:
raise ValueError(HANDLE_RECEIPT_MISSING)
if compiled.agent_run_id != pack.agent_run_id:
raise ValueError(HANDLE_RECEIPT_MISMATCH)
if pack.digest != draft_pack_digest:
raise ValueError(HANDLE_DIGEST_MISMATCH)
if pack.status != "save_eligible":