Preserve named actors across population fission

This commit is contained in:
Meta Vens 2026-08-31 23:32:06 +02:00
commit 44c89e39df
7 changed files with 72 additions and 35 deletions

View file

@ -3552,13 +3552,7 @@ fn complexity_parent_candidates(
let mut by_realm = BTreeMap::<String, Vec<(std::cmp::Reverse<u64>, String)>>::new();
for (id, profile) in campaign.gestalts.keys().filter_map(|id| {
let profile = campaign.agency_profiles.get(id)?;
(profile.active_leaf
&& profile.simulation_eligible
&& !campaign
.gestalt_members
.values()
.any(|member| member.gestalt_id == *id && member.materialized_actor_id.is_some()))
.then_some((id, profile))
(profile.active_leaf && profile.simulation_eligible).then_some((id, profile))
}) {
if let Some(realm) = complexity_realm_for_profile(profile, demand)
&& realm_pressure.get(&realm).copied().unwrap_or(0) > 0

View file

@ -1270,9 +1270,6 @@ impl ModelWorldComplexityWorker {
|| !profile.simulation_eligible
|| profile.subject_kind != crate::domain::AgencySubjectKind::Gestalt
})
|| campaign.gestalt_members.values().any(|member| {
member.gestalt_id == *parent_id && member.materialized_actor_id.is_some()
})
{
return Err(anyhow!(
"complexity round parent is not an unresolved active Gestalt"
@ -1828,7 +1825,7 @@ impl ElaborationSubAgentPort<WorldComplexityProposal> for ModelWorldComplexityWo
"Propose only child ids, names, partition values, the residual child id, and exact member/resource assignments; the deterministic tool constructs inherited child state and frozen bindings.",
"Create 2 through 8 non-overlapping children with distinct partition values.",
"Exactly one residual child must have partition value other/unknown.",
"Assign every scarce resource and dormant named member exactly once.",
"Assign every scarce resource and named member exactly once; materialized people retain their Actor identity while changing population affiliation.",
"Do not repeat inherited capabilities, knowledge, goals, pressures, evidence, or approval fields."
]
}),

View file

@ -3079,10 +3079,23 @@ fn project_member_population_transfer(
let member = campaign
.gestalt_members
.get(member_id)
.filter(|member| {
member.materialized_actor_id.is_none() && member.gestalt_id == source_population_id
})
.filter(|member| member.gestalt_id == source_population_id)
.ok_or_else(|| anyhow!("accepted member transfer has stale aggregate source"))?;
if let Some(actor_id) = &member.materialized_actor_id {
if actor_id != &crate::domain::gestalt_member_subject_id(member_id)
|| !campaign.actors.contains_key(actor_id)
{
return Err(anyhow!(
"accepted materialized member transfer lost its stable actor"
));
}
campaign
.gestalt_members
.get_mut(member_id)
.expect("member source was resolved")
.gestalt_id = destination_population_id.into();
return Ok(());
}
let source = campaign
.gestalts
.get(source_population_id)

View file

@ -3459,13 +3459,6 @@ pub fn validate_fission(campaign: &Campaign, preview: &GestaltFissionPreview) ->
format!("member {member} is assigned to unknown child {child}"),
);
}
require(
!campaign
.gestalt_members
.values()
.any(|member| member.gestalt_id == parent.id && member.materialized_actor_id.is_some()),
"parent has a materialized member and cannot be fissioned".into(),
);
require(
assigned_resources == parent.resources,
format!(
@ -5085,6 +5078,31 @@ pub(crate) mod tests {
"other"
);
let john_actor_id = crate::domain::gestalt_member_subject_id("john");
value.actors.insert(
john_actor_id.clone(),
ActorState {
id: john_actor_id.clone(),
name: "John".into(),
location_id: "center".into(),
capabilities: BTreeSet::from(["farm".into(), "smith".into()]),
knowledge: BTreeSet::from(["local roads".into()]),
equipment: BTreeSet::from(["hammer".into()]),
conditions: BTreeSet::new(),
obligations: BTreeSet::new(),
relationships: BTreeMap::new(),
goals: vec!["survive winter".into()],
memories: vec!["met the traveler".into()],
},
);
value
.gestalt_members
.get_mut("john")
.unwrap()
.materialized_actor_id = Some(john_actor_id.clone());
ensure_agency_profiles(&mut value);
let john_before_nested_fission = value.actors[&john_actor_id].clone();
let mut nested_residual = child("other-unknown", "Other unclassified villagers");
nested_residual.resources.insert("granary".into());
let nested = GestaltFissionPreview {
@ -5134,6 +5152,13 @@ pub(crate) mod tests {
BTreeSet::from(["granary".into()])
);
assert_eq!(value.gestalt_members["john"].gestalt_id, "other-smiths");
assert_eq!(value.actors[&john_actor_id], john_before_nested_fission);
assert_eq!(
value.gestalt_members["john"]
.materialized_actor_id
.as_deref(),
Some(john_actor_id.as_str())
);
assert_eq!(value.gestalt_members["john"].version, 5);
assert_eq!(
value.gestalt_members["john"].memories,

View file

@ -25,18 +25,19 @@ own volatile workspace identity and the release witness owns deployed identity.
## Current full-world pressure test
Preserve immutable Runs 75 through 88. Run 88 completed complexity round 6 at
383 meaningful subjects, generated all 186 frozen round-7 proposals, and
admitted the first 45 before one later fission found its proposed child ID had
been occupied by an earlier parallel fission. Its canonical prefix ends at
`complexity-round-007-commit-0213.json`; do not replay it.
Preserve immutable Runs 75 through 91. Run 91 completed complexity round 9 at
1,168 meaningful actionable subjects, then stopped before round 10 because the
candidate query excluded every active population after its first person had
materialized. Rounds 1 through 9 and their session checkpoints are canonical;
do not replay them.
Bounded parallel title-by-realm compaction is pushed and proved by Run 88. The
current local verified cut treats only occupied parallel fission child IDs as
syntactic contention: rebase deterministically moves the colliding ID into its
assigned parent's namespace and rewrites every child reference before normal
validation. Commit and push, clone Run 88, and resume its preview at commit
0214. The acceptance launcher retains one 35 MiB content-addressed runner per
Bounded parallel title-by-realm compaction and deterministic parallel child-ID
reconciliation are pushed and proved. The current local verified cut removes
the scale dead end at the fission transition owner: every exact member is still
assigned once, dormant deltas rebase against the child baseline, and a
materialized person's Actor remains byte-identical while their backing member
affiliation moves to the child. Commit and push, clone Run 91, and begin round
10. The acceptance launcher retains one 35 MiB content-addressed runner per
exact source commit and deletes disposable compiler output; do not restore a
persistent Cargo target tree.

View file

@ -1454,6 +1454,13 @@ 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.

View file

@ -329,8 +329,8 @@ current_status:
provider_acceptance_checkpoint: Exact pushed commit `139b8a6` completed Run 60 under `character-newsroom.v10` without world or per-wave replay. Its acceptance witness and terminal status bind the completed page and exact resume lineage. The independently dispatched blind reviewer, shown only the reader-facing fantasy newspaper, read it as a real left-populist civic broadsheet and did not immediately identify procedural generation, so the narrative reverse-Turing criterion passes. The review's substantive criticism is that the three stories feel like three rewrites of one briefing; accepted Run 60 remains immutable. The run used 96,902 prompt tokens and reported zero cache hits. Its delivered typeset artifact is `output/pdf/canopy-ledger-run-60-front-page.pdf`; frozen-source and visual verification remain accepted. Exact pushed `bc2ca39` then produced frozen-fact newsroom-only Run 61 Issues 13, 15, 16, 17, and 18 without world or wave model replay. Provider output proves `special_issue` convergence in Issues 13 and 15, independent `general_issue` beats in Issues 16 through 18, and assignment-selector cache hits. Blind review of Issues 13, 15, 16, and 17 passes both distinct recurring voices and issue-shape diversity, recognizing Ossan, Mera, Corin, and Lysa's biases plus modest cross-issue evolution. Run 62 exercised v12 without world or wave replay and failed only because two lead articles proposed invalid datelines; recurring reporter calls still recorded zero cache hits. Run 63 used exact pushed v13 `a52d57b`; Issues 17 and 18 completed before root stopped the final weekly recomposition, both repeated bylines again recorded zero cache hits, and live services remained unchanged. Preserve Runs 61 through 63 as stopped or completed immutable evidence. Copy defects remain later deadline-correction work rather than a reason to reopen accepted issue artifacts.
implementation_checkpoint: Exact pushed v13 `a52d57b` keeps one stable reporter action schema, places a common stable house charter before recurring identity and dynamic assignment, and projects deterministic `allowed_datelines` from cited records while retaining copy-desk factual authority and deterministic cited-place admission; 480 library tests and the all-target check pass. Run 63 falsifies reporter-cache pursuit as a useful acceptance target for sporadic independent filings. The proposed v14 cache-floor prompt growth was removed. Append-only agent contexts remain the natural cache beneficiary; accepted Run 60 remains immutable. The strategic cut extracts one shared `validate_strategic_individuation_proposals` owner used by resolution validation and by the scheduler before it returns an optional proposal. An invalid optional identity emits a semantic-invalid receipt and produces no individuation instead of aborting the recoverable wave. Focused valid and invalid regressions pass, and exact-source Run 68 exercises the corrected provider path through twelve committed waves; no further validator implementation is pending. The newsroom-only cut adds a navigation-only directory of completed public changes grouped by period and exact source timestamps to new v14 audit citations. The directory derives context from canonical records and gains no fact or world authority. Legacy empty source times are omitted from both rendering and serialization, preserving inherited v13 receipt bytes and digests; new v14 nonempty source times remain rendered and serialized. Exact-source Run 73 proves that compatibility path and final recomposition mechanically. Current source gives the assignment editor bounded full-ledger queries and explicitly asks it to search sideways for opposition and countermoves; Run 73 falsifies the stronger assumption that this access and instruction alone guarantee balanced selection. Exact pushed v15 source `b6787d909bd79b68ed3a4d143b7f6dd438e00fa2` binds accountability, opposition, and counter-narrative pitches to two distinct named parties and selected citations through a typed conflict axis, and preserves canonical ledger order. Run 74 falsifies the stronger v15 assumption: its lone accountability pitch used the same transfer citation for cultivators and a passive Tribunal, while four of five pitches avoided the adversarial axis through lead or consequence functions. Two cited names did not prove two moves. Exact pushed v16 `86fe6ed89d51da26b65ab6a031608075840b1527` binds each adversarial axis to two distinct cited public moves or positions and rejects one record presented as both sides; it adds no event writer, judge, process, dependency, or persistent authority. Formatting, 27 focused newspaper tests, 484 full library tests, and 16 strategic-smoke tests pass.
full_world_acceptance_checkpoint: Run 68 at exact source `69c811a2669fc38f19f9199bf57088dc250bfc3e` is mechanically complete at world revision 27 with 12/12 strategic waves, 240 events, 514 public news rows, and a final newspaper. Independent editorial and grounding reviews both fail. Earlier per-wave papers prove the immutable record already contains dramatic completed facts, including an organ breaching the rail capital, a dead pump, and families crossing borders; the final paper failed to make that committed change legible. Preserve Run 68 unchanged. Run 69 at source `84b31e57a462710eb939c4559e0437eb5d6a7a28` failed before any model call when immutable recomposition verification encountered an empty rendered `Source time:` line in inherited v13 per-wave issues. Run 70 at source `ec45952b843e102dc2ebddda3a3bbb4058687175` also failed before any model call because v14 serialization changed the legacy recomposition digest. Exact-source Run 73 `b827d897b9579c2091a67c363d35b8695288ba2f` is terminal complete at `/var/lib/gamecult/ghostlight-dungeon/acceptance/full-world-delvehold-b827d89-73`: world revision 27, 12/12 waves, 240 events, 514 news rows, inherited artifacts byte-identical to Run 68, manifest valid, and archive SHA-256 `090d05f304c8f3d33c9dccd728bffbf3e5dc2969a7aeeffc2f9d7bafe701ac8a`. Exact-source Run 74 `b6787d909bd79b68ed3a4d143b7f6dd438e00fa2` is mechanically complete at `/var/lib/gamecult/ghostlight-dungeon/acceptance/full-world-delvehold-b6787d9-74`: revision 27, 12/12 waves, 240 events, 514 news rows, Run 68 inherited artifacts byte-identical, manifest valid, unchanged live services, and archive SHA-256 `957b11a5d584d27d23bf4d50ed1fbc8d067faf67953b03f80705bfb9587c496d`. Independent editorial review fails: the page has a coherent throughline and sharp prose but no sustained adversarial narrative; opposing decision-makers, motives, responses, and countermoves are largely absent, scandal and public reaction are missing, lived costs remain abstract, and the result reads as polished minutes with conclusions. Its post-press correction notice has two items: `The corridor had begun closing hours earlier` overstates a source that says the prolonged oath-route closure was diverting arrivals six hours before the breach; `no relief or assignment of liability has followed` must narrow to `no tribunal remedy is recorded yet`. Run 75 launched at exact source `86fe6ed89d51da26b65ab6a031608075840b1527` under the superseded 240-cell-only acceptance shape and was stopped cleanly at the operator's scale correction. Preserve `/var/lib/gamecult/ghostlight-dungeon/acceptance/full-world-delvehold-86fe6ed-75` as stopped non-acceptance evidence: preflight, world-region and titled-elaboration checkpoints, a wave-one cell terminal checkpoint, partial pulses 01/02, and two rejected pulse receipts exist. `ghostlight-full-world-run75.service` invocation `86bfe6a3ef504a7d99f579b3d67710ab` is inactive/dead after explicit stop; live services remain unchanged. Do not claim terminal success or failure. Preserve Runs 64 through 75. Mechanical completion of the earlier world is proven, but final newspaper acceptance under the corrected scale target is not.
scale_checkpoint: The active 240-cell entitlement is an attention budget, not the world-size claim. The approximately 2,400 potentially acting entities are a target for causally meaningful latent complexity, not a raw population or roster count. Multiresolution Gestalts compress the unresolved population; repeated admitted elaboration must fission them and promote individuals and institutions whose agency, relationships, resources, pressures, or authority can actually participate in consequences, then remeasure the deficit. Exact pushed `df66ec989c1e44a7a8b21ed159e9589778426238` defines consumer-authored `WorldScaleIntent` and deterministic `WorldElaborationDemand`; at 240 cells and 1,000 cover basis points it derives a numeric 2,400-subject target, current-subject deficit, weighted per-realm shares, and bounded `round_mutation_budget`. Pushed `a017737` owns title-by-realm persistent logical elaborator sessions with agentic bounded compaction, compact mutation drafts, exact failed-dispatch-only resume, both Gestalt fission and grounded named-person promotion, WorldKernel-only commit, and post-round canonical remeasurement. Pushed `e7ceb2c` requires exact frozen resource and dormant-member assignment keys. Pushed `8a81ea2`, `36bcc84`, `92d6742`, `ca64b9c`, and `b4cc3a2` make fission atomically rebind civic residency and political relations, reconcile the one admitted legacy split, prove historical checkpoints independently from evolved current state, and bound lineage lookup by actual descendant IDs. Pushed `5582f61` runs independent session compactions concurrently under existing bounded parallelism. Run 88 completed round 6 at 383 meaningful subjects and admitted the first 45 of 186 frozen round-7 proposals; the verified local rebase cut deterministically namespaces only child IDs occupied by an earlier parallel fission and rewrites their internal references before ordinary validation. Resolution owns derived cover membership. Nemesis receives an existing cover and assigns bounded causal decision windows among eligible responders; it does not allocate that cover.
scale_checkpoint: The active 240-cell entitlement is an attention budget, not the world-size claim. The approximately 2,400 potentially acting entities are a target for causally meaningful latent complexity, not a raw population or roster count. Multiresolution Gestalts compress the unresolved population; repeated admitted elaboration must fission them and promote individuals and institutions whose agency, relationships, resources, pressures, or authority can actually participate in consequences, then remeasure the deficit. `WorldScaleIntent` and deterministic `WorldElaborationDemand` derive the 2,400-subject target, deficit, weighted per-realm shares, and bounded mutation budget. Persistent title-by-realm sessions use bounded agentic compaction; proposal failure resumes only failed dispatches; WorldKernel alone commits; canonical complexity is remeasured after every round. Exact resource/member assignment, civic fission rebinding, legacy reconciliation, evolved-checkpoint proof, bounded lineage lookup, parallel session compaction, and deterministic parallel child-ID reconciliation are pushed and proven through Run 91. Run 91 completed round 9 at 1,168 subjects, then exposed a stale rule that made one materialized person permanently disqualify the whole population from later fission. The verified local cut transfers materialized affiliation through the same exact fission membership transition while preserving Actor state byte-identically; dormant members still rebase their deltas against the selected child. Resolution owns derived cover membership. Nemesis receives an existing cover and assigns bounded causal decision windows among eligible responders; it does not allocate that cover.
presentation_checkpoint: The historical press-layout and seed-ownership split are complete. `notes/historical-newspaper-layout-grammar.md` remains the durable grammar. Manifest v2 at `output/tex/canopy-ledger-run-61-style-1847-flow-723.manifest.toml` independently binds `style_seed=1847`, `flow_seed=723`, frozen source SHA-256 `8f195140f52a40ba705d6a66987146a1500ae89668e5d82b01d1792eb3afb882`, and the final artifact `output/pdf/canopy-ledger-run-61-style-1847-flow-723.pdf`, SHA-256 `a457f4b1702a7a52480e42fce0039f0dbe677ff32958e98f1c412b346237190c`. An identical seed pair produces byte-identical TeX and PDF; changing only flow preserves the exact style section while materially changing a plausible layout, and changing only style preserves flow topology. Cut-first and cut-midstory templates pass visual inspection; the failed split-card template is deleted. Frozen copy/assets, actual PDF `/BM /Multiply`, and economic-layer advertising authority remain invariant.
public_reference_checkpoint: Public architecture reference is complete. Canonical Ghostlight commit `15ea0f0` owns five pages under `docs/public-architecture` covering overview, authority, pipelines, 43 named production stages, and eight titled elaborators. Site commit `ea0b026` publishes exact projections under `F:\Projects\GhostlightDungeon-site\content\Documentation`, adds the sync/check script, explorer and table-of-contents navigation, scoped documentation layout, and homepage Architecture link. Local Quartz build and visual browser QA pass. GitHub Pages workflow `33408004480` succeeded. `https://ghostlight.gamecult.org/Documentation/` and the extensionless `Documentation/Agents-and-model-stages` route are live; the stage page exposes seven tables and 51 rows. Ghostlight remains technical authority; the site repository owns public composition and deployment.
next_action: Preserve Runs 75 through 88. Run 88 completed complexity round 6 at 383 meaningful subjects, then generated all 186 round-7 proposals and admitted the first 45 before two independent fissions collided on one globally scoped child ID. Commit and push the verified deterministic rebase cut that remaps only occupied child IDs into the assigned parent's content-addressed namespace and rewrites every internal child reference before ordinary fission validation. Clone immutable Run 88 and resume the frozen round-7 preview from commit 0213 without replaying any proposal or admitted mutation. Retain bounded parallel title-by-realm compaction and the exact-source 35 MiB runner cache. Continue until canonical remeasurement reaches 2,400 meaningful actionable subjects, then require ten strategic waves, publications, archive hashes, and unchanged live-service identities. Preserve Resolution cover ownership, Nemesis's bounded causal-window role, the completed public reference, the two-seed press checkpoint, and the economic-layer advertising boundary.
next_action: Preserve Runs 75 through 91. Run 91 completed complexity round 9 at 1,168 meaningful subjects, then proved the candidate pool was exhausted because every active population leaf had been excluded after its first materialized person. Commit and push the verified transition-owner cut: fission may transfer materialized member affiliation while preserving the Actor byte-identically, dormant member deltas still rebase against the child baseline, worker construction and parent selection no longer exclude those populations, and every exact member remains assigned once through the existing component transition and WorldKernel commit. Clone immutable Run 91 and resume at complexity round 10 without replaying rounds 1 through 9. Retain deterministic child-ID reconciliation, bounded parallel title-by-realm compaction, and the exact-source runner cache. Continue until canonical remeasurement reaches 2,400 meaningful actionable subjects, then require ten strategic waves, publications, archive hashes, and unchanged live-service identities. Preserve Resolution cover ownership, Nemesis's bounded causal-window role, the completed public reference, the two-seed press checkpoint, and the economic-layer advertising boundary.
gestalt_population: Gestalt Personas own shared population baselines; persistent member deltas own named individuality; WorldKernel materialization and approval-gated fission preserve lineage and identity. Materialisation/folding changes only representation and the exact member delta, advances resolution epoch, and retires the old cover; it has no Gestalt-wide effect authority. Selected actionable member exceptions are mandatory Projector perspective owners, so aggregation cannot silently erase their decision. Presence projection is limited to nearby active leaves and exact-location dormant members, includes reciprocal player relationship evidence, and may propose an earned cast without committing it. Simulation cells are derived covers only.