Remove legacy newsroom reconciliation authority

This commit is contained in:
Meta Vens 2026-08-30 06:16:01 +02:00
commit c0a001c55c
6 changed files with 121 additions and 1187 deletions

View file

@ -62,6 +62,43 @@ struct HistoricalWorldNewspaperArticleV2 {
event_ids: Vec<String>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct HistoricalWorldNewspaperGroundingVerdict {
accepted: bool,
assessment: String,
findings: Vec<ghostlight_dungeon::newspaper::WorldNewspaperGroundingFinding>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct HistoricalWorldNewspaperEditorialVerdict {
accepted: bool,
assessment: String,
findings: Vec<HistoricalWorldNewspaperEditorialFinding>,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct HistoricalWorldNewspaperEditorialFinding {
article_index: u16,
category: HistoricalWorldNewspaperEditorialCategory,
passage: String,
reason: String,
rewrite_goal: String,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
enum HistoricalWorldNewspaperEditorialCategory {
BuriedLede,
ProceduralForeground,
ThroughlineDropped,
StakesAbstracted,
TensionFlattened,
RepetitiveUpdate,
}
#[allow(clippy::too_many_arguments)]
fn validate_completed_newspaper_recomposition_receipt(
recomposition: &serde_json::Value,
@ -180,7 +217,7 @@ fn validate_completed_newspaper_recomposition_receipt(
)
}
} else if current_schema {
let grounding: ghostlight_dungeon::newspaper::WorldNewspaperGroundingVerdict =
let grounding: HistoricalWorldNewspaperGroundingVerdict =
serde_json::from_value(recomposition["newspaper_grounding"].clone()).map_err(
|error| {
anyhow::anyhow!(
@ -194,7 +231,7 @@ fn validate_completed_newspaper_recomposition_receipt(
)
}
if recomposition_schema == Some("ghostlight.newspaper_wave_recomposition.v2") {
let editorial: ghostlight_dungeon::newspaper::WorldNewspaperEditorialVerdict =
let editorial: HistoricalWorldNewspaperEditorialVerdict =
serde_json::from_value(recomposition["newspaper_editorial"].clone()).map_err(
|error| {
anyhow::anyhow!(
@ -293,16 +330,6 @@ struct FoundationCheckpoint {
model_receipts: Vec<ghostlight_dungeon::model::ModelStageReceipt>,
}
#[derive(serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct NewspaperReconciliationImportEnvelope {
schema: String,
wave_index: u64,
recovery_start_wave: usize,
world_revision: u64,
import: ghostlight_dungeon::newspaper::WorldNewspaperReconciliationImport,
}
#[derive(serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
struct ClockBindingProposalCheckpoint {
@ -974,10 +1001,6 @@ async fn main() -> anyhow::Result<()> {
let initial_location_ids = campaign.locations.keys().cloned().collect::<Vec<_>>();
(campaign, vec![], vec![], None, initial_location_ids)
};
let newspaper_reconciliation_import_path =
std::env::var_os("GHOSTLIGHT_STRATEGIC_NEWSPAPER_RECONCILIATION_IMPORT")
.map(std::path::PathBuf::from);
let mut newspaper_reconciliation_import_consumed = false;
if resume {
ghostlight_dungeon::compiler::validate_campaign_runtime(&campaign)?;
} else {
@ -1903,9 +1926,8 @@ async fn main() -> anyhow::Result<()> {
issue_path,
issue_audit_path,
newspaper_error,
newspaper_reconciliation_checkpoint,
) = match issue_composition {
Ok(ghostlight_dungeon::newspaper::WorldNewspaperAdvance::Accepted { composition }) => {
Ok(composition) => {
let issue_path = root.join(format!("newspaper-wave-{wave_index:02}.md"));
let issue_audit_path =
root.join(format!("newspaper-wave-{wave_index:02}.audit.md"));
@ -1929,22 +1951,8 @@ async fn main() -> anyhow::Result<()> {
Some(issue_path),
Some(issue_audit_path),
None,
None,
)
}
Ok(ghostlight_dungeon::newspaper::WorldNewspaperAdvance::Pending {
checkpoint,
model_receipts,
}) => (
None,
None,
None,
model_receipts,
None::<std::path::PathBuf>,
None::<std::path::PathBuf>,
None,
Some(checkpoint),
),
Err(error) => {
let Some(failure) = error.downcast_ref::<
ghostlight_dungeon::newspaper::WorldNewspaperCompositionFailure,
@ -1959,7 +1967,6 @@ async fn main() -> anyhow::Result<()> {
None::<std::path::PathBuf>,
None::<std::path::PathBuf>,
Some(error.to_string()),
None,
)
}
};
@ -1978,7 +1985,6 @@ async fn main() -> anyhow::Result<()> {
"newspaper_press_close":newspaper_press_close,
"newspaper_model_receipts":newspaper_model_receipts,
"newspaper_error":newspaper_error,
"newspaper_reconciliation_checkpoint":newspaper_reconciliation_checkpoint,
"issue_path":issue_path,
"issue_audit_path":issue_audit_path,
});
@ -2025,31 +2031,6 @@ async fn main() -> anyhow::Result<()> {
let recomposition = if recomposition_path.is_file() {
read_checkpoint::<serde_json::Value>(&recomposition_path)?
} else {
if let Some(import_path) = newspaper_reconciliation_import_path.as_deref() {
let import =
read_checkpoint::<NewspaperReconciliationImportEnvelope>(import_path)?;
if import.wave_index == wave_index {
if import.schema
!= "ghostlight.strategic_newspaper_reconciliation_import.v1"
|| import.recovery_start_wave != newspaper_recovery_start_wave
|| import.world_revision != issue_campaign.revision
{
anyhow::bail!(
"strategic newspaper reconciliation import does not bind this missing issue"
)
}
ghostlight_dungeon::newspaper::admit_world_newspaper_reconciliation_import(
&issue_campaign,
&issue_title,
&newspaper_voice,
&newsroom,
5,
&store,
import.import,
)?;
newspaper_reconciliation_import_consumed = true;
}
}
let composition = match compose_persisted_newspaper(
model.as_ref(),
&issue_campaign,
@ -2060,40 +2041,7 @@ async fn main() -> anyhow::Result<()> {
)
.await
{
Ok(ghostlight_dungeon::newspaper::WorldNewspaperAdvance::Accepted {
composition,
}) => composition,
Ok(ghostlight_dungeon::newspaper::WorldNewspaperAdvance::Pending {
checkpoint,
model_receipts,
}) => {
let checkpoint_id = checkpoint.id().to_owned();
let checkpoint_digest = strategic_smoke_digest(&checkpoint)?;
let checkpoint_suffix = checkpoint_digest
.strip_prefix("sha256:")
.ok_or_else(|| anyhow::anyhow!("invalid checkpoint digest"))?;
publish_immutable_checkpoint(
&root.join(format!(
"newspaper-wave-{wave_index:02}-recomposition-pending-{checkpoint_suffix}.json"
)),
&serde_json::json!({
"schema":"ghostlight.newspaper_wave_recomposition_pending.v1",
"wave_index":wave_index,
"recovery_start_wave":newspaper_recovery_start_wave,
"world_revision":issue_campaign.revision,
"source_campaign_digest":source_campaign_digest,
"editorial_contract_digest":editorial_contract_digest,
"checkpoint_digest":checkpoint_digest,
"checkpoint":checkpoint,
"model_receipt_set_digest":strategic_smoke_digest(&model_receipts)?,
"model_receipts":model_receipts,
}),
)?;
anyhow::bail!(
"newspaper reconciliation is pending at checkpoint {}",
checkpoint_id
)
}
Ok(composition) => composition,
Err(error) => {
let model_receipts = error
.downcast_ref::<
@ -2193,11 +2141,6 @@ async fn main() -> anyhow::Result<()> {
);
report.insert("newspaper_error".into(), serde_json::Value::Null);
}
if newspaper_reconciliation_import_path.is_some()
&& !newspaper_reconciliation_import_consumed
{
anyhow::bail!("configured newspaper reconciliation import was not consumed")
}
}
let final_plan = final_wave_field(&wave_reports, "plan")?;
let final_commit = final_wave_field(&wave_reports, "commit")?;
@ -2222,57 +2165,7 @@ async fn main() -> anyhow::Result<()> {
)
.await
{
Ok(ghostlight_dungeon::newspaper::WorldNewspaperAdvance::Accepted { composition }) => {
composition
}
Ok(ghostlight_dungeon::newspaper::WorldNewspaperAdvance::Pending {
checkpoint,
model_receipts,
}) => {
let checkpoint_id = checkpoint.id().to_owned();
let pending_result = serde_json::json!({
"schema":"ghostlight.live_strategic_smoke_pending.v1",
"scenario_id":scenario_id,
"pressure":pressure,
"wave_count":wave_count,
"newspaper_recovery_start_wave":newspaper_recovery_start_wave,
"campaign_id":campaign.id,
"elapsed_seconds":started.elapsed().as_secs_f64(),
"model_runtime":model_selection.status("configured"),
"world_compile":&world_compile,
"model_receipt_hash":&final_model_receipt_hash,
"model_stage_receipts":&model_stage_receipts,
"plan":&final_plan,
"commit":&final_commit,
"waves":&wave_reports,
"event_count":campaign.events.len(),
"news_count":campaign.news.len(),
"final_newspaper_checkpoint":checkpoint,
"final_newspaper_model_receipts":model_receipts,
"player_location_unchanged":true,
"player_state_unchanged":true,
"store":root.join("campaign.cc")
});
let result_path = root.join("result.json");
std::fs::write(&result_path, serde_json::to_vec_pretty(&pending_result)?)?;
std::fs::write(
root.join("status.json"),
serde_json::to_vec_pretty(&serde_json::json!({
"schema":"ghostlight.live_strategic_smoke_status.v1",
"state":"pending_newspaper_reconciliation",
"waves_completed":wave_count,
"waves_requested":wave_count,
"newspaper_recovery_start_wave":newspaper_recovery_start_wave,
"world_revision":campaign.revision,
"event_count":campaign.events.len(),
"news_count":campaign.news.len(),
"updated_at":Utc::now(),
"result_path":result_path,
"newspaper_checkpoint_id":checkpoint_id,
}))?,
)?;
anyhow::bail!("final newspaper reconciliation is pending at checkpoint {checkpoint_id}")
}
Ok(composition) => composition,
Err(error) => {
let final_newspaper_model_receipts = error
.downcast_ref::<ghostlight_dungeon::newspaper::WorldNewspaperCompositionFailure>()
@ -2394,7 +2287,7 @@ async fn compose_persisted_newspaper(
editorial_voice: &str,
max_articles: usize,
store: &ghostlight_dungeon::persistence::CampaignStore,
) -> anyhow::Result<ghostlight_dungeon::newspaper::WorldNewspaperAdvance> {
) -> anyhow::Result<ghostlight_dungeon::newspaper::WorldNewspaperComposition> {
ghostlight_dungeon::newspaper::advance_world_newspaper(
model,
campaign,
@ -2814,7 +2707,8 @@ fn strategic_campaign() -> ghostlight_dungeon::domain::Campaign {
#[cfg(test)]
mod tests {
use super::{
HistoricalWorldNewspaperArticleV2, HistoricalWorldNewspaperIssueV2,
HistoricalWorldNewspaperArticleV2, HistoricalWorldNewspaperEditorialVerdict,
HistoricalWorldNewspaperGroundingVerdict, HistoricalWorldNewspaperIssueV2,
admitted_public_channel, civic_manifest_is_committed_candidate,
committed_elaboration_mutation_proof, completed_wave_issue_campaign, final_wave_field,
latest_partial_wave_checkpoint, missing_newspaper_report_indices,
@ -3008,12 +2902,12 @@ mod tests {
let audit_copy =
ghostlight_dungeon::newspaper::render_world_newspaper_audit_markdown(&issue);
let receipts: Vec<ghostlight_dungeon::model::ModelStageReceipt> = Vec::new();
let grounding = ghostlight_dungeon::newspaper::WorldNewspaperGroundingVerdict {
let grounding = HistoricalWorldNewspaperGroundingVerdict {
accepted: true,
assessment: "Exact current grounding".into(),
findings: Vec::new(),
};
let editorial = ghostlight_dungeon::newspaper::WorldNewspaperEditorialVerdict {
let editorial = HistoricalWorldNewspaperEditorialVerdict {
accepted: true,
assessment: "Exact current editorial acceptance".into(),
findings: Vec::new(),

File diff suppressed because it is too large Load diff

View file

@ -380,7 +380,7 @@ impl CampaignRegistry {
&self,
request: WorldNewspaperRequest,
model: &dyn ModelPort,
) -> Result<crate::newspaper::WorldNewspaperAdvance> {
) -> Result<crate::newspaper::WorldNewspaperComposition> {
if request.schema != "ghostlight.world_newspaper_request.v3"
|| request.max_articles == 0
|| request.max_articles > 6
@ -1453,8 +1453,6 @@ mod tests {
.compose_world_newspaper(newspaper_request.clone(), &RegistryNewspaperModel)
.await
.unwrap()
.into_accepted()
.unwrap()
.issue;
assert_eq!(newspaper.source_world_revision, 0);
assert!(newspaper.articles.is_empty());
@ -1673,8 +1671,6 @@ mod tests {
.compose_world_newspaper(newspaper_request.clone(), &RegistryNewspaperModel)
.await
.unwrap()
.into_accepted()
.unwrap()
.issue;
assert_eq!(newspaper.source_world_revision, 3);
assert_eq!(newspaper.articles.len(), 1);
@ -1700,8 +1696,6 @@ mod tests {
.compose_world_newspaper(newspaper_request.clone(), &RegistryNewspaperModel)
.await
.unwrap()
.into_accepted()
.unwrap()
.issue;
assert_eq!(repeated_newspaper.id, newspaper.id);
assert_eq!(
@ -1719,9 +1713,7 @@ mod tests {
let closed = registry
.compose_world_newspaper(rejected_request, &RejectingRegistryNewspaperModel)
.await
.unwrap()
.into_accepted()
.expect("the Night Editor must close the marked page once");
.unwrap();
assert_eq!(closed.model_receipts.len(), 6);
assert_eq!(closed.copy_desk.queries.len(), 1);
assert!(closed.press_close.night_editor_action_applied);

View file

@ -1377,9 +1377,16 @@ assignments and cited facts, and the affected reporter profiles; she gets one
chance to resolve exactly those objections while preserving the story. The
one-shot whole-page writer and generic byline registry are deleted.
Deterministic press admission still owns structure, provenance, query
disposition, and closure. Focused gates pass 475/475 library tests, 16/16
strategic-smoke tests, and all-target checks. No provider or simulation run has
been launched for v9.
disposition, and closure.
Run 60 attempts 1 and 2 stopped before any v9 provider call. Attempt 1 exposed
the missing `wave_count + 1` final-only sentinel. Attempt 2 reached final
composition without simulation or per-wave replay, then exposed automatic v7
close import as obsolete live authority. The current uncommitted cut deletes
legacy reconciliation/import from live newsroom ownership, makes advance return
one composition, and leaves the exact-current close checkpoint as the sole
resume owner. Gates pass 474/474 library tests, 16/16 strategic-smoke tests, and
all-target checks. Provider and reverse-Turing acceptance remain unproven.
Run 54 exposed one separate upstream publicity defect: a public strategic
activity propagates its channel to private `MemberMemory` outcomes, which is
@ -1390,9 +1397,10 @@ materializing a `NewsIssue`.
1. Preserve immutable Run 59 and its later-publication correction debt; do not
rewrite or resimulate it.
2. Run the authorized newsroom-only provider acceptance for exact pushed
`901cfcd58794acc35b24be3d1e149fd2df0f6c3d`. Measure actual cached tokens and
freeze the resulting reader-facing v9 front page without world replay.
2. Commit and push the verified resume-ownership cut. Resume the same Run 60
root at final composition without simulation or per-wave replay; do not
launch a fresh campaign or import a v7 close. Measure actual cached tokens
and freeze the resulting reader-facing v9 front page.
3. Dispatch an independent blind reviewer with only that fantasy newspaper and
a request for its journalistic opinion. Do not expose generation mechanics,
prompts, receipts, provenance, or the acceptance hypothesis. Pass only if

View file

@ -1433,23 +1433,29 @@ The deliberative newsroom boundary is live under this authority map:
all delegate to `advance_world_newspaper`. Resume begins from the immutable
close checkpoint and does not rerun assignment, journalists, or copy desk. A
persisted composition is revalidated against its close checkpoint and exact
stored receipts, then returned without model work.
stored receipts, then returned without model work. Every caller receives one
completed `WorldNewspaperComposition` or an error; there is no pending
reconciliation result for a caller to interpret or advance.
- **Persistence and compatibility:** the live internal contract is
`character-newsroom.v9`. Public request schema v3 carries the publication
roster and binds it into the task and editorial identities. Close checkpoint
v1 binds the assigned agenda, assembled page, single copy report, task and exact editorial bindings, source
checkpoint when present, and immutable receipt chain. Composition v3 stores
v1 binds the assigned agenda, assembled page, single copy report, task and
exact editorial bindings, and immutable receipt chain. Its only valid origin
is `InitialCopyDesk`, and its compatibility-shaped `source_checkpoint_id`
must be absent; validation rejects any other origin or imported ancestry.
Composition v3 stores
the printed issue, copy report, press-close witness, and receipts. Public issue
schema v3 remains unchanged. Candidate agendas and front-page proofs remain
ephemeral. V7 reconciliation checkpoint v3 is read-only resume provenance:
an explicit external import may materialize the exact immutable Run 58 copy
tip once, but v9 never appends to or advances that chain. Only a v7 tip whose
rejecting owner is the copy desk can become one v9 close checkpoint; its
draft, agenda, query report, bindings, and receipt ancestry must validate
exactly. A v7 Night Editor rejection fails closed rather than being recast as
copy evidence. Run 58's v7 copy tip is imported into one v9 Night Editor
close without replaying ledger queries, agenda selection, journalists, copy desk,
world mechanics, strategic waves, or accepted per-wave publications.
ephemeral. Historical v7 reconciliation rows may remain in archived or
resumed stores as inert provenance, but the live newspaper module defines no
reconciliation loader, import envelope, or conversion path and does not
deserialize or rebind them. Historical strategic recomposition v1/v2 receipts
are a separate acceptance-driver verification surface; their typed validators
can prove original artifacts but cannot write newsroom state. Resume authority
belongs only to an exact-current close checkpoint bound to the same v9 task,
newsroom, facts, page, copy report, and receipt prefix. Run 58's v7 tip and Run
59's printed edition remain immutable evidence in their original artifacts,
not v9 close inputs.
- **Cut line:** the generic byline list and one-shot whole-page writer are
deleted. Assignment-owned section, journalist, byline, citations, and order
are no longer regenerated in prose output. Tool schema text and prior-action
@ -1459,6 +1465,10 @@ The deliberative newsroom boundary is live under this authority map:
repairs, repeated copy calls, Night rereview, post-close model judgment, and
edits to unqueried articles remain absent. Whole-article prose is the sole
Night Editor close unit, and exactly the query-bearing articles are mandatory.
The legacy reconciliation schemas and advance loop, automatic store lookup,
explicit import API and environment path, v7-to-v9 close conversion, and
pending consumer branches are deleted from live authority. Existing bytes are
not migrated or erased; nothing in the live path can make them decide a close.
The roster, query projection, front-page proof, and article assembly reuse the
generic agent harness and existing public-record, agenda, accepted issue, and
audit shapes. No dependency, crate, binary, daemon, persistent schema,
@ -1474,10 +1484,11 @@ The deliberative newsroom boundary is live under this authority map:
stage, deterministic source/printed digests, exact receipt ancestry,
close-checkpoint resume without reporter or copy replay, idempotent persisted
composition validation, printing the checkpointed page after a structurally
rejected close, and conversion of one legacy v7 copy tip into one v9 close
without replay. Strategic recomposition v3 binds the copy
report and press witness by digest while v1/v2 remain historical validation
inputs. Independent blind editorial and grounding reviews evaluate the
rejected close. The close validator admits only `InitialCopyDesk` checkpoints
with no source ancestry, while exact-current resume and idempotence regressions
exercise the only surviving resume path. Strategic recomposition v3 binds the
copy report and press witness by digest while v1/v2 remain historical
validation inputs. Independent blind editorial and grounding reviews evaluate the
resulting artifact for the acceptance experiment only; they are deliberately
outside runtime publication authority. Verification remains bounded to the
existing newspaper library and strategic-smoke targets plus formatting,
@ -1506,64 +1517,6 @@ or communicated public scope before `NewsIssue` materialization. Revision 27
remains immutable evidence and is not rewritten for this newsroom-only
acceptance.
The v8 close persistence and legacy-resume boundary is live:
- **Owner:** `newspaper::advance_world_newspaper` owns fresh composition,
close-checkpoint resume, legacy-tip conversion, press witnessing, and
accepted-composition idempotence. `CampaignStore` owns immutable storage.
Registry and strategic smoke provide policy inputs and consume results; they
do not reconstruct or judge the newsroom.
- **Inputs:** one exact campaign snapshot, title, voice, article budget, model
port, and store; the current v8 publication and editorial bindings; and,
during the bounded transition, an optional exact v7 reconciliation tip under
its legacy bindings. The close receives one agenda, one writer page, one copy
report, and their complete ordered receipts.
- **Outputs:** a nonempty edition yields composition v3 with one issue, one copy
report, one `WorldNewspaperPressClose`, and the receipt chain. A close action
that passes structural admission records every query and changed article. A
structurally rejected one-action close prints the checkpointed page and marks
`night_editor_action_applied=false`; it does not become pending editorial work.
Provider, schema, persistence, or checkpoint-integrity failures remain errors
before an immutable composition exists.
- **Persistent and derived state:** close checkpoint v1 persists once before the
Night Editor acts. The press witness derives exact source and printed page
digests, copy and Night Editor receipt IDs, action-applied status, addressed
query indices, and changed article indices. Composition validation reloads
every receipt, validates checkpoint lineage, reconstructs the printed draft,
re-derives the typed issue, and rejects any drift. These witnesses observe the
edition; they do not make its claims true.
- **Resume and shared paths:** every caller checks accepted composition v3,
resumes one current close checkpoint if present, then optionally converts the
unique validated v7 copy tip into one v8 close checkpoint. That conversion
retains the v7 tip's exact draft, agenda, copy findings, source identity, and
receipts while rebinding only the current task. It never invokes assignment,
writer, copy desk, mechanics, or waves. Fresh work reaches the same close
owner after assignment, writer, and copy. Live per-wave, recovery, and final
combined publication all use the thin common delegate.
- **Forbidden writers:** v8 cannot append a v7 reconciliation generation or
resume its rewrite loop. An explicit import may admit one external immutable
v7 checkpoint as provenance, but cannot infer it from error prose, fork an
existing chain, or mutate it after admission. Strategic smoke, renderers,
reviewers, and world organs cannot alter a close checkpoint, press witness,
accepted issue, or source campaign. A later correction must be new
publication state; overwriting the closed edition is forbidden.
- **Cut line:** the rewrite-desk cadence, repeated desk verdicts, pending
reconciliation advances, and copy/editor rereplay paths are absent from live
v8 authority. `WorldNewspaperAdvance::Pending` and its consumer branches
remain compatibility-shaped surface only; the v8 newspaper owner has no
pending producer. Legacy v7 schemas remain solely to validate and convert the
Run 58 copy tip.
- **Verification layer:** focused tests prove one-action close admission,
structural rejection printing the bound source page, exact press-witness
re-derivation, tamper rejection, close resume without writer or copy replay,
accepted-composition idempotence, and exact Run-58-shaped v7 copy-tip
conversion into one v8 Night Editor close. Negative gates reject incomplete
query disposition, missing mandatory or duplicate article rewrites, mutation
of frozen assignment fields, v7 Night Editor rejection masquerading as copy
evidence, multiple close checkpoints, source drift, receipt drift, and witness
drift. No event,
simulation, selector, agenda, or provenance authority moved.
The typed issue retains exact event IDs, channels, reliability, source
revision, and model receipts as audit data. Its internal issue time is derived
from the latest cited publication record without exposing that clock to
@ -1592,7 +1545,9 @@ write world state.
snapshot, the preceding wave checkpoint's committed news-ledger boundary,
the configured title and voice, the explicit resume recovery boundary
(`GHOSTLIGHT_STRATEGIC_NEWSPAPER_RECOVERY_START_WAVE`, defaulting to wave one
and validated within `1..=wave_count`), and the same campaign receipt store
and validated within `1..=wave_count + 1`; selecting `wave_count + 1` is the
final-only sentinel: it recovers no per-wave editions but leaves final combined
composition enabled), and the same campaign receipt store
used by ordinary newspaper composition. When an accepted recomposition
already exists, its immutable receipt and exact named reader/audit files are
additional inputs.
@ -1619,7 +1574,9 @@ write world state.
configured recovery boundary whose issue is absent. Earlier missing reports
remain historical gaps, while any already successful issue inside the selected
range is left untouched. The configured recovery boundary owns selection of
the missing reports in the current invocation. A completed recomposition's
the missing reports in the current invocation; the final-only sentinel derives
an empty per-wave selection because no report can reach `wave_count + 1`. A
completed recomposition's
recorded recovery boundary is immutable provenance for the invocation that
produced it; it does not become a second selector or invalidate the accepted
issue when a later invocation selects a narrower range.
@ -1631,7 +1588,8 @@ write world state.
combined composition all call the thin `compose_persisted_newspaper` delegate
into `advance_world_newspaper`, including the same assignment, writer, single
copy report, one deadline close, checkpoint-resume, and receipt-persistence
owner. A later invocation resumes a close checkpoint without rerunning the
owner. The final combined composition still runs when the recovery selector
returns no per-wave reports. A later invocation resumes a close checkpoint without rerunning the
writer or copy desk. Once printed, it
consumes the successful recomposition artifact instead of paying for the
newspaper again. The driver recomputes its wave, source-campaign, and
@ -1669,7 +1627,9 @@ write world state.
`Vec<ModelStageReceipt>` before hashing and rejects an invalid receipt shape,
so creation and verification share one representation. A scope-selection
regression proves that earlier missing issues and successful issues are
skipped while later missing issues are selected. Dedicated regressions prove
skipped while later missing issues are selected, and that the
`wave_count + 1` boundary selects no per-wave reports for a final-only resume.
Dedicated regressions prove
that historical v2 preserves its recorded original recovery boundary and
accepts exact historical bytes without current rendering while rejecting byte
drift, that current issue v3 still requires typed deserialization and exact

View file

@ -325,7 +325,7 @@ data_flow:
current_status:
summary: Ghostlight's generic consumer boundary admits sparse WorldSeeds, runs the hundreds-class parallel cell machinery used by Dungeon, and projects grounded newspapers from committed public events. Local acceptance proves 1,000 subjects across 200 cells and two-wave durable named-person emergence. Exact-source provider run 38 at `596e50679244b5d42b4cfdf70d723f815751b8ff` resumed the preserved world at revision 8 without replaying compilation or four committed locality elaborations, recovered 51 of 52 strategic-wave cells on pulse three and the final cell on pulse four, then committed all six waves through revision 14. Pushed commit `3a69306f3004e4af2cd57bba612a6ad8d1b8132f` implements the mapped clock-consequence owner and is verified locally: world clocks own declared consequence text and exact observable scope; a bounded agent may propose legacy scope binding, while `WorldKernel` alone admits it and materializes stable threshold-crossing events and public news through the common mutation path. Binding, emitted-event ancestry, mutation receipts, and the next newspaper boundary persist atomically. Exact-source run 39 resumed run 38 without replaying its six committed waves, bound clock consequences, committed six new waves through revision 21, and emitted Issues 7 through 12 plus a final digest. This completes the mechanical provider acceptance path; all inherited wave 1-6 checkpoint hashes match run 38 exactly and live services were unchanged. Independent blind editorial review returns FAIL: only Issue 7 approaches spicy, while Issues 8-12 are dominated by plans, filings, inspections, warnings, and abstract relationship deltas without betrayal, scandal, public reaction, sustained reversal, or material lived cost. That run-39 diagnosis is superseded for the current phase: run 51 closes the world and reconciliation mechanics, and the active defect belongs to newsroom narrative selection and self-contained semantic provenance over immutable facts. Independent grounding review also returns FAIL: Issue 9 inflates a planned expedited agenda into completion, while Issue 8 assigns unsupported feminine pronouns to Sela Venn and Eryn Tal. Other grounding mechanics pass: 208/208 citations resolve, no future events appear, no replay occurred, the player remained unchanged, all 116/116 manifest entries verify, the archive is exact, and root independently confirmed the live service PIDs and invocation IDs remained unchanged. Editorial and grounding acceptance are terminally failed for run 39. Eight titled elaborators use the generic agent harness under deterministic weighted scheduling, bounded parallelism, and Luna/Terra/Sol routing. Workers remain proposal-only; deterministic admission binds exact frozen schedules, dispatch, receipts, conflicts, and semantic verification, and `WorldKernel` alone owns atomic CultCache persistence. Destination reconciliation is a private transactional workbench, provider schema compatibility is lowered once at the shared model-connector boundary, and durable elaboration and strategic-pulse checkpoints bind to their canonical mutation proofs. The generic ModelAgent harness remains consumer-neutral transport. Provider run 23 remains stopped; earlier failed runs and checkpoint archives remain immutable provenance. The live daemons remain outside the acceptance body. Dungeon play remains regression pressure, the Delvehold game-side adapter remains unimplemented, and unpublished Mars and Kalsa destination previews remain unapproved.
provider_acceptance_checkpoint: Exact-source Run 59 at pushed commit `161ff2f19021249563e192cce9e6f76f00429d48` is printed from immutable Run 58 at world revision 27 with no selection, writer, copy-desk, world, or wave replay. Its acceptance witness binds one copy report with five queries, one Night Editor close, `night_editor_action_applied=true`, three changed articles, and unchanged live-service PID/invocation identities. Newspaper SHA-256 is `ee2ce08ceb627d433ac2d4ff7e1ebecb1437bf28b1399d23bfb3d5b066c8ab27`; audit is `b210d50d4ef1a350315d528f6d37e1e7b618926346713f737c4169c49df26b49`; immutable local archive `F:\GameCult\GhostlightDungeon\acceptance\elven-realms-autonomous-161ff2f-59.tar` is `ecb4db41e9a40ee4db8b0f83dce42d74e40f940e5930b1d3c1ced227dfec76b3`. A finalizer verifier incorrectly expected a schema field on the assessment-plus-queries report; finalization resumed without another model call. The edition satisfies the press and delivery boundary.
implementation_checkpoint: Exact pushed commit `901cfcd58794acc35b24be3d1e149fd2df0f6c3d` implements and locally verifies `character-newsroom.v9`. The assignment editor sees one embodied publication roster and owns story, section, evidence, and journalist assignment. One bounded journalist agent writes each assigned story from only its own profile, pitch, and exact cited records; assignment-owned byline, section, citations, and order are assembled deterministically. Dalen Marr alone emits one complete factual checklist. Meret Sorn receives only queried articles, affected assignments, their cited facts, and affected reporter profiles, then gets one checklist-bound close action over exactly those articles. The generic model harness now preserves typed append-only user/assistant request prefixes, keeps schemas out of prompt text, and routes stable stage/model/schema cache keys; selector query/proposal/commit and Night close each keep one stable action schema while their private deterministic workbenches enforce current legality. The one-shot whole-page writer and generic byline registry are deleted. No dependency, crate, binary, daemon, persistent schema, event authority, or simulation pass was added. Gates pass 475/475 library tests, 16/16 strategic-smoke tests, and all-target checks. Provider and reverse-Turing acceptance remain unproven.
next_action: Preserve Run 59 as immutable evidence and run the authorized newsroom-only provider acceptance for exact pushed `901cfcd58794acc35b24be3d1e149fd2df0f6c3d`; do not replay world simulation. Capture real cached-token behavior and the immutable v9 front page, then dispatch an independent blind reviewer with only that reader-facing fantasy newspaper and a request for its journalistic opinion. Pass only if the reviewer is not immediately tipped that the page is procedurally generated; do not expose mechanics, prompts, receipts, provenance, or the acceptance hypothesis, and do not redefine a merely less-bad result as passage. Preserve Run 59 findings as later publication debt and defer multi-publication expansion, TeX layout, and engraved cuts.
provider_acceptance_checkpoint: Run 60 remains the active `character-newsroom.v9` acceptance root and has made no v9 provider call. Attempt 1 stopped on the missing `wave_count + 1` final-only sentinel. Attempt 2 reached final composition without simulation or per-wave replay, then stopped because automatic v7 close import still claimed live resume authority. Run 59 remains the prior immutable printed evidence with its exact press proof and later-publication debt; neither Run 60 attempt changes it or supplies reverse-Turing evidence.
implementation_checkpoint: Exact pushed commit `901cfcd58794acc35b24be3d1e149fd2df0f6c3d` implements `character-newsroom.v9`. The assignment editor sees one embodied publication roster and owns story, section, evidence, and journalist assignment. One bounded journalist agent writes each assigned story from only its own profile, pitch, and exact cited records; assignment-owned byline, section, citations, and order are assembled deterministically. Dalen Marr alone emits one complete factual checklist. Meret Sorn receives only queried articles, affected assignments, their cited facts, and affected reporter profiles, then gets one checklist-bound close action over exactly those articles. The generic model harness preserves typed append-only user/assistant request prefixes, keeps schemas out of prompt text, and routes stable stage/model/schema cache keys. The current uncommitted resume-ownership cut removes legacy reconciliation/import from live newsroom authority, makes advance return exactly one composition, and leaves the exact-current close checkpoint as the sole resume owner. Gates pass 474/474 library tests, 16/16 strategic-smoke tests, and all-target checks. Provider and reverse-Turing acceptance remain unproven.
next_action: Commit and push the verified resume-ownership cut, then resume the same Run 60 root at final composition without replaying simulation or per-wave publications. Capture real cached-token behavior and the immutable v9 front page, then dispatch the independent blind journalistic review under the exact reverse-Turing criterion. Preserve Run 59 and both failed Run 60 attempts; do not launch a fresh campaign, import a v7 close, or redefine a merely less-bad review as passage. Defer multi-publication expansion, TeX layout, and engraved cuts.
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.