Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/generate_spreadsheet_programme_workflow_seed.py
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ def build_bundle() -> dict[str, object]:
return {
"family_id": "spreadsheet_programme_representation_workflow_seed_bundle",
"schema_version": "repo_seed_workflow_bundle.v1",
"seed_version": "14",
"seed_version": "15",
"source_tag": "JVNAUTOSCI-2592",
"managed_by": "spreadsheet_programme_workflow_vontology_service",
"processing_authority_fingerprint": authority_fingerprint,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"family_id": "#V#kr_design_materialisation_workflow_family",
"managed_by": "kr_materialisation_workflow_vontology_service",
"schema_version": "repo_seed_workflow_bundle.v1",
"seed_version": "JVNAUTOSCI-2592-write-guard-v1",
"seed_version": "2",
"source_tag": "JVNAUTOSCI-2271",
"supported_action_ids": [
"llm.action",
Expand Down Expand Up @@ -201,15 +201,13 @@
},
{
"key": "kr_concept_id",
"skip_if_unresolved": true,
"value_from_context_options": [
"current_kr_concept_spec.existing_concept_id",
"current_kr_concept_spec.concept_id"
]
},
{
"key": "kr_concept_create_concepts",
"skip_if_unresolved": true,
"value_from_context": "current_kr_concept_spec.concepts"
},
{
Expand All @@ -221,12 +219,10 @@
},
{
"key": "kr_concept_parent_rationale",
"skip_if_unresolved": true,
"value_from_context": "current_kr_concept_spec.parent_rationale"
},
{
"key": "kr_concept_blocking_reason",
"skip_if_unresolved": true,
"value_from_context": "current_kr_concept_spec.blocking_reason"
}
]
Expand Down Expand Up @@ -1055,7 +1051,6 @@
[
{
"key": "kr_relationship_key",
"skip_if_unresolved": true,
"value_from_context_options": [
"current_kr_relationship_spec.key",
"current_kr_relationship_spec.relationship_key"
Expand All @@ -1075,12 +1070,10 @@
},
{
"key": "kr_relationship_rationale",
"skip_if_unresolved": true,
"value_from_context": "current_kr_relationship_spec.rationale"
},
{
"key": "kr_relationship_blocking_reason",
"skip_if_unresolved": true,
"value_from_context": "current_kr_relationship_spec.blocking_reason"
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
"managed_by": "spreadsheet_programme_workflow_vontology_service",
"processing_authority_dependencies": {
"kr_materialisation_workflow_seed_bundle": {
"canonical_payload_sha256": "sha256:25b49e8f2585139ca51a46914f7e34a373320e99a4c5b8e3c7abfde639ea61f4",
"canonical_payload_sha256": "sha256:ce53d8c2ba252fb1b251f778444a797cb4c436fc2bbb94fa50391b5c7a1307f6",
"family_id": "#V#kr_design_materialisation_workflow_family",
"seed_version": "JVNAUTOSCI-2592-write-guard-v1"
"seed_version": "2"
}
},
"processing_authority_fingerprint": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac",
"processing_authority_fingerprint": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87",
"schema_version": "repo_seed_workflow_bundle.v1",
"seed_version": "14",
"seed_version": "15",
"source_tag": "JVNAUTOSCI-2592",
"support_concepts": [
{
Expand Down Expand Up @@ -306,7 +306,7 @@
},
{
"key": "processing_authority_fingerprint",
"value": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac"
"value": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87"
}
],
"tool_output_mapping_specs": [
Expand Down Expand Up @@ -702,7 +702,7 @@
},
{
"key": "processing_authority_fingerprint",
"value": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac"
"value": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87"
}
],
"tool_output_mapping_specs": [
Expand Down Expand Up @@ -776,7 +776,7 @@
},
{
"key": "processing_authority_fingerprint",
"value": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac"
"value": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87"
}
],
"tool_output_mapping_specs": [
Expand Down Expand Up @@ -1234,7 +1234,7 @@
},
{
"key": "processing_authority_fingerprint",
"value": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac"
"value": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87"
}
],
"tool_output_mapping_specs": [
Expand Down Expand Up @@ -1557,7 +1557,7 @@
},
{
"key": "processing_authority_fingerprint",
"value": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac"
"value": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87"
}
],
"tool_output_mapping_specs": [
Expand Down Expand Up @@ -1625,7 +1625,7 @@
},
{
"key": "processing_authority_fingerprint",
"value": "sha256:a9e37d52c2f4d842cdf15793c08a6f0ddaa25c764fcccb21902a14bf2c6bc1ac"
"value": "sha256:62aaed4941a0e0dbb16d5c4bd6c2fc8b09ff34f1e905c561c40004c04d840c87"
}
],
"tool_output_mapping_specs": [
Expand Down
133 changes: 133 additions & 0 deletions tests/backend/test_kr_materialisation_workflow_vontology_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@

from scripts import publish_kr_materialisation_workflows as publish_cli
from src.backend.services import kr_materialisation_workflow_vontology_service as mod
from src.backend.workflows.action_registry import (
ActionRegistry,
WorkflowEnvironment,
)
from src.backend.workflows.durable.control_flow_actions import (
register_control_flow_actions,
)
from src.backend.workflows.execution_contracts import (
WORKFLOW_CONTROL_ACTION_CONTEXT_SET_ID,
)
from src.backend.workflows.metadata_validation import (
validate_state_metadata_post_action,
)

_PROJECT_ROOT = Path(__file__).resolve().parents[2]
_SEED_BUNDLE_PATH = (
Expand Down Expand Up @@ -47,6 +60,58 @@ def _iter_publication_steps(bundle: Mapping[str, Any]) -> Iterator[Mapping[str,
yield step


def _publication_step(
bundle: Mapping[str, Any],
*,
workflow_id: str,
state_id: str,
) -> Mapping[str, Any]:
workflow = next(
row
for row in bundle.get("workflows") or []
if isinstance(row, Mapping) and row.get("workflow_id") == workflow_id
)
publication_spec = workflow.get("publication_spec")
assert isinstance(publication_spec, Mapping)
return next(
row
for row in publication_spec.get("steps") or []
if isinstance(row, Mapping) and row.get("state_id") == state_id
)

Comment on lines +69 to +81

def _validate_context_set_writes(
*,
step: Mapping[str, Any],
context: dict[str, Any],
) -> dict[str, Any]:
bindings = dict(step.get("static_input_bindings") or [])
assignments = bindings.get("assignments")
assert isinstance(assignments, list)
registry = ActionRegistry()
register_control_flow_actions(
registry,
definition_loader=lambda _workflow_id: None,
)
context_before = dict(context)
result = registry.execute(
WORKFLOW_CONTROL_ACTION_CONTEXT_SET_ID,
inputs={"assignments": assignments},
context=context,
env=WorkflowEnvironment(llm_client=None),
)
assert result.status == "success"
context.update(result.outputs)
validation = validate_state_metadata_post_action(
state_id=str(step.get("state_id") or ""),
metadata={"writes_context_keys": step.get("writes_context_keys") or []},
context_before=context_before,
context_after=context,
)
assert validation.ok is True
return context


def test_kr_seed_bundle_uses_prompt_concepts_not_inline_prompt_text() -> None:
bundle = json.loads(_SEED_BUNDLE_PATH.read_text(encoding="utf-8"))
rendered_bundle = json.dumps(bundle, sort_keys=True)
Expand Down Expand Up @@ -145,6 +210,74 @@ def test_kr_seed_bundle_validates_as_workflow_contracts() -> None:
assert validation["valid"] is True


def test_kr_optional_initialiser_fields_satisfy_enforced_write_metadata() -> None:
bundle = json.loads(_SEED_BUNDLE_PATH.read_text(encoding="utf-8"))
concept_step = _publication_step(
bundle,
workflow_id=mod.KR_DESIGN_CONCEPT_MATERIALISATION_ITEM_WORKFLOW_ID,
state_id="initialise_from_concept_spec",
)
relationship_step = _publication_step(
bundle,
workflow_id=mod.KR_DESIGN_RELATIONSHIP_ASSERTION_ITEM_WORKFLOW_ID,
state_id="initialise_from_relationship_spec",
)

reuse_context = _validate_context_set_writes(
step=concept_step,
context={
"current_kr_concept_spec": {
"key": "candidate",
"decision": "reuse_existing",
"target_name": "Stable candidate",
"target_kind": "instance",
"parent_id": "#V#doctoral_candidate",
"existing_concept_id": "#V#stable_candidate",
"description_text": "Bounded provenance-bearing candidate.",
}
},
)
assert reuse_context["kr_concept_create_concepts"] is None
assert reuse_context["kr_concept_parent_rationale"] is None
assert reuse_context["kr_concept_blocking_reason"] is None

create_context = _validate_context_set_writes(
step=concept_step,
context={
"current_kr_concept_spec": {
"key": "candidate",
"decision": "create",
"target_name": "Stable candidate",
"target_kind": "instance",
"parent_id": "#V#doctoral_candidate",
"concepts": [
{
"name": "Stable candidate",
"kind": "instance",
"description": "Bounded provenance-bearing candidate.",
}
],
"description_text": "Bounded provenance-bearing candidate.",
}
},
)
assert create_context["kr_concept_id"] is None

relationship_context = _validate_context_set_writes(
step=relationship_step,
context={
"current_kr_relationship_spec": {
"source_id": "#V#stable_candidate",
"predicate": "#V#has_doctoral_programme",
"target_id": "#V#stable_programme",
}
},
)
assert relationship_context["kr_relationship_key"] is None
assert relationship_context["kr_relationship_rationale"] is None
assert relationship_context["kr_relationship_blocking_reason"] is None


def test_publish_script_validate_all_uses_seed_bundle(capsys) -> None:
exit_code = publish_cli.main(["validate-all"])
output = capsys.readouterr().out
Expand Down
Loading