Rebuild qualified world elaboration
This commit is contained in:
parent
7174703f6f
commit
661cfbad9f
13 changed files with 6864 additions and 1078 deletions
8
acceptance/full-world-delvehold-regions-v2.txt
Normal file
8
acceptance/full-world-delvehold-regions-v2.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
Beyond the Confluence, approach and admit a politically inhabited elven forest realm whose watershed law, living-landscape institutions, rival offices, settlements, and public routes respond independently to the deep crisis.
|
||||
Beyond the Confluence, approach and admit a politically inhabited human rail-capital realm with a government, opposition, university, mage interests, labor constituencies, dependent infrastructure, surrounding settlements, and public routes.
|
||||
Beyond the Confluence, approach and admit a politically inhabited orcish oathland realm with several councils and communities, guardian-species obligations, contested enforcement, trade interests, dissent, and public routes.
|
||||
Beyond the Confluence, approach and admit a politically inhabited halfling grain-and-river realm with farms, market towns, tenants, cooperatives, water authorities, insurers, faiths, political movements, and public routes.
|
||||
Beyond the Confluence, approach and admit a politically inhabited goblin deep-route realm with distinct settlements, route guilds, kin networks, custodians, brokers, radicals, discounted expertise, and public routes.
|
||||
Beyond the Confluence, approach and admit a second politically inhabited human polity: a tidal mercantile republic with elected harbor offices, hereditary creditors, dock unions, displaced fisher wards, rival courts, naval contracts, and public routes independent of the rail capital.
|
||||
Beyond the Confluence, approach and admit a mixed border federation whose member towns, mobile communities, species, faiths, and trade leagues retain local authority while sharing delegates, mutual-aid stores, contested asylum law, watershed obligations, and public routes.
|
||||
Beyond the Confluence, approach and admit an autonomous deep-ecology polity of dungeon organs, custodial communities, symbiotic species, and negotiated human-scale envoys, with legible law, dissent, material means, territorial claims, redress, and public routes; do not make it a single mystical will.
|
||||
|
|
@ -91,10 +91,16 @@ ontology or turn the Greathold into an autonomous character.
|
|||
insurers suspend cover, armies secure infrastructure, displaced families
|
||||
cross borders, and an unknown party circulates proof that several foreign
|
||||
governments secretly financed the extraction they now condemn.`
|
||||
- World locality elaborations: `5` (one per admitted realm jurisdiction)
|
||||
- Ordered outer-realm requests:
|
||||
`acceptance/full-world-delvehold-regions-v2.txt` (eight requests, one per
|
||||
line; their order is part of the acceptance input)
|
||||
- World locality elaborations: `8` (one per ordered outer-realm request)
|
||||
- World elaboration parallelism: `8`
|
||||
- Active cell budget: `240`
|
||||
- Strategic waves: `12`
|
||||
- Target active-cover basis points: `2000` (exactly `1200` qualified subjects)
|
||||
- World complexity parallelism: `8`
|
||||
- Maximum world complexity rounds: `128`
|
||||
- Strategic waves: `1`
|
||||
- Maximum rejected pulses per wave: `4`
|
||||
- Provider routing: Luna fast, Terra balanced, Sol capable through the existing
|
||||
Codex connector
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -6,7 +6,7 @@ use std::collections::{BTreeMap, BTreeSet};
|
|||
fn main() -> Result<()> {
|
||||
let mut args = std::env::args().skip(1);
|
||||
let store_path = args.next().context(
|
||||
"usage: ghostlight-world-explore <campaign.cc> <overview|search|region|subject> [query]",
|
||||
"usage: ghostlight-world-explore <campaign.cc> <overview|quality|search|region|subject> [query]",
|
||||
)?;
|
||||
let command = args.next().unwrap_or_else(|| "overview".into());
|
||||
let operand = args.next();
|
||||
|
|
@ -17,6 +17,7 @@ fn main() -> Result<()> {
|
|||
let campaign = load_campaign(&store_path)?;
|
||||
let output = match command.as_str() {
|
||||
"overview" => overview(&campaign),
|
||||
"quality" => quality(&campaign),
|
||||
"search" => search(
|
||||
&campaign,
|
||||
operand
|
||||
|
|
@ -35,12 +36,607 @@ fn main() -> Result<()> {
|
|||
.as_deref()
|
||||
.context("subject requires one exact subject ID")?,
|
||||
)?,
|
||||
other => bail!("unknown command {other:?}; expected overview, search, region, or subject"),
|
||||
other => bail!(
|
||||
"unknown command {other:?}; expected overview, quality, search, region, or subject"
|
||||
),
|
||||
};
|
||||
println!("{}", serde_json::to_string_pretty(&output)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn normalized_text(value: &str) -> String {
|
||||
value
|
||||
.chars()
|
||||
.filter(|character| character.is_alphanumeric())
|
||||
.flat_map(char::to_lowercase)
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn terminal_name_token(value: &str) -> String {
|
||||
value
|
||||
.split(|character: char| !character.is_alphanumeric())
|
||||
.filter(|token| !token.is_empty())
|
||||
.last()
|
||||
.map(normalized_text)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn duplicate_groups(entries: impl IntoIterator<Item = (String, String)>) -> Value {
|
||||
let mut groups: BTreeMap<String, Vec<String>> = BTreeMap::new();
|
||||
for (key, id) in entries {
|
||||
if !key.is_empty() {
|
||||
groups.entry(key).or_default().push(id);
|
||||
}
|
||||
}
|
||||
let mut groups = groups
|
||||
.into_iter()
|
||||
.filter(|(_, ids)| ids.len() > 1)
|
||||
.map(|(key, mut ids)| {
|
||||
ids.sort();
|
||||
let count = ids.len();
|
||||
ids.truncate(20);
|
||||
json!({"key":key,"count":count,"subjectIdSample":ids})
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
groups.sort_by(|left, right| {
|
||||
right["count"]
|
||||
.as_u64()
|
||||
.cmp(&left["count"].as_u64())
|
||||
.then_with(|| left["key"].as_str().cmp(&right["key"].as_str()))
|
||||
});
|
||||
let group_count = groups.len();
|
||||
let occurrence_count = groups
|
||||
.iter()
|
||||
.filter_map(|group| group["count"].as_u64())
|
||||
.sum::<u64>();
|
||||
let member_sample_truncated = groups.iter().any(|group| {
|
||||
group["count"].as_u64().unwrap_or(0)
|
||||
> group["subjectIdSample"]
|
||||
.as_array()
|
||||
.map_or(0, |sample| sample.len()) as u64
|
||||
});
|
||||
groups.truncate(20);
|
||||
json!({
|
||||
"groupCount":group_count,
|
||||
"occurrenceCount":occurrence_count,
|
||||
"groupsSample":groups,
|
||||
"truncated":group_count > 20 || member_sample_truncated,
|
||||
"groupSampleLimit":20,
|
||||
"subjectIdSampleLimitPerGroup":20,
|
||||
})
|
||||
}
|
||||
|
||||
fn gestalt_semantic_key(gestalt: &ghostlight_dungeon::domain::GestaltPersonaState) -> String {
|
||||
serde_json::to_string(&(
|
||||
&gestalt.shared_capabilities,
|
||||
&gestalt.shared_knowledge,
|
||||
&gestalt.goals,
|
||||
&gestalt.pressures,
|
||||
))
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn lineage_depth(campaign: &Campaign, subject_id: &str) -> usize {
|
||||
let mut depth = 0;
|
||||
let mut current = subject_id;
|
||||
let mut visited = BTreeSet::new();
|
||||
while visited.insert(current.to_owned()) {
|
||||
let Some(parent) = campaign
|
||||
.agency_profiles
|
||||
.get(current)
|
||||
.and_then(|profile| profile.parent_subject_id.as_deref())
|
||||
else {
|
||||
break;
|
||||
};
|
||||
depth += 1;
|
||||
current = parent;
|
||||
}
|
||||
depth
|
||||
}
|
||||
|
||||
fn repeated_texts<'a>(values: impl IntoIterator<Item = (&'a str, &'a String)>) -> Value {
|
||||
duplicate_groups(
|
||||
values
|
||||
.into_iter()
|
||||
.map(|(id, value)| (normalized_text(value), id.to_owned())),
|
||||
)
|
||||
}
|
||||
|
||||
fn has_structurally_complete_named_person_shape(
|
||||
has_goal: bool,
|
||||
has_memory: bool,
|
||||
has_detail_state: bool,
|
||||
) -> bool {
|
||||
has_goal && has_memory && has_detail_state
|
||||
}
|
||||
|
||||
fn quality(campaign: &Campaign) -> Value {
|
||||
let residual_ids = campaign
|
||||
.gestalt_lineages
|
||||
.values()
|
||||
.map(|lineage| lineage.residual_child_id.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
let raw_actionable_ids = campaign
|
||||
.agency_profiles
|
||||
.values()
|
||||
.filter(|profile| profile.active_leaf && profile.simulation_eligible)
|
||||
.map(|profile| profile.subject_id.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
let qualified_ids = ghostlight_dungeon::elaboration::canonical_actionable_subject_ids(campaign);
|
||||
let qualified_count =
|
||||
ghostlight_dungeon::elaboration::canonical_actionable_subject_count(campaign);
|
||||
let twenty_percent_target = u32::from(campaign.resolution_policy.active_cell_budget) * 5;
|
||||
let qualified_target_delta = i64::from(twenty_percent_target) - i64::from(qualified_count);
|
||||
|
||||
let materialized_member_actor_ids = campaign
|
||||
.gestalt_members
|
||||
.values()
|
||||
.flat_map(|member| {
|
||||
member
|
||||
.materialized_actor_id
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(std::iter::once(format!("member:{}", member.id)))
|
||||
})
|
||||
.collect::<BTreeSet<_>>();
|
||||
let person_name_records = campaign
|
||||
.actors
|
||||
.values()
|
||||
.filter(|actor| {
|
||||
actor.id != campaign.player_actor_id
|
||||
&& !materialized_member_actor_ids.contains(&actor.id)
|
||||
})
|
||||
.map(|actor| (actor.name.clone(), format!("actor:{}", actor.id)))
|
||||
.chain(
|
||||
campaign
|
||||
.gestalt_members
|
||||
.values()
|
||||
.map(|member| (member.name.clone(), format!("member:{}", member.id))),
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
let population_name_records = campaign
|
||||
.gestalts
|
||||
.values()
|
||||
.filter(|gestalt| qualified_ids.contains(&gestalt.id))
|
||||
.map(|gestalt| (gestalt.name.clone(), gestalt.id.clone()))
|
||||
.collect::<Vec<_>>();
|
||||
let invalid_person_identity_ids = person_name_records
|
||||
.iter()
|
||||
.filter(|(name, _)| normalized_text(name).is_empty())
|
||||
.map(|(_, id)| id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let invalid_population_identity_ids = population_name_records
|
||||
.iter()
|
||||
.filter(|(name, _)| normalized_text(name).is_empty())
|
||||
.map(|(_, id)| id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let duplicate_person_names = duplicate_groups(
|
||||
person_name_records
|
||||
.iter()
|
||||
.map(|(name, id)| (normalized_text(name), id.clone())),
|
||||
);
|
||||
let duplicate_population_names = duplicate_groups(
|
||||
population_name_records
|
||||
.iter()
|
||||
.map(|(name, id)| (normalized_text(name), id.clone())),
|
||||
);
|
||||
let repeated_person_terminal_tokens = duplicate_groups(
|
||||
person_name_records
|
||||
.iter()
|
||||
.map(|(name, id)| (terminal_name_token(name), id.clone())),
|
||||
);
|
||||
let repeated_population_terminal_tokens = duplicate_groups(
|
||||
population_name_records
|
||||
.iter()
|
||||
.map(|(name, id)| (terminal_name_token(name), id.clone())),
|
||||
);
|
||||
|
||||
// This is a structural record-shape count, not a judgment of semantic quality.
|
||||
// A counted standalone actor has at least one goal, at least one memory, and at
|
||||
// least one capability, knowledge item, equipment item, condition, obligation,
|
||||
// or relationship. The player and actor projections of gestalt members are
|
||||
// excluded. A counted gestalt member has at least one goal, at least one memory,
|
||||
// and at least one capability addition, knowledge addition, equipment item,
|
||||
// condition, obligation, or relationship. Naming validity is measured separately.
|
||||
let structurally_complete_actor_count = campaign
|
||||
.actors
|
||||
.values()
|
||||
.filter(|actor| {
|
||||
actor.id != campaign.player_actor_id
|
||||
&& !materialized_member_actor_ids.contains(&actor.id)
|
||||
})
|
||||
.filter(|actor| {
|
||||
has_structurally_complete_named_person_shape(
|
||||
!actor.goals.is_empty(),
|
||||
!actor.memories.is_empty(),
|
||||
!actor.capabilities.is_empty()
|
||||
|| !actor.knowledge.is_empty()
|
||||
|| !actor.equipment.is_empty()
|
||||
|| !actor.conditions.is_empty()
|
||||
|| !actor.obligations.is_empty()
|
||||
|| !actor.relationships.is_empty(),
|
||||
)
|
||||
})
|
||||
.count();
|
||||
let structurally_complete_member_count = campaign
|
||||
.gestalt_members
|
||||
.values()
|
||||
.filter(|member| {
|
||||
has_structurally_complete_named_person_shape(
|
||||
!member.goals.is_empty(),
|
||||
!member.memories.is_empty(),
|
||||
!member.capability_additions.is_empty()
|
||||
|| !member.knowledge_additions.is_empty()
|
||||
|| !member.equipment.is_empty()
|
||||
|| !member.conditions.is_empty()
|
||||
|| !member.obligations.is_empty()
|
||||
|| !member.relationships.is_empty(),
|
||||
)
|
||||
})
|
||||
.count();
|
||||
let actor_person_count = campaign
|
||||
.actors
|
||||
.values()
|
||||
.filter(|actor| {
|
||||
actor.id != campaign.player_actor_id
|
||||
&& !materialized_member_actor_ids.contains(&actor.id)
|
||||
})
|
||||
.count();
|
||||
let named_person_count = actor_person_count + campaign.gestalt_members.len();
|
||||
|
||||
let qualified_gestalts = campaign
|
||||
.gestalts
|
||||
.values()
|
||||
.filter(|gestalt| qualified_ids.contains(&gestalt.id))
|
||||
.collect::<Vec<_>>();
|
||||
let semantic_clone_groups = duplicate_groups(
|
||||
qualified_gestalts
|
||||
.iter()
|
||||
.map(|gestalt| (gestalt_semantic_key(gestalt), gestalt.id.clone())),
|
||||
);
|
||||
let repeated_goals = repeated_texts(qualified_gestalts.iter().flat_map(|gestalt| {
|
||||
gestalt
|
||||
.goals
|
||||
.iter()
|
||||
.map(|value| (gestalt.id.as_str(), value))
|
||||
}));
|
||||
let repeated_pressures = repeated_texts(qualified_gestalts.iter().flat_map(|gestalt| {
|
||||
gestalt
|
||||
.pressures
|
||||
.iter()
|
||||
.map(|value| (gestalt.id.as_str(), value))
|
||||
}));
|
||||
let direct_fission_deltas = qualified_gestalts
|
||||
.iter()
|
||||
.filter_map(|gestalt| {
|
||||
let parent_id = campaign
|
||||
.agency_profiles
|
||||
.get(&gestalt.id)?
|
||||
.parent_subject_id
|
||||
.as_ref()?;
|
||||
let parent = campaign.gestalts.get(parent_id)?;
|
||||
Some((
|
||||
gestalt.id.as_str(),
|
||||
gestalt
|
||||
.shared_capabilities
|
||||
.difference(&parent.shared_capabilities)
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>(),
|
||||
gestalt
|
||||
.shared_knowledge
|
||||
.difference(&parent.shared_knowledge)
|
||||
.cloned()
|
||||
.collect::<BTreeSet<_>>(),
|
||||
gestalt
|
||||
.goals
|
||||
.iter()
|
||||
.filter(|goal| !parent.goals.contains(goal))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
gestalt
|
||||
.pressures
|
||||
.iter()
|
||||
.filter(|pressure| !parent.pressures.contains(pressure))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>(),
|
||||
))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let repeated_direct_added_goals = repeated_texts(
|
||||
direct_fission_deltas
|
||||
.iter()
|
||||
.flat_map(|(id, _, _, goals, _)| goals.iter().map(|value| (*id, value))),
|
||||
);
|
||||
let repeated_direct_added_pressures = repeated_texts(
|
||||
direct_fission_deltas
|
||||
.iter()
|
||||
.flat_map(|(id, _, _, _, pressures)| pressures.iter().map(|value| (*id, value))),
|
||||
);
|
||||
let exact_direct_delta_clone_groups = duplicate_groups(direct_fission_deltas.iter().map(
|
||||
|(id, capabilities, knowledge, goals, pressures)| {
|
||||
(
|
||||
serde_json::to_string(&(capabilities, knowledge, goals, pressures))
|
||||
.unwrap_or_default(),
|
||||
(*id).to_owned(),
|
||||
)
|
||||
},
|
||||
));
|
||||
|
||||
let mut raw_relation_degrees = qualified_ids
|
||||
.iter()
|
||||
.map(|id| (id.clone(), 0usize))
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let mut non_inherited_relation_degrees = raw_relation_degrees.clone();
|
||||
let mut raw_relation_kind_counts = BTreeMap::<String, usize>::new();
|
||||
let mut non_inherited_relation_kind_counts = BTreeMap::<String, usize>::new();
|
||||
let mut mechanically_inherited_relation_count = 0usize;
|
||||
for relation in campaign
|
||||
.agency_relations
|
||||
.values()
|
||||
.filter(|relation| relation.active)
|
||||
{
|
||||
if let Some(degree) = raw_relation_degrees.get_mut(&relation.from_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
if let Some(degree) = raw_relation_degrees.get_mut(&relation.to_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
let kind = format!("{:?}", relation.kind).to_lowercase();
|
||||
*raw_relation_kind_counts.entry(kind.clone()).or_default() += 1;
|
||||
if relation.id.contains(":fission:") {
|
||||
mechanically_inherited_relation_count += 1;
|
||||
continue;
|
||||
}
|
||||
if let Some(degree) = non_inherited_relation_degrees.get_mut(&relation.from_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
if let Some(degree) = non_inherited_relation_degrees.get_mut(&relation.to_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
*non_inherited_relation_kind_counts.entry(kind).or_default() += 1;
|
||||
}
|
||||
let mut individual_relationship_entries = 0usize;
|
||||
let mut record_individual_relationship = |from_subject_id: &str, to_subject_id: &str| {
|
||||
individual_relationship_entries += 1;
|
||||
if let Some(degree) = raw_relation_degrees.get_mut(from_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
if let Some(degree) = raw_relation_degrees.get_mut(to_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
if let Some(degree) = non_inherited_relation_degrees.get_mut(from_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
if let Some(degree) = non_inherited_relation_degrees.get_mut(to_subject_id) {
|
||||
*degree += 1;
|
||||
}
|
||||
*raw_relation_kind_counts
|
||||
.entry("individual_relationship".into())
|
||||
.or_default() += 1;
|
||||
*non_inherited_relation_kind_counts
|
||||
.entry("individual_relationship".into())
|
||||
.or_default() += 1;
|
||||
};
|
||||
for actor in campaign.actors.values() {
|
||||
for other_subject_id in actor.relationships.keys() {
|
||||
record_individual_relationship(&actor.id, other_subject_id);
|
||||
}
|
||||
}
|
||||
for member in campaign.gestalt_members.values() {
|
||||
let default_actor_id = ghostlight_dungeon::domain::gestalt_member_subject_id(&member.id);
|
||||
let projected_actor_exists = campaign.actors.contains_key(&default_actor_id)
|
||||
|| member
|
||||
.materialized_actor_id
|
||||
.as_ref()
|
||||
.is_some_and(|actor_id| campaign.actors.contains_key(actor_id));
|
||||
if projected_actor_exists {
|
||||
continue;
|
||||
}
|
||||
for other_subject_id in member.relationships.keys() {
|
||||
record_individual_relationship(&default_actor_id, other_subject_id);
|
||||
}
|
||||
}
|
||||
let raw_isolated_subject_ids = raw_relation_degrees
|
||||
.iter()
|
||||
.filter(|(_, degree)| **degree == 0)
|
||||
.map(|(id, _)| id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let non_inherited_isolated_subject_ids = non_inherited_relation_degrees
|
||||
.iter()
|
||||
.filter(|(_, degree)| **degree == 0)
|
||||
.map(|(id, _)| id.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let raw_degree_sum = raw_relation_degrees.values().sum::<usize>();
|
||||
let non_inherited_degree_sum = non_inherited_relation_degrees.values().sum::<usize>();
|
||||
|
||||
let civic_signatures = duplicate_groups(campaign.civic_systems.values().map(|civic| {
|
||||
let institutions = civic
|
||||
.governing_institution_ids
|
||||
.iter()
|
||||
.filter_map(|id| campaign.institutions.get(id))
|
||||
.map(|institution| {
|
||||
(
|
||||
normalized_text(&institution.posture),
|
||||
institution
|
||||
.goals
|
||||
.iter()
|
||||
.map(|value| normalized_text(value))
|
||||
.collect::<BTreeSet<_>>(),
|
||||
institution
|
||||
.resources
|
||||
.iter()
|
||||
.map(|value| normalized_text(value))
|
||||
.collect::<BTreeSet<_>>(),
|
||||
)
|
||||
})
|
||||
.collect::<BTreeSet<_>>();
|
||||
let residents = civic
|
||||
.resident_population_ids
|
||||
.iter()
|
||||
.filter_map(|id| campaign.gestalts.get(id))
|
||||
.map(gestalt_semantic_key)
|
||||
.collect::<BTreeSet<_>>();
|
||||
(
|
||||
serde_json::to_string(&(institutions, residents)).unwrap_or_default(),
|
||||
civic.jurisdiction_location_id.clone(),
|
||||
)
|
||||
}));
|
||||
|
||||
let event_kind_counts =
|
||||
campaign
|
||||
.events
|
||||
.iter()
|
||||
.fold(BTreeMap::<String, usize>::new(), |mut counts, event| {
|
||||
*counts.entry(event.kind.clone()).or_default() += 1;
|
||||
counts
|
||||
});
|
||||
let repeated_event_summaries = duplicate_groups(
|
||||
campaign
|
||||
.events
|
||||
.iter()
|
||||
.map(|event| (normalized_text(&event.summary), event.id.clone())),
|
||||
);
|
||||
let distribution_by_root = campaign
|
||||
.locations
|
||||
.values()
|
||||
.filter(|location| location.container_id.is_none())
|
||||
.map(|location| {
|
||||
let places = descendant_location_ids(campaign, &location.id);
|
||||
let count = qualified_ids
|
||||
.iter()
|
||||
.filter(|id| {
|
||||
campaign
|
||||
.agency_profiles
|
||||
.get(*id)
|
||||
.is_some_and(|profile| !profile.location_ids.is_disjoint(&places))
|
||||
})
|
||||
.count();
|
||||
(location.id.clone(), count)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let spread_by_jurisdiction = campaign
|
||||
.civic_systems
|
||||
.keys()
|
||||
.filter(|location_id| campaign.locations.contains_key(*location_id))
|
||||
.map(|location_id| {
|
||||
let places = descendant_location_ids(campaign, location_id);
|
||||
let location_counts = places
|
||||
.iter()
|
||||
.map(|place_id| {
|
||||
let count = qualified_ids
|
||||
.iter()
|
||||
.filter(|id| {
|
||||
campaign
|
||||
.agency_profiles
|
||||
.get(*id)
|
||||
.is_some_and(|profile| profile.location_ids.contains(place_id))
|
||||
})
|
||||
.count();
|
||||
(place_id.clone(), count)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let occupied_location_count = location_counts
|
||||
.values()
|
||||
.filter(|count| **count > 0)
|
||||
.count();
|
||||
let location_assignment_count = location_counts.values().sum::<usize>();
|
||||
let largest_location_count = location_counts.values().copied().max().unwrap_or(0);
|
||||
(
|
||||
location_id.clone(),
|
||||
json!({
|
||||
"qualifiedSubjects":qualified_ids.iter().filter(|id|campaign.agency_profiles.get(*id).is_some_and(|profile|!profile.location_ids.is_disjoint(&places))).count(),
|
||||
"occupiedLocationCount":occupied_location_count,
|
||||
"locationAssignmentCount":location_assignment_count,
|
||||
"largestLocationShareBasisPoints":if location_assignment_count == 0 { None } else { Some(largest_location_count * 10_000 / location_assignment_count) },
|
||||
"qualifiedSubjectCountsByLocation":location_counts,
|
||||
}),
|
||||
)
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let occupied_location_count = campaign
|
||||
.locations
|
||||
.keys()
|
||||
.filter(|location_id| {
|
||||
qualified_ids.iter().any(|id| {
|
||||
campaign
|
||||
.agency_profiles
|
||||
.get(id)
|
||||
.is_some_and(|profile| profile.location_ids.contains(*location_id))
|
||||
})
|
||||
})
|
||||
.count();
|
||||
|
||||
json!({
|
||||
"schema":"ghostlight.world_quality.v1",
|
||||
"campaign":{"id":campaign.id,"revision":campaign.revision,"strategicTickCount":campaign.strategic_tick_count},
|
||||
"scale":{
|
||||
"rawActionableSubjects":raw_actionable_ids.len(),
|
||||
"qualifiedActionableSubjects":qualified_count,
|
||||
"residualActionableSubjects":raw_actionable_ids.intersection(&residual_ids).count(),
|
||||
"twentyPercentTarget":twenty_percent_target,
|
||||
"qualifiedTargetDelta":qualified_target_delta,
|
||||
"qualifiedCoverBasisPoints":if qualified_count == 0 { None } else { Some(u32::from(campaign.resolution_policy.active_cell_budget) * 10_000 / qualified_count) },
|
||||
"rawCoverBasisPoints":if raw_actionable_ids.is_empty() { None } else { Some(usize::from(campaign.resolution_policy.active_cell_budget) * 10_000 / raw_actionable_ids.len()) },
|
||||
"maximumQualifiedLineageDepth":qualified_ids.iter().map(|id|lineage_depth(campaign,id)).max().unwrap_or(0),
|
||||
"qualifiedDistributionByRootLocation":distribution_by_root,
|
||||
"occupiedLocationCount":occupied_location_count,
|
||||
"qualifiedSpreadByJurisdiction":spread_by_jurisdiction,
|
||||
"geographyFissionCount":campaign.gestalt_lineages.values().filter(|lineage|lineage.partition_axis == ghostlight_dungeon::domain::AgencyAxis::Geography).count(),
|
||||
},
|
||||
"identity":{
|
||||
"namedPersons":named_person_count,
|
||||
"structurallyCompleteNamedPersons":structurally_complete_actor_count + structurally_complete_member_count,
|
||||
"invalidPublicPersonIdentityIds":invalid_person_identity_ids,
|
||||
"invalidQualifiedPopulationIdentityIds":invalid_population_identity_ids,
|
||||
"duplicatePersonNames":duplicate_person_names,
|
||||
"duplicateQualifiedPopulationNames":duplicate_population_names,
|
||||
"repeatedPersonTerminalNameTokens":repeated_person_terminal_tokens,
|
||||
"repeatedQualifiedPopulationTerminalNameTokens":repeated_population_terminal_tokens,
|
||||
"lexicalDiagnosticsOnly":true,
|
||||
},
|
||||
"causality":{
|
||||
"qualifiedGestalts":qualified_gestalts.len(),
|
||||
"qualifiedGestaltsWithoutGoals":qualified_gestalts.iter().filter(|gestalt|gestalt.goals.is_empty()).count(),
|
||||
"qualifiedGestaltsWithoutPressures":qualified_gestalts.iter().filter(|gestalt|gestalt.pressures.is_empty()).count(),
|
||||
"qualifiedGestaltsWithoutCapabilities":qualified_gestalts.iter().filter(|gestalt|gestalt.shared_capabilities.is_empty()).count(),
|
||||
"qualifiedGestaltsWithoutKnowledge":qualified_gestalts.iter().filter(|gestalt|gestalt.shared_knowledge.is_empty()).count(),
|
||||
"inheritanceInclusiveExactSemanticCloneGroups":semantic_clone_groups,
|
||||
"inheritanceInclusiveRepeatedGoals":repeated_goals,
|
||||
"inheritanceInclusiveRepeatedPressures":repeated_pressures,
|
||||
"exactDirectFissionDeltaCloneGroups":exact_direct_delta_clone_groups,
|
||||
"repeatedDirectAddedGoals":repeated_direct_added_goals,
|
||||
"repeatedDirectAddedPressures":repeated_direct_added_pressures,
|
||||
},
|
||||
"relationships":{
|
||||
"collectiveAgencyActiveRelations":campaign.agency_relations.values().filter(|relation|relation.active).count(),
|
||||
"individualRelationshipEntries":individual_relationship_entries,
|
||||
"rawActiveRelationshipEntries":campaign.agency_relations.values().filter(|relation|relation.active).count() + individual_relationship_entries,
|
||||
"estimatedMechanicallyInheritedFissionRelationsByIdConvention":mechanically_inherited_relation_count,
|
||||
"nonInheritedActiveRelationshipEntries":campaign.agency_relations.values().filter(|relation|relation.active && !relation.id.contains(":fission:")).count() + individual_relationship_entries,
|
||||
"rawRelationKindCounts":raw_relation_kind_counts,
|
||||
"nonInheritedRelationKindCounts":non_inherited_relation_kind_counts,
|
||||
"rawIsolatedQualifiedSubjects":raw_isolated_subject_ids.len(),
|
||||
"rawIsolatedQualifiedSubjectSample":raw_isolated_subject_ids.into_iter().take(50).collect::<Vec<_>>(),
|
||||
"nonInheritedIsolatedQualifiedSubjects":non_inherited_isolated_subject_ids.len(),
|
||||
"nonInheritedIsolatedQualifiedSubjectSample":non_inherited_isolated_subject_ids.into_iter().take(50).collect::<Vec<_>>(),
|
||||
"rawMeanQualifiedDegree":if raw_relation_degrees.is_empty() { 0.0 } else { raw_degree_sum as f64 / raw_relation_degrees.len() as f64 },
|
||||
"nonInheritedMeanQualifiedDegree":if non_inherited_relation_degrees.is_empty() { 0.0 } else { non_inherited_degree_sum as f64 / non_inherited_relation_degrees.len() as f64 },
|
||||
"inheritanceClassification":"estimate based on the current :fission: relation-ID convention; authored IDs can confound it",
|
||||
},
|
||||
"politics":{
|
||||
"civicJurisdictions":campaign.civic_systems.len(),
|
||||
"exactCivicSignatureCloneGroups":civic_signatures,
|
||||
"exactSignatureDiagnosticsDoNotMeasureSemanticPoliticalDiversity":true,
|
||||
},
|
||||
"behavior":{
|
||||
"eventKindCounts":event_kind_counts,
|
||||
"exactRepeatedEventSummaryGroups":repeated_event_summaries,
|
||||
"newsIssues":campaign.news.len(),
|
||||
"exactSummaryDiagnosticsDoNotMeasureSemanticDramaticDiversity":true,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
fn load_campaign(path: &str) -> Result<Campaign> {
|
||||
let store = CampaignStore::open(path)?;
|
||||
let key = store
|
||||
|
|
@ -388,3 +984,50 @@ fn location_name<'a>(campaign: &'a Campaign, id: &str) -> Option<&'a str> {
|
|||
.get(id)
|
||||
.map(|location| location.name.as_str())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{duplicate_groups, has_structurally_complete_named_person_shape};
|
||||
|
||||
#[test]
|
||||
fn named_person_structural_completeness_requires_goal_memory_and_detail_state() {
|
||||
assert!(has_structurally_complete_named_person_shape(
|
||||
true, true, true
|
||||
));
|
||||
assert!(!has_structurally_complete_named_person_shape(
|
||||
false, true, true
|
||||
));
|
||||
assert!(!has_structurally_complete_named_person_shape(
|
||||
true, false, true
|
||||
));
|
||||
assert!(!has_structurally_complete_named_person_shape(
|
||||
true, true, false
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn duplicate_report_preserves_complete_prevalence_while_sampling_large_results() {
|
||||
let mut entries = (0..25)
|
||||
.map(|index| ("shared".to_owned(), format!("shared-{index:02}")))
|
||||
.collect::<Vec<_>>();
|
||||
for group in 0..21 {
|
||||
entries.push((format!("group-{group:02}"), format!("group-{group:02}-a")));
|
||||
entries.push((format!("group-{group:02}"), format!("group-{group:02}-b")));
|
||||
}
|
||||
|
||||
let report = duplicate_groups(entries);
|
||||
|
||||
assert_eq!(report["groupCount"], 22);
|
||||
assert_eq!(report["occurrenceCount"], 67);
|
||||
assert_eq!(report["groupsSample"].as_array().unwrap().len(), 20);
|
||||
assert_eq!(report["groupsSample"][0]["count"], 25);
|
||||
assert_eq!(
|
||||
report["groupsSample"][0]["subjectIdSample"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.len(),
|
||||
20
|
||||
);
|
||||
assert_eq!(report["truncated"], true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1236,6 +1236,20 @@ pub enum WorldCommand {
|
|||
#[serde(default)]
|
||||
model_stage_receipts: Vec<crate::model::ModelStageReceipt>,
|
||||
},
|
||||
ElaborateGestaltFission {
|
||||
expected_revision: u64,
|
||||
preview: GestaltFissionPreview,
|
||||
qualification: crate::elaboration::WorldComplexityFissionQualification,
|
||||
#[serde(default)]
|
||||
model_stage_receipts: Vec<crate::model::ModelStageReceipt>,
|
||||
},
|
||||
ElaborateGestaltIndividuation {
|
||||
expected_revision: u64,
|
||||
individuation: GestaltIndividuation,
|
||||
qualification: crate::elaboration::WorldComplexityIndividuationQualification,
|
||||
#[serde(default)]
|
||||
model_stage_receipts: Vec<crate::model::ModelStageReceipt>,
|
||||
},
|
||||
ReconcileFissionCivicBindings {
|
||||
expected_revision: u64,
|
||||
},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1144,6 +1144,74 @@ fn execute(
|
|||
Some((transition, mutation_receipt)),
|
||||
)
|
||||
}
|
||||
WorldCommand::ElaborateGestaltFission {
|
||||
expected_revision,
|
||||
preview,
|
||||
qualification,
|
||||
model_stage_receipts,
|
||||
} => {
|
||||
require_revision(&campaign, expected_revision)?;
|
||||
if qualification.schema != "ghostlight.world_complexity_fission_qualification.v1"
|
||||
|| !(1..=6).contains(&qualification.target_actionable_gain)
|
||||
|| model_stage_receipts.is_empty()
|
||||
{
|
||||
return Err(KernelError::Invalid(
|
||||
"elaborated fission lacks its exact qualification or model provenance".into(),
|
||||
));
|
||||
}
|
||||
let parent = campaign
|
||||
.gestalts
|
||||
.get(&preview.parent_gestalt_id)
|
||||
.ok_or_else(|| KernelError::Invalid("fission parent is unknown".into()))?;
|
||||
let proposal = crate::elaboration::WorldComplexityProposal::Fission {
|
||||
preview: preview.clone(),
|
||||
qualification: qualification.clone(),
|
||||
};
|
||||
crate::resolution::validate_elaborated_fission(&campaign, &preview)
|
||||
.and_then(|_| {
|
||||
crate::elaboration::validate_complexity_fission_semantics(
|
||||
&campaign,
|
||||
parent,
|
||||
&preview,
|
||||
qualification.title,
|
||||
&qualification.jurisdiction_location_id,
|
||||
qualification.target_actionable_gain,
|
||||
)
|
||||
})
|
||||
.and_then(|_| {
|
||||
crate::elaboration::validate_world_complexity_semantic_provenance(
|
||||
&campaign,
|
||||
&proposal,
|
||||
&qualification.semantic,
|
||||
&model_stage_receipts,
|
||||
)
|
||||
})
|
||||
.map_err(|error| KernelError::Invalid(error.to_string()))?;
|
||||
let transition = crate::legacy_transition::lower_elaborated_fission(
|
||||
&campaign,
|
||||
&preview,
|
||||
Utc::now() + Duration::minutes(5),
|
||||
)
|
||||
.map_err(|error| KernelError::Invalid(error.to_string()))?;
|
||||
let mutation_receipt = crate::legacy_transition::apply_lowered_elaborated_fission(
|
||||
&mut campaign,
|
||||
&preview,
|
||||
&transition,
|
||||
Utc::now(),
|
||||
)
|
||||
.map_err(|error| KernelError::Invalid(error.to_string()))?;
|
||||
commit_with_records(
|
||||
store,
|
||||
row,
|
||||
campaign,
|
||||
"elaborate_gestalt_fission",
|
||||
Vec::new(),
|
||||
Vec::new(),
|
||||
model_stage_receipts,
|
||||
None,
|
||||
Some((transition, mutation_receipt)),
|
||||
)
|
||||
}
|
||||
WorldCommand::ReconcileFissionCivicBindings { expected_revision } => {
|
||||
require_revision(&campaign, expected_revision)?;
|
||||
let transition = crate::legacy_transition::lower_fission_civic_reconciliation(
|
||||
|
|
@ -1618,6 +1686,7 @@ fn execute(
|
|||
campaign,
|
||||
"materialize_gestalt_member",
|
||||
"direct materialization command",
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
WorldCommand::IndividuateGestaltMember {
|
||||
|
|
@ -1634,6 +1703,67 @@ fn execute(
|
|||
campaign,
|
||||
"individuate_gestalt_member",
|
||||
"direct individuation command",
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
WorldCommand::ElaborateGestaltIndividuation {
|
||||
expected_revision,
|
||||
individuation,
|
||||
qualification,
|
||||
model_stage_receipts,
|
||||
} => {
|
||||
require_revision(&campaign, expected_revision)?;
|
||||
if qualification.schema != "ghostlight.world_complexity_individuation_qualification.v1"
|
||||
|| model_stage_receipts.is_empty()
|
||||
{
|
||||
return Err(KernelError::Invalid(
|
||||
"elaborated individuation lacks its exact qualification or model provenance"
|
||||
.into(),
|
||||
));
|
||||
}
|
||||
let proposal = crate::elaboration::WorldComplexityProposal::Individuate {
|
||||
individuation: individuation.clone(),
|
||||
qualification: qualification.clone(),
|
||||
};
|
||||
if crate::elaboration::unique_containing_jurisdiction(
|
||||
&campaign,
|
||||
&BTreeSet::from([individuation.location_id.clone()]),
|
||||
&BTreeSet::from([qualification.jurisdiction_location_id.clone()]),
|
||||
)
|
||||
.as_deref()
|
||||
!= Some(qualification.jurisdiction_location_id.as_str())
|
||||
{
|
||||
return Err(KernelError::Invalid(
|
||||
"elaborated individuation escaped its qualified jurisdiction".into(),
|
||||
));
|
||||
}
|
||||
crate::resolution::validate_gestalt_individuation(&campaign, &individuation)
|
||||
.and_then(|_| {
|
||||
crate::elaboration::validate_complexity_individuation_semantics(
|
||||
&campaign,
|
||||
qualification.title,
|
||||
&individuation,
|
||||
)
|
||||
})
|
||||
.and_then(|_| {
|
||||
crate::elaboration::validate_world_complexity_semantic_provenance(
|
||||
&campaign,
|
||||
&proposal,
|
||||
&qualification.semantic,
|
||||
&model_stage_receipts,
|
||||
)
|
||||
})
|
||||
.map_err(|error| KernelError::Invalid(error.to_string()))?;
|
||||
let before = campaign.clone();
|
||||
apply_individuation(&mut campaign, &individuation)?;
|
||||
commit_gestalt_presence(
|
||||
store,
|
||||
row,
|
||||
before,
|
||||
campaign,
|
||||
"elaborate_gestalt_individuation",
|
||||
"model-qualified world-complexity individuation",
|
||||
model_stage_receipts,
|
||||
)
|
||||
}
|
||||
WorldCommand::DematerializeGestaltMember {
|
||||
|
|
@ -1650,6 +1780,7 @@ fn execute(
|
|||
campaign,
|
||||
"dematerialize_gestalt_member",
|
||||
"direct dematerialization command",
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
WorldCommand::ReconcileGestaltPresence {
|
||||
|
|
@ -1722,6 +1853,7 @@ fn execute(
|
|||
candidate,
|
||||
"reconcile_gestalt_presence",
|
||||
&reason,
|
||||
Vec::new(),
|
||||
)
|
||||
}
|
||||
WorldCommand::ResolveReactionWave {
|
||||
|
|
@ -2235,7 +2367,7 @@ fn apply_promotion(
|
|||
}
|
||||
let member = campaign
|
||||
.gestalt_members
|
||||
.get_mut(&promotion.member_id)
|
||||
.get(&promotion.member_id)
|
||||
.ok_or_else(|| KernelError::Invalid("gestalt member is unknown".into()))?;
|
||||
if member.gestalt_id != promotion.gestalt_id
|
||||
|| member.version != promotion.expected_member_version
|
||||
|
|
@ -2250,11 +2382,19 @@ fn apply_promotion(
|
|||
));
|
||||
}
|
||||
let actor_id = crate::domain::gestalt_member_subject_id(&member.id);
|
||||
if campaign.actors.contains_key(&actor_id) {
|
||||
if crate::resolution::canonical_subject_id_is_occupied_except_member(
|
||||
campaign,
|
||||
&actor_id,
|
||||
Some(&promotion.member_id),
|
||||
) {
|
||||
return Err(KernelError::Invalid(
|
||||
"materialized actor id collides".into(),
|
||||
"materialized actor id collides with an established canonical subject identity".into(),
|
||||
));
|
||||
}
|
||||
let member = campaign
|
||||
.gestalt_members
|
||||
.get_mut(&promotion.member_id)
|
||||
.ok_or_else(|| KernelError::Invalid("gestalt member is unknown".into()))?;
|
||||
let actor = materialize_actor(&gestalt, member, &actor_id, &promotion.location_id);
|
||||
member.materialized_actor_id = Some(actor_id.clone());
|
||||
member.last_location_id = Some(promotion.location_id.clone());
|
||||
|
|
@ -3762,6 +3902,7 @@ fn commit_gestalt_presence(
|
|||
mut campaign: Campaign,
|
||||
kind: &str,
|
||||
reason: &str,
|
||||
model_receipts: Vec<crate::model::ModelStageReceipt>,
|
||||
) -> Result<CommandResult, KernelError> {
|
||||
let previous_resolution_epoch = campaign.resolution_policy.resolution_epoch;
|
||||
crate::resolution::ensure_agency_profiles(&mut campaign);
|
||||
|
|
@ -3853,7 +3994,14 @@ fn commit_gestalt_presence(
|
|||
};
|
||||
let key = format!("{}-{}", campaign.id, campaign.revision);
|
||||
store
|
||||
.append_gestalt_presence(&row, &campaign, &key, &receipt, &gestalt_receipt)
|
||||
.append_gestalt_presence(
|
||||
&row,
|
||||
&campaign,
|
||||
&key,
|
||||
&receipt,
|
||||
&gestalt_receipt,
|
||||
&model_receipts,
|
||||
)
|
||||
.map_err(persist)?;
|
||||
Ok(CommandResult::Committed { campaign, receipt })
|
||||
}
|
||||
|
|
@ -5301,6 +5449,92 @@ pub(crate) mod tests {
|
|||
assert_eq!(persisted.actors["taren"].name, "Taren");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn individuation_validation_and_application_share_the_canonical_subject_namespace() {
|
||||
let mut value = campaign();
|
||||
value.gestalts.insert(
|
||||
"refugees".into(),
|
||||
GestaltPersonaState {
|
||||
schema: "ghostlight.gestalt_persona_state.v1".into(),
|
||||
id: "refugees".into(),
|
||||
name: "Refugees".into(),
|
||||
version: 0,
|
||||
home_location_id: "room".into(),
|
||||
shared_capabilities: BTreeSet::new(),
|
||||
shared_knowledge: BTreeSet::new(),
|
||||
resources: BTreeSet::new(),
|
||||
goals: vec![],
|
||||
pressures: vec![],
|
||||
},
|
||||
);
|
||||
crate::resolution::ensure_agency_profiles(&mut value);
|
||||
let member = GestaltMemberDelta {
|
||||
schema: "ghostlight.gestalt_member_delta.v1".into(),
|
||||
id: "relay-volunteer".into(),
|
||||
gestalt_id: "refugees".into(),
|
||||
version: 0,
|
||||
name: "Relay Volunteer".into(),
|
||||
capability_additions: BTreeSet::new(),
|
||||
capability_removals: BTreeSet::new(),
|
||||
knowledge_additions: BTreeSet::new(),
|
||||
knowledge_removals: BTreeSet::new(),
|
||||
equipment: BTreeSet::new(),
|
||||
conditions: BTreeSet::new(),
|
||||
obligations: BTreeSet::new(),
|
||||
relationships: BTreeMap::new(),
|
||||
goals: vec![],
|
||||
memories: vec![],
|
||||
last_location_id: Some("room".into()),
|
||||
materialized_actor_id: None,
|
||||
last_relevant_revision: 0,
|
||||
relevance_lease_until_revision: 0,
|
||||
};
|
||||
let actor_id = crate::domain::gestalt_member_subject_id(&member.id);
|
||||
let mut reservation = value.agency_profiles["refugees"].clone();
|
||||
reservation.id = actor_id.clone();
|
||||
reservation.subject_id = "detached-profile-subject".into();
|
||||
reservation.active_leaf = false;
|
||||
reservation.simulation_eligible = false;
|
||||
value
|
||||
.agency_profiles
|
||||
.insert("detached-profile-key".into(), reservation);
|
||||
let individuation = GestaltIndividuation {
|
||||
gestalt_id: "refugees".into(),
|
||||
expected_gestalt_version: 0,
|
||||
member: member.clone(),
|
||||
location_id: "room".into(),
|
||||
};
|
||||
|
||||
let diagnostic = crate::resolution::validate_gestalt_individuation(&value, &individuation)
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
assert!(diagnostic.contains("established canonical subject identity"));
|
||||
|
||||
value.gestalt_members.insert(member.id.clone(), member);
|
||||
let error = apply_promotion(
|
||||
&mut value,
|
||||
&GestaltPromotion {
|
||||
gestalt_id: "refugees".into(),
|
||||
expected_gestalt_version: 0,
|
||||
member_id: "relay-volunteer".into(),
|
||||
expected_member_version: 0,
|
||||
location_id: "room".into(),
|
||||
},
|
||||
)
|
||||
.unwrap_err();
|
||||
assert!(
|
||||
error
|
||||
.to_string()
|
||||
.contains("established canonical subject identity")
|
||||
);
|
||||
assert!(!value.actors.contains_key(&actor_id));
|
||||
assert!(
|
||||
value.gestalt_members["relay-volunteer"]
|
||||
.materialized_actor_id
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn composite_selected_action_commits_atomically_and_rebuilds_derived_lanes() {
|
||||
let mut value = campaign();
|
||||
|
|
|
|||
|
|
@ -153,7 +153,28 @@ pub fn lower_fission(
|
|||
preview: &GestaltFissionPreview,
|
||||
expires_at: DateTime<Utc>,
|
||||
) -> Result<LoweredLegacyTransition> {
|
||||
crate::resolution::validate_fission(campaign, preview)?;
|
||||
lower_fission_with_validation(campaign, preview, expires_at, false)
|
||||
}
|
||||
|
||||
pub fn lower_elaborated_fission(
|
||||
campaign: &Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
expires_at: DateTime<Utc>,
|
||||
) -> Result<LoweredLegacyTransition> {
|
||||
lower_fission_with_validation(campaign, preview, expires_at, true)
|
||||
}
|
||||
|
||||
fn lower_fission_with_validation(
|
||||
campaign: &Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
expires_at: DateTime<Utc>,
|
||||
allow_semantic_additions: bool,
|
||||
) -> Result<LoweredLegacyTransition> {
|
||||
if allow_semantic_additions {
|
||||
crate::resolution::validate_elaborated_fission(campaign, preview)?;
|
||||
} else {
|
||||
crate::resolution::validate_fission(campaign, preview)?;
|
||||
}
|
||||
let preview_digest = digest_serializable(preview)?;
|
||||
let source_receipt_id = format!(
|
||||
"fission-preview:{}",
|
||||
|
|
@ -196,6 +217,81 @@ pub fn lower_fission(
|
|||
.collect(),
|
||||
remainder_population: Some(population_subject(&preview.residual_child_id)),
|
||||
});
|
||||
if allow_semantic_additions {
|
||||
for child in &preview.children {
|
||||
let subject = population_subject(&child.id);
|
||||
for capability in child
|
||||
.shared_capabilities
|
||||
.difference(&campaign.gestalts[&preview.parent_gestalt_id].shared_capabilities)
|
||||
{
|
||||
mutations.push(WorldMutation::ChangeCapability {
|
||||
subject: subject.clone(),
|
||||
operation: CapabilityMutationOperation::Grant,
|
||||
capability_id: capability.clone(),
|
||||
description: Some(capability.clone()),
|
||||
});
|
||||
}
|
||||
for statement in child
|
||||
.shared_knowledge
|
||||
.difference(&campaign.gestalts[&preview.parent_gestalt_id].shared_knowledge)
|
||||
{
|
||||
let (proposition, needs_admission) =
|
||||
elaborated_fission_proposition(campaign, statement)?;
|
||||
if needs_admission {
|
||||
mutations.push(WorldMutation::AdmitEntity {
|
||||
subject: proposition.clone(),
|
||||
initial_components: BTreeSet::from([
|
||||
WorldComponentKind::Knowledge,
|
||||
WorldComponentKind::PropositionContent,
|
||||
]),
|
||||
initial_place: None,
|
||||
initial_profile: Some(AdmittedEntityProfile::Proposition {
|
||||
statement: statement.clone(),
|
||||
scope: FactScope::ProvisionalLocal,
|
||||
evidence_receipt_ids: BTreeSet::new(),
|
||||
discoverable_at_places: BTreeSet::new(),
|
||||
}),
|
||||
admission_receipt_id: source_receipt_id.clone(),
|
||||
});
|
||||
}
|
||||
mutations.push(WorldMutation::ChangeKnowledge {
|
||||
operation: KnowledgeMutationOperation::Acquire,
|
||||
proposition,
|
||||
knower: Some(subject.clone()),
|
||||
speaker: None,
|
||||
recipients: Vec::new(),
|
||||
channel: None,
|
||||
});
|
||||
}
|
||||
for goal in child
|
||||
.goals
|
||||
.iter()
|
||||
.skip(campaign.gestalts[&preview.parent_gestalt_id].goals.len())
|
||||
{
|
||||
mutations.push(WorldMutation::ChangeCommitment {
|
||||
subject: subject.clone(),
|
||||
operation: CommitmentMutationOperation::Create,
|
||||
kind: CommitmentKind::Goal,
|
||||
commitment_id: format!("goal:elaboration:{}", short_digest(goal)),
|
||||
counterparty: None,
|
||||
description: Some(goal.clone()),
|
||||
});
|
||||
}
|
||||
for pressure in child.pressures.iter().skip(
|
||||
campaign.gestalts[&preview.parent_gestalt_id]
|
||||
.pressures
|
||||
.len(),
|
||||
) {
|
||||
mutations.push(WorldMutation::ChangePressure {
|
||||
pressure: gestalt_pressure_subject(&child.id, pressure),
|
||||
owner: subject.clone(),
|
||||
operation: PressureMutationOperation::Create,
|
||||
amount: Some(4),
|
||||
label: Some(pressure.clone()),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
for (resource, child_id) in &preview.resource_child_assignments {
|
||||
mutations.push(WorldMutation::TransferCustody {
|
||||
resource: resource_subject(campaign, &parent, resource),
|
||||
|
|
@ -227,6 +323,11 @@ pub fn lower_fission(
|
|||
system,
|
||||
});
|
||||
}
|
||||
let effect_ceiling = if allow_semantic_additions {
|
||||
"Admit the approved child populations, preserve their inherited baseline, add only each child's explicitly qualified capabilities, knowledge, goals, and pressures, partition each exact resource once, transfer each named member once, and record one population lineage split."
|
||||
} else {
|
||||
"Admit the approved child populations, preserve their inherited baseline, partition each exact resource once, transfer each named member once, and record one population lineage split."
|
||||
};
|
||||
lower_exact_mutations(
|
||||
campaign,
|
||||
mutations,
|
||||
|
|
@ -234,7 +335,7 @@ pub fn lower_fission(
|
|||
None,
|
||||
MutationOutcomeBinding::Deterministic,
|
||||
Some(campaign.resolution_policy.resolution_epoch),
|
||||
"Admit the approved child populations, preserve their inherited baseline, partition each exact resource once, transfer each named member once, and record one population lineage split.",
|
||||
effect_ceiling,
|
||||
&source_receipt_id,
|
||||
Some(digest_serializable(&(
|
||||
"fission",
|
||||
|
|
@ -246,6 +347,51 @@ pub fn lower_fission(
|
|||
)
|
||||
}
|
||||
|
||||
fn elaborated_fission_proposition(
|
||||
campaign: &Campaign,
|
||||
statement: &str,
|
||||
) -> Result<(SubjectRef, bool)> {
|
||||
if let Some(fact) = campaign
|
||||
.facts
|
||||
.values()
|
||||
.find(|fact| fact.statement == statement)
|
||||
{
|
||||
return Ok((proposition_subject(&fact.id), false));
|
||||
}
|
||||
let already_known = campaign
|
||||
.actors
|
||||
.values()
|
||||
.any(|actor| actor.knowledge.contains(statement))
|
||||
|| campaign
|
||||
.gestalts
|
||||
.values()
|
||||
.any(|gestalt| gestalt.shared_knowledge.contains(statement))
|
||||
|| campaign.gestalt_members.values().any(|member| {
|
||||
member.knowledge_additions.contains(statement)
|
||||
&& !member.knowledge_removals.contains(statement)
|
||||
});
|
||||
if already_known {
|
||||
return Ok((
|
||||
proposition_subject(&format!("legacy-knowledge:{}", short_digest(statement))),
|
||||
false,
|
||||
));
|
||||
}
|
||||
let fact_id = format!(
|
||||
"fact:complexity-fission:{:x}",
|
||||
Sha256::digest(statement.as_bytes())
|
||||
);
|
||||
if let Some(existing) = campaign.facts.get(&fact_id) {
|
||||
return if existing.statement == statement {
|
||||
Ok((proposition_subject(&fact_id), false))
|
||||
} else {
|
||||
Err(anyhow!(
|
||||
"content-addressed complexity knowledge collided with another fact"
|
||||
))
|
||||
};
|
||||
}
|
||||
Ok((proposition_subject(&fact_id), true))
|
||||
}
|
||||
|
||||
fn fission_civic_system_rebindings(
|
||||
campaign: &Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
|
|
@ -425,7 +571,30 @@ pub fn apply_lowered_fission(
|
|||
transition: &LoweredLegacyTransition,
|
||||
now: DateTime<Utc>,
|
||||
) -> Result<WorldMutationReceipt> {
|
||||
crate::resolution::validate_fission(campaign, preview)?;
|
||||
apply_lowered_fission_with_validation(campaign, preview, transition, now, false)
|
||||
}
|
||||
|
||||
pub fn apply_lowered_elaborated_fission(
|
||||
campaign: &mut Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
transition: &LoweredLegacyTransition,
|
||||
now: DateTime<Utc>,
|
||||
) -> Result<WorldMutationReceipt> {
|
||||
apply_lowered_fission_with_validation(campaign, preview, transition, now, true)
|
||||
}
|
||||
|
||||
fn apply_lowered_fission_with_validation(
|
||||
campaign: &mut Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
transition: &LoweredLegacyTransition,
|
||||
now: DateTime<Utc>,
|
||||
allow_semantic_additions: bool,
|
||||
) -> Result<WorldMutationReceipt> {
|
||||
if allow_semantic_additions {
|
||||
crate::resolution::validate_elaborated_fission(campaign, preview)?;
|
||||
} else {
|
||||
crate::resolution::validate_fission(campaign, preview)?;
|
||||
}
|
||||
let snapshot = component_snapshot(campaign)?;
|
||||
let application =
|
||||
apply_component_world_batch(&snapshot, &transition.authority, &transition.batch, now)?;
|
||||
|
|
@ -962,6 +1131,116 @@ fn project_accepted_region_expansion(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn verify_fission_child_components(
|
||||
next: &ComponentWorldState,
|
||||
child: &GestaltPersonaState,
|
||||
) -> Result<()> {
|
||||
let subject = population_subject(&child.id);
|
||||
let capabilities = next
|
||||
.capabilities
|
||||
.iter()
|
||||
.filter(|(key, value)| key.subject == subject && !value.suspended)
|
||||
.map(|(key, value)| {
|
||||
if value.description != key.entry_id {
|
||||
return Err(anyhow!(
|
||||
"accepted fission capability identity diverged from its description"
|
||||
));
|
||||
}
|
||||
Ok(key.entry_id.clone())
|
||||
})
|
||||
.collect::<Result<BTreeSet<_>>>()?;
|
||||
let knowledge = next
|
||||
.knowledge
|
||||
.iter()
|
||||
.filter(|(key, value)| key.knower == subject && value.status == "known")
|
||||
.map(|(key, _)| {
|
||||
next.propositions
|
||||
.get(&key.proposition)
|
||||
.map(|value| value.statement.clone())
|
||||
.ok_or_else(|| anyhow!("accepted fission knowledge lost proposition content"))
|
||||
})
|
||||
.collect::<Result<BTreeSet<_>>>()?;
|
||||
let goals = next
|
||||
.commitments
|
||||
.iter()
|
||||
.filter(|(key, value)| {
|
||||
key.subject == subject && value.kind == CommitmentKind::Goal && value.status == "active"
|
||||
})
|
||||
.map(|(_, value)| value.description.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
let pressures = next
|
||||
.pressures
|
||||
.values()
|
||||
.filter(|value| value.owner == subject && !value.resolved)
|
||||
.map(|value| value.label.clone())
|
||||
.collect::<BTreeSet<_>>();
|
||||
if capabilities != child.shared_capabilities
|
||||
|| knowledge != child.shared_knowledge
|
||||
|| goals != child.goals.iter().cloned().collect()
|
||||
|| pressures != child.pressures.iter().cloned().collect()
|
||||
{
|
||||
return Err(anyhow!(
|
||||
"accepted fission component semantics diverged from the approved child"
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn project_elaborated_fission_facts(
|
||||
campaign: &mut Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
next: &ComponentWorldState,
|
||||
) -> Result<()> {
|
||||
let parent = campaign
|
||||
.gestalts
|
||||
.get(&preview.parent_gestalt_id)
|
||||
.ok_or_else(|| anyhow!("accepted complexity fact lost its fission parent"))?;
|
||||
let mut admitted = BTreeMap::new();
|
||||
for child in &preview.children {
|
||||
let knower = population_subject(&child.id);
|
||||
for statement in child.shared_knowledge.difference(&parent.shared_knowledge) {
|
||||
let (proposition_id, needs_admission) =
|
||||
elaborated_fission_proposition(campaign, statement)?;
|
||||
if !needs_admission {
|
||||
continue;
|
||||
}
|
||||
let knowledge_key = KnowledgeKey {
|
||||
knower: knower.clone(),
|
||||
proposition: proposition_id.clone(),
|
||||
};
|
||||
if !next.knowledge.contains_key(&knowledge_key) {
|
||||
return Err(anyhow!(
|
||||
"accepted complexity fact was not acquired by its approved child"
|
||||
));
|
||||
}
|
||||
let proposition = next
|
||||
.propositions
|
||||
.get(&proposition_id)
|
||||
.ok_or_else(|| anyhow!("accepted complexity fact lost proposition content"))?;
|
||||
admitted.insert(
|
||||
proposition_id.id.clone(),
|
||||
WorldFact {
|
||||
id: proposition_id.id.clone(),
|
||||
statement: proposition.statement.clone(),
|
||||
scope: proposition.scope.clone(),
|
||||
evidence_receipt_ids: proposition
|
||||
.evidence_receipt_ids
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
discoverable_at_location_ids: proposition
|
||||
.discoverable_at_places
|
||||
.iter()
|
||||
.map(|place| place.id.clone())
|
||||
.collect(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
campaign.facts.extend(admitted);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn project_accepted_fission(
|
||||
campaign: &mut Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
|
|
@ -982,6 +1261,7 @@ fn project_accepted_fission(
|
|||
})
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
project_elaborated_fission_facts(campaign, preview, next)?;
|
||||
|
||||
for approved in &preview.children {
|
||||
let subject = population_subject(&approved.id);
|
||||
|
|
@ -995,21 +1275,12 @@ fn project_accepted_fission(
|
|||
.get(&format!("identity:canonical:{}", approved.id))
|
||||
.filter(|identity| identity.subject == subject && identity.active)
|
||||
.ok_or_else(|| anyhow!("accepted fission child lacks exact identity"))?;
|
||||
campaign.gestalts.insert(
|
||||
approved.id.clone(),
|
||||
GestaltPersonaState {
|
||||
schema: "ghostlight.gestalt_persona_state.v1".into(),
|
||||
id: approved.id.clone(),
|
||||
name: identity.value.clone(),
|
||||
version: 0,
|
||||
home_location_id: place.id.clone(),
|
||||
shared_capabilities: parent.shared_capabilities.clone(),
|
||||
shared_knowledge: parent.shared_knowledge.clone(),
|
||||
resources: BTreeSet::new(),
|
||||
goals: parent.goals.clone(),
|
||||
pressures: parent.pressures.clone(),
|
||||
},
|
||||
);
|
||||
verify_fission_child_components(next, approved)?;
|
||||
let mut accepted = approved.clone();
|
||||
accepted.name = identity.value.clone();
|
||||
accepted.home_location_id = place.id.clone();
|
||||
accepted.resources.clear();
|
||||
campaign.gestalts.insert(approved.id.clone(), accepted);
|
||||
}
|
||||
|
||||
let member_ids = campaign
|
||||
|
|
@ -3888,6 +4159,111 @@ mod tests {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn elaborated_fission_commits_qualified_child_semantics_in_one_typed_batch() {
|
||||
let mut campaign = campaign();
|
||||
let inherited_knowledge = campaign.facts["fact:route"].statement.clone();
|
||||
let parent = GestaltPersonaState {
|
||||
schema: "ghostlight.gestalt_persona_state.v1".into(),
|
||||
id: "residents".into(),
|
||||
name: "Residents".into(),
|
||||
version: 0,
|
||||
home_location_id: "room".into(),
|
||||
shared_capabilities: BTreeSet::from(["keep the public stair open".into()]),
|
||||
shared_knowledge: BTreeSet::from([inherited_knowledge.clone()]),
|
||||
resources: BTreeSet::new(),
|
||||
goals: vec!["keep the hall inhabited".into()],
|
||||
pressures: vec!["the night watch is thin".into()],
|
||||
};
|
||||
campaign.gestalts.insert(parent.id.clone(), parent.clone());
|
||||
crate::resolution::ensure_agency_profiles(&mut campaign);
|
||||
|
||||
let situated_knowledge =
|
||||
"The eastern lintel rings when the sealed cistern changes pressure.".to_owned();
|
||||
let mut specific = parent.clone();
|
||||
specific.id = "lintel-keepers".into();
|
||||
specific.name = "Lintel Keepers".into();
|
||||
specific
|
||||
.shared_capabilities
|
||||
.insert("sound the lintel before opening the cistern".into());
|
||||
specific.shared_knowledge.insert(situated_knowledge.clone());
|
||||
specific
|
||||
.goals
|
||||
.push("win custody of the eastern cistern key".into());
|
||||
specific
|
||||
.pressures
|
||||
.push("the cistern key is promised to two rival crews".into());
|
||||
let mut residual = parent.clone();
|
||||
residual.id = "residents-unresolved".into();
|
||||
residual.name = "Unresolved Residents".into();
|
||||
let preview = GestaltFissionPreview {
|
||||
schema: "ghostlight.gestalt_fission_preview.v1".into(),
|
||||
campaign_id: campaign.id,
|
||||
expected_world_revision: campaign.revision,
|
||||
parent_gestalt_id: parent.id.clone(),
|
||||
partition_axis: crate::domain::AgencyAxis::Ideology,
|
||||
children: vec![specific.clone(), residual],
|
||||
child_partition_values: BTreeMap::from([
|
||||
(specific.id.clone(), "lintel custody".into()),
|
||||
("residents-unresolved".into(), "other/unknown".into()),
|
||||
]),
|
||||
residual_child_id: "residents-unresolved".into(),
|
||||
member_child_assignments: BTreeMap::new(),
|
||||
resource_child_assignments: BTreeMap::new(),
|
||||
evidence_receipt_ids: vec![],
|
||||
gaps: vec![],
|
||||
canon_candidates: vec![],
|
||||
requires_approval: true,
|
||||
};
|
||||
|
||||
assert!(lower_fission(&campaign, &preview, Utc::now() + Duration::minutes(5)).is_err());
|
||||
let transition =
|
||||
lower_elaborated_fission(&campaign, &preview, Utc::now() + Duration::minutes(5))
|
||||
.unwrap();
|
||||
assert!(transition.batch.mutations.iter().any(|mutation| matches!(
|
||||
mutation.mutation,
|
||||
WorldMutation::AdmitEntity {
|
||||
initial_profile: Some(AdmittedEntityProfile::Proposition { .. }),
|
||||
..
|
||||
}
|
||||
)));
|
||||
assert!(
|
||||
transition.batch.mutations.iter().any(|mutation| matches!(
|
||||
mutation.mutation,
|
||||
WorldMutation::ChangeCapability { .. }
|
||||
))
|
||||
);
|
||||
assert!(
|
||||
transition
|
||||
.batch
|
||||
.mutations
|
||||
.iter()
|
||||
.any(|mutation| matches!(mutation.mutation, WorldMutation::ChangeKnowledge { .. }))
|
||||
);
|
||||
assert!(
|
||||
transition.batch.mutations.iter().any(|mutation| matches!(
|
||||
mutation.mutation,
|
||||
WorldMutation::ChangeCommitment { .. }
|
||||
))
|
||||
);
|
||||
assert!(
|
||||
transition
|
||||
.batch
|
||||
.mutations
|
||||
.iter()
|
||||
.any(|mutation| matches!(mutation.mutation, WorldMutation::ChangePressure { .. }))
|
||||
);
|
||||
|
||||
apply_lowered_elaborated_fission(&mut campaign, &preview, &transition, Utc::now()).unwrap();
|
||||
assert_eq!(campaign.gestalts[&specific.id], specific);
|
||||
assert!(campaign.facts.values().any(|fact| {
|
||||
fact.statement == situated_knowledge
|
||||
&& fact.scope == crate::domain::FactScope::ProvisionalLocal
|
||||
}));
|
||||
crate::transition::validate_component_world(&component_snapshot(&campaign).unwrap())
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shared_learning_updates_the_materialized_member_projection() {
|
||||
let mut campaign = campaign();
|
||||
|
|
|
|||
|
|
@ -5498,12 +5498,14 @@ fn player_http_command_allowed(command: &WorldCommand, player_actor_id: &str) ->
|
|||
| WorldCommand::MaterializeGestaltMember { .. }
|
||||
| WorldCommand::DematerializeGestaltMember { .. }
|
||||
| WorldCommand::IndividuateGestaltMember { .. }
|
||||
| WorldCommand::ElaborateGestaltIndividuation { .. }
|
||||
| WorldCommand::ReconcileGestaltPresence { .. }
|
||||
| WorldCommand::ResolveReactionWave { .. }
|
||||
| WorldCommand::ResolveNpcAction { .. }
|
||||
| WorldCommand::SetProviderParallelism { .. }
|
||||
| WorldCommand::ReplaceResolutionPins { .. }
|
||||
| WorldCommand::FissionGestalt { .. }
|
||||
| WorldCommand::ElaborateGestaltFission { .. }
|
||||
| WorldCommand::ReconcileFissionCivicBindings { .. }
|
||||
| WorldCommand::BindClockConsequences { .. } => false,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1174,6 +1174,7 @@ impl CampaignStore {
|
|||
receipt_key: &str,
|
||||
world_receipt: &WorldCommitReceipt,
|
||||
gestalt_receipt: &GestaltMaterializationReceipt,
|
||||
model_receipts: &[crate::model::ModelStageReceipt],
|
||||
) -> Result<CultCacheEnvelope> {
|
||||
let next_row = envelope(
|
||||
&expected.r#type,
|
||||
|
|
@ -1181,7 +1182,7 @@ impl CampaignStore {
|
|||
&expected.key,
|
||||
next,
|
||||
)?;
|
||||
let rows = vec![
|
||||
let mut rows = vec![
|
||||
next_row.clone(),
|
||||
envelope(
|
||||
"world_commit_receipt.v1",
|
||||
|
|
@ -1196,10 +1197,34 @@ impl CampaignStore {
|
|||
gestalt_receipt,
|
||||
)?,
|
||||
];
|
||||
if !self
|
||||
.inner
|
||||
.compare_and_swap_batch(std::slice::from_ref(expected), rows)?
|
||||
{
|
||||
let mut expected_rows = vec![expected.clone()];
|
||||
let mut unique_model_receipts = BTreeMap::<String, &ModelStageReceipt>::new();
|
||||
for item in model_receipts {
|
||||
if let Some(existing) = unique_model_receipts.get(item.storage_key()) {
|
||||
if !existing.same_receipted_content(item) {
|
||||
return Err(anyhow!(
|
||||
"immutable model-stage receipt conflict: {}",
|
||||
item.storage_key()
|
||||
));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
unique_model_receipts.insert(item.storage_key().to_owned(), item);
|
||||
}
|
||||
for item in unique_model_receipts.into_values() {
|
||||
if let Some(existing) = self.matching_model_stage_receipt(item)? {
|
||||
expected_rows.push(existing.clone());
|
||||
rows.push(existing);
|
||||
} else {
|
||||
rows.push(envelope(
|
||||
"persona_stage_receipt.v1",
|
||||
"ghostlight.persona_stage_receipt.v1",
|
||||
item.storage_key(),
|
||||
item,
|
||||
)?);
|
||||
}
|
||||
}
|
||||
if !self.inner.compare_and_swap_batch(&expected_rows, rows)? {
|
||||
return Err(anyhow!("stale CultCache snapshot"));
|
||||
}
|
||||
Ok(next_row)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,38 @@ pub fn information_channel_is_concrete(channel: &str) -> bool {
|
|||
!channel.is_empty() && channel.len() <= 160 && !channel.eq_ignore_ascii_case("unknown")
|
||||
}
|
||||
|
||||
/// Canonical world subjects and their agency projections share one ID space.
|
||||
/// Keep this predicate deterministic and side-effect free: validators, rebases,
|
||||
/// and kernel application all consult the same occupied-set definition.
|
||||
pub(crate) fn canonical_subject_id_is_occupied(campaign: &Campaign, subject_id: &str) -> bool {
|
||||
canonical_subject_id_is_occupied_except_member(campaign, subject_id, None)
|
||||
}
|
||||
|
||||
pub(crate) fn canonical_subject_id_is_occupied_except_member(
|
||||
campaign: &Campaign,
|
||||
subject_id: &str,
|
||||
permitted_member_id: Option<&str>,
|
||||
) -> bool {
|
||||
let permitted_member_id =
|
||||
permitted_member_id.map(crate::domain::canonical_gestalt_member_local_id);
|
||||
campaign.actors.contains_key(subject_id)
|
||||
|| campaign.institutions.contains_key(subject_id)
|
||||
|| campaign.gestalts.contains_key(subject_id)
|
||||
|| campaign.gestalt_members.iter().any(|(member_id, member)| {
|
||||
permitted_member_id.as_deref()
|
||||
!= Some(crate::domain::canonical_gestalt_member_local_id(member_id).as_str())
|
||||
&& crate::domain::gestalt_member_subject_id(&member.id) == subject_id
|
||||
})
|
||||
|| campaign
|
||||
.agency_profiles
|
||||
.iter()
|
||||
.any(|(profile_key, profile)| {
|
||||
profile_key == subject_id
|
||||
|| profile.id == subject_id
|
||||
|| profile.subject_id == subject_id
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Candidate {
|
||||
left: String,
|
||||
|
|
@ -2258,6 +2290,27 @@ pub fn validate_gestalt_individuation(
|
|||
if member.name.chars().count() > 160 {
|
||||
findings.push("member name exceeds 160 characters".to_owned());
|
||||
}
|
||||
let public_name_key = public_identity_key(&member.name);
|
||||
if public_name_key.is_empty() {
|
||||
findings.push("member name has no public identity characters".to_owned());
|
||||
}
|
||||
if campaign
|
||||
.actors
|
||||
.values()
|
||||
.any(|actor| public_identity_key(&actor.name) == public_name_key)
|
||||
&& !public_name_key.is_empty()
|
||||
{
|
||||
findings.push("member name duplicates an established public Actor identity".to_owned());
|
||||
}
|
||||
if campaign
|
||||
.gestalt_members
|
||||
.values()
|
||||
.any(|existing| public_identity_key(&existing.name) == public_name_key)
|
||||
&& !public_name_key.is_empty()
|
||||
{
|
||||
findings
|
||||
.push("member name duplicates an established public population identity".to_owned());
|
||||
}
|
||||
if member.goals.len() > 8 {
|
||||
findings.push("member has more than eight goals".to_owned());
|
||||
}
|
||||
|
|
@ -2278,11 +2331,11 @@ pub fn validate_gestalt_individuation(
|
|||
{
|
||||
findings.push("member id duplicates an established population identity".to_owned());
|
||||
}
|
||||
if campaign
|
||||
.actors
|
||||
.contains_key(&crate::domain::gestalt_member_subject_id(&member.id))
|
||||
{
|
||||
findings.push("member id duplicates an established Actor identity".to_owned());
|
||||
if canonical_subject_id_is_occupied(
|
||||
campaign,
|
||||
&crate::domain::gestalt_member_subject_id(&member.id),
|
||||
) {
|
||||
findings.push("member id duplicates an established canonical subject identity".to_owned());
|
||||
}
|
||||
let unsupported_relationships = member
|
||||
.relationships
|
||||
|
|
@ -2313,6 +2366,17 @@ pub fn validate_gestalt_individuation(
|
|||
}
|
||||
}
|
||||
|
||||
/// Public names are an interface identity, not merely decorative text. Fold
|
||||
/// case and punctuation so spelling variants such as `Flint-Measure` and
|
||||
/// `Flintmeasure` cannot silently create two apparently identical people.
|
||||
pub fn public_identity_key(value: &str) -> String {
|
||||
value
|
||||
.chars()
|
||||
.filter(|character| character.is_alphanumeric())
|
||||
.flat_map(char::to_lowercase)
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn validate_strategic_individuation_proposals(
|
||||
campaign: &Campaign,
|
||||
proposals: &[StrategicGestaltIndividuation],
|
||||
|
|
@ -3337,6 +3401,9 @@ pub(crate) fn project_fission_resolution(
|
|||
campaign.gestalts.insert(child.id.clone(), child.clone());
|
||||
let mut profile = profile_for_gestalt(child, &preview.evidence_receipt_ids);
|
||||
profile.parent_subject_id = Some(preview.parent_gestalt_id.clone());
|
||||
if child.id == preview.residual_child_id {
|
||||
profile.simulation_eligible = false;
|
||||
}
|
||||
profile.facets = inherited.facets.clone();
|
||||
profile
|
||||
.facets
|
||||
|
|
@ -3365,6 +3432,36 @@ pub(crate) fn project_fission_resolution(
|
|||
}
|
||||
|
||||
pub fn validate_fission(campaign: &Campaign, preview: &GestaltFissionPreview) -> Result<()> {
|
||||
validate_fission_shape(campaign, preview, false)
|
||||
}
|
||||
|
||||
pub fn validate_elaborated_fission(
|
||||
campaign: &Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
) -> Result<()> {
|
||||
validate_fission_shape(campaign, preview, true)
|
||||
}
|
||||
|
||||
fn preserves_inherited_prefix_with_unique_additions(
|
||||
values: &[String],
|
||||
inherited: &[String],
|
||||
) -> bool {
|
||||
if !values.starts_with(inherited) {
|
||||
return false;
|
||||
}
|
||||
let inherited_len = inherited.len();
|
||||
let inherited = inherited.iter().collect::<BTreeSet<_>>();
|
||||
let mut additions = BTreeSet::new();
|
||||
values[inherited_len..]
|
||||
.iter()
|
||||
.all(|value| !inherited.contains(value) && additions.insert(value))
|
||||
}
|
||||
|
||||
fn validate_fission_shape(
|
||||
campaign: &Campaign,
|
||||
preview: &GestaltFissionPreview,
|
||||
allow_semantic_additions: bool,
|
||||
) -> Result<()> {
|
||||
let parent = campaign
|
||||
.gestalts
|
||||
.get(&preview.parent_gestalt_id)
|
||||
|
|
@ -3457,8 +3554,8 @@ pub fn validate_fission(campaign: &Campaign, preview: &GestaltFissionPreview) ->
|
|||
format!("child {label} version is not zero"),
|
||||
);
|
||||
require(
|
||||
!campaign.gestalts.contains_key(&child.id),
|
||||
format!("child {label} already exists"),
|
||||
!canonical_subject_id_is_occupied(campaign, &child.id),
|
||||
format!("child {label} collides with an established canonical subject identity"),
|
||||
);
|
||||
require(
|
||||
campaign.locations.contains_key(&child.home_location_id),
|
||||
|
|
@ -3470,20 +3567,45 @@ pub fn validate_fission(campaign: &Campaign, preview: &GestaltFissionPreview) ->
|
|||
format!("child {label} changed home outside a geography fission"),
|
||||
);
|
||||
require(
|
||||
child.shared_capabilities == parent.shared_capabilities,
|
||||
format!("child {label} changed inherited capabilities"),
|
||||
if allow_semantic_additions {
|
||||
child
|
||||
.shared_capabilities
|
||||
.is_superset(&parent.shared_capabilities)
|
||||
} else {
|
||||
child.shared_capabilities == parent.shared_capabilities
|
||||
},
|
||||
format!("child {label} changed inherited capabilities outside its authority"),
|
||||
);
|
||||
require(
|
||||
child.shared_knowledge == parent.shared_knowledge,
|
||||
format!("child {label} changed inherited knowledge"),
|
||||
if allow_semantic_additions {
|
||||
child.shared_knowledge.is_superset(&parent.shared_knowledge)
|
||||
} else {
|
||||
child.shared_knowledge == parent.shared_knowledge
|
||||
},
|
||||
format!("child {label} changed inherited knowledge outside its authority"),
|
||||
);
|
||||
require(
|
||||
child.goals == parent.goals,
|
||||
format!("child {label} changed inherited goals"),
|
||||
if allow_semantic_additions {
|
||||
preserves_inherited_prefix_with_unique_additions(&child.goals, &parent.goals)
|
||||
} else {
|
||||
child.goals == parent.goals
|
||||
},
|
||||
format!(
|
||||
"child {label} must preserve inherited goals as an exact prefix and add no duplicates"
|
||||
),
|
||||
);
|
||||
require(
|
||||
child.pressures == parent.pressures,
|
||||
format!("child {label} changed inherited pressures"),
|
||||
if allow_semantic_additions {
|
||||
preserves_inherited_prefix_with_unique_additions(
|
||||
&child.pressures,
|
||||
&parent.pressures,
|
||||
)
|
||||
} else {
|
||||
child.pressures == parent.pressures
|
||||
},
|
||||
format!(
|
||||
"child {label} must preserve inherited pressures as an exact prefix and add no duplicates"
|
||||
),
|
||||
);
|
||||
require(
|
||||
preview.child_partition_values.contains_key(&child.id),
|
||||
|
|
@ -3659,6 +3781,118 @@ pub(crate) mod tests {
|
|||
value
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fission_validation_uses_the_unified_canonical_subject_id_namespace() {
|
||||
let mut value = campaign(1, 1);
|
||||
value.gestalts.insert(
|
||||
"villagers".into(),
|
||||
GestaltPersonaState {
|
||||
schema: "ghostlight.gestalt_persona_state.v1".into(),
|
||||
id: "villagers".into(),
|
||||
name: "Villagers".into(),
|
||||
version: 0,
|
||||
home_location_id: "center".into(),
|
||||
shared_capabilities: BTreeSet::new(),
|
||||
shared_knowledge: BTreeSet::new(),
|
||||
resources: BTreeSet::new(),
|
||||
goals: vec![],
|
||||
pressures: vec![],
|
||||
},
|
||||
);
|
||||
ensure_agency_profiles(&mut value);
|
||||
let mut detached_profile = value.agency_profiles["villagers"].clone();
|
||||
detached_profile.id = "reserved-profile-id".into();
|
||||
detached_profile.subject_id = "reserved-profile-subject".into();
|
||||
detached_profile.active_leaf = false;
|
||||
detached_profile.simulation_eligible = false;
|
||||
value
|
||||
.agency_profiles
|
||||
.insert("reserved-profile-key".into(), detached_profile);
|
||||
value.gestalt_members.insert(
|
||||
"reserved-member".into(),
|
||||
GestaltMemberDelta {
|
||||
schema: "ghostlight.gestalt_member_delta.v1".into(),
|
||||
id: "reserved-member".into(),
|
||||
gestalt_id: "villagers".into(),
|
||||
version: 0,
|
||||
name: "Reserved Member".into(),
|
||||
capability_additions: BTreeSet::new(),
|
||||
capability_removals: BTreeSet::new(),
|
||||
knowledge_additions: BTreeSet::new(),
|
||||
knowledge_removals: BTreeSet::new(),
|
||||
equipment: BTreeSet::new(),
|
||||
conditions: BTreeSet::new(),
|
||||
obligations: BTreeSet::new(),
|
||||
relationships: BTreeMap::new(),
|
||||
goals: vec![],
|
||||
memories: vec![],
|
||||
last_location_id: Some("center".into()),
|
||||
materialized_actor_id: None,
|
||||
last_relevant_revision: 0,
|
||||
relevance_lease_until_revision: 0,
|
||||
},
|
||||
);
|
||||
|
||||
let child = |id: &str, name: &str| GestaltPersonaState {
|
||||
schema: "ghostlight.gestalt_persona_state.v1".into(),
|
||||
id: id.into(),
|
||||
name: name.into(),
|
||||
version: 0,
|
||||
home_location_id: "center".into(),
|
||||
shared_capabilities: BTreeSet::new(),
|
||||
shared_knowledge: BTreeSet::new(),
|
||||
resources: BTreeSet::new(),
|
||||
goals: vec![],
|
||||
pressures: vec![],
|
||||
};
|
||||
let preview = GestaltFissionPreview {
|
||||
schema: "ghostlight.gestalt_fission_preview.v1".into(),
|
||||
campaign_id: value.id,
|
||||
expected_world_revision: value.revision,
|
||||
parent_gestalt_id: "villagers".into(),
|
||||
partition_axis: AgencyAxis::Ideology,
|
||||
children: vec![
|
||||
child("new-villagers", "New villagers"),
|
||||
child("other", "Other"),
|
||||
],
|
||||
child_partition_values: BTreeMap::from([
|
||||
("new-villagers".into(), "new".into()),
|
||||
("other".into(), "other/unknown".into()),
|
||||
]),
|
||||
residual_child_id: "other".into(),
|
||||
member_child_assignments: BTreeMap::new(),
|
||||
resource_child_assignments: BTreeMap::new(),
|
||||
evidence_receipt_ids: vec![],
|
||||
gaps: vec![],
|
||||
canon_candidates: vec![],
|
||||
requires_approval: true,
|
||||
};
|
||||
|
||||
for occupied_id in [
|
||||
"player",
|
||||
"faction-0000",
|
||||
"villagers",
|
||||
"reserved-profile-key",
|
||||
"reserved-profile-id",
|
||||
"reserved-profile-subject",
|
||||
"member:reserved-member",
|
||||
] {
|
||||
let mut colliding = preview.clone();
|
||||
colliding.children[0].id = occupied_id.into();
|
||||
colliding.child_partition_values.remove("new-villagers");
|
||||
colliding
|
||||
.child_partition_values
|
||||
.insert(occupied_id.into(), "new".into());
|
||||
let diagnostic = validate_fission(&value, &colliding)
|
||||
.unwrap_err()
|
||||
.to_string();
|
||||
assert!(
|
||||
diagnostic.contains("collides with an established canonical subject identity"),
|
||||
"{occupied_id} escaped the canonical subject namespace: {diagnostic}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn profile_maintenance_never_promotes_knowledge_into_public_channels() {
|
||||
let mut value = campaign(1, 1);
|
||||
|
|
@ -5104,6 +5338,8 @@ pub(crate) mod tests {
|
|||
assert!(!value.agency_profiles["villagers"].active_leaf);
|
||||
assert!(value.agency_profiles["traditionalists"].active_leaf);
|
||||
assert!(value.agency_profiles["other"].active_leaf);
|
||||
assert!(value.agency_profiles["traditionalists"].simulation_eligible);
|
||||
assert!(!value.agency_profiles["other"].simulation_eligible);
|
||||
assert!(value.gestalts["villagers"].resources.is_empty());
|
||||
assert!(value.gestalts["traditionalists"].resources.is_empty());
|
||||
assert_eq!(
|
||||
|
|
@ -5189,6 +5425,8 @@ pub(crate) mod tests {
|
|||
.unwrap();
|
||||
assert!(!value.agency_profiles["other"].active_leaf);
|
||||
assert!(value.agency_profiles["other-smiths"].active_leaf);
|
||||
assert!(value.agency_profiles["other-smiths"].simulation_eligible);
|
||||
assert!(!value.agency_profiles["other-unknown"].simulation_eligible);
|
||||
assert!(value.gestalts["other"].resources.is_empty());
|
||||
assert!(value.gestalts["other-smiths"].resources.is_empty());
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -1292,8 +1292,8 @@ outside this authority.
|
|||
- **Outputs:** one frozen ordered `world-regions-plan.json`, one immutable
|
||||
proposal checkpoint before each mutation, one sequential kernel commit per
|
||||
genuinely new realm, and an immutable `world-region-NN-checkpoint.json`
|
||||
binding request, origin, committed jurisdiction, kernel receipt, and
|
||||
model-receipt hashes. Committed
|
||||
binding request, origin, committed jurisdiction, exact compiler mutation
|
||||
proof, kernel receipt, and model-receipt hashes. Committed
|
||||
jurisdiction IDs become the locality set for later elaboration and strategic
|
||||
simulation.
|
||||
- **Derived state:** `status.json` progress and the jurisdiction list are
|
||||
|
|
@ -1309,8 +1309,10 @@ outside this authority.
|
|||
- **Shared paths:** fresh and resumed runs use the same frozen ordered plan,
|
||||
destination compiler, and kernel admission path. Resume rejects omitted or
|
||||
reordered requests, skips a region only when its checkpoint and canonical
|
||||
receipt agree, and recovers the kernel-commit/checkpoint crash interval from
|
||||
the immutable proposal plus canonical campaign and commit receipt.
|
||||
receipt and mutation proof agree. Foundation, region, titled, and complexity
|
||||
recovery all bind the immutable prepared candidate to the exact canonical
|
||||
receipt; the presence of a plausible ID or checkpoint file is never treated
|
||||
as proof that its content committed.
|
||||
- **Cut line:** whole-world scope is not overloaded onto the root compiler. The
|
||||
driver reuses existing destination compilation and kernel admission; there is
|
||||
no second region generator or event authority.
|
||||
|
|
@ -1322,335 +1324,185 @@ outside this authority.
|
|||
Runs 64 and 65 stopped before that claim was established and remain failure
|
||||
evidence rather than accepted full-world runs.
|
||||
|
||||
#### Iterative latent-world complexity and elaborator continuity
|
||||
#### Qualified latent-world complexity and elaborator continuity
|
||||
|
||||
- **Owner:** the strategic acceptance driver owns round orchestration,
|
||||
deterministic titled-elaborator scheduling, checkpoint publication, and
|
||||
bounded termination. `WorldScaleIntent` is consumer-authored;
|
||||
`derive_world_elaboration_demand` deterministically owns the target, deficit,
|
||||
realm shares, and per-round mutation pressure. Each titled elaborator owns
|
||||
only its compact title-by-realm working frontier and mutation draft. The
|
||||
acceptance driver owns deterministic parent-to-jurisdiction routing. After a
|
||||
frozen parallel batch it also owns exact member-ID collision supersession by
|
||||
retaining the lowest dispatch ordinal.
|
||||
`WorldComplexityTool` owns construction of the complete frozen proposal from
|
||||
the draft. `WorldKernel` remains the sole canonical mutation owner, and
|
||||
Resolution remains the owner of the later active cover.
|
||||
- **Inputs:** the admitted campaign after region and locality elaboration; its
|
||||
active-cell entitlement; a target cover ratio; equal acceptance-driver realm
|
||||
weights; a weighted titled-elaborator profile; bounded parallelism and round
|
||||
limits; active, simulation-eligible Gestalt leaves without a currently
|
||||
materialized member; the prior title-by-realm session checkpoint; and the
|
||||
exact frozen parent state, members, profile, and local relations for each assigned
|
||||
mutation. Scheduler title deterministically selects the proposal lane:
|
||||
Hearth and Veil individuate one consequential member; the other six titles
|
||||
fission the assigned population along their fixed agency axis. The model sees
|
||||
the assigned parent projection and compacted session, but its action schema
|
||||
admits only the lane-specific delta. A fission draft contains child IDs,
|
||||
names, partition values, the residual child, and exact member/resource
|
||||
assignments. An individuation draft is a compact
|
||||
`WorldComplexityMemberDraft`: the model owns only the proposed local ID,
|
||||
public name, capability and knowledge deltas, equipment, conditions,
|
||||
obligations, exact-ID relationships, goals, and memories.
|
||||
`elaboration::unique_containing_jurisdiction` is the single read-only owner
|
||||
for deriving parent jurisdiction from canonical topology. For every exact
|
||||
operating place in `AgencyProfile.location_ids`, it walks
|
||||
`Location.container_id` ancestry until it reaches a consumer realm named by
|
||||
`realm_subject_targets`. Exactly one
|
||||
distinct realm target returns that jurisdiction. Zero targets or multiple
|
||||
distinct targets return no jurisdiction; a containment cycle terminates that
|
||||
ancestry walk without inventing one. Strategic candidate allocation and
|
||||
title-by-realm session routing call this same resolver, and
|
||||
`ModelWorldComplexityWorker` constructor admission calls it again against the
|
||||
assigned jurisdiction before accepting the parent-to-jurisdiction map.
|
||||
- **Outputs:** each round publishes an immutable frozen preview with demand,
|
||||
wave and schedule receipts, exact parent bindings, proposals, and model
|
||||
receipt hashes; then one immutable mutation checkpoint per sequentially
|
||||
admitted fission or individuation; one compacted checkpoint for each title
|
||||
that obtained an admitted mutation in that round; and a terminal round
|
||||
checkpoint carrying the scheduler state, mutation paths, immutable
|
||||
superseded-invocation checkpoint paths for same-batch duplicate member IDs,
|
||||
the accumulated
|
||||
title-by-realm session checkpoints keyed by stable
|
||||
`<lowercase-title>:<jurisdiction-id>` session ID, and remeasured
|
||||
actionable-subject count. Per-round session filenames contain the title plus
|
||||
a stable digest suffix of that session ID; filenames are storage addresses,
|
||||
while the map key and checkpoint's own `session_id` carry routing identity.
|
||||
The final count and round reports are acceptance metadata, not canonical
|
||||
world state.
|
||||
- **Derived state:** actionable complexity is the count of canonical active,
|
||||
simulation-eligible agency leaves. Dormant member rows, census texture,
|
||||
model calls, dispatches, mutation budget, and compacted prose do not satisfy
|
||||
the target. Inherited child capabilities, knowledge, goals, pressures,
|
||||
evidence fields, campaign/revision binding, approval requirement, parent
|
||||
version, partition axis, and individuation location are deterministic
|
||||
projections of the frozen assignment, not model-authored state. An
|
||||
individuated member's public name is presentation state attached to its stable local
|
||||
member ID and canonical `member:<local-id>` subject ID; name equality does
|
||||
not merge subjects, resolve an address, or grant authority over another
|
||||
Actor or population member.
|
||||
checkpoint's title, jurisdiction, frontier summary, unresolved leads,
|
||||
rejection findings, digest chain, and recent commit IDs are bounded steering
|
||||
memory. Raw provider sessions, request history, and transcripts are neither
|
||||
continuity nor world state; the checkpoint is the only carried elaborator
|
||||
context, while the campaign and kernel commit receipts remain truth.
|
||||
Resolution cover membership and Nemesis decision windows are downstream
|
||||
derivations and do not feed back into complexity admission authority.
|
||||
Same-batch individuation supersession is scheduling evidence, not canonical
|
||||
member state: the earliest dispatch ordinal for one canonicalized local
|
||||
member ID is retained, while later matching invocations contribute no commit
|
||||
or session-memory journal. The following round derives fresh demand from the
|
||||
admitted campaign rather than treating supersession as completed complexity.
|
||||
- **Forbidden writers:** elaborators, session compaction, the scheduler,
|
||||
demand derivation, preview files, round files, and acceptance metadata cannot
|
||||
write campaign state, declare a target satisfied, allocate the Resolution
|
||||
cover, or turn narrative memory into facts. A fission proposal cannot approve
|
||||
or commit itself, invent evidence, promote raw roster rows, or rewrite a
|
||||
parent. An individuation cannot invent a population, duplicate an existing
|
||||
exact actor or member ID, materialize itself, or acquire relationships to
|
||||
nonexistent subject IDs. Public names are not writers of identity or
|
||||
authority: no lookup, relationship, action target, or admission decision may
|
||||
select or merge a subject by display-name equality. The model cannot emit or
|
||||
override the member schema, parent Gestalt ID, version, exact location,
|
||||
materialization state, or relevance revisions because those deterministic
|
||||
fields are absent from `WorldComplexityMemberDraft`. The model cannot restate
|
||||
or alter inherited child
|
||||
Persona constitutions, campaign identity, parent identity/version, location,
|
||||
partition axis, evidence, or approval authority because those fields do not
|
||||
exist in its mutation-draft schema. The model provider cannot select a realm,
|
||||
merge title sessions, persist a transcript as memory, or redirect a
|
||||
checkpoint to another title or jurisdiction. Neither the proposing model nor
|
||||
commit order may choose the winner of a same-batch exact member-ID collision;
|
||||
later duplicate invocations cannot write commits or compaction journals.
|
||||
Sequential commits may update
|
||||
only the optimistic revision of a frozen fission proposal after the exact
|
||||
parent binding remains unchanged; individuation instead revalidates its exact
|
||||
Gestalt version and location against current state.
|
||||
- **Shared paths:** all round workers use the existing generic elaborator
|
||||
dispatcher and weighted schedule. `WorldComplexityTool` first lowers a
|
||||
compact draft into the existing full proposal algebra. For fission, it clones
|
||||
the frozen parent Persona into every child, replaces only child identity,
|
||||
name, version, and assigned resources, builds the child-partition map,
|
||||
attaches the exact campaign/revision/parent/axis and empty
|
||||
evidence/gap/canon fields, and fixes `requires_approval=true`. For
|
||||
individuation, it lowers `WorldComplexityMemberDraft` into the canonical
|
||||
`GestaltMemberDelta`: it fixes the member schema, parent Gestalt ID, version
|
||||
zero, exact first parent-profile location, unmaterialized state, and zeroed
|
||||
relevance revisions around the model-owned semantic member content. Every
|
||||
constructed proposal then passes the existing fission or individuation
|
||||
validator and the existing
|
||||
`WorldCommand::FissionGestalt` or `WorldCommand::IndividuateGestaltMember`
|
||||
mailbox. `resolution::validate_gestalt_individuation` is the single local
|
||||
authority for exact member-ID uniqueness, parent version, exact location,
|
||||
bounds, and exact relationship subject IDs; strategic action-bound selection
|
||||
and direct kernel admission both reuse it. Canonical member addressing uses
|
||||
`canonical_gestalt_member_local_id` and `gestalt_member_subject_id`, while
|
||||
strategic actions and relationships carry exact subject IDs rather than
|
||||
public names. It accumulates every failed deterministic clause in
|
||||
one rejection so the generic agent loop can repair the exact bounded draft in
|
||||
its next semantic step; the tool does not add a second judge or relax kernel
|
||||
admission. Direct individuation then follows the ordinary
|
||||
presence path: `apply_individuation` inserts the canonical member delta and
|
||||
promotes it into an Actor, `commit_gestalt_presence` calls
|
||||
`ensure_agency_profiles`, and the new active simulation-eligible actor profile
|
||||
becomes visible to `canonical_actionable_subject_count`. Parallel workers
|
||||
read one frozen campaign. Before serial admission, the round runner
|
||||
canonicalizes every proposed local member ID, retains the invocation with the
|
||||
earliest dispatch ordinal for each ID, and publishes one immutable
|
||||
`ghostlight.complexity_superseded_invocation.v1` checkpoint for every later
|
||||
duplicate, binding its dispatch, retained ordinal, canonical member ID, and
|
||||
diagnostic. Only retained invocations enter session routing, kernel commit,
|
||||
and successful compaction journals. IDs already present in the frozen
|
||||
canonical campaign remain ordinary semantic failures owned by
|
||||
`validate_gestalt_individuation`; supersession does not weaken that check.
|
||||
Retained commits serialize through WorldKernel. Unrelated
|
||||
earlier fissions may be rebased,
|
||||
while any change to the assigned parent, its profile, or its members rejects
|
||||
the later proposal instead of silently reconciling it.
|
||||
Compaction runs only after successful mutations have produced admitted commit
|
||||
journals routed by the invocation's stable title-by-realm session ID. The
|
||||
resulting checkpoint is stored under that ID and supplied only when a later
|
||||
dispatch has the same title and deterministically derived jurisdiction.
|
||||
The existing `ElaboratorSessionCompactionTool` owns the model-boundary
|
||||
compaction contract: its action schema requires a nonempty frontier summary
|
||||
of at most 4,000 characters, at most 32 unresolved leads, and each lead to
|
||||
contain 1 through 600 characters. Tool admission rechecks those same bounds
|
||||
and returns the complete indexed mismatch set; checkpoint construction then
|
||||
revalidates the identical shape before hashing and persistence.
|
||||
The exact failure partition, frozen schedule, completed proposals, receipts,
|
||||
and diagnostics remain in the resumable failure checkpoint; they are not
|
||||
folded into successful session compaction.
|
||||
- **Cut line:** this cut reuses Gestalt fission, strategic Gestalt
|
||||
individuation, WorldKernel admission, model receipts, the generic scheduler,
|
||||
and immutable acceptance checkpoints. It adds no second population or member
|
||||
insertion path, campaign store, parallel commit owner, cover allocator, or
|
||||
transcript-shaped session log. `WorldComplexityAction` is a model-boundary
|
||||
draft, not a new canonical mutation or persistent state authority; the
|
||||
existing `WorldComplexityProposal` remains the checked checkpoint and kernel
|
||||
handoff. The prior partial-wave checkpoint remains recovery for one frozen
|
||||
dispatch partition; it is not
|
||||
elaborator memory. The title-by-realm checkpoint map replaces both the former
|
||||
title-only global memory and any temptation to preserve provider transcripts;
|
||||
it introduces no provider-session store or second jurisdiction allocator.
|
||||
Compact checkpoints replace accumulated working history without replacing
|
||||
canonical commits. Individuation admission requires unique exact IDs, not a
|
||||
global public-name registry; the cut adds no alias table, fuzzy resolver, or
|
||||
name-disambiguation authority. `WorldComplexityMemberDraft` is only the
|
||||
model-boundary semantic payload; it is not a second member-state schema or
|
||||
persistence owner, and deterministic lifecycle fields do not cross the model
|
||||
boundary. The compaction repair adds no compactor, checkpoint type, session
|
||||
store, or memory authority; it closes the item-bound seam between the
|
||||
existing model schema, tool admission, and checkpoint validator. Parallel
|
||||
member-ID supersession adds no namespace allocator, alias registry,
|
||||
reconciliation pass, or alternate admission owner; it is a deterministic
|
||||
filter over one frozen round's already-produced invocations.
|
||||
- **Verification layer:** checkpoint shape and digest bind title, session,
|
||||
campaign, target location, generation, world revision, prior checkpoint, and
|
||||
bounded narrative fields. Frozen parent digests make conflicting parallel
|
||||
mutations uncommittable. Existing fission validation proves lineage, child
|
||||
partitioning, resource custody, and member transfer; shared individuation
|
||||
validation proves active parent and location, exact version, unique bounded
|
||||
member/Actor IDs, exact valid relationship targets, and non-materialized
|
||||
member state. Equal public names on distinct exact IDs remain admissible and
|
||||
do not change address resolution or authority. The focused tool regression
|
||||
admits a new member whose name matches an established Actor, still rejects a
|
||||
colliding canonical Actor ID and unsupported relationship subject, and
|
||||
confirms name collision is absent from the rejection. WorldKernel
|
||||
revalidates either lane before atomic mutation. The model schema exposes only
|
||||
the assigned operation, bounds fission children to two through eight,
|
||||
requires exactly the frozen parent resource and dormant-member IDs as
|
||||
assignment-map keys while leaving child custody model-authored, and for
|
||||
individuation exposes only semantic member fields and contains no `schema`,
|
||||
`gestalt_id`, `version`, `last_location_id`, `materialized_actor_id`,
|
||||
`last_relevant_revision`, or `relevance_lease_until_revision`; a focused
|
||||
schema regression proves those deterministic fields are absent and the tool
|
||||
still constructs an admissible canonical individuation. Tool-level
|
||||
construction additionally rejects duplicate child IDs/partitions or
|
||||
incomplete exact
|
||||
member assignment before shared semantic validation. The shared fission
|
||||
validator owns one complete deterministic mismatch set, including frozen
|
||||
binding, child structure and inheritance, member assignments, resource
|
||||
conservation and custody, approval, and parent profile eligibility; every
|
||||
caller receives that set rather than a generic first-failure umbrella.
|
||||
Worker construction requires exactly one jurisdiction for every assigned
|
||||
parent, rejects extra routes, and reuses
|
||||
`unique_containing_jurisdiction` to prove that the assigned jurisdiction
|
||||
contains that parent's exact profile locations. Resume and
|
||||
worker construction require every checkpoint
|
||||
map key to equal both the embedded session ID and the session ID recomputed
|
||||
from its embedded title and target location; checkpoint validation binds
|
||||
those fields to its digest and current campaign. Runtime lookup
|
||||
derives the expected ID from the current dispatch title and routed realm.
|
||||
Routing tests prove that equal titles in different realms and different
|
||||
titles in one realm produce different IDs. Each round must strictly
|
||||
increase the canonical actionable count; completion requires a freshly
|
||||
derived zero deficit rather than exhaustion of calls or rounds. Focused tests
|
||||
cover scale arithmetic, checkpoint tampering and cross-title rejection, exact
|
||||
compaction ancestry, assigned-parent validation, and safe revision rebasing.
|
||||
A focused compaction regression proves the generated schema carries the
|
||||
per-lead 1/600 character bounds and that empty and overlong leads in one
|
||||
action produce separate index-addressed findings rather than one generic
|
||||
combined diagnostic.
|
||||
A focused batch regression proves that two parallel individuations with one
|
||||
canonical member ID retain the lower dispatch ordinal, publish the later
|
||||
invocation as superseded with the exact retained ordinal and ID, and leave
|
||||
an unrelated member ID retained.
|
||||
- **Failure and resume:** a provider failure publishes an immutable
|
||||
round-failure generation with the exact completed and failed dispatches and
|
||||
receipts, then stops that run. Explicit resume rehydrates the latest failure,
|
||||
preserves completed invocations, and invokes only the failed original
|
||||
dispatches through `resume_elaboration_wave`; repeated failures publish
|
||||
numbered generations without changing the frozen schedule. A published
|
||||
successful round preview may also be reused on explicit resume. Existing
|
||||
mutation checkpoints suppress replay, title-by-realm compaction checkpoints
|
||||
suppress recompaction, immutable superseded-invocation checkpoints must
|
||||
exactly match recomputed collision ownership and suppress commit/journal work
|
||||
for those later duplicates, and consecutive completed round checkpoints
|
||||
restore scheduler fairness and session memory before the first unfinished
|
||||
round.
|
||||
After mutation admission, independent title-by-realm journals compact in
|
||||
parallel under the same bounded complexity parallelism entitlement. Each
|
||||
compactor reads the same committed campaign revision and only its own prior
|
||||
session checkpoint and journal; the runner persists every successful model
|
||||
receipt and immutable session checkpoint before returning any sibling
|
||||
failure. Session checkpoints remain independent memory owners rather than a
|
||||
shared round transcript, and canonical mutation order remains serial.
|
||||
Tool-internal rejection findings are not currently copied into later
|
||||
successful compaction. That is a bounded continuity limitation: the compacted
|
||||
title-by-realm mind may lose a useful rejected path, but no live proposal is
|
||||
orphaned because exact failed dispatches remain owned by the resumable failure
|
||||
checkpoint. This limitation was not the Run 93 blocker.
|
||||
Missing eligible parents, stale or malformed checkpoints, changed parent
|
||||
bindings, zero-growth rounds, and a nonzero deficit at the configured round
|
||||
ceiling are terminal failures. Canonical CultCache state, not the checkpoint
|
||||
prose, decides whether already admitted mutations exist after interruption.
|
||||
Parallel fission proposals may independently choose the same globally scoped
|
||||
child identifier. Rebase treats that as syntactic contention rather than a
|
||||
semantic contradiction: only an occupied child ID is deterministically moved
|
||||
into the assigned parent's content-addressed namespace, with partition,
|
||||
residual, member, and resource references rewritten together before the
|
||||
ordinary complete fission validator runs. Names, partition meaning, custody,
|
||||
and membership remain model-authored; canonical state still admits the result
|
||||
only through WorldKernel.
|
||||
|
||||
One boundary remains intentionally narrow in this acceptance-driver cut.
|
||||
Fission and named-member individuation are live, but institution promotion is
|
||||
not. Dormant member rows still do not count; the individuation lane earns its
|
||||
increment by atomically promoting the admitted member into an Actor and deriving
|
||||
that Actor's active agency profile through the shared presence-commit path.
|
||||
Materializing one person does not retire their population as an elaboration
|
||||
parent. A later fission transfers every exact member affiliation once. Dormant
|
||||
members have their deltas rebased against the selected child baseline;
|
||||
materialized people keep their Actor state byte-identical while their backing
|
||||
member row moves to the selected child. The complete member-assignment map,
|
||||
component membership transition, shared fission validator, and WorldKernel
|
||||
commit remain the single path for both cases.
|
||||
Architecture claims that complexity has no production caller, no durable
|
||||
elaborator compaction owner, no partial-failure resume, or only a fission
|
||||
proposal lane are stale.
|
||||
|
||||
The strategic acceptance runner exercises this path as a deliberate hybrid.
|
||||
The existing destination compiler first commits the complete civic foundation
|
||||
for one canonical locality. A second revision-bound titled wave then adds one
|
||||
Patina child place with exact reciprocal routes, preserves the next civic
|
||||
manifest version through Charter, and admits title-specific facts and a
|
||||
political relation before independent civic verification and a second kernel
|
||||
commit. The acceptance profile allocates three Patina calls and two calls to
|
||||
each other title per locality; a seventeen-slot pass therefore invokes workers
|
||||
in exact configured proportion under bounded parallelism. This proves the
|
||||
titled path against a real provider without claiming that the older civic
|
||||
foundation compiler has already been replaced by the swarm.
|
||||
The strategic acceptance harness persists compiler, foundation, titled-wave,
|
||||
and completed strategic-wave checkpoints beside the CultCache campaign. On an
|
||||
explicit resume it loads canonical world state from CultCache, rehydrates model
|
||||
receipts by content hash, restores scheduler state from the consumed schedule,
|
||||
and continues at the first incomplete authority boundary. A committed
|
||||
foundation is checked against its preserved civic apparatus. A titled preview
|
||||
is not completion authority: only a post-kernel completion checkpoint bound to
|
||||
the before/after revisions, semantic verifier, model receipts, exact
|
||||
`WorldCommitReceipt`, and the kernel-owned mutation authority, batch, and
|
||||
receipt may skip that commit. New checkpoints also bind the admission digest;
|
||||
legacy inference instead binds the finalized candidate through the persisted
|
||||
mutation proof before minting its checkpoint. The batch's
|
||||
`intended_effect_digest` binds the complete finalized candidate before
|
||||
deterministic aggregate projection, so the
|
||||
resume verifier does not duplicate the reducer's set and ordering rules.
|
||||
Run-32's older committed Canopy pass can be admitted once through that persisted
|
||||
mutation proof plus its complete civic candidate, then gains the same durable
|
||||
completion checkpoint. A partial titled wave routes through
|
||||
`resume_elaboration_wave`. Each later terminal partial result is published as a
|
||||
new immutable generation by same-directory atomic rename, preserving the prior
|
||||
valid generation. A committed strategic tick without its matching durable wave
|
||||
checkpoint is refused rather than guessed or replayed.
|
||||
|
||||
Both destination paths synthesize the smallest compatible branch-local routes,
|
||||
geometry, people, supplies, procedures, capacity, responsibility, and doctrine
|
||||
needed for play. Those choices remain visible as `branch_assumptions`; they may
|
||||
vary between campaigns unless the Vault pins them. A `gap` is reserved for
|
||||
contradictory canon baselines, an explicitly requested exact canon baseline that
|
||||
cannot be anchored, or conflict with an approved capability. Ordinary source
|
||||
silence is not a gap. Preview approval remains the only path from this proposal
|
||||
into canonical world state.
|
||||
- **Owner:** `elaboration::canonical_actionable_subject_ids` is the single
|
||||
qualification derivation for world-scale complexity. It reads the canonical
|
||||
campaign and returns the active subjects allowed to pay the scale target.
|
||||
`derive_world_elaboration_demand` owns target and deficit arithmetic.
|
||||
The strategic acceptance driver owns bounded round orchestration and selects
|
||||
parents only from the same qualified-ID set. `WorldKernel` remains the sole
|
||||
canonical mutation owner.
|
||||
- **Inputs:** the admitted campaign; active, simulation-eligible agency profiles;
|
||||
Gestalt lineages and residual IDs; each fission child's retained parent
|
||||
semantics; the active-cell budget; the consumer-authored target cover basis
|
||||
points; realm weights; topology-derived jurisdiction; realm pressure and
|
||||
detail debt; bounded round and concurrency limits; model receipts; and the
|
||||
compact title-by-jurisdiction elaborator checkpoint.
|
||||
- **Qualification invariant:** compiler-admitted roots and individuated people
|
||||
enter through their owning admission gates. A fission child qualifies only
|
||||
when it is not any lineage residual, retains the exact parent baseline, and
|
||||
has additions in at least two of capability, knowledge, goal, and pressure.
|
||||
Residual populations preserve unresolved membership and lineage only. They
|
||||
are non-simulation state, do not enter the public action namespace, do not pay
|
||||
the complexity target, and cannot become recursive complexity parents.
|
||||
Ordinary inherited-baseline fission children remain simulatable without
|
||||
satisfying the qualified world-size bill.
|
||||
- **Demand invariant:** the target actionable-subject count is
|
||||
`ceil(active_cell_budget * 10_000 / target_cover_basis_points)`. An active
|
||||
cell budget of 240 at a 20% cover target therefore requires 1,200 qualified
|
||||
subjects. The demand is re-derived from accepted canonical state after every
|
||||
round. The pre-wave phase boundary requires the qualified count to equal the
|
||||
target exactly; a larger count is not accepted as a satisfied target. On
|
||||
post-wave resume, the last fully validated complexity checkpoint owns that
|
||||
historical pre-wave count because legitimate strategic individuation may
|
||||
have increased the current campaign count.
|
||||
- **Round dataflow:** frozen campaign -> qualified-ID derivation -> distinct
|
||||
qualified parent selection by jurisdiction pressure and detail debt ->
|
||||
deterministic titled dispatch -> parallel model proposals -> semantic
|
||||
validation and same-batch supersession -> sequential kernel commits ->
|
||||
qualified-ID re-derivation. Every accepted round must strictly increase the
|
||||
qualified count. Missing parents, zero growth, or a nonzero deficit at the
|
||||
round ceiling is terminal failure rather than completion telemetry.
|
||||
- **Gain allocation:** `ModelWorldComplexityWorker` distributes the remaining
|
||||
deficit over the assigned distinct parents, with an exact target gain of one
|
||||
through six per dispatch. An elaborated fission emits target gain plus two
|
||||
children because the retained parent retires and the residual child does not
|
||||
qualify. The semantic validator checks the resulting
|
||||
`children.len() - 2` against the qualification.
|
||||
- **Proposal lanes:** Hearth, Tangle, and Veil individuate one consequential
|
||||
member. Patina, Charter, Ledger, Ember, and Numen elaborate a population
|
||||
fission. The model owns only the lane-specific draft; the tool reconstructs
|
||||
campaign ID, revision, parent, axis, evidence and approval bindings around
|
||||
that draft.
|
||||
- **Fission draft and output:** each child draft contains an ID, public name,
|
||||
partition value, home location, capability additions, knowledge additions,
|
||||
goal additions, and pressure additions. The draft also names the residual
|
||||
child and exact member and resource assignments. The tool clones the frozen
|
||||
parent baseline, applies only those additions, and emits a
|
||||
`WorldComplexityFissionQualification` binding title, jurisdiction, and exact
|
||||
target actionable gain.
|
||||
- **Fission semantic invariant:** every specific child has a normalized public
|
||||
identity distinct from existing Gestalts and its siblings, remains inside its
|
||||
assigned jurisdiction, and contributes at least two bounded causal
|
||||
dimensions. Additions are bounded to two capabilities, two knowledge
|
||||
statements, one goal, and one pressure, and must be semantically distinct
|
||||
from the parent and siblings. Only Geography fission may move children away
|
||||
from the parent home; when multiple admitted places exist it must use at
|
||||
least two. The residual stays at the parent home with the exact parent
|
||||
capability, knowledge, goal, and pressure baseline and the
|
||||
`other/unknown` partition.
|
||||
- **Title-specific fission shapes:** Patina requires a capability and goal.
|
||||
Charter and Ledger require a goal, pressure, and either capability or
|
||||
knowledge. Ember requires a pressure and either capability or knowledge.
|
||||
Numen requires goal, pressure, and knowledge.
|
||||
- **Individuation invariant:** every admitted member has a goal, a concrete
|
||||
memory, and at least one additional identity-bearing dimension. Hearth also
|
||||
requires a concrete care or belonging obligation. Tangle requires an exact
|
||||
relationship to an existing canonical subject. Veil requires knowledge not
|
||||
held by the parent population. The resolution validator rejects normalized
|
||||
public-name collisions with existing actors and members; same-batch duplicate
|
||||
canonical member IDs or public identities are superseded by the lowest
|
||||
dispatch ordinal. Actor, institution, Gestalt, dormant member projection,
|
||||
agency-profile key, profile ID, and profile subject ID share one canonical
|
||||
subject-ID collision predicate at proposal validation, deterministic rebase,
|
||||
and kernel application. Promotion alone may claim the exact member's own
|
||||
reserved projection.
|
||||
- **Typed mutation path:** `WorldCommand::ElaborateGestaltFission` carries the
|
||||
preview, exact qualification, and model provenance. The kernel revalidates
|
||||
both elaborated-fission structure and titled complexity semantics before
|
||||
lowering. The lineage split first inherits the parent's component baseline.
|
||||
Only this elaborated command may add the approved capability grants,
|
||||
proposition admissions and knowledge acquisitions, goal commitments, and
|
||||
pressures in the same component-world batch as identity, occupancy, custody,
|
||||
membership, relationship, and civic rebindings.
|
||||
- **Projection invariant:** component-batch application occurs against a cloned
|
||||
overlay and validates the complete next world before aggregate projection.
|
||||
Projection verifies exact capability entry IDs and descriptions, known
|
||||
proposition statements, active goal descriptions, and unresolved pressure
|
||||
labels against each approved child. It persists exactly the approved
|
||||
preview-minus-parent knowledge additions as campaign facts through the
|
||||
shared proposition resolver, copies the approved child semantics with typed
|
||||
identity and occupancy, and derives resources from accepted custody. Campaign,
|
||||
authority, batch, and receipt records persist only after projection succeeds.
|
||||
- **Ordinary fission boundary:** `WorldCommand::FissionGestalt` retains the
|
||||
strict inherited-baseline contract. Its lowering emits no semantic-delta
|
||||
mutations. Elaborated semantic additions cannot enter through that path.
|
||||
- **Relationship contribution:** the lineage reducer inherits every active
|
||||
parent relationship to each child and aggregate projection retires the parent
|
||||
relation. Fission has no free-form relationship-addition field. New
|
||||
relationship texture enters qualified complexity through Tangle
|
||||
individuation, while locality elaboration owns new civic relations.
|
||||
- **Horizontal expansion boundary:** destination compilation and locality
|
||||
elaboration own places, routes, population roots, institutions, civic
|
||||
apparatus, and local political relations. Complexity fission may distribute
|
||||
a Geography split across admitted places but cannot invent geography or a
|
||||
parallel political apparatus. Horizontal civic foundations must therefore be
|
||||
admitted before vertical complexity can elaborate them. Each admitted realm
|
||||
must contain at least three mutually reachable internal places with resident
|
||||
homes in at least three. At scale completion, each jurisdiction must place
|
||||
qualified subjects in at least three locations and no one location may hold
|
||||
more than four fifths of its qualified subjects.
|
||||
- **Civic diversity context:** destination compilation and its semantic verifier
|
||||
receive up to eight peer civic apparatus contexts. Candidate generation
|
||||
requires materially executable means, preserves mixed, diasporic, and
|
||||
cross-border constituencies, rejects ancestry-only civic partitions, and
|
||||
admits locally coherent forms of redress. Verification separately requires
|
||||
`political_form_distinct_or_deliberately_shared`,
|
||||
`opposed_interests_have_distinct_means`, and
|
||||
`candidate_text_intact`. Prompt excerpts are truncated only at word
|
||||
boundaries.
|
||||
- **Outputs:** canonical actors, Gestalts, members, agency profiles, lineages,
|
||||
facts, component capabilities, knowledge, commitments, pressures,
|
||||
relationships, memberships, occupancy, custody, civic bindings, and mutation
|
||||
receipts. Qualified actionable IDs and the current deficit are always
|
||||
derived from those canonical outputs; there is no independently writable
|
||||
qualification flag.
|
||||
- **Derived telemetry:** elaboration demand, round reports, previews, model
|
||||
receipts, session compactions, supersession reports, and resume checkpoints
|
||||
explain orchestration and recovery. They do not own world truth or
|
||||
qualification. Session memory is bounded by title and jurisdiction and binds
|
||||
only committed receipts; raw model sessions and transcripts are not
|
||||
canonical state.
|
||||
- **Recovery invariant:** every completed complexity round reopens its frozen
|
||||
preview and validates every mutation, supersession, rejection, model receipt,
|
||||
semantic verdict, canonical world receipt, and exact fission or individuation
|
||||
mutation proof in one contiguous revision chain. An existing commit
|
||||
checkpoint is accepted only after the same validator proves both historical
|
||||
authority and the committed proposal effect. The cumulative session set must
|
||||
equal prior memory plus every exact accepted/rejected invocation journal;
|
||||
untouched sessions remain byte-equivalent and touched generations bind their
|
||||
receipts, findings, prior digest, and round-end revision. Verifier transport
|
||||
failure is a generational resumable checkpoint and never masquerades as
|
||||
semantic rejection or causes the elaborator proposal to replay.
|
||||
- **Forbidden writers:** model workers, schedulers, reports, checkpoints,
|
||||
compaction text, cover construction, strategic cells, and renderers may not
|
||||
create canonical subjects, mark a subject qualified, alter the target, or
|
||||
repair semantic state after commit. Ordinary fission may not grant semantic
|
||||
additions. Complexity fission may not create places, institutions, civic
|
||||
systems, or arbitrary relationships. Residuals may not pay or recursively
|
||||
service the target.
|
||||
- **Shared paths:** initial runs and resumed runs derive demand and qualified
|
||||
parents through the same functions. Rebase may update only the expected
|
||||
revision when the frozen parent binding is unchanged; child-ID collisions are
|
||||
renamed deterministically before revalidation. All fission writes, including
|
||||
relationship inheritance and resource/member movement, pass through the same
|
||||
typed batch and kernel commit boundary.
|
||||
- **Cut line:** qualification is derived from canonical campaign semantics and
|
||||
lineage, not stored beside them. The count, parent selector, progress check,
|
||||
and completion check all consume that derivation. Any alternate active-leaf
|
||||
counter, residual-inclusive quota path, or report-owned completion opinion is
|
||||
outside the live authority model.
|
||||
- **Verification layer:** focused tests prove 240 active cells at 20% require
|
||||
1,200 subjects; residual and ordinary relabel fission children do not pay the
|
||||
qualified bill; exact target gain is enforced; title-specific additions are
|
||||
bounded and distinct; public identities cannot collide; duplicate
|
||||
individuations supersede deterministically; elaborated fission commits its
|
||||
capability, proposition, knowledge, commitment, pressure, relationship,
|
||||
custody, membership, and fact projection atomically; component re-snapshot
|
||||
validates; ordinary lowering rejects a semantic preview; and the destination
|
||||
verifier enforces political distinctness, materially opposed means, and
|
||||
intact candidate text.
|
||||
|
||||
Autonomous strategic waves run the same admitted agency state through parallel
|
||||
cell membranes under a provider concurrency gate. Action-bound individuation
|
||||
|
|
|
|||
Loading…
Reference in a new issue