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 apps/backend/engram/console/model_presets_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def test_openai_chat_policies_ship_the_reasoning_request_shape() -> None:
shape = _task_model(PRESET_BY_KEY[key], task_type)['metadata']['request_shape']
assert shape['completion_tokens_param'] == 'max_completion_tokens'
assert shape['temperature'] is None
assert shape['reasoning_effort']['curation_decision_v1'] == 'minimal'
assert shape['reasoning_effort']['curation_decision_v2'] == 'minimal'


def test_only_the_flex_preset_requests_the_flex_tier() -> None:
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/engram/console/views/model_setup_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,7 @@ def test_apply_openai_all_persists_the_reasoning_request_shape(
assert curation.model == 'gpt-5-mini'
assert curation.metadata['request_shape']['completion_tokens_param'] == 'max_completion_tokens'
assert curation.metadata['request_shape']['temperature'] is None
assert curation.metadata['request_shape']['reasoning_effort']['curation_decision_v1'] == 'minimal'
assert curation.metadata['request_shape']['reasoning_effort']['curation_decision_v2'] == 'minimal'
assert 'service_tier' not in curation.metadata

embedding = ModelPolicy.objects.get(organization=f_setup_org, task_type='embedding', active=True)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,15 @@ def test_threshold_miss_exits_nonzero(tmp_path: Path) -> None:
target = next(
case for case in cases if case['bucket'] == 'equivalent_merge' and case['scope_control'] == 'in_scope'
)
entry = target['input']['shortlist']['entries'][0]
lines: list[str] = []
for case in cases:
if case['gate'] != 'semantic' or case['fixture_verdict'] is None or case['bucket'] == 'provider_fault':
continue
verdict = case['fixture_verdict']
if case['case_id'] == target['case_id']:
verdict = {
'schema_version': 1,
'outcome': 'open_conflict',
'relation': 'mutually_incompatible',
'target_memory_version_id': entry['memory_version_id'],
'candidate_evidence_refs': list(target['input']['candidate']['evidence_refs']),
'comparisons': [
{
'memory_version_id': entry['memory_version_id'],
'relation': 'mutually_incompatible',
'target_evidence_refs': list(entry['evidence_refs']),
}
],
'applicability': 'same',
'temporal_order': 'unordered',
'reason_code': 'same_scope_contradiction',
'schema_version': 2,
'comparisons': [{'index': 1, 'relation': 'mutually_incompatible', 'applicability': 'same'}],
'reason': 'injected incompatible verdict',
}
lines.append(json.dumps({'case_id': case['case_id'], 'verdict': verdict}))
Expand Down
21 changes: 10 additions & 11 deletions apps/backend/engram/memory/c53_orchestrator_test_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
from engram.memory.curation_judge import (
ClaimEvidence,
CurationEvidenceContext,
CurationJudgeComparisonV1,
CurationJudgeComparison,
CurationJudgeResult,
CurationJudgeVerdictV1,
CurationJudgeVerdict,
)
from engram.memory.curation_shortlist import CurationShortlist, CurationShortlistEntry
from engram.memory.distillation_provenance import session_candidate_content_hash
Expand Down Expand Up @@ -230,38 +230,37 @@ def stub_evidence(


_OUTCOME_TABLE = {
'publish_new': ('unrelated', 'distinct_claim', 'different', 'not_applicable'),
'publish_new': ('unrelated', 'distinct_claim', 'not_applicable', 'not_applicable'),
'merge_evidence': ('equivalent', 'equivalent_claim', 'same', 'not_applicable'),
'revise_memory': ('candidate_revises', 'same_subject_revision', 'same', 'candidate_newer'),
'supersede_memory': ('candidate_supersedes', 'ordered_replacement', 'same', 'candidate_newer'),
'open_conflict': ('mutually_incompatible', 'same_scope_contradiction', 'same', 'unordered'),
}


def stub_verdict(outcome: str, *, target: MemoryVersion | None = None) -> CurationJudgeVerdictV1:
def stub_verdict(outcome: str, *, target: MemoryVersion | None = None) -> CurationJudgeVerdict:
relation, reason_code, applicability, temporal = _OUTCOME_TABLE[outcome]
comparisons: tuple[CurationJudgeComparisonV1, ...] = ()
comparisons: tuple[CurationJudgeComparison, ...] = ()
target_id = None
if target is not None:
target_id = target.id
comparisons = (CurationJudgeComparisonV1(target.id, relation, ('tref-1',)),)
comparisons = (CurationJudgeComparison(target.id, relation, applicability),)

return CurationJudgeVerdictV1(
schema_version=1,
return CurationJudgeVerdict(
schema_version=2,
outcome=outcome,
relation=relation,
target_memory_version_id=target_id,
candidate_evidence_refs=('cref-1',),
comparisons=comparisons,
applicability=applicability,
temporal_order=temporal,
reason_code=reason_code,
reason='decision under contract v1',
reason='decision under contract v2',
)


def stub_judge_result(
verdict: CurationJudgeVerdictV1,
verdict: CurationJudgeVerdict,
call_record: ProviderCallRecord,
policy: ModelPolicy,
shortlist: CurationShortlist,
Expand Down
12 changes: 8 additions & 4 deletions apps/backend/engram/memory/curation_derivation.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class DerivedDecision:
relation: str
target_memory_version_id: UUID | None
temporal_order: str
applicability: str
reason_code: str
rung: int
suppressed_identity_relations: tuple[tuple[UUID, str], ...]
Expand Down Expand Up @@ -160,14 +161,14 @@ def feasible_outcomes(facts: DerivationFacts) -> frozenset[str]:
def _select_target(
facts: DerivationFacts,
relations: dict[UUID, str],
applicability: str,
applicability: dict[UUID, str],
) -> tuple[int, str, str, TargetFacts] | None:
for rung, outcome, relation, eligible, requires_same in _LADDER:
if requires_same and applicability != 'same':
continue
for target in facts.targets:
if relations.get(target.memory_version_id) != relation:
continue
if requires_same and applicability.get(target.memory_version_id) != 'same':
continue
if eligible(facts, target):
return rung, outcome, relation, target

Expand Down Expand Up @@ -196,7 +197,7 @@ def _suppressed(
def derive_decision(
facts: DerivationFacts,
relations: dict[UUID, str],
applicability: str,
applicability: dict[UUID, str],
) -> DerivedDecision | None:
selected = _select_target(facts, relations, applicability)
if selected is not None:
Expand All @@ -207,6 +208,7 @@ def derive_decision(
relation=relation,
target_memory_version_id=target.memory_version_id,
temporal_order=target.temporal_order,
applicability=applicability.get(target.memory_version_id, 'not_applicable'),
reason_code=_REASON_CODES[(outcome, relation)],
rung=rung,
suppressed_identity_relations=_suppressed(facts, relations, target.memory_version_id),
Expand All @@ -220,6 +222,7 @@ def derive_decision(
relation=relation,
target_memory_version_id=None,
temporal_order='not_applicable',
applicability='not_applicable',
reason_code=_REASON_CODES[('publish_new', relation)],
rung=6,
suppressed_identity_relations=_suppressed(facts, relations, None),
Expand All @@ -231,6 +234,7 @@ def derive_decision(
relation='unsupported',
target_memory_version_id=None,
temporal_order='not_applicable',
applicability='not_applicable',
reason_code=_REASON_CODES[('reject_candidate', 'unsupported')],
rung=7,
suppressed_identity_relations=_suppressed(facts, relations, None),
Expand Down
Loading