THE CHAMBER · WHAT IS ON CHAIN

What is on chain

What a stranger can read, run and rely on, without asking us. First what the two contracts let anyone do; then every public function of both, from the verified ABI.

THE TESTA thing is not open if using it needs private code, privileged authority, undocumented state or a server. Every read below needs a node and nothing else; each write says who may call it.

At a glance

Two contracts, one shape: almost everything is a read, and each write says who may send it.

Perception Chamber Canary

0x6f54E1aAE0E9A679A52e5E733645cB11e0cE6127

functions
40 public, 34 of them reads
writes to the work
1: saveMind, the token's holder, and no operator or approval
the standard
12 ERC-721 functions: transfers and approvals, which move the token and nothing else
tokens
1, deployed 2026-09-17
the surface
the mind 6 · the learner, as a service 3 · the program 2 · the work 4 · the one write 1 · the pointers and constants 12
THE REFERENCE ↓

The Chamber

0x75FD5A9c4440c38561A0099B216F825b7C6db924

functions
36 public, 29 of them reads
writes to the work
2, both spent: mint, lock
the standard
12 ERC-721 functions: transfers and approvals, which move the token and nothing else
tokens
64, deployed 2026-09-08, locked
the surface
the program 3 · the work 6 · the table 6 · the words 1 · the pointers and constants 6 · writes, both spent 2
THE REFERENCE ↓

What anyone can do

The reference below is organised by the nouns the contracts keep. This is the same surface by what you can do with it; every name links to its row. Then four of those things, as commands against any node.

READ

what is there

RUN

make it compute, on the chain or off it

VERIFY

check a claim against the rules

WRITE

change a work

Four ways to use it

Read a mindPERCEPTION

The head brain of the canary, 834 bytes, from any node.

cast call 0x6f54E1aAE0E9A679A52e5E733645cB11e0cE6127 'brain(uint256)(bytes)' 1 --rpc-url $RPC

Pull a program out and run it off the chainTHE CHAMBER

Any Chamber token's program, stamped with the block you pulled it at. Save the hex as a file and it is an ordinary C64 program; a browser emulator will boot it.

cast call 0x75FD5A9c4440c38561A0099B216F825b7C6db924 'prg(uint256)(bytes)' 55 --rpc-url $RPC | python3 -c "import sys;open('chamber-55.prg','wb').write(bytes.fromhex(sys.stdin.read().strip()[2:]))"

Train a brain without owning a tokenPERCEPTION

The same replay the contract uses to judge a save, as a free call: hand it any admissible 834-byte parent and any lesson stream, get the child back.

cast call 0x6f54E1aAE0E9A679A52e5E733645cB11e0cE6127 'replay(bytes,bytes)(bytes,uint16)' $PARENT_HEX $LESSONS_HEX --rpc-url $RPC

Pin a revision for everPERCEPTION

Every revision's brain is its own data contract. Read the record, take the blob's address, and read the bytes straight from it - skipping the first byte, which is a STOP.

cast call 0x6f54E1aAE0E9A679A52e5E733645cB11e0cE6127 'revision(uint256,uint32)' 1 3 --rpc-url $RPC   # the first word is the brain blob's address
cast code $BLOB --rpc-url $RPC   # 0x00 then the 834 bytes

Who can change what

Open is a claim about authority before it is a claim about functions. The two contracts answer it differently, and both answers are checkable from the ABI and the chain.

Perception Chamber Canary

No owner, no admin and no upgrade path: the ABI has no function that could add one. The program, the page, the image and the words are four immutable pointers, set at construction and checked against commitments there. One write changes the work's state, saveMind, and only the token's holder may send it; an approved operator cannot, because the holder check is ownerOf itself. The standard's writes move the token and nothing else.

  • the only write outside the ERC-721 standard is saveMind. derived from the ABI by the exporter, which refuses to run if that changes
  • the holder, and no operator or approval. in the verified source, _holderOf is ownerOf; the four pointers and totalSupply are declared immutable

The Chamber

Two writes, both spent. mint could be called by the minter until the lock, once per id, with that id's row of the table; lock could be called once, only after all sixty-four existed, and it set the minter to the zero address. Since then nothing an address can change remains, and the base program, the image and the renderer were immutable from construction.

  • the only writes outside the ERC-721 standard are mint and lock. derived from the ABI by the exporter, which refuses to run if that changes
  • the lock, done. locked() true and minter() the zero address since block 25,929,620, 8 September 2026 · tx 0x10118db3… block 25,929,620

Not exposed

Where the surface stops. Each of these is a decision, recorded, not an oversight.

asking a mind what it would do
the forward pass and argmax are internal to the learner library, inlined into the token; they run on every lesson of every save and are not callable on their own. For now you run the learner yourself. A decision for the 64-token release.
the retina table as a view
the 240-byte vocabulary is a parameter of the interpreter in the code and pinned in the deployed replay; a different world needs a later contract.
who taught
no contract can say. savedBy is the address that committed a save, not who held the joystick.
the contract source on GitHub
the source is public as verified code on Etherscan; a public repository is a parked decision.

Contract reference

Every public function of both contracts, from the verified ABI, grouped by what the contract keeps. Nothing in this section is hand-maintained: a wrong line is fixed at the export and the page is rebuilt.

A line with the mark is the contract’s own @notice, from the verified source. The rest are ours. READ and PURE are the ABI’s own words for a call that costs nothing; PURE reads no chain state at all.

Perception Chamber Canary

0x6f54E1aAE0E9A679A52e5E733645cB11e0cE6127 · deployed 2026-09-17 from 74e9963 · 40 functions, 34 of them reads

the mind

brain(uint256 id)→ bytesthe head brain's 834 bytes, from its blobREAD anyone
head(uint256 tokenId)→ uint32the head revision index of an existing token: 0 at genesis, n after n savesREAD anyone
revision(uint256 tokenId, uint32 r)→ (address brain, uint32 parent, uint16 lessons, uint16 educationCount, uint8 learner, address education, uint64 savedAtBlock, bytes32 canonicalHash, address savedBy)revision r of an existing token; 0 is the implicit genesis recordREAD anyone
education(uint256 id, uint32 r)→ bytesthe ordered accepted lesson stream of revision r, from its blob (empty for genesis)READ anyone
educationHashOf(uint256 tokenId, uint32 r)→ bytes32the education blob's bytes hashed: derived, never stored (zero for genesis)READ anyone
revisionIdOf(uint256 tokenId, uint32 r)→ bytes32the global, domain-separated name of a revision; derivable by anyone from the recordREAD anyone

the learner, as a service

replay(bytes parent, bytes lessons)→ bytes child, uint16 educationCountthe same replay saveMind runs, as a view, so a save can be checked before it is sentPURE anyone
canonicalHashOf(bytes slot)→ bytes32sha256 of a slot: the canonical content identityPURE anyone
requireAdmissible(bytes slot)reverts with the reason if slot is not an admissible BRAIN025 slot; returns otherwisePURE anyone

the program

prg()→ bytesthe frozen programREAD anyone
prgWithBrain(uint256 id)→ bytes pthe program with the head brain written at the slot's file offset: a derived file, stamped nowhere, the same thing a holder can make by hand from prg() and brain(id)READ anyone

the work

tokenURI(uint256 id)→ stringthe token's metadata as a data URI, entirely on chain: the JSON, the image and the page inside itREAD anyone
json(uint256 id)→ bytesthe JSON before base64, for readers and testsREAD anyone
page(uint256 id)→ stringthe page before base64READ anyone
lineageJSON(uint256 id)→ bytesthe state the page embeds: the head, and at most LINEAGE_WINDOW recent revisions, oldest first. Bounded on purpose, so tokenURI does not grow with the history; every revision stays readable from revision(id, r).READ anyone

the one write

saveMind(uint256 tokenId, uint32 expectedParentRevision, bytes32 expectedParentHash, bytes lessons, bytes32 claimedChildHash)→ uint32 revisionIndex, address brain, address educationadvance the canonical history of tokenId by one revisionWRITE HOLDER ONLY the token's holder, and no operator or approval

the pointers and constants

program()→ addressthe frozen program's contract, pinned at deployREAD anyone
launcher()→ addressthe page's contract, pinned at deployREAD anyone
image()→ addressthe image's contract, pinned at deployREAD anyone
metadata()→ addressthe words' contract, pinned at deployREAD anyone
MAX_BATCH()→ uint16the most lessons one saveMind accepts; set at construction, never changedREAD anyone
LINEAGE_WINDOW()→ uint32how many recent revisions the page embeds; the whole history stays readable from revision()READ anyone
SUPPLY_CAP()→ uint16the collection's ceiling; a deployment mints 1..SUPPLY_CAP tokens in its constructor and never moreREAD anyone
totalSupply()→ uint256how many tokens existREAD anyone
GENESIS_BRAIN()→ addressthe genesis brain's blob: STOP || the blank slot, persisted once by this contract, shared by allREAD anyone
GENESIS_HASH()→ bytes32the blank slot's canonical hashREAD anyone
LEARNER_BRAIN025()→ uint8the learner's identifier, recorded in every revisionREAD anyone
REVISION_DOMAIN()→ bytes32the domain separator that names revisionsREAD anyone

And the ERC-721 standard set, for wallets and marketplaces: approve, balanceOf, getApproved, isApprovedForAll, name, ownerOf, safeTransferFrom, safeTransferFrom, setApprovalForAll, supportsInterface, symbol, transferFrom.

The Chamber

0x75FD5A9c4440c38561A0099B216F825b7C6db924 · deployed 2026-09-08 from 4124590 · 36 functions, 29 of them reads

the program

prg(uint256 id)→ bytesThe program this token runs right now: the base with the 42-byte parameter block written. Save it as a .prg and it runs on a real C64; the copy is stamped with the block you took it at.READ anyone
renderBlock()→ bytes32 h, uint256 nThe seed and floor number a render uses: the previous block's hash, or a substitute when a client returns zero for it, and that block's number, which is what the floor carves.READ anyone
seedOf(uint256 id)→ bytes32The 32 seed bytes this token gets at this block: the block hash mixed with the token id, with the three room-class values forced in. Bytes 3, 15, 20 and 28 are the dice's and are left to the hash.READ anyone

the work

tokenURI(uint256 id)→ stringthe token's metadata as a data URI, entirely on chainREAD anyone
json(uint256 id)→ bytesThe metadata before base64, for readers and tests.READ anyone
attributes(uint8 beh, uint8 col, uint8 wall, uint8 bats, uint8 candle, bytes32 base)→ bytesthe traits, as marketplace attributesPURE anyone
description(uint256 id)→ bytesThe description as it reads right now, at this block.READ anyone
description(uint256 id, uint256 renderedFrom)→ bytesThe description: what this buddy does, the room he was born into, what moves, the block this render came from in full (the floor carries only its last eight digits), how to take the program, and the credits.PURE anyone
image()→ addressthe image: the character alone in his colour, an animated SVG built in the contractREAD anyone

the table

characterName(uint8 beh)→ stringthe character a behaviour number namesPURE anyone
characterSentence(uint8 beh)→ stringthe one sentence the description carries for a behaviourPURE anyone
wallName(uint8 wall)→ stringa wall code as a wordPURE anyone
batsName(uint8 bats)→ stringa bats code as a wordPURE anyone
colourName(uint8 c)→ stringa colour number as a wordPURE anyone
tableRow(uint256 id)→ uint8 behaviour, uint8 colour, uint8 wall, uint8 bats, uint8 candleThe table row, decoded, for anyone checking the collection's promise.PURE anyone

the words

README()→ stringThe whole story, one click away on any contract explorer.PURE anyone

the pointers and constants

renderer()→ addressOne program and one page for all sixty-four, set once here and never again: there is no setter, and the collection cannot be made to mix.READ anyone
base()→ addressthe base program's data contractREAD anyone
SUPPLY()→ uint256sixty-fourREAD anyone
totalSupply()→ uint256how many tokens existREAD anyone
locked()→ booltrue since 8 September 2026READ anyone
minter()→ addressthe zero address: nobodyREAD anyone

writes, both spent

mint(address to, uint256[] ids)Mint token ids from the table, in any order, in any number of transactions, until lock(). Each id exists once.WRITE SPENT nobody: the minter is zero
lock()Renounce minting. Only once every one of the sixty-four exists: a lock on an incomplete collection would be permanent, so the contract refuses it rather than trusting a script to check first. After this there is no privileged caller.WRITE SPENT nobody: already done

And the ERC-721 standard set, for wallets and marketplaces: approve, balanceOf, getApproved, isApprovedForAll, name, ownerOf, safeTransferFrom, safeTransferFrom, setApprovalForAll, supportsInterface, symbol, transferFrom.

About this page

Generated, never hand-edited: from the pinned compile of the verified sources (forge 1.5.1, solc 0.8.30, evm cancun, bytecode_hash ipfs), exported at 23b47f5 on 2026-09-22 by scripts/export-surface.py. The rows are the ABI’s. The groups, the verbs, the summaries, the gaps and the recipes are ours, and the build is held to the same file, so this page cannot describe a function the contracts do not have. To check it, compile the verified source from Etherscan with the toolchain above and compare the ABI.