Can the bot simply ask for level 16? The request alone gives no power. The host checks the work, saves the proof it accepts, and sets a ceiling on usable power. This chapter follows that saved proof from one accepted check to the short boost the knight can actually use.
Starts with: A result that has passed a host check.
Ends with: Saved proof and a maximum allowed power level.
Question: What did the check prove, whose proof is it, and which earlier checks does it depend on?
Ask for 16, get 4: one SERRATE example
Suppose the bot completes Entry, the first ABYSS step, for SERRATE sword power. The host accepts two checks: DualView and EntryLoop. It saves an EntryProof for this run's SERRATE track. Then the bot requests Drive levels [16, 0, 0]. This asks for maximum sword power and no shield or magnet power. This request is an example; it is not from the reference bot.
The host calls one accepted receipt a certificate. It saves certificates in a proof node such as EntryProof. The node names the step, owner, power track, and accepted certificates. A later step must link to the correct earlier node. Writing level = 16 in bot memory cannot replace that history.
Three objects that are easy to confuse
An execution result records what the inner program did or returned, and the host still has to judge it. A certificate records one check that the host accepted. A proof node holds accepted certificates for one run and one power track, with links to earlier nodes. The code calls it a provenance node.
Here, DualView and EntryLoop are certificate kinds, EntryProof is their node, and [16, 0, 0] is a later request to use that proof. Entry has no earlier proof node.
The repository has an accepted Entry body and an altered body, both on bank 0 and SERRATE. Both pass the row grammar and row/column XOR checks, and the accepted body's last tile has the required column operations C D E 8.
The altered body has E F 4 2, so the host's column check rejects it. Passing the earlier row and XOR checks is not enough.
A fresh run has no earlier Entry proof. Read each lane down: accepting a call's format is only the first door.
Accepted witness
1 · Call receivedHost copies the frame and runs the Entry work.
2 · Both readers agreeRows and XORs pass. Last-tile columns spell C D E 8.
3 · Receipt and proofHost can accept DualView and EntryLoop, then save this track's EntryProof.
4 · Later Drive requestEntry can support at most level 4, if that new request passes too.
Altered control
1 · Call receivedHost still copies the frame and runs the Entry work.
2 · One reader disagreesRows and XORs pass, but columns spell E F 4 2. The required pattern fails.
3 · No Entry proofThe inner result does not pass the full check. The host saves no EntryProof for this attempt.
4 · Later Drive requestThis attempt supplied no new Entry authority. Asking for level 4 cannot make the missing proof appear.
A public call status can look ordinary in both lanes. The meaningful difference is the host-owned proof saved after all Entry checks, not a number the bot can put in its memory.
The host checks all requirements before it saves proof. The code's proof_eligible value requires valid Entry bytes and both calls in order. It also requires the same paused work, valid completion, and a real session slot. One valid-looking row cannot replace these checks:
let proof_eligible = provisional.braid_semantic_valid
& provisional.first_sequence_valid
& sequence_valid
& fibre_valid
& completion.semantic_valid()
& (provisional.reserved_slot != NO_SESSION)
& session_slot_exists;The source test checks both sides of the contrast. Its row grammar and both XOR checks pass:
let mutant = evaluate_braid(&mutant_body, bank, lineage_u8);
assert!(mutant.rows.grammar_valid);
assert!(mutant.rows.parity_valid);
assert!(mutant.rows.events.iter().all(|event| event.row_valid));
assert!(mutant.rows.events.iter().all(|event| event.parity_valid));
assert!(mutant.columns.parity_valid);
assert!(mutant.columns.events.iter().all(|event| event.parity_valid));But the column program and full Entry result fail:
assert!(!mutant.columns.skeleton_valid);
assert_eq!(mutant.columns.lineage_match_count, 0);
assert!(mutant.derived_lineage().is_none());
assert!(!mutant.expected_lineage_valid);
assert!(!mutant.conditioner_valid);
assert!(!mutant.semantic_valid());A program can calculate a value without earning a certificate. It can earn one certificate without reaching a later proof step. A later step can still lack a certificate kind needed for full power. One unlocked switch cannot record these differences.
Certificates have identities and bindings
A certificate kind identifies the check that passed. The host defines six kinds:
| Kind | Concept represented | Why a separate kind matters |
|---|---|---|
DualView |
How input is read | Reading bytes and agreeing on their meaning are separate checks |
EntryLoop |
What actually ran | A request that looks right is not proof that the program ran correctly |
CostTranscript |
How work is counted | The engine has rules for the cost of each step |
RootBinding |
Who the proof belongs to | Proof for one owner cannot be reused as someone else's |
StaleDispatch |
What happened across resource lifetimes | Timing and reuse matter; a still picture of the input is not enough |
ModuleAudit |
What the inner module did | Finishing the inner program requires several separate checks |
The host records these accepted checks. A guest cannot create one by storing a name or setting a bit.
Each receipt has a 16-byte binding. This value identifies the evidence that the host accepted. The code makes it in this order:
- Add a fixed 16-byte label,
TAG_CERT, so these bytes cannot be confused with another kind of hash in the game. - Add the 12-byte owner root. A different world seed changes this root; changing only the uploaded image does not.
- Add one byte naming the check kind. A
DualViewreceipt cannot be relabeledModuleAudit. - Add the checked evidence, up to 128 bytes. A different result changes the message.
- Hash those bytes with SHA-256 and keep the first 16 bytes.
The source shows the byte ranges: 0..16 holds the label, 16..28 holds the owner, byte 28 holds the kind, and 29..used holds the evidence. The host hashes only the used bytes:
pub(super) fn derive_certificate_binding(
owner_root: [u8; 12],
kind: CertificateKind,
canonical_evidence: &[u8],
) -> Result<[u8; 16], ProvenanceError> {
if canonical_evidence.len() > MAX_CERTIFICATE_EVIDENCE {
return Err(ProvenanceError::CertificateEvidenceTooLong);
}
let mut message = [0u8; 16 + 12 + 1 + MAX_CERTIFICATE_EVIDENCE];
let used = 29 + canonical_evidence.len();
message[0..16].copy_from_slice(&TAG_CERT);
message[16..28].copy_from_slice(&owner_root);
message[28] = kind.as_u8();
message[29..used].copy_from_slice(canonical_evidence);
Ok(prefix16(sha256(&message[..used])))
}Changing the owner, check kind, or evidence changes the binding. The binding identifies an accepted check, but it does not perform that check. Host code makes the receipt only after its checker passes, so a bot cannot earn one by computing a hash in guest memory.
An absent receipt has an all-zero binding, and a receipt cannot be renamed for a different accepted event. The owner root is seed-bound, while the checked evidence and host-owned proof records carry the other distinctions, such as a different upload.
The receipt list has two format rules. A present receipt needs a nonzero binding, and an absent receipt needs a zero binding. Unknown check kinds also fail, so these rules prevent hidden data in empty slots and empty bindings on claimed receipts.
Check the container as a truth table:
| Present? | Binding | Result |
|---|---|---|
| No | All zero | Correct way to say “no receipt” |
| No | Nonzero | Rejected: an absent slot is hiding data |
| Yes | All zero | Rejected: a claimed receipt has no binding |
| Yes | Nonzero | The shape is valid; the host still checks the proof and its earlier records |
The last row passes only the format check. It does not let a guest create a valid certificate. Only the host's check paths can save accepted proof.
The format check rejects unknown kind bits. It also rejects a present kind with zero binding or an absent kind with nonzero binding. This function checks the container's format. It does not rerun DualView or another work check:
fn validate_for_set(&self, certificate_set: u8) -> Result<(), ProvenanceError> {
if certificate_set & !0x3f != 0 {
return Err(ProvenanceError::InvalidCertificateSet);
}
for kind in CertificateKind::ALL {
let present = certificate_set & kind.bit() != 0;
let zero = is_zero_digest(&self.values[kind.index()]);
if present && zero {
return Err(ProvenanceError::MissingCertificateBinding);
}
if !present && !zero {
return Err(ProvenanceError::UnexpectedCertificateBinding);
}
}
Ok(())
}Why “rank” is a population count here
The code calls this number rank. It counts different kinds of accepted host check. Think of collecting six different stickers: two copies of the same sticker still fill one spot. The host defines all six kinds, and the bot cannot add a seventh.
pub(super) const fn certificate_rank(certificate_set: u8) -> Option<u8> {
if certificate_set & !0x3f != 0 {
None
} else {
Some(certificate_set.count_ones() as u8)
}
}The host can count set bits because each bit has one fixed check kind. If the guest could choose the bits, this count would prove nothing.
| Number of independent kinds | Evidence-derived level ceiling |
|---|---|
| 0 | 0 |
| 1 | 2 |
| 2 | 4 |
| 3 | 6 |
| 4 | 8 |
| 5 | 12 |
| 6 | 16 |
Five different kinds allow level 12. All six allow level 16. The sixth different kind raises the limit from 12 to 16. No single kind has extra value by itself. Completing the set matters.
The proof step is a second limit
Drive has three separate proof tracks. The source fixes their order:
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum Lineage {
Serrate = 0,
Bastion = 1,
Trawl = 2,
}
impl Lineage {
pub(super) const ALL: [Self; 3] = [Self::Serrate, Self::Bastion, Self::Trawl];| Proof track | Position in the three-number Drive vector | What it helps with |
|---|---|---|
Serrate |
0 | Offense |
Bastion |
1 | Survival and movement |
Trawl |
2 | Collection and supply |
A Serrate proof can raise the first number, but it does not raise Bastion or Trawl. Each track needs its own earlier proof and certificates. The short-lived Drive setting stores the three levels in that same order:
pub(super) const LINEAGE_COUNT: usize = 3;
pub(super) const SERRATE: usize = 0;
pub(super) const BASTION: usize = 1;
pub(super) const TRAWL: usize = 2;
pub(super) const MAX_LEVEL: u8 = 16;The proof step sets another maximum. Entry allows up to level 4, Rift up to 8, Chasm up to 12, and the full ABYSS step up to 16. Their saved records are EntryProof, CalibratedProof, StaleDispatchProof, and ModuleProof. The host uses the smallest of the requested level, step limit, and accepted-check limit. It first checks the owner, earlier proof links, and receipt bindings before using those numbers.
The walkthrough uses combinations from the real proof path. Select a saved SERRATE record. Then change the requested level and compare the three limits. At Module base, the step allows 16. But five accepted kinds limit power to 12. At Module audited, the sixth kind raises the limit to 16.
Follow one real proof path
Choose a saved SERRATE record. Gold tiles show different host checks that passed. Dark tiles show checks that are still missing. Then ask for a level. The host uses the smallest of the three numbers below.
These are real combinations of proof step and check kinds. They limit a later Drive request. Selecting buttons here does not earn proof or start a boost.
The walkthrough follows SERRATE only. BASTION and TRAWL need their own proof records. A receipt for one run or track cannot support another.
How the proof history keeps its links
The code calls its proof store an arena. Here, an arena is a table for 64 proof records. It is not the knight's game map. Each record has an ID. A later record can use that ID to link to earlier proof.
The walkthrough shows one possible SERRATE history. In this route, the first Module check finishes but its final audit fails. A strict retry then passes. If the first audit passes, the host can go straight from Chasm to a fully audited Module record. The five-kind Module record is not required.
The host fixes the certificate sets. Entry has two kinds, Rift four, Chasm five, and an audited Module six. A base Module has five. These are the exact sets:
const ENTRY_CERTIFICATE_SET: u8 = 0x03;
const CALIBRATED_CERTIFICATE_SET: u8 = 0x0f;
const STALE_CERTIFICATE_SET: u8 = 0x1f;
pub(super) const MODULE_BASE_CERTIFICATE_SET: u8 = 0x1f;
pub(super) const MODULE_COMPLETE_CERTIFICATE_SET: u8 = 0x3f;
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub(super) enum CertificateKind {
DualView = 0,
EntryLoop = 1,
CostTranscript = 2,
RootBinding = 3,
StaleDispatch = 4,
ModuleAudit = 5,
}This is one track's history. BASTION and TRAWL need their own records. A Module proposal can list other accepted roots as parents. But only its primary parent supplies the certificate kinds. SERRATE cannot borrow BASTION's ModuleAudit receipt.
What is inside one saved record? The fields answer different questions:
Field in ProvNode |
Plain meaning |
|---|---|
kind |
Which rung this record reached |
scope |
Which power track it belongs to |
parents and parent_count |
Which earlier saved records this one builds on |
certificate_set |
Which of the six different checks have passed |
certificate_bindings |
The host-made fingerprints for those accepted checks |
payload_digest |
A fingerprint of this rung's checked contents |
node_digest |
A fingerprint tying the owner, rung, track, parents, checks, and contents together |
The host saves links to check the path through earlier work. A level number alone cannot show that path. Each step constructor makes a record for one power track. Its fingerprint includes the run's owner root.
The 64-slot limit can stop a proposal. The host also rejects missing or repeated parent links and parents of the wrong kind. A proposal fails if it uses old arena state. Two different records cannot claim the same key. These are defined proof-system failures.
Repeated work has two different outcomes:
| Existing key | Proposed bound contents | Meaning |
|---|---|---|
| Same | Same accepted contents | The same accepted change again; no second slot is needed |
| Same | Different contents | Integrity conflict; equality of a key is insufficient |
An identical accepted record needs no second slot. The same key with different contents is an error.
Prepare and commit are separate moments
First, the host prepares a proposed node. It checks earlier links and available space. Only then does it commit the node to the saved arena. If a check fails, saved proof stays unchanged.
The host checks the whole proof record before it makes the record visible. Otherwise, other code could see a node ID before its bindings exist.
A prepared node uses a specific arena state. If that state changes before commit, the host can return StaleProposal. An earlier pass cannot overwrite newer proof.
Private evidence is not public telemetry
The host performs the hash work even when a certificate is absent. It then changes the absent result to zero. This keeps the work closer for present and absent cases. Otherwise, a caller could measure time to learn a private fact. Source comments call this the fixed-work timing rule.
One fixed-work check does not make the whole path equal-time. Table walks, hashing, rejected proposals, and resumed work can take different times. The release's timing tests measure the full path. One helper alone cannot guarantee it.
Keep VM cost and real time separate. The VM counts work with fixed rules. Real time depends on the host computer and service. Equal VM cost does not prove equal real time.
Authority outlives its current effect
Accepted proof stays saved. It gives permission to request power, not a permanent boost. Think of a membership card versus a short ride pass: the card survives after this ride ends. The active Drive setting, by contrast, can expire. This diagram connects saved proof to the game:
The same five steps are shown as cards below →
| Step | What happens | Who owns the result |
|---|---|---|
| Proof exists | Earlier host checks left accepted records on the three power tracks | Gate proof store |
| Bot asks | The outer bot sends a Drive request for SERRATE, BASTION, and TRAWL levels | Guest request, then a host-owned copy |
| Host installs | The host checks fresh work for this request, its owner, saved proof, and level limits. If allowed, it stores the limited three-number result in a short-lived DriveLatch |
Gate state |
| Game reads | After the VM slice, the engine asks for active effects and copies the resulting damage, defense, movement, and pickup values into its ordinary fields | World state |
| Boost ends | An expired setting returns zero levels; the accepted proof is still saved and can support a later permitted request | Gate proof and active boost remain separate |
- Proof existsEarlier host checks saved records for the three power tracks.Owner: Gate proof store
- Bot asksThe outer bot requests SERRATE, BASTION, and TRAWL levels.Owner: bot request, copied by the host
- Host installsThe host checks this request’s fresh work, owner, proof, and limits. If allowed, it saves levels in a short-lived
DriveLatch.Owner: Gate state - Game readsThe engine turns active levels into damage, defense, movement, and pickup values. The movement boost starts next VM tick; moves already made this tick do not change.Owner: world state
- Boost endsThe active levels fall back to zero. The accepted proof stays saved.Owner: proof and boost stay separate
Installing a boost without half-saving it
This Drive path shows the install decision. The host prepares a candidate setting. If the attempt fails, it keeps the old setting. Failed work cannot install new levels:
let retained_latch = self.drive_latch;
let mut installed_latch = retained_latch;
installed_latch.commit(applied, self.current_tick);
self.drive_latch = if valid {
installed_latch
} else {
retained_latch
};Suppose all three tracks have accepted level-4 proof. A permitted [4,4,4] request can install those levels for a short time. It does not award EXP. The knight must still fight and collect gems. After expiry, the game reads zero levels until another allowed request passes.
The code shows this boundary. active_effects turns the active levels into limited gameplay values. The engine then stages movement and writes the engine's local knight fields (self.hero in the code):
pub fn active_effects(&self, tick: u32, honest_cooldown: u16) -> DriveEffects {
effects_for(self.drive_latch.active(tick), honest_cooldown)
}
pub fn active_levels(&self, tick: u32) -> [u8; LINEAGE_COUNT] {
self.drive_latch.active(tick)
} fn resolve_abyss_levers(&mut self) {
let honest_cooldown = self.hero.swing_cd_ticks;
let effects = match self.device.as_ref() {
Some(device) => device.active_effects(self.tick, honest_cooldown),
None => DriveEffects::default(),
};
if let Some(device) = self.device.as_mut() {
device.stage_next_gait(effects.gait_bonus);When the timer runs out
Suppose a valid SERRATE request installs [4, 0, 0] on tick 100. The host saves through_tick = 100 + 7 = 107. Tick 100 is the first of eight active ticks. This example uses sword power. Movement has a separate next-tick rule.
[4, 0, 0]The host installs the limited levels. Combat later in this tick can use the level-4 sword effect.
[4, 0, 0]The game reads the same levels without making a new proof record.
[0, 0, 0]The game gets no active Drive levels. The saved SERRATE proof is still in the host's proof store.
A later Drive request can use that saved proof again, but it must pass its own fresh request checks. No part of this clock adds EXP; the knight still has to fight and collect gems.
These functions set and read the timer. commit caps each level at 16 and saves the last active tick. It marks the boost active only if a level has an effect. active returns the saved levels through that tick. Afterward, it returns three zeroes. Neither function deletes the proof record:
pub(super) fn commit(&mut self, applied: [u8; LINEAGE_COUNT], challenge_tick: u32) {
self.applied = applied.map(|level| level.min(MAX_LEVEL));
self.through_tick = challenge_tick.saturating_add(7);
self.live = levels_have_effect(self.applied);
}
pub(super) fn active(&self, tick: u32) -> [u8; LINEAGE_COUNT] {
if self.live && tick <= self.through_tick {
self.applied
} else {
[0; LINEAGE_COUNT]
}
}The next chapter follows that vector into combat, survival, and collection.