Stamp every knowledge row with its own acquisition revision (PA.f44)

The recency marker was `minted_at > last_acted_at`, and minted_at is set only
by a speech or a display event's own fan-out. A row AcquireKnowledge lands, a
row Witness lands, and a row declaration-time seeding lands all carry no
minted_at, so `new` computed with `>` a `None` was always false for them: a
fact landed by a patch, a seed, or a ruling could never surface to a Persona
as new, however long after the subject's last act it arrived.

Knowledge now carries acquired_at: u64, the revision this write's own commit
resolves to (matching how DecisionEvent.revision and the minted_at scan built
from it are computed: one past the pre-increment state.revision apply runs
against). Every writer of the knowledge map sets it: AcquireKnowledge,
Communicate's fan-out, Display's fan-out, and Witness. The marker becomes
`acquired_at > last_acted_at`, with a subject that never acted (last_acted_at
is None) seeing every row it holds as new outright, matching the ruling
exactly rather than leaning on Option ordering.

minted_at keeps its own meaning — which act minted a spoken or displayed claim
— and stays on KnowledgeSnapshot and on the wire; no schema bump, since no
consumer.v6 store exists yet. AcquireKnowledge's own no-op refusal now
compares confidence and source alone, not the whole row, so a later
acquired_at cannot make an identical re-assertion stop refusing as
"knowledge operation changes nothing".

Tests: a row AcquireKnowledge lands after the subject's last act is new; one
that lands before it is not; the acquisition revision survives a journal
reopen; and the Cut 0 stimulus test's third row — seeded with no minted_at,
previously "new": false — now reads "new": true, because its subject never
acted and PA.f44 says every row such a subject holds is new.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-22 09:33:13 +02:00
commit 3b1f412b92
3 changed files with 344 additions and 29 deletions

View file

@ -4852,9 +4852,15 @@ impl SelectedDecision {
};
// The recency marker: strictly after the subject's own last
// exercised decision, so a subject that never acted
// (`last_acted_at` is `None`) sees every minted row as new,
// (`last_acted_at` is `None`) sees every row it holds as new,
// and the subject's own acting revision is not itself new.
let new = entry.minted_at > self.subject.last_acted_at;
// `acquired_at` is written by every knowledge writer (PA.f44),
// unlike `minted_at`, which a patch, a seed, or a ruling never
// sets, so this marker sees rows those writers land too.
let new = match self.subject.last_acted_at {
None => true,
Some(acted_at) => entry.acquired_at > acted_at,
};
json!({
"how": how,
"by": by,
@ -7003,6 +7009,7 @@ mod tests {
via: None,
},
minted_at: Some(40),
acquired_at: 40,
},
// Mara also saw Iris do something. The row is Iris's own
// sentence, marked as seen and never as said.
@ -7013,6 +7020,7 @@ mod tests {
confidence: Confidence::Believed,
source: KnowledgeSource::Seen { by: speaker_id },
minted_at: Some(41),
acquired_at: 41,
},
],
commitments: Vec::new(),
@ -7042,6 +7050,7 @@ mod tests {
confidence: Confidence::Certain,
source: KnowledgeSource::Witnessed,
minted_at: None,
acquired_at: 0,
}],
commitments: Vec::new(),
pressures: Vec::new(),
@ -7616,6 +7625,7 @@ mod tests {
confidence: Confidence::Believed,
source: KnowledgeSource::Witnessed,
minted_at: Some(1),
acquired_at: 1,
},
KnowledgeSnapshot {
fact: EntityId::issue(),
@ -7624,6 +7634,7 @@ mod tests {
confidence: Confidence::Believed,
source: KnowledgeSource::Witnessed,
minted_at: Some(2),
acquired_at: 2,
},
KnowledgeSnapshot {
fact: EntityId::issue(),
@ -7632,6 +7643,7 @@ mod tests {
confidence: Confidence::Believed,
source: KnowledgeSource::Witnessed,
minted_at: Some(3),
acquired_at: 3,
},
];
let boundary_selected = SelectedDecision {
@ -7732,6 +7744,242 @@ mod tests {
}
}
/// PA.f44: a row `AcquireKnowledge` lands — a patch, not a minting speech
/// or display act — after the subject's own last act is new. Before
/// PA.f44 this row carried no `minted_at` at all, so the old marker
/// (`minted_at > last_acted_at`, `None` never beats `Some`) could never
/// flag it, whatever revision it actually landed on.
#[test]
fn a_row_acquired_by_a_patch_after_the_last_act_is_new() {
use crate::tests::{
FLOOD_STATEMENT, auth_principal, command, operations, opportunity_for, owner,
speech_world, submit_owner,
};
use crate::{
AuthenticatedCaller, AuthoredSource, DecisionInvocation, Ref, Role, RoleBinding,
Statement, SubmitReceipt, Target, WorldKernel,
};
let directory = tempfile::tempdir().unwrap();
let mut kernel = WorldKernel::create(
directory.path().join("world.cc"),
crate::tests::creation(CommandId::new(), "PatchAfterAct"),
&auth_principal(owner()),
)
.expect("a created world")
.0;
let (speech, active) = speech_world(&mut kernel);
// The listener acts once, so it carries a `last_acted_at`.
let opportunity = opportunity_for(&active, speech.listener);
let caller = CallerId::Controller(opportunity.controller_id);
let receipt = kernel
.submit(
command(
&active,
CommandId::new(),
caller.clone(),
CommandBody::ExerciseDecision {
opportunity,
invocation: DecisionInvocation {
affordance: speech.whisper,
bindings: vec![RoleBinding {
role: Role("target".into()),
target: Target::Subject(speech.speaker),
}],
proposed: Vec::new(),
speech: Some(Statement::new("I have something to say.").unwrap()),
display: None,
},
},
),
&AuthenticatedCaller::fixture(caller),
)
.expect("the whisper commits");
assert!(matches!(receipt, SubmitReceipt::Applied(_)));
let after_act = kernel.snapshot().unwrap();
// A patch, after the act, lands a row the listener never spoke or
// saw: the sole scenario PA.f44 exists for.
submit_owner(
&mut kernel,
&after_act,
operations(vec![crate::patch::ComponentOp::AcquireKnowledge {
subject: Ref::Existing(speech.listener),
fact: Ref::Existing(speech.flood),
source: AuthoredSource::Witnessed,
confidence: Confidence::Believed,
}]),
);
let after_patch = kernel.snapshot().unwrap();
let subject = after_patch
.subjects
.iter()
.find(|subject| subject.id == speech.listener)
.unwrap()
.clone();
assert!(subject.last_acted_at.is_some());
let row = subject
.knowledge
.iter()
.find(|row| row.fact == speech.flood)
.expect("the patch landed the row");
assert_eq!(row.minted_at, None, "a patch mints no event");
let opportunity = opportunity_for(&after_patch, speech.listener);
let granted: Vec<AffordanceSnapshot> = after_patch
.affordances
.iter()
.filter(|entry| subject.affordances.contains(&entry.id))
.cloned()
.collect();
let selected = SelectedDecision {
snapshot: after_patch,
subject,
opportunity,
granted,
};
let rendered = selected
.projector_knowledge()
.into_iter()
.find(|row| row["text"] == Value::String(FLOOD_STATEMENT.into()))
.expect("the flood row is rendered");
assert_eq!(rendered["new"], Value::Bool(true));
}
/// PA.f44's other boundary: a row `AcquireKnowledge` lands *before* the
/// subject's own last act is not new, exactly as a row minted by an act
/// before it is not.
#[test]
fn a_row_acquired_by_a_patch_before_the_last_act_is_not_new() {
use crate::tests::{
FLOOD_STATEMENT, auth_principal, command, operations, opportunity_for, owner,
speech_world, submit_owner,
};
use crate::{
AuthenticatedCaller, AuthoredSource, DecisionInvocation, Ref, Role, RoleBinding,
Statement, SubmitReceipt, Target, WorldKernel,
};
let directory = tempfile::tempdir().unwrap();
let mut kernel = WorldKernel::create(
directory.path().join("world.cc"),
crate::tests::creation(CommandId::new(), "PatchBeforeAct"),
&auth_principal(owner()),
)
.expect("a created world")
.0;
let (speech, active) = speech_world(&mut kernel);
// The patch lands first, before the listener has ever acted.
submit_owner(
&mut kernel,
&active,
operations(vec![crate::patch::ComponentOp::AcquireKnowledge {
subject: Ref::Existing(speech.listener),
fact: Ref::Existing(speech.flood),
source: AuthoredSource::Witnessed,
confidence: Confidence::Believed,
}]),
);
let after_patch = kernel.snapshot().unwrap();
// Now the listener acts, so its `last_acted_at` moves past the patch.
let opportunity = opportunity_for(&after_patch, speech.listener);
let caller = CallerId::Controller(opportunity.controller_id);
let receipt = kernel
.submit(
command(
&after_patch,
CommandId::new(),
caller.clone(),
CommandBody::ExerciseDecision {
opportunity,
invocation: DecisionInvocation {
affordance: speech.whisper,
bindings: vec![RoleBinding {
role: Role("target".into()),
target: Target::Subject(speech.speaker),
}],
proposed: Vec::new(),
speech: Some(Statement::new("I have something to say.").unwrap()),
display: None,
},
},
),
&AuthenticatedCaller::fixture(caller),
)
.expect("the whisper commits");
assert!(matches!(receipt, SubmitReceipt::Applied(_)));
let after_act = kernel.snapshot().unwrap();
let subject = after_act
.subjects
.iter()
.find(|subject| subject.id == speech.listener)
.unwrap()
.clone();
assert!(subject.last_acted_at.is_some());
let opportunity = opportunity_for(&after_act, speech.listener);
let granted: Vec<AffordanceSnapshot> = after_act
.affordances
.iter()
.filter(|entry| subject.affordances.contains(&entry.id))
.cloned()
.collect();
let selected = SelectedDecision {
snapshot: after_act,
subject,
opportunity,
granted,
};
let rendered = selected
.projector_knowledge()
.into_iter()
.find(|row| row["text"] == Value::String(FLOOD_STATEMENT.into()))
.expect("the flood row is rendered");
assert_eq!(rendered["new"], Value::Bool(false));
}
/// PA.f44: `acquired_at` is real committed state, not a snapshot-only
/// derivation, so it must survive a journal reopen exactly as
/// `minted_at`'s source events do.
#[test]
fn the_acquisition_revision_survives_replay() {
use crate::tests::{auth_principal, operations, owner, speech_world};
use crate::{AuthoredSource, Ref, WorldKernel};
let directory = tempfile::tempdir().unwrap();
let mut kernel = WorldKernel::create(
directory.path().join("world.cc"),
crate::tests::creation(CommandId::new(), "AcquisitionReplay"),
&auth_principal(owner()),
)
.expect("a created world")
.0;
let (speech, active) = speech_world(&mut kernel);
crate::tests::submit_owner(
&mut kernel,
&active,
operations(vec![crate::patch::ComponentOp::AcquireKnowledge {
subject: Ref::Existing(speech.listener),
fact: Ref::Existing(speech.flood),
source: AuthoredSource::Witnessed,
confidence: Confidence::Believed,
}]),
);
let acquired_at = kernel.state.knowledge[&speech.listener][&speech.flood].acquired_at;
let world_id = kernel.state.world_id;
drop(kernel);
let reopened =
WorldKernel::open(directory.path().join("world.cc"), world_id).expect("it replays");
assert_eq!(
reopened.state.knowledge[&speech.listener][&speech.flood].acquired_at,
acquired_at
);
}
/// Verification: `turn` refuses any mode but `NarrativePersona`, and
/// `narrate` refuses any mode but `Human` — before either ever reaches the
/// mailbox.
@ -7936,9 +8184,14 @@ mod tests {
/// PA-Q2's default plus Cut 6: the stimulus is exactly Cut 0's capture
/// (session scratchpad `play-cut0/base-stimulus.txt`: one `Told` row, one
/// `Seen` row, one held fact with no author) with exactly one `"new"`
/// field added per row. This subject never acted, so both minted rows are
/// new; the third row was never minted by an event at all (no
/// `minted_at`), so it carries no arrival time to compare and is not new.
/// field added per row. This subject never acted (`last_acted_at` is
/// `None`), so every row it holds is new (PA.f44) — including the third,
/// which carries no `minted_at` at all (no minting event ever asserted
/// it) but still carries `acquired_at`, the field every knowledge writer
/// sets. Before PA.f44 that row read `"new": false`: a row with no
/// `minted_at` could never be new, which is exactly the bug — a fact
/// landed by a patch, a seed, or a ruling would never surface to a
/// Persona as new.
#[test]
fn the_stimulus_equals_cut_zeros_capture_plus_the_marker() {
let subject_id = SubjectId::issue();
@ -7979,6 +8232,7 @@ mod tests {
via: None,
},
minted_at: Some(1),
acquired_at: 1,
},
KnowledgeSnapshot {
fact: EntityId::issue(),
@ -7987,6 +8241,7 @@ mod tests {
confidence: Confidence::Believed,
source: KnowledgeSource::Seen { by: speaker_id },
minted_at: Some(2),
acquired_at: 2,
},
KnowledgeSnapshot {
fact: EntityId::issue(),
@ -7995,6 +8250,9 @@ mod tests {
confidence: Confidence::Certain,
source: KnowledgeSource::Witnessed,
minted_at: None,
// No minting event ever asserted this row (declaration-time
// seeding, PA.f44) but it still carries `acquired_at`.
acquired_at: 0,
},
],
commitments: Vec::new(),
@ -8073,7 +8331,7 @@ mod tests {
"by": null,
"certainty": "certain",
"how": "known",
"new": false,
"new": true,
"text": "The rain gate sticks in the cold."
}
]))

View file

@ -1074,6 +1074,10 @@ pub(crate) struct KnowledgeSnapshot {
/// The revision of the act that minted this claim, spoken or displayed,
/// when some committed event asserted it.
pub(crate) minted_at: Option<u64>,
/// The revision at which this subject acquired this row, from `Knowledge`
/// directly: always present, unlike `minted_at`, so the recency marker can
/// see a row a patch, a seed, or a ruling landed with no minting event.
pub(crate) acquired_at: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -2718,23 +2722,38 @@ fn apply_operation(
"knowledge operation names no live subject, or evidences a claim".into(),
));
}
let entry = Knowledge {
confidence: *confidence,
source: match source {
AuthoredSource::Witnessed => KnowledgeSource::Witnessed,
AuthoredSource::Evidenced => KnowledgeSource::Evidenced,
},
let source = match source {
AuthoredSource::Witnessed => KnowledgeSource::Witnessed,
AuthoredSource::Evidenced => KnowledgeSource::Evidenced,
};
// Compared on `confidence` and `source` alone: `acquired_at` is
// this write's own revision, not part of what the author asserts,
// so a re-assertion identical in everything the author controls
// still refuses as a no-op even though it would land a later
// `acquired_at`.
if state
.knowledge
.get(subject)
.and_then(|held| held.get(fact))
.is_some_and(|held| *held == entry)
.is_some_and(|held| held.confidence == *confidence && held.source == source)
{
return Err(KernelError::Invariant(
"knowledge operation changes nothing".into(),
));
}
// Matches `DecisionEvent.revision` and the `minted_at` scan built
// from it (`action::exercise`, `snapshot`): both name the revision
// this commit resolves to, one past `state.revision` here, which
// still holds the *previous* revision until `submit` bumps it.
let acquired_at = state
.revision
.checked_add(1)
.ok_or_else(|| KernelError::Serialization("world revision overflow".into()))?;
let entry = Knowledge {
confidence: *confidence,
source,
acquired_at,
};
state
.knowledge
.entry(*subject)
@ -2773,6 +2792,12 @@ fn apply_operation(
// An empty fan-out is legal: the delta of a telling is a property of
// the world — an empty room, a silenced channel — not a defect in
// the proposal. Speaking alone commits the claim and lands nothing.
// `acquired_at` matches `minted_at`: one past `state.revision`, the
// revision this commit resolves to (PA.f44).
let acquired_at = state
.revision
.checked_add(1)
.ok_or_else(|| KernelError::Serialization("world revision overflow".into()))?;
for listener in fan_out(state, *speaker, *fact, to) {
state.knowledge.entry(listener).or_default().insert(
*fact,
@ -2782,6 +2807,7 @@ fn apply_operation(
by: *speaker,
via: to.channel(),
},
acquired_at,
},
);
}
@ -2804,12 +2830,17 @@ fn apply_operation(
"an actor displays from no place".into(),
));
}
let acquired_at = state
.revision
.checked_add(1)
.ok_or_else(|| KernelError::Serialization("world revision overflow".into()))?;
for viewer in fan_out(state, *actor, *fact, &room) {
state.knowledge.entry(viewer).or_default().insert(
*fact,
Knowledge {
confidence: Confidence::Believed,
source: KnowledgeSource::Seen { by: *actor },
acquired_at,
},
);
}
@ -2840,12 +2871,17 @@ fn apply_operation(
"a witness reaches nobody who does not already hold the fact".into(),
));
}
let acquired_at = state
.revision
.checked_add(1)
.ok_or_else(|| KernelError::Serialization("world revision overflow".into()))?;
for witness in recipients {
state.knowledge.entry(witness).or_default().insert(
*fact,
Knowledge {
confidence: *confidence,
source: KnowledgeSource::Witnessed,
acquired_at,
},
);
}
@ -3845,6 +3881,7 @@ fn snapshot(state: &WorldState) -> Result<WorldSnapshot, KernelError> {
confidence: held.confidence,
source: held.source,
minted_at: minted_at.get(fact).copied(),
acquired_at: held.acquired_at,
})
})
.collect::<Result<Vec<_>, KernelError>>()?;
@ -9752,6 +9789,7 @@ mod knowledge_tests {
by: speech.speaker,
via: None,
},
acquired_at: active.revision + 1,
})
);
// The yard is inside the hall, but a voice fills a room and not the
@ -9922,6 +9960,7 @@ mod knowledge_tests {
Some(Knowledge {
confidence: Confidence::Believed,
source: KnowledgeSource::Seen { by: speech.speaker },
acquired_at: active.revision + 1,
})
);
for blind in [speech.bystander, speech.stranger, speech.speaker] {
@ -10260,6 +10299,7 @@ mod knowledge_tests {
by: speech.speaker,
via: Some(speech.horn),
},
acquired_at: active.revision + 1,
})
);
}
@ -10779,6 +10819,7 @@ mod soul_knowledge_tests {
by: speech.speaker,
via: Some(speech.horn),
},
acquired_at: active.revision + 1,
})
);
// The controller gains no knowledge of its own claim: it is outside
@ -11051,6 +11092,7 @@ mod soul_knowledge_tests {
by: speech.speaker,
via: None,
},
acquired_at: active.revision + 1,
})
);
}
@ -11504,10 +11546,11 @@ mod witness_tests {
.copied()
}
fn seen(confidence: Confidence) -> Option<Knowledge> {
fn seen(confidence: Confidence, acquired_at: u64) -> Option<Knowledge> {
Some(Knowledge {
confidence,
source: KnowledgeSource::Witnessed,
acquired_at,
})
}
@ -11528,11 +11571,11 @@ mod witness_tests {
);
assert_eq!(
knows(&kernel, world.villager, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, active.revision + 1)
);
assert_eq!(
knows(&kernel, world.neighbour, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, active.revision + 1)
);
assert_eq!(knows(&kernel, world.coaster, world.asteroid), None);
assert_eq!(knows(&kernel, world.drifter, world.asteroid), None);
@ -11555,7 +11598,7 @@ mod witness_tests {
] {
assert_eq!(
knows(&kernel, subject, world.moon),
seen(Confidence::Certain)
seen(Confidence::Certain, after.revision + 1)
);
}
@ -11586,8 +11629,10 @@ mod witness_tests {
by: world.coaster,
via: None,
},
acquired_at: 0,
};
let mut state = kernel.state.clone();
let state_revision = state.revision;
state
.knowledge
.entry(world.villager)
@ -11609,6 +11654,7 @@ mod witness_tests {
Knowledge {
confidence: Confidence::Certain,
source: KnowledgeSource::Witnessed,
acquired_at: state_revision + 1,
}
);
}
@ -11738,7 +11784,7 @@ mod witness_tests {
);
assert_eq!(
knows(&kernel, world.coaster, world.asteroid),
seen(Confidence::Certain)
seen(Confidence::Certain, seeded.revision + 1)
);
// The inverse: the coast's only stander leaves before the witness, so
@ -11831,6 +11877,7 @@ mod witness_tests {
site: Site::Operation(0)
}]
);
let before_admit = kernel.state.revision;
let admitted = submit(&mut kernel, world.village);
assert!(
matches!(admitted, Ok(SubmitReceipt::Applied(_))),
@ -11838,7 +11885,7 @@ mod witness_tests {
);
assert_eq!(
knows(&kernel, world.villager, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, before_admit + 1)
);
}
@ -12080,11 +12127,11 @@ mod witness_tests {
);
assert_eq!(
knows(&kernel, world.villager, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, active.revision + 1)
);
assert_eq!(
knows(&kernel, world.neighbour, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, active.revision + 1)
);
assert_eq!(knows(&kernel, world.coaster, world.asteroid), None);
@ -12130,7 +12177,7 @@ mod witness_tests {
assert_eq!(reopened.state, committed);
assert_eq!(
knows(&reopened, world.villager, world.asteroid),
seen(Confidence::Certain)
seen(Confidence::Certain, active.revision + 1)
);
}
@ -12152,6 +12199,7 @@ mod witness_tests {
Knowledge {
confidence: Confidence::Doubted,
source: KnowledgeSource::Witnessed,
acquired_at: 0,
},
);
for root in [world.hemisphere, world.region, world.village, world.coast] {
@ -12227,6 +12275,7 @@ mod witness_tests {
// reach it. Presence is read from `positions` alone: there is no second
// notion of being somewhere for a placeless subject to fall back on.
let mut adrift = kernel.state.clone();
let adrift_revision = adrift.revision;
adrift.positions.remove(&world.drifter);
for root in [
world.hemisphere,
@ -12263,6 +12312,7 @@ mod witness_tests {
Knowledge {
confidence: Confidence::Certain,
source: KnowledgeSource::Witnessed,
acquired_at: adrift_revision + 1,
}
);
}
@ -12364,6 +12414,7 @@ mod witness_tests {
// Declared and placed under the witnessed place: the resolver's
// candidate map carries the draft position, and the apply pass derives
// the same subject from live state.
let before_arrival = kernel.state.revision;
let receipt = arrival(
&mut kernel,
"arrival",
@ -12383,17 +12434,17 @@ mod witness_tests {
.0;
assert_eq!(
knows(&kernel, arrived, world.asteroid),
seen(Confidence::Certain)
seen(Confidence::Certain, before_arrival + 1)
);
// The standers who already held it kept their own rows, so the landing
// was exactly the draft subject.
// The standers who already held it kept their own rows, from the
// earlier witness, and this landing did not touch them.
assert_eq!(
knows(&kernel, world.villager, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, active.revision + 1)
);
assert_eq!(
knows(&kernel, world.neighbour, world.asteroid),
seen(Confidence::Believed)
seen(Confidence::Believed, active.revision + 1)
);
}
@ -12445,12 +12496,12 @@ mod witness_tests {
assert!(matches!(receipt, SubmitReceipt::Applied(_)), "{receipt:?}");
assert_eq!(
knows(&kernel, world.villager, world.asteroid),
seen(Confidence::Certain),
seen(Confidence::Certain, seeded.revision + 1),
"the forgotten subject was not re-reached"
);
assert_eq!(
knows(&kernel, world.neighbour, world.asteroid),
seen(Confidence::Believed),
seen(Confidence::Believed, active.revision + 1),
"a holder the patch did not touch was overwritten"
);
}

View file

@ -417,6 +417,12 @@ pub(crate) enum KnowledgeSource {
pub(crate) struct Knowledge {
pub(crate) confidence: Confidence,
pub(crate) source: KnowledgeSource,
/// The revision at which this subject acquired this row: witnessed,
/// told, shown, or seeded by an author. Written by every writer of this
/// map (PA.f44), so the Projector's recency marker can tell a row minted
/// with no `minted_at` — a patch, a seed, a ruled fact — from one the
/// subject already held before its last act.
pub(crate) acquired_at: u64,
}
/// The source an author may write. `Told` is unrepresentable here: only