Metadata Fields

Metadata Record Schema

This page describes MODE A — hash-only attestation, the one integration path built, verified and offered today. The 36 fields below are OUR record schema, not a list you populate. Details of these fields and relationships, and their implications, are set out in full on their own page

What Mode A asks of you: one value, a hash. Your commit path computes a cryptographic digest of the committed transaction and publishes it through a signed call. Two optional values may accompany it — the name of the algorithm you used, and a correlation reference of your own so you can find the record again in your systems. The hash function is yours: SHA-256 by default, any digest length accepted, so you need not adopt a primitive your cryptographic standards have not already approved.

Everything else in the record is produced by us, not sourced by you. Your tenant identifier, your federation identifier, the transaction id, the authenticated principal and the calling node all come from the credential that authenticated the call, never from its payload. The block and slab position, the Merkle root and the trace digest are computed by the platform. Not one of the 36 fields is supplied by your application at Mode A, so there is no field-mapping programme, no schema to extend in your core systems, and no registry for your team to coordinate with.

One field name invites a wrong reading, so it is worth naming plainly. The field called user_id records the authenticated principal — the subject of the credential that made the call. At Mode A that is the service identity your integration authenticates as. It is not a named person, not one of your customers or staff, and not something we ask you to provide. We receive no end-user identity at Mode A, because we receive nothing but a digest.

The list is published anyway, because a digest proves nothing unless every party computes it over the same fields in the same form. An auditor, a regulator or your own engineers can see exactly what the platform records and how it is digested — the fixed definition that lets a third party recompute a proof without trusting us. The encoding rules further down are OUR discipline for extending this schema, published for transparency rather than as instructions to a customer.

  1. Federation Id (federationId – 32-bits for the Sector’s and Pyramid’s federations)
  2. Enterprise Id with ITOTCCA (entnum – Big Integer)
  3. TransactionId (txId – UUID String)
  4. BusinessSector (sector – Big Integer)
  5. CounterSector (counterSector – Big Integer)
  6. Pyramid (pyramid – Big Integer)
  7. CounterPyramid (counterPyramid – Big Integer)
  8. CounterFederationId (counterFederationId – 32-bits; counterparty member-class)
  9. CounterEntnum (counterEntnum – Big Integer; counterparty tenant)
  10. DataCentre (dataCentre – String)
  11. CounterDataCentre (counterDataCentre – String)
  12. Country (country – Integer)
  13. CounterCountry (counterCountry – Integer)
  14. Database (database – 104-bits)
  15. Schema (schema – 104-bits)
  16. Table (table – 104-bits)
  17. Record Key (recordId – Unique 104-bits)
  18. Original Tx Hash (hash – 32 bytes (sha256 digest / Merkle Leaf))
  19. ClientNodeId (clientNodeId – String)
  20. TxSignStr (txSignStr – String)
  21. BlockId (blockId – UUID String)
  22. SlabId (slabId – Big Integer)
  23. BlockHeight (blockHeight – Big Integer)
  24. Amounts (REDACTED WHERE REQUIRED) (int64Amounts – List of Big Integers [JSONB])
  25. Exponents (REDACTED WHERE REQUIRED) (int32Exponents – List of Integers [JSONB])
  26. OpCodeExec (opCodeExec – Boolean)
  27. OpCodeCommit (opCodeCommit – Boolean)
  28. MerkleRootHex (merkleRootHex – Hexadecimal String)
  29. RequType (reqType – enum)
  30. IsTower (isTower – Boolean)
  31. CounterIsTower (counterIsTower – Boolean)
  32. UserId (userId – string)
  33. RoleId (roleId – string)
  34. CustomerDid (customerDid – String; the DID whose key signed the content attestation. Resolved on chain by an auditor, never from a platform table)
  35. ContentDigest (contentDigest – String; digest of the request body the customer submitted)
  36. ContentAttestation (contentAttestation – String; detached signature over that digest. It authorises nothing, so it can be retained for the life of the record and handed to an auditor)

_____________________

Customer content binding

Fields 34 to 36 differ in kind from the other thirty-three. Every other field here is something the platform observed or produced. These three are signed by a key the platform does not hold, which makes them the only input to the audit tier that the operator of this network cannot forge.

They are optional on the wire and empty for clients that have not yet adopted them. Absent and present-but-invalid are different findings and are kept apart deliberately: the first is a coverage gap, the second is substitution.

_____________________

Field encoding rules

All identifier and hash fields in this schema follow a single encoding convention; please don’t deviate per-field without amending this section.

Byte alignment. Prefer byte-aligned widths (multiples of 8) for new fields. Hashing, signing and equality comparison operate on the full container including padding bits — implementations that strip padding will produce divergent Merkle roots and break BFT replay determinism.

Allocation discipline. Identifier widths assume sequential allocation by ITOTCCA, not random generation. federationId at 32 bits permits 2^32 ≈ 4.3 x 10^9 lifetime member-class IDs sequentially, but orders of magnitude less before collision under random allocation (birthday bound). Any field whose width is below 128 bits must be allocated by a central registry, never client-generated.

String-encoded fields. Where a field is declared as a hex or UUID string (e.g. txId, blockId, merkleRootHex), the on-wire form is the canonical ASCII representation (lowercase hex; 8-4-4-4-12 UUID). The underlying value is the decoded byte array; equality is over decoded bytes, not the string form.

Quick reference for the 36 fields:

Field Width Storage Allocation
federationId 32 bits 4 bytes sequential index assigned at onboarding; resolvable from your entnum, so you need not send it
counterFederationId 32 bits 4 bytes sequential supplied by the sender: it names a party on another mesh and cannot be derived from yours
database, schema, table, recordId 104 bits 13 bytes network-registry
hash 32 bytes 32 bytes (all significant, sha256 digest) computed
merkleRootHex 64 hex chars 32 bytes decoded (canonical ASCII hex form of a sha256 digest) computed
entnum, counterEntnum, sector, counterSector, pyramid, counterPyramid, slabId, blockHeight Big Integer variable sequential computed
country, counterCountry 32 bits 4 bytes member-declared, registry-verified. OPTIONAL: zero means not asserted and no check is made
dataCentre, counterDataCentre String string network-registry
txId, blockId UUID string 36 chars UUIDv4
customerDid, contentDigest, contentAttestation String string customer-signed, not platform-issued

_____________________

Who supplies each field, field by field

Generated from ops/metadata-field-attribution.json and verified against the proto on every build, so this table cannot drift from the code.

It answers two separate questions, because running them together is what made an earlier version of this page misleading. Is the field populated at Mode A? is one question. Who supplies it, if it is populated? is a different one with a different answer — and the difference between “you declare this once at registration” and “your application sends this on every transaction” is the whole point. No field is in the second category, at any mode.

11 of the 36 carry a value at Mode A. Those 11 are populated identically in all four modes, because every mode reaches us through the same single call and we assemble the record on one shared code path afterwards. The other 25 are structurally absent at Mode A — several of them describe a written data row, and Mode A writes no data row.

# Field Type Populated at Mode A? Who supplies it, if populated
1 tx_id string yes — and in all four modes us — derived from your call
2 tx_sign_str string yes — and in all four modes us — computed at signing
3 hash bytes yes — and in all four modes us — computed at signing
4 sector int64 no you declare it ONCE at registration — never per transaction
5 database bytes no us — platform
6 schema bytes no us — platform
7 table bytes no us — platform
8 req_type RequType no — set only at B, C and D an artefact YOU author: a WAL operation, a route entry, an outbox column
9 recordId bytes no us — platform
10 block_id string yes — and in all four modes us — consensus
11 block_height int64 yes — and in all four modes us — consensus
12 slab_id int64 yes — and in all four modes us — platform
13 client_node_id string yes — and in all four modes us — the calling node’s gateway identity
14 role_id string no not yet established from code; recorded as unknown rather than guessed at
15 user_id string yes — and in all four modes us — the authenticated principal
16 op_code_exec bool no not yet established from code; recorded as unknown rather than guessed at
17 op_code_commit bool no not yet established from code; recorded as unknown rather than guessed at
18 int64Amounts int64 no not yet established from code; recorded as unknown rather than guessed at
19 federationId uint32 yes — and in all four modes us — from your credential
20 int32Exponents int32 no not yet established from code; recorded as unknown rather than guessed at
21 pyramid int64 no not yet established from code; recorded as unknown rather than guessed at
22 merkleRootHex string yes — and in all four modes us — computed
55 counterPyramid int64 no the sender, where a counterparty exists on another mesh
56 entnum int64 yes — and in all four modes us — from your credential
57 counterSector int64 no the sender, where a counterparty exists on another mesh
58 country int32 no you declare it ONCE at registration — never per transaction
59 counterCountry int32 no the sender, where a counterparty exists on another mesh
60 dataCentre string no you declare it ONCE at registration — never per transaction
61 counterDataCentre string no the sender, where a counterparty exists on another mesh
62 counterFederationId uint32 no the sender, where a counterparty exists on another mesh
63 counterEntnum int64 no the sender, where a counterparty exists on another mesh
64 isTower bool no us — registry or deployment
65 counterIsTower bool no us — registry or deployment
66 customer_did string no signed by a key we do not hold
67 content_digest string no signed by a key we do not hold
68 content_attestation string no signed by a key we do not hold

At Mode A — hash-only attestation, the only integration path we offer today — a customer supplies ONE required value: a content hash, in any length, under any algorithm they choose. Two optional values accompany it: the algorithm name, and a correlation reference of their own. Nothing else on this page is sourced by the customer at Mode A. The tenant boundary is stamped from a verified identity rather than taken from the payload; transaction id, block id, slab id, block height, the Merkle root and the trace hash are produced by the platform; and amounts, counterparties and semantic intent are by design never sent at all. That is not a limitation to work around — it is the privacy property Mode A exists to provide.

The remaining fields become operative only in the roadmap modes, and the counterparty fields only where a transaction genuinely has a counterparty on another mesh. Anyone reading this list as an integration checklist for Mode A would be sourcing data the platform never asks them for.

What we do NOT ask you to define. ITOTCCA allocates no country code. Your country is something you declare once when you register an identity claim; each transaction re-asserts it and the registry confirms it has not changed. Send zero and no check is made at all. The same is true of your federation identifier: it is an index we assign at onboarding, in the same way a BIC is assigned by SWIFT or an LEI by an accredited issuer, and because your entnum is stamped from your verified identity rather than taken from your payload, we can resolve it ourselves. The one identifier that must come from you is counterFederationId, which names the party you are transacting with on a different mesh — a value chosen locally cannot address someone else’s mesh, and two members choosing independently would collide.

In banking, a federation is one country, so for banks the country fields are derivable from the federation identifiers and carry no information those do not already. That is not true of every member network — the Social Housing Supply Network federates by trade or profession, where country and federation are independent axes — which is why the fields exist and are optional rather than removed.

_____________________

Beyond Mode A — the three deeper modes

Everything above is Mode A. Three deeper integration modes exist, and they differ from Mode A in one decisive respect: at B, C and D the platform begins to receive content, not only a digest of it. That changes what you are asking us to hold, so the requirements are set out separately rather than folded in here.

Mode B — change-data-capture observer. We read your database’s logical replication stream. Forensic by construction: your own write has already happened by the time we see it, so nothing can be refused.

Mode C — gateway-mediated. We sit inline, in front of your backend. The only one of the three that is preventative: it can refuse a request before your systems ever see it.

Mode D — SDK / dual-write relay. Your application writes to an outbox in the same transaction as its business write, and a relay forwards it. Carries explicit semantic intent — REVERSAL, CORRECTION, RESTATEMENT — which no other mode does.

All three have their core mechanisms built and verified end to end against a real running chain. All three are reference implementations your own team adapts, not packaged products you can install, and no customer has yet been onboarded through any of them. Mode A is what you would be buying today.

What each of B, C and D actually requires of your systems — the replication settings, the route table, the outbox schema, and what changes about custody once content crosses — is set out in full on its own page.

_____________________

What the mode decides beyond metadata: which shared levels you can use

The 36 fields above are what reaches us. The mode also decides something the field list cannot show, which is which of the network’s three shared levels a transaction can actually use. They do not all need the same thing from you.

Shared level What it must do What that needs from the record Usable at
Level 1 — the registry Who is a member, in which federation, with what standing An identity, established at REGISTRATION rather than per transaction Every mode, Mode A included. The verified tenant identity Mode A already carries is exactly what the registry exists to establish.
Level 2 — gov-reg and gov-comm What may cross, under which regime, and the record that it did The parties, and the nature of the transaction Mode B or deeper. A digest cannot be regime-checked. At Mode A there is nothing for Level 2 to evaluate — by construction, which is the same reason there is nothing for us to leak.
Level 0 — cross-border The same question across jurisdictions As Level 2 Mode B or deeper, and designed rather than built.

Mode A is therefore not shut out of the network, it is shut out of regulation. A Mode A member is a member: registered, in good standing, its records provable. What no shared tier does is evaluate its transactions, because no shared tier has been shown anything to evaluate. That is the trade Mode A makes, and it is the same trade that gives it no custody exposure at all.

Where this collides with the data-visibility ladder. Level 2 must READ a transaction to apply a regime to it. The ladder exists to stop that reading. At Rungs 1 and 2, plaintext or the platform’s own key, the platform can read and Level 2 functions fully. At Rungs 3 and 4, your key or a named partner’s, it cannot: Level 2 can still record THAT something crossed, but not evaluate WHAT crossed, and its regime function degrades to bookkeeping. This is the same trade the audit tier already makes — Rung 1 buys full cross-checking, Rung 3 buys secrecy and costs you the cross-checking.

Keyed commitments are what would dissolve it: a key-holder proves a value matches what was committed without revealing the value, so a claim about a transaction can be verified without the transaction being seen. That layer is implemented across the relevant tiers and switched on in none of them — no commitments have been written in any running deployment.

So, stated plainly rather than left to be discovered in a security review: today you can have the upper rungs of the ladder, or you can have Level 2 doing its job. Not both.

_____________________


Tx-Rails — Built by IT/OT Chain & Cloud Australia (ITOTCCA). Sydney · London.