What this is. A companion to BRC-514 holding two things: diagrams of the
fold the spec defines in prose, and the evidence line between what is deployed in 1sat-stack and what
this document specifies for the first time. The spec says what resolution is; this shows how it runs, and how much of it
already does.
Section numbers in the form §5.6 refer to BRC-514. Other BRCs are cited by number. BRC-515 is the first consumer; its required follow-up changes are listed at the end.
Unlike the BRC-515 companion, this page accompanies a fresh draft: the open questions are decisions a reviewer still has to ratify, each with a recommendation.
The fold
Resolution is a fold: start from the empty state at the origin, apply every revision in order, read the result. A record's revisions are the links of its 1Sat chain, so the sequence is structural — the spend graph fixes it, and a reorg cannot reorder it. “The state in effect at the tip” means nothing more than the fold over all revisions; the state at any earlier point is the fold cut short (§7).
This is §5.7's example, traced. Four revisions exercise five of the six commands — SELECT appears as context inside revision 2. The one not exercised is REMOVE.
ADD tags b c appends only c,
because value equality is byte equality and b is already a member. Revision 3's CLEAR reaches
backward — the dashed arrow — and is the reason the tip state matches the state after revision 1, with
title gone and a restored. That backward reach is drawn out in
CLEAR re-folds.Four orderings, nested
Every revision applies in exactly one place in a total order, fixed at four nesting levels — chain, script,
instruction set, push. The two inner levels are where independent implementations diverge today, because nothing wrote them
down: the deployed parser reads only the first command of a segment, so a ::: in the wild is silently swallowed
into the previous command's pushes.
::: position,
and its own push position.What counts as a revision — and what does not
A revision is the MAP data on the chain link's own output. Everything else is excluded, and the two exclusions are
load-bearing: they are what keep SELECT and CLEAR — commands that name arbitrary txids —
from becoming write access to other people's records.
SELECT cases. Omitted: the instruction set addresses its own record, because the
carrying transaction is a revision of it. Naming an earlier revision's txid: same record, folds — the form BRC-503
requires for REMOVE and DELETE. Naming anything else: ignored for this record. SELECT
never time-travels — the command after it operates on the state at the point in the fold where its revision sits.SELECT's whole purpose
is naming other transactions.CLEAR re-folds
Five of the six commands are functions of the accumulated state: give SET, ADD,
REMOVE, DELETE, or SELECT the state so far, and the next state follows. CLEAR
is the exception. It voids the writes of a named earlier transaction, and the accumulated state no longer remembers
which member came from which revision. The only general implementation is the one §5.6 defines the result by: re-fold
the sequence with the named revisions skipped.
tags=[a,b,c]), and state that
existed disappears (title). An indexer MAY compute it any way it likes; the result MUST equal this re-fold.
The same context constraint as SELECT confines it — a txid outside the record's own revision sequence is
ignored.CLEAR as erasing an object's entire resolved state. MAP and BRC-503 §2.6 scope it to the writes of the
named transactions, which is what this document follows. §2.1 now reads: “CLEAR <txid>
folds per BRC-514 §5.6: it voids the writes of the named revision, not the whole record.” An object cleared
at one revision can still be placed by another.Deployed versus specified
BRC-514 is part documentation, part first specification, and §8 draws the line. The picture for an implementer:
the deployed resolver in 1sat-stack gets the outer machinery right — the sequence index, chain-order fold,
revision boundary, script-order merge, historical addressing — and folds exactly one of the six commands.
The ledger, verified in code
Each row was checked against current source, and the evidence column names what carries it. Files:
1sat-stack/pkg/ordfs/ordfs.go, interfaces.go, and pkg/template/bitcom/map.go.
| behavior | status | evidence |
|---|---|---|
| Chain-order fold, origin → tip, per-key last-write-wins | deployed | loadMergedMap iterates GetAllMapUpTo(origin, seq) in sequence order and overwrites per key |
| Sequencing substrate: per-origin sequence index | deployed | OriginStore key layout — org: / seq: / rev: / map: / par: per origin per sequence |
| Revision = the chain link's own output, nothing else in the tx | deployed | the map: entry points at the chain-link output itself |
| Piped MAP segments in one output merge in script order | deployed | parseOutput walks protocol segments in order |
| Sequence-addressed historical resolution (§7) | deployed | GetLatestMapBefore, seq-parameterised resolution |
Partial SET: trailing key without value dropped, prior pairs kept (§6) | deployed | DecodeMap's read loop reverts the dangling key and keeps what parsed |
Repeated key in one SET: last pair wins (§3.4) | deployed | falls out of DecodeMap's map assignment in read order |
Fold semantics of ADD, DELETE, REMOVE, SELECT, CLEAR (§5) | specified first here | deployed parser matches SET only; other five decode to nothing |
| Ordered-set value model with byte-equality dedup (§4) | specified first here | no deployed lists exist; warrant is MAP's own JS-Set framing — see Q2 |
::: ordering within a segment (§3.3) | specified first here | deployed parser reads only the first command of a segment |
| Non-canonical substrates: supplied total order, output-index tiebreak (§3.2) | specified first here | nothing deployed exercises it; required by the authorization-agnostic scope |
Deployed, and deliberately left out
Three behaviors run in production and are not in the spec, on
purpose: the NUL-byte→space sanitization of keys and values (a serialization convenience, not fold semantics); the
nested-JSON expansion of subTypeData and royalties (a 1Sat-collections concern, owned by that
consumer); and the merged: cache layer (an optimization — §5.6 already permits any implementation
whose result equals the re-fold).
Open questions, with recommendations
Decisions a reviewer must ratify before this draft hardens. Q1 has since been settled in 514's favour and 515 corrected; the rest are open. Each card states the choice the draft made, the alternative, and a recommendation. Four smaller items follow in the table.
highresolved Q1 — CLEAR: BRC-514 and BRC-515 disagreed
The draft follows MAP and BRC-503 §2.6: CLEAR <txid> voids the named transactions' writes and
nothing else. An earlier draft of BRC-515 §2.1 said CLEAR “erases the object's entire resolved MAP
state”. Under this draft, CLEAR <spent-tip-txid> voids one revision's writes and the object may
remain placed by an earlier one. BRC-515 has been rewritten to match.
CLEAR folds per 514 §5.6; writers wanting to unplace use SELECT <txid> REMOVE
quadkey; erasing everything means naming every revision that wrote state. If the owner prefers 515's whole-state
reading instead, 514 §5.6 needs an explicit special case and diverges from BRC-503 §2.6 — that divergence
should then be stated loudly, in both documents.medopen Q2 — ADD: ordered set, or list with duplicates?
The draft makes every value list an ordered set: ADD dedups by byte equality, first occurrence keeps its
position. The alternative is a plain list that appends duplicates — closer to the word “append”, simpler
to implement, but it makes DELETE ambiguous: remove one occurrence, or all?
ADD/DELETE
via a JavaScript Set, and the set model is the one under which DELETE has exactly one meaning.medopen Q3 — SELECT breadth: any earlier revision, or the spent tip only?
514 §5.1 lets SELECT name any earlier revision of the record. BRC-515 §2.1 binds <txid> to the transaction carrying the record being edited. Compatible — every 515 write is 514-conforming — but the reverse
case needs a decision: what does a 515 indexer do with a SELECT naming the origin txid, valid under 514 and
outside 515's writer profile?
medopen Q4 — bare REMOVE and DELETE inside a chain
§5.1's first bullet makes SELECT optional in-chain: an instruction set with no SELECT
addresses the record its revision belongs to. That is derived, from MAP's rule that omitting SELECT makes the
current transaction the context, plus the fact that the current transaction is a revision. BRC-503's letter says
REMOVE and DELETE are “used with SELECT”, so this is an extension, and a
reviewer must ratify or strike it.
SELECT is pure ceremony — it can only name
what the chain already fixes — and requiring it forces every writer to look up a txid it already spent.lowopen Q5 — a conformance class for SET-only resolvers?
§8 calls the deployed resolver incomplete rather than divergent and says implementations SHOULD converge on the full command set. The open choice: name a SET-only conformance subset, or make full six-command support a MUST for any conformance claim.
SET and silently wrong on any other — a named subset would bless the silent case. Keep the SHOULD while
the corpora are SET-only; tighten to MUST when a consumer spec starts writing list commands.Smaller items
| # | item | status | disposition |
|---|---|---|---|
| Q6 | MAP README grammar defects | closed | Raised against a pre-merge README. On opldotdev/MAP master the DELETE block carries its <key> and the SELECT list reads SET | REMOVE | ADD | DELETE. Nothing to fix. |
| Q7 | Object storage (JSON / BSON / MSGPACK) | closed | The merged README documents no such feature — only JSON-fenced worked examples. There is nothing to fold. |
| Q8 | Authorship block | owner | Draft lists Luke as author, David Case as contributor (he built the resolver being documented). Confirm against the corpus OPL header before upstreaming. |
| Q9 | File placement and links | pending | Relative links assume a sibling of tokens/ — scripts/, next to 0503, is the intended home. BRC-502/503/504 are cited by number without links until opldotdev/BRCs PR #1 lands; convert then. 514 was verified free across all branches; the brc-314-native-app-substrate branch informally heading for this slot should take 516. |
What BRC-515 changed once 514 existed
BRC-515 anticipated this document, and its interim resolution rule carried its own supersession clause. Three of these edits are applied on PR #3, two do not apply, and one remains a choice.
| where | change | state |
|---|---|---|
| §5, resolution paragraph | Delete the interim rule; cite BRC-514. The citation replaces the wording rather than sitting beside it: the interim “within one transaction, output order” is superseded by 514's sharper canonical rule (the chain-link output only). Outcomes agree for well-formed 515 writers. | applied |
§2.1, CLEAR sentence | Rewrite per Q1: CLEAR voids the named revision's writes; unplacing is SELECT <txid> REMOVE quadkey; erasing everything means naming every writing revision. | applied |
| §2.1, command table | 514 §5.1 makes bare REMOVE quadkey / DELETE quadkey <cell> valid in-chain. Keep the SELECT forms as the writer profile or admit both — either way, cite 514. | open |
| Stale-anchor rule | Rephrase as a read-layer rule. 514 §6 forbids consumer filtering from altering resolved state, so an un-accompanied SET quadkey means the resolved coordinates.* / geohash / h3 are disregarded as 515's anchor — indexers do not drop them from the state, and other consumers of those keys still see them. | n/a |
| References | Add BRC-514 as a numbered footnote; point “the quadkey in effect at the tip” at 514 §1's definition of resolved state. | applied |
| Schema & implementation sections | Unaffected. | n/a |