///|
priv struct V4CategoryGraph {
base : ClassificationModelV3Graph
inferences : Json
}
///|
fn v4_empty_category_graph(
history : HistoryV4,
reason : String,
) -> V4CategoryGraph {
let normalized = match history.payload {
RegisterSnapshot(_, Some(n)) => n
ListSnapshot(parsed) => parsed.normalized
RelationSnapshot(parsed) => parsed.normalized
_ => Json::object(Map([]))
}
{
base: {
normalized,
transactions: [],
edges: [],
sources: Map([]),
validity_gaps: [],
history: None,
list_parsed: None,
complete: false,
reason,
},
inferences: Json::null(),
}
}
///|
fn v4_register_direct_gap(
gaps : Array[Json],
keyed : Map[String, Map[String, Bool]],
unkeyed : Map[String, Bool],
code : String,
edge : Edge,
) -> Unit {
match edge.key {
Some(key) => {
let seen = keyed.get_or_default(code, Map([]))
if seen.contains(key) {
return
}
seen[key] = true
keyed[code] = seen
}
None => {
if unkeyed.contains(code) {
return
}
unkeyed[code] = true
}
}
gaps.push({
"code": Json(code),
"severity": "uncertainty",
"message": "A legacy serialization constraint lacks the resolved version order or source metadata required for a direct category RW edge",
"transactions": Json([edge.from, edge.to]),
"key": match edge.key {
Some(key) => Json(key)
None => Json::null()
},
"ops": Json(([] : Array[Json])),
"edge": edge_json(edge),
})
}
///|
fn v4_register_rw_metadata(
by_id : Map[String, Transaction],
edge : Edge,
) -> Bool {
match
(edge.key, edge.from_version, edge.to_version, edge.from_op, edge.to_op) {
(Some(key), Some(first), Some(last), Some(from_op), Some(to_op)) =>
match (by_id.get(edge.from), by_id.get(edge.to)) {
(Some(source), Some(target)) if source.status == Committed &&
target.status == Committed &&
from_op >= 0 &&
from_op < source.ops.length() &&
to_op >= 0 &&
to_op < target.ops.length() => {
let read = source.ops[from_op]
let write = target.ops[to_op]
read.kind == Read &&
read.key == key &&
read.version == first &&
write.kind == Write &&
write.key == key &&
write.version == last
}
_ => false
}
_ => false
}
}
///|
/// The legacy analyzer also emits transitive serialization constraints. The
/// category adapter retains RW only to the resolved immediate installed version.
/// An own successor was removed by add_edge and must never be skipped here.
fn v4_register_direct_category_edges(
history : History,
report : Report,
) -> (Array[Edge], Array[Json]) {
let ranks : Map[String, Map[String, Int32]] = Map([])
for key, order in report.inferred_orders {
let positions : Map[String, Int32] = Map([])
for position, version in order {
positions[version] = position
}
ranks[key] = positions
}
let by_id : Map[String, Transaction] = Map([])
for transaction in history.transactions {
by_id[transaction.id] = transaction
}
let edges : Array[Edge] = []
let gaps : Array[Json] = []
let keyed : Map[String, Map[String, Bool]] = Map([])
let unkeyed : Map[String, Bool] = Map([])
for edge in report.edges {
if edge.kind != RW {
edges.push(edge)
continue
}
if !v4_register_rw_metadata(by_id, edge) {
v4_register_direct_gap(
gaps, keyed, unkeyed, "register_direct_rw_source_unresolved", edge,
)
continue
}
let key = edge.key.unwrap()
match ranks.get(key) {
None =>
v4_register_direct_gap(
gaps, keyed, unkeyed, "register_direct_rw_order_unresolved", edge,
)
Some(positions) => {
let first = positions.get_or_default(edge.from_version.unwrap(), -1)
let last = positions.get_or_default(edge.to_version.unwrap(), -1)
if first < 0 || last < 0 || last <= first {
v4_register_direct_gap(
gaps, keyed, unkeyed, "register_direct_rw_version_unresolved", edge,
)
} else if last == first + 1 {
edges.push(edge)
}
}
}
}
(edges, gaps)
}
///|
fn v4_category_graph(
history : HistoryV4,
list_graph : String,
max_list_graph_checks : Int32,
) -> V4CategoryGraph raise {
if list_graph == "effective-v1" {
return match history.payload {
ListSnapshot(parsed) => {
let result = list_graph_effective_v4(
parsed,
max_checks=max_list_graph_checks,
)
{
base: result.base,
inferences: {
"listGraph": list_graph_effective_v4_summary_json(result),
},
}
}
_ =>
v4_empty_category_graph(
history, "effective-list-graph-requires-append-list-v1",
)
}
}
match history.payload {
RegisterSnapshot(Some(input), normalized) => {
let raw_operations = match normalized {
Some(Object(fields)) =>
match fields.get("observations") {
Some(Array(events)) =>
events
.filter(event => {
let kind = object_fields_unchecked_v3(event).get("kind")
kind == Some(Json("read")) || kind == Some(Json("write"))
})
.length()
_ => count_ops(input)
}
_ => count_ops(input)
}
if input.transactions.length() > 128 || raw_operations > 4096 {
return v4_empty_category_graph(
history, "register-category-capacity-128-4096",
)
}
// Real-time edges have their own categories; never mix them into G0/G1c/G2.
let data_history : History = { ..input, model: Serializable, }
let report = analyze_internal(data_history, false, complete_search=false)
let (direct_edges, direct_gaps) = v4_register_direct_category_edges(
data_history, report,
)
let validity_gaps = report.findings
.filter(f => f.severity == "error" || f.severity == "uncertainty")
.map(finding_json)
for gap in direct_gaps {
validity_gaps.push(gap)
}
let complete = !report.graph.edge_budget_exceeded &&
validity_gaps.is_empty()
{
base: {
normalized: normalized.unwrap_or(Json::object(Map([]))),
transactions: data_history.transactions,
edges: direct_edges,
sources: Map([]),
validity_gaps,
history: Some(data_history),
list_parsed: None,
complete,
reason: if complete {
"complete"
} else {
"required-version-order-source-or-graph-incomplete"
},
},
inferences: {
"versionOrders": Json(report.inferred_orders),
"versionOrderSources": Json(report.order_sources),
},
}
}
RegisterSnapshot(None, _) =>
v4_empty_category_graph(history, "capture-coverage-incomplete")
ListSnapshot(parsed) =>
{
// The source remains the original capture; no synthetic events are made.
base: classification_models_v3_list(
history.source_text,
parsed.normalized,
),
inferences: { "versionOrderCompletion": false },
}
RelationSnapshot(_) =>
v4_empty_category_graph(
history, "relation-category-classification-not-supported",
)
}
}
///|
fn v4_register_category_witness(
graph : ClassificationModelV3Graph,
cycle : Array[Edge],
) -> Json {
let history = graph.history.unwrap()
let by_id : Map[String, Transaction] = Map([])
for tx in history.transactions {
by_id[tx.id] = tx
}
let proof = cycle.map(edge => {
let from_seq = match edge.from_op {
Some(index) =>
classification_v3_observation_sources(
graph.normalized,
edge.from,
by_id.at(edge.from).ops[index],
)
None => []
}
let to_seq = match edge.to_op {
Some(index) =>
classification_v3_observation_sources(
graph.normalized,
edge.to,
by_id.at(edge.to).ops[index],
)
None => []
}
let order = match edge.key {
Some(key) =>
match history.version_orders.get(key) {
Some(order) => Json(order)
None => Json::null()
}
None => Json::null()
}
(
{
"edge": edge_json(edge),
"fromObservationSeq": Json(from_seq),
"toObservationSeq": Json(to_seq),
"inputVersionOrder": order,
} : Json)
})
{
"kind": "source-bound-register-category-cycle",
"specificCategory": Json(
if cycle.all(e => e.kind == WW) {
"G0"
} else if cycle.any(e => e.kind == RW) {
"G2-item"
} else {
"G1c"
},
),
"edges": Json(proof),
"minimality": "simple cycle for the requested category; no shortest-cycle claim",
"sourceScope": "original capture observation identities or caller-declared transaction operation indices; input assertions do not authenticate a database",
}
}
///|
fn v4_classification_effects(history : HistoryV4) -> Json {
let normalized = match history.payload {
RegisterSnapshot(Some(h), None) => return v4_declared_effects(h)
RegisterSnapshot(_, Some(n)) => n
ListSnapshot(parsed) => parsed.normalized
RelationSnapshot(parsed) => parsed.normalized
_ => return Json::null()
}
{
"basis": "captured-write-effects",
"entries": object_fields_unchecked_v3(normalized).get_or_default(
"effects",
Json(([] : Array[Json])),
),
}
}
///|
fn v4_classification_record(
history : HistoryV4,
status : String,
rules : Json,
implied : Array[String],
graph : V4CategoryGraph,
categories : Array[String],
max_states : Int32,
max_edge_checks : Int32,
list_graph : String,
max_list_graph_checks : Int32,
) -> ClassificationV4 {
let record : Json = {
"format": "moontxnwitness-classification/v4",
"schemaVersion": 4,
"semanticContract": "moontxnwitness-category-classification-v4-1",
"algorithm": Json(
if categories.contains("G-single") {
"v4-source-bound-category-g-single-1"
} else {
"v4-source-bound-category-bfs-1"
},
),
"dataModel": Json(v4_model_name(history.data_model)),
"observations": {
"sourceFormat": Json(history.source_format),
"authenticityVerified": false,
"document": history.source_document,
},
"writeEffects": v4_classification_effects(history),
"inferences": graph.inferences,
"judgment": {
"status": Json(status),
"acceptsIsolationModels": false,
"scope": Json(
if categories.contains("G-single") {
"requested point-register-v1/append-list-v1 item-dependency categories only; G-single has exactly one item RW edge; checked-compatible does not accept a complete isolation model or certify a database"
} else {
"requested dependency-cycle categories only; checked-compatible does not accept a complete isolation model or certify a database"
},
),
"dependencyGraphComplete": Json(graph.base.complete),
"dependencies": Json(graph.base.edges.map(edge_json)),
"sourceOrOrderGaps": Json(graph.base.validity_gaps),
"rules": rules,
"impliedAnomalies": Json(implied),
},
"execution": {
"counterContract": Json(
if categories.contains("G-single") {
"v4-category-g-single-seed-bfs-counters-1"
} else {
"v4-category-seed-bfs-counters-1"
},
),
"categories": Json(categories.copy()),
"versionOrderCompletion": false,
"limits": {
"registerTransactions": 128,
"registerOperations": 4096,
"listCommittedTransactions": 6,
"listOperations": 128,
"edges": 50000,
"statesPerCategory": Json(max_states),
"edgeChecksPerCategory": Json(max_edge_checks),
},
},
}
if list_graph == "effective-v1" {
let root = object_fields_unchecked_v3(record)
root["algorithm"] = Json("v4-source-bound-category-list-effective-1")
let judgment = object_fields_unchecked_v3(root.at("judgment"))
judgment["scope"] = Json(
"requested append-list-v1 effective item-dependency categories only; source-incompatible keys are isolated; checked-compatible does not accept a complete isolation model or certify a database",
)
let execution = object_fields_unchecked_v3(root.at("execution"))
execution["counterContract"] = Json("v4-list-effective-category-counters-1")
execution["listGraph"] = Json(list_graph)
match graph.inferences {
Object(inferences) =>
match inferences.get("listGraph") {
Some(Object(summary)) =>
execution["listGraphConstruction"] = summary.at("execution")
_ => ()
}
_ => ()
}
let limits = object_fields_unchecked_v3(execution.at("limits"))
let _ = limits.remove("listCommittedTransactions")
limits["listTransactions"] = Json(128)
limits["listOperations"] = Json(4096)
limits["listGraphChecks"] = Json(max_list_graph_checks)
}
{ status, record, }
}
///|
/// Each requested category has its own search and budget over one shared graph.
pub fn classify_v4(
history : HistoryV4,
categories~ : Array[String] = ["G0", "G1c", "G2-item"],
max_states~ : Int32 = 100000,
max_edge_checks~ : Int32 = 1000000,
list_graph~ : String = "legacy",
max_list_graph_checks~ : Int32 = 1000000,
) -> ClassificationV4 {
let categories = categories.copy()
let seen : Map[String, Bool] = Map([])
let valid = !categories.is_empty() &&
categories.all(category => {
if !["G0", "G1c", "G2-item", "G-single"].contains(category) ||
seen.contains(category) {
false
} else {
seen[category] = true
true
}
}) &&
max_states >= 0 &&
max_states <= 100000 &&
max_edge_checks >= 0 &&
max_edge_checks <= 1000000 &&
["legacy", "effective-v1"].contains(list_graph) &&
max_list_graph_checks >= 0 &&
max_list_graph_checks <= 1000000 &&
(list_graph == "effective-v1" || max_list_graph_checks == 1000000)
if !valid {
return v4_classification_record(
history,
"invalid",
Json::object(Map([])),
[],
v4_empty_category_graph(history, "invalid-options"),
categories,
max_states,
max_edge_checks,
list_graph,
max_list_graph_checks,
)
}
let graph = v4_category_graph(history, list_graph, max_list_graph_checks) catch {
_ =>
return v4_classification_record(
history,
"invalid",
Json::object(Map([])),
[],
v4_empty_category_graph(history, "invalid-graph-state"),
categories,
max_states,
max_edge_checks,
list_graph,
max_list_graph_checks,
)
}
let index = adjacency(graph.base.transactions, graph.base.edges)
let rules : Map[String, Json] = Map([])
let implied : Array[String] = []
let mut status = "checked-compatible"
for category in categories {
let budget : ClassificationV3Budget = {
max_states,
max_edge_checks,
states: 0,
edge_checks: 0,
limited: false,
reason: "complete",
}
let cycle = if category == "G-single" {
g_single_cycle_v4(
graph.base.transactions.length(),
graph.base.edges,
index,
budget,
)
} else {
classification_v3_cycle(
graph.base.transactions,
graph.base.edges,
index,
category,
budget,
)
}
let rule_status = if history.data_model == RelationSetV4 ||
(list_graph == "effective-v1" && history.data_model != AppendListV4) {
"unsupported"
} else if !cycle.is_empty() {
"refuted"
} else if budget.limited || !graph.base.complete {
"unknown"
} else {
"checked-compatible"
}
let reason = if !cycle.is_empty() {
"source-bound-cycle"
} else if budget.limited {
budget.reason
} else {
graph.base.reason
}
if rule_status == "refuted" {
status = "refuted"
let specific = if cycle.all(edge => edge.kind == WW) {
"G0"
} else if cycle.any(edge => edge.kind == RW) {
"G2-item"
} else {
"G1c"
}
let implications = if category == "G-single" {
[
"G-single-item", "G-single", "G-nonadjacent-item", "G-nonadjacent", "G2-item",
"G2",
]
} else {
classification_v3_implications(specific)
}
for label in implications {
if !implied.contains(label) {
implied.push(label)
}
}
} else if status != "refuted" {
if rule_status == "unsupported" {
status = "unsupported"
} else if rule_status == "unknown" {
status = "inconclusive"
}
}
rules[category] = {
"status": Json(rule_status),
"reason": Json(reason),
"states": Json(budget.states),
"edgeChecks": Json(budget.edge_checks),
"evidence": if cycle.is_empty() {
Json::null()
} else {
let witness = if history.data_model == RegisterV4 {
v4_register_category_witness(graph.base, cycle)
} else {
classification_models_v3_witness(graph.base, cycle)
}
if list_graph == "effective-v1" {
let fields = object_fields_unchecked_v3(witness)
fields["kind"] = Json(
"source-checked-effective-list-dependency-cycle",
)
fields["sourceScope"] = Json(
"raw delivered reads with effective own suffix at each program position, final committed append groups, and validated external item order; not SQL authenticity",
)
}
if category == "G-single" {
g_single_category_witness_v4(witness, cycle)
} else {
witness
}
},
}
}
v4_classification_record(
history,
status,
Json::object(rules),
implied,
graph,
categories,
max_states,
max_edge_checks,
list_graph,
max_list_graph_checks,
)
}
///|
pub fn classification_v4_json(result : ClassificationV4) -> Json {
v4_json_copy(result.record)
}
///|
pub fn render_classification_v4(result : ClassificationV4) -> String {
result.record.stringify(indent=2)
}
///|
pub fn verify_classification_v4(
history : HistoryV4,
supplied : Json,
categories~ : Array[String] = ["G0", "G1c", "G2-item"],
max_states~ : Int32 = 100000,
max_edge_checks~ : Int32 = 1000000,
list_graph~ : String = "legacy",
max_list_graph_checks~ : Int32 = 1000000,
) -> Bool {
supplied ==
classify_v4(
history,
categories~,
max_states~,
max_edge_checks~,
list_graph~,
max_list_graph_checks~,
).record
}