feat: classify gear and weapon mods
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Game Data Capture Contracts
|
||||
|
||||
RG-1 freezes contract version 1 for the taxonomy, workflow states, evidence model, archive manifest, and ISAC handoff boundary.
|
||||
RG-1 freezes contract version 1 for the taxonomy, workflow states, evidence model, archive manifest, and ISAC handoff boundary. The approved GDC-001 mod-family change extends version 1 with `weapon_mod` and `gear_mod`.
|
||||
|
||||
## Files
|
||||
|
||||
@@ -8,11 +8,23 @@ RG-1 freezes contract version 1 for the taxonomy, workflow states, evidence mode
|
||||
- `screenshot-classification.schema.json` validates one hierarchical screen classification.
|
||||
- `evidence-archive-manifest-v1.schema.json` validates a private evidence archive manifest.
|
||||
- `isac-handoff-v1.schema.json` validates a bounded draft handoff for authenticated ISAC intake.
|
||||
- `examples/classification/` contains one valid and one invalid classification for each family, including explicit `unknown` abstention.
|
||||
- `examples/classification/` contains one valid and one invalid classification for each family, including Weapon Mod, Gear Mod, and explicit `unknown` abstention.
|
||||
- `examples/archive/` and `examples/handoff/` exercise each versioned document schema.
|
||||
|
||||
The schemas use JSON Schema Draft 2020-12, internal `$ref` values, standard formats, and no implementation-specific keywords. Python `jsonschema` and TypeScript validators such as Ajv can compile the files without model conversion. Consumers must reject a document unless `schema_version` equals the schema's `const` value. Consumers must also run semantic reference validation because JSON Schema cannot prove that an ID points to an item in another array.
|
||||
|
||||
## Mod Screen Semantics
|
||||
|
||||
Repository source data and editors establish `weapon_mod` and `gear_mod` as separate canonical aggregates. Each family currently supports only the `detail` view and its same-named record type. A Mod classification never sets the six-slot `gear_slot` field. The Weapon Mod slot, quality, compatibility, secondary-option, Mod Effect, exotic-attribute, and weapon-lock data and the Gear Mod quality and secondary-option data remain evidence-backed fields or relationships on the owning aggregate. They are not separate screen views or record types.
|
||||
|
||||
The `record_types` array still supports composite screens. No repository evidence establishes another independent canonical record type on a Weapon Mod or Gear Mod detail screen, so these two mappings each contain one record type. A classifier must use `unknown` with an abstention reason for another Mod view, an ambiguous family, or unsupported content.
|
||||
|
||||
## Version Decision
|
||||
|
||||
The approved additive taxonomy change remains schema version 1. The document shapes, trust boundary, bounds, and meanings of every existing value are unchanged, and all existing version 1 labels and documents remain valid. This utility and its payloads are prototype formats; no production-stable archive or handoff version has been declared. A version increment would force a document migration without representing a structural or semantic break.
|
||||
|
||||
Consumers must update their closed version 1 vocabularies before they accept Mod labels. Older consumers reject the new values, which keeps the boundary fail closed. Existing stored labels need validation against the revised vocabulary but no value rewrite. The capture-label UI, storage regression coverage, classifier, extraction dispatch, evidence export, and ISAC adapter mappings must consume both families and their exact `detail`/record-type pairs before their respective gates can pass. This contract change does not alter those downstream implementations.
|
||||
|
||||
## Evidence Rules
|
||||
|
||||
Capture workers store source text, a normalized value, confidence, engine identity, an image digest, a bounded region, and append-only correction history for each evidence value. A null normalized value requires a `missing_reason`. A present normalized value requires a null `missing_reason`. Each correction's `before` state must match the preceding `after` state. Timestamps must increase, and the final `after` state must match the current evidence value.
|
||||
|
||||
@@ -48,6 +48,18 @@
|
||||
"rank_details": ["specialization_tree_rank"]
|
||||
}
|
||||
},
|
||||
"weapon_mod": {
|
||||
"gear_slot": false,
|
||||
"views": {
|
||||
"detail": ["weapon_mod"]
|
||||
}
|
||||
},
|
||||
"gear_mod": {
|
||||
"gear_slot": false,
|
||||
"views": {
|
||||
"detail": ["gear_mod"]
|
||||
}
|
||||
},
|
||||
"unknown": {
|
||||
"gear_slot": false,
|
||||
"views": {"unknown": []}
|
||||
|
||||
@@ -40,13 +40,13 @@
|
||||
"id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$"},
|
||||
"sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"},
|
||||
"timestamp": {"type": "string", "format": "date-time", "maxLength": 40},
|
||||
"family": {"enum": ["weapon", "gear", "skill_chip", "os_protocol", "specialization", "unknown"]},
|
||||
"family": {"enum": ["weapon", "gear", "skill_chip", "os_protocol", "specialization", "weapon_mod", "gear_mod", "unknown"]},
|
||||
"recordType": {"enum": [
|
||||
"weapon", "weapon_talent", "weapon_augmentation_profile", "gear", "brand_set",
|
||||
"gear_talent", "gear_augmentation_profile", "skill_chip_set", "skill_chip_set_bonus",
|
||||
"skill_chip_roll_pool", "skill_chip_talent", "os_protocol", "os_protocol_secondary_profile",
|
||||
"os_protocol_talent", "specialization", "specialization_focus", "specialization_ability",
|
||||
"specialization_tree_node", "specialization_tree_rank"
|
||||
"specialization_tree_node", "specialization_tree_rank", "weapon_mod", "gear_mod"
|
||||
]},
|
||||
"missingReason": {"enum": [
|
||||
"not_visible", "occluded", "unreadable", "not_present_on_screen", "unsupported",
|
||||
@@ -177,6 +177,8 @@
|
||||
{"properties": {"family": {"const": "skill_chip"}, "view": {"enum": ["detail", "set_bonus", "talent"]}, "gear_slot": {"const": null}, "record_types": {"minItems": 1, "items": {"enum": ["skill_chip_set", "skill_chip_set_bonus", "skill_chip_roll_pool", "skill_chip_talent"]}}, "abstention_reason": {"const": null}}},
|
||||
{"properties": {"family": {"const": "os_protocol"}, "view": {"enum": ["detail", "secondary_profile", "talent"]}, "gear_slot": {"const": null}, "record_types": {"minItems": 1, "items": {"enum": ["os_protocol", "os_protocol_secondary_profile", "os_protocol_talent"]}}, "abstention_reason": {"const": null}}},
|
||||
{"properties": {"family": {"const": "specialization"}, "view": {"enum": ["overview", "details", "ability", "focus_details", "focus_tree", "rank_details"]}, "gear_slot": {"const": null}, "record_types": {"minItems": 1, "items": {"enum": ["specialization", "specialization_focus", "specialization_ability", "specialization_tree_node", "specialization_tree_rank"]}}, "abstention_reason": {"const": null}}},
|
||||
{"properties": {"family": {"const": "weapon_mod"}, "view": {"const": "detail"}, "gear_slot": {"const": null}, "record_types": {"minItems": 1, "maxItems": 1, "items": {"const": "weapon_mod"}}, "abstention_reason": {"const": null}}},
|
||||
{"properties": {"family": {"const": "gear_mod"}, "view": {"const": "detail"}, "gear_slot": {"const": null}, "record_types": {"minItems": 1, "maxItems": 1, "items": {"const": "gear_mod"}}, "abstention_reason": {"const": null}}},
|
||||
{"properties": {"family": {"const": "unknown"}, "view": {"const": "unknown"}, "gear_slot": {"const": null}, "record_types": {"maxItems": 0}, "abstention_reason": {"enum": ["low_confidence", "ambiguous_family", "ambiguous_view", "unsupported_family", "unsupported_view", "insufficient_visual_evidence", "occluded", "corrupt_image", "resource_limit", "cancelled"]}}}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"family": "gear_mod",
|
||||
"view": "detail",
|
||||
"gear_slot": "Mask",
|
||||
"record_types": ["gear_mod"],
|
||||
"confidence": 0.95,
|
||||
"abstention_reason": null
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"family": "gear_mod",
|
||||
"view": "detail",
|
||||
"gear_slot": null,
|
||||
"record_types": ["gear_mod"],
|
||||
"confidence": 0.95,
|
||||
"abstention_reason": null
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"family": "weapon_mod",
|
||||
"view": "effect",
|
||||
"gear_slot": null,
|
||||
"record_types": ["weapon_mod"],
|
||||
"confidence": 0.96,
|
||||
"abstention_reason": null
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"family": "weapon_mod",
|
||||
"view": "detail",
|
||||
"gear_slot": null,
|
||||
"record_types": ["weapon_mod"],
|
||||
"confidence": 0.96,
|
||||
"abstention_reason": null
|
||||
}
|
||||
@@ -44,7 +44,7 @@
|
||||
"gear_talent", "gear_augmentation_profile", "skill_chip_set", "skill_chip_set_bonus",
|
||||
"skill_chip_roll_pool", "skill_chip_talent", "os_protocol", "os_protocol_secondary_profile",
|
||||
"os_protocol_talent", "specialization", "specialization_focus", "specialization_ability",
|
||||
"specialization_tree_node", "specialization_tree_rank"
|
||||
"specialization_tree_node", "specialization_tree_rank", "weapon_mod", "gear_mod"
|
||||
]},
|
||||
"missingReason": {"enum": [
|
||||
"not_visible", "occluded", "unreadable", "not_present_on_screen", "unsupported",
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"additionalProperties": false,
|
||||
"required": ["family", "view", "gear_slot", "record_types", "confidence", "abstention_reason"],
|
||||
"properties": {
|
||||
"family": {"enum": ["weapon", "gear", "skill_chip", "os_protocol", "specialization", "unknown"]},
|
||||
"family": {"enum": ["weapon", "gear", "skill_chip", "os_protocol", "specialization", "weapon_mod", "gear_mod", "unknown"]},
|
||||
"view": {"type": "string"},
|
||||
"gear_slot": {"type": ["string", "null"]},
|
||||
"record_types": {"type": "array", "uniqueItems": true, "maxItems": 8, "items": {"type": "string"}},
|
||||
@@ -59,6 +59,24 @@
|
||||
"abstention_reason": {"const": null}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"family": {"const": "weapon_mod"},
|
||||
"view": {"const": "detail"},
|
||||
"gear_slot": {"const": null},
|
||||
"record_types": {"minItems": 1, "maxItems": 1, "items": {"const": "weapon_mod"}},
|
||||
"abstention_reason": {"const": null}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"family": {"const": "gear_mod"},
|
||||
"view": {"const": "detail"},
|
||||
"gear_slot": {"const": null},
|
||||
"record_types": {"minItems": 1, "maxItems": 1, "items": {"const": "gear_mod"}},
|
||||
"abstention_reason": {"const": null}
|
||||
}
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"family": {"const": "unknown"},
|
||||
|
||||
Reference in New Issue
Block a user