{"generatedAt":"2026-09-02T19:44:13.891Z","algo":"sha256-canonicaljson-v6","activeSalons":2,"ledgerSalons":2,"truncated":false,"received":15,"published":15,"withdrawn":{"GDPR_ERASURE":0,"LEGAL_TAKEDOWN":0,"COURT_ORDER":0,"REVIEWER_WITHDRAWN":0,"PARENT_DELETED":0,"LEGACY_MODERATION":0},"withdrawnReviews":0,"meanResponseRateBp":0,"ratingDistribution":{"1":0,"2":0,"3":0,"4":0,"5":15},"negativeSurvivalRateBp":null,"chain":{"salons":2,"entries":19,"head":{"day":"2026-09-01","merkleRoot":"e90d58786ee53f06ceb0364a5a6351b81d6a3a3a376462d505fb83de404276b1","anchorStatus":"SUBMITTED"}},"scope":"platform","nextAggregation":"2026-09-02T20:44:13.891Z","invitationRule":"inv-v2","policyUrl":"https://primer.tech/despre-recenzii","anchorAge":{"firstAnchoredAt":"2026-08-31","firstConfirmedAt":"2026-08-31","anchoredDaysCount":2,"confirmedDaysCount":1,"pendingDaysCount":1},"anchorHonestyNote":"This register began anchoring on 2026-08-31 — 2 day(s) of anchored history, 1 confirmed in a Bitcoin block, the first on 2026-08-31. SUBMITTED means an OpenTimestamps calendar accepted the digest; it is not yet a Bitcoin confirmation. Trust here accumulates with time and is not declared.","salons":[{"salonId":"cmj2w4mlb0004fti9apf9cftw","exportUrl":"https://primer.tech/api/public/reviews/log?salon=cmj2w4mlb0004fti9apf9cftw","wellKnownUrl":"https://www.salontransilvania.ro/.well-known/reviews-log.json","inclusionUrl":"https://primer.tech/api/public/reviews/network/inclusion?salon=cmj2w4mlb0004fti9apf9cftw","currentHead":{"seq":9,"entryHash":"b28a2c7fbce664d32539b4d111525f74c4e51cd3f0fa2e9defe977845047d852"},"anchorState":"ANCHORED","firstAnchoredAt":"2026-08-31","anchoredDaysCount":2,"funnel":{"invited":22,"responded":7,"published":7,"publishedFromInvitation":7,"publishedOrganic":0,"withdrawnReviews":0,"negativeFinal":0,"negativeSurviving":0},"pilot":false},{"salonId":"cmmgouon00k01gpwkj57yah3i","exportUrl":"https://primer.tech/api/public/reviews/log?salon=cmmgouon00k01gpwkj57yah3i","wellKnownUrl":"https://www.frizeria.com/.well-known/reviews-log.json","inclusionUrl":"https://primer.tech/api/public/reviews/network/inclusion?salon=cmmgouon00k01gpwkj57yah3i","currentHead":{"seq":10,"entryHash":"032755e2f4962aa9257d1c012972a4c39feb3fe7603591ee30c2a33021423187"},"anchorState":"ANCHORED","firstAnchoredAt":"2026-08-31","anchoredDaysCount":2,"funnel":{"invited":24,"responded":8,"published":8,"publishedFromInvitation":8,"publishedOrganic":0,"withdrawnReviews":0,"negativeFinal":0,"negativeSurviving":0},"pilot":false}],"salonsListed":2,"salonsListedTruncated":false,"platformChain":{"id":"__platform__","exportUrl":"https://primer.tech/api/public/reviews/log?salon=__platform__","head":{"seq":1,"entryHash":"3e787b438424071ac329d72210c0043bd5341dd8d921273574d3bcf0f82ac8ae"},"keyAnchors":[{"seq":1,"kid":"primer-network-2026-08-prod","publicKeyX":"OZkt3rVNej3TQTyUyhiOR2J9yVEzbsGLW4iebzj1sHs","scope":"platform","custody":"platform","supersedesKid":null,"activatedAt":"2026-08-31T15:11:14.651Z"}],"keyAnchorsUnresolved":[]},"endpoints":{"jwksUrl":"https://primer.tech/.well-known/jwks.json","anchorsUrl":"https://primer.tech/api/public/reviews/anchors","networkUrl":"https://primer.tech/.well-known/reviews-network.json"},"verifier":{"npmPackage":"primer-verify","repoUrl":"https://github.com/iclaudiumihaila/primer-verify","specUrl":"https://github.com/iclaudiumihaila/primer-verify/blob/d5b28e3d1371411f67a9cf1f766c9a51d8a62d00/SPEC.md","specVersion":"1.1.0"},"claimSources":{"activeSalons":"platform","ledgerSalons":"platform","received":"platform","published":"platform","withdrawn":"platform","withdrawnReviews":"platform","meanResponseRateBp":"platform","negativeSurvivalRateBp":"platform","ratingDistribution":"platform","truncated":"platform","chain":"platform","salons":"platform","salonsListedTruncated":"platform"},"disclosure":{"derivedFrom":"append-only review ledger + immutable Review rows","editableInputs":"none","invitationPolicy":"Who is invited is decided by ONE platform rule and never by a salon, and the rule has two forms because the law does. In the countries whose transposition of art. 13(2) of Directive 2002/58 has been read and cleared (today: RO), every customer who completes an appointment is invited to review that visit, on the legitimate interest of the salon, of Primer and of the public in a complete and unselected register (art. 6(1)(f) GDPR) plus the existing-customer exception — limited to the contacts collected through a booking door that showed them that notice, or who authorised messaging themselves. EVERYWHERE ELSE, and whenever a salon's country cannot be established, the narrower consent basis applies: only customers who agreed to receive messages FROM THAT SALON are invited — the agreement is recorded per register, so it neither carries over from one salon to another nor is cancelled at one salon by an objection sent to another — and it is a record the salon can switch off. Which of the two is in force for one register is published in that register's own reviews-log.json. Neither form is configurable by a salon, and no invitation of either form carries advertising. UNDER BOTH FORMS THE LEVERS A SALON HOLDS ARE THESE AND NO OTHERS — its own block list, an objection its staff relay at the counter, recording a finished visit as an absence (a correction with no deadline, which ends an invitation already sent, is refused once a review has been written, and cannot be undone), and, under consent only, the customer's messaging agreement. That is every lever there is under legitimate interest, and one more — the agreement — wherever consent is the basis. Every one of them REMOVES a person and each is counted on that salon's own register screen, the absence correction also raising a public signal in this register; none of them can add a name, because the only way into a population is a booking door that showed the customer the notice. WHICH VISITS: every finished visit — closed at the till, closed with the finish button, or closed automatically at least 2 hours after its end time — unless it was cancelled or recorded as an absence, in which case no invitation is sent and any invitation already sent stops working. Who closed the visit decides nothing and is not a gate: this register publishes no closer for any single visit, and the source is recorded on the salon's own appointments screen. THIS RULE IS VERSIONED: it is inv-v2, declared as invitationRule beside these documents' hash rule, and disclosure.invitationRules publishes what every earlier version said and from which date this one applies — the previous rule invited only the visits a person had closed, and visits finished under it are not invited retroactively. At most one invitation every 30 days per person, at most 3 unanswered invitations ever, and never again after a STOP. ONE PERSON, ONE REVIEW: a customer whose review is still published at this salon is never invited again, however often they come back. There is no renewal invitation at all: it is switched off platform-wide, and no salon can switch it on. The gate is the published review, not the act of having written one — but a removal that is about the PERSON does not put them back in the pool: when a review is removed at the reviewer's own request, or under the right to erasure, the same narrow objection a STOP records is written for that person at that salon, so no further review invitation is ever sent to them there. Their booking confirmations and reminders are untouched — those are a different purpose. A removal on a ground about the CONTENT, such as a takedown or a court order, leaves the person's standing exactly as it was. These limits are platform-wide and identical for every salon — they are not configurable by a salon.","invitationUnit":"The unit of this policy is the PERSON: invited and responded in this document's funnel are counts of distinct people, one invitation per person per visit, and the limits stated in invitationPolicy are per person. A customer with three invited visits is one invited person, never three.","invitationRules":"The current invitation rule is inv-v2, and it is declared as invitationRule above. It says WHICH VISITS are asked about; invitationPolicy says which PEOPLE may be asked and on what legal ground, and the two are separate questions. What each rule changed: inv-v1 — only visits a PERSON closed were invited — at the till, or with the finish button. A visit nobody closed by hand, which the automatic close caught instead, was never asked about, so a register could shrink the population it published simply by not closing tickets. inv-v2 — every finished visit is invited — at the till or automatically, at least 2 hours after its end time, unless it was cancelled or recorded as an absence. Who closed the visit stops deciding anything: the source (completionSource) is no longer a gate, it is published for no single visit here, and it stays on the salon's own appointments screen. Applies to visits finished after 2026-09-01; visits finished before that date were governed by inv-v1 and are not invited retroactively. THE RULE FOR ONE VISIT IS THE RULE IN FORCE WHEN THAT VISIT FINISHED, never the rule this document declares — a register whose older entries were collected under inv-v1 is correct behaviour and not a fork, exactly as a chain that mixes hash rules is. AND ONE THING THAT IS NOT A RULE CHANGE: nothing here touches how an entry is hashed or what a payload contains, so the hash rule is unaffected and a reader should not look for a new one.","hashRules":"The current hash rule is sha256-canonicaljson-v6, and it is declared as algo above. Every rule a live chain may honestly carry is published here — sha256-canonicaljson-v2, sha256-canonicaljson-v3, sha256-canonicaljson-v4, sha256-canonicaljson-v5, sha256-canonicaljson-v6 — because THE ALGO GATE IS A MEMBERSHIP TEST, NOT EQUALITY WITH THE NEWEST RULE: a chain legitimately mixes rules, one per entry, and branding every pre-current entry unverifiable the day a new rule shipped would falsely unverify the honest back-catalogue. What each rule changed: sha256-canonicaljson-v2 — the base rule: sha256 over canonical JSON, with supersedesReviewId inside the ENTRY preimage so a reader can tell a corrected review from a hidden one from the export alone. sha256-canonicaljson-v3 — adds four economic flags to the PUBLISH/SUPERSEDE payload — paidVisit, paymentMethod, returningClient, visitCount. Present-as-null changes the canonical string, so the add could not be unconditional: that is why it is a new rule and not a field. sha256-canonicaljson-v4 — keeps those four flags but forces them present-as-null for an ANONYMOUS author, because an exact visit count re-identifies a hidden author on a small register. A v4 NAMED payload is byte-identical to a v3 one. sha256-canonicaljson-v5 — adds one field, synthetic (bool|null): true when the row was written by a declared seed path. Absent under every earlier rule, and absent means \"written before the flag existed\", never \"asserted genuine\". sha256-canonicaljson-v6 — adds one field, authorLanguage (str|null): the language the review was WRITTEN in, taken at the write door from the page the author actually read and validated against this platform's locale list. It exists because nothing in this register knew a review's language and the public structured data published one anyway — from the locale segment of whichever URL a page was fetched at, and from the salon's configured default — so one review could be published as several different languages at once. Absent under every earlier rule; null means NOT RECORDED, and neither ever means \"this review is in the salon's language\". Nothing else changes: sha256-canonicaljson-v6 is sha256-canonicaljson-v5 plus this key. NONE of the rules after the base one touches the ENTRY preimage — all of them change only the PUBLISH/SUPERSEDE payload the payloadHash is taken over, which is why an entry's link structure re-derives identically under every rule. The rule for ONE entry is the rule stamped ON that entry (its hashAlgo field), never the rule this document declares: a permalink showing an entry under an older rule inside a register declaring the newest one is correct behaviour and not a fork. AND ONE THING THAT IS NOT A RULE CHANGE: the funnel no longer publishing an absolute count of visits is a change to what these DOCUMENTS represent, not to how a ledger entry is hashed — no funnel field has ever entered an entry preimage or a payload, so there is no rule after sha256-canonicaljson-v6 and a reader should not look for one. AND ONE THING ABOUT THE TOOL THIS DOCUMENT NAMES: the published verifier release quoted in verifier above may predate the newest rule in the list above, and while it does it will report ALGO_UNKNOWN — \"I cannot check this\" — against the entries carrying that rule, never INVALID. Everything else about those entries still verifies: the chain links, the Merkle inclusion and the anchors are rule-independent. Read a mixed run that way rather than as a finding against the register, and check the repository for a release naming sha256-canonicaljson-v6. AND A SECOND THING THAT IS NOT A RULE CHANGE, on the same law one level down: NO REVIEW PUBLISHED FROM THIS BUILD ONWARD CARRIES A COUNT OF THAT PERSON'S VISITS. visitCount is still a field of the sha256-canonicaljson-v3/sha256-canonicaljson-v4/sha256-canonicaljson-v5/sha256-canonicaljson-v6 payload and is still hashed — the rule did not move, and no new rule exists — but this platform no longer derives or stores it, so a new entry commits visitCount as null for EVERY author, named as well as anonymous, exactly as the sha256-canonicaljson-v4 coarsening already committed it for anonymous ones. Entries published BEFORE this build keep the integer they committed to and re-derive byte-for-byte: the payload is rebuilt from the review row, so changing what an old entry publishes would have broken every proof already anchored — which is why this is a change to what is WRITTEN and not to how anything is hashed. A null therefore means \"this platform does not publish a person's visit count\", never \"this customer had no visits\", and a mixed register — old entries with a number, new ones with null — is correct and expected. AND THE ENTRY RULE ITSELF, so a reader need not leave this document to recompute one: entryHash = sha256(canonicalJson({algo, seq, salonId, reviewId, kind, payloadHash, prevHash, supersedesReviewId, createdAt})) — those fields, that order, nothing else. Two shapes an independent reimplementation gets wrong, named here because they were measured rather than imagined: the preimage key is algo, while the EXPORTED entry names the same value hashAlgo — one value, two field names, and a verifier threads the exported hashAlgo back in as algo. And salonId is INSIDE the preimage but is NOT a field of the exported entry: it comes from the register's own address, the salon the export was fetched for, which is exactly what binds an entry to its register.","economicFlags":"WHAT THIS REGISTER SAYS ABOUT MONEY, AND WHAT IT DELIBERATELY DOES NOT. A review payload carries paidVisit and paymentMethod under sha256-canonicaljson-v3, sha256-canonicaljson-v4, sha256-canonicaljson-v5 and sha256-canonicaljson-v6, and from this build onward this platform writes them as follows. paidVisit IS TRUE OR ABSENT, NEVER FALSE: true when the visit was closed through Primer's own till, null in every other case. A null therefore means UNDECLARED — this platform does not know how the visit was settled — and it NEVER means \"unpaid\": the salon may have taken the money at its counter, on paper, or on a device this platform never sees, and the register cannot tell those apart. WHAT THIS REMOVES AND WHAT IT DOES NOT, SAID PLAINLY BECAUSE A READER CAN CHECK IT: the absence is the EXACT COMPLEMENT of the positive — true when the till saw the visit, null in every other case, by rule and with no exception, A SNAPSHOT TAKEN AT THE PUBLISH INSTANT AND FROZEN THERE rather than a standing fact about the visit: a till transaction created after the review was published leaves the entry null, and one voided afterwards leaves it true — so THE ABSENCES CAN BE COUNTED, and this document does not pretend otherwise. Over the entries of NAMED authors (an anonymous author's economic fields are coarsened to null under sha256-canonicaljson-v4, sha256-canonicaljson-v5 and sha256-canonicaljson-v6 whatever the row holds, so those entries carry no signal either way; under sha256-canonicaljson-v3 they are NOT coarsened, so an anonymous entry of that generation publishes the row's own values) such a count recovers ONE QUANTITY PER GROUPING THE PAYLOAD SUPPORTS — over the whole register, or per day, per stylist, per service, per location, per rating, because every one of those travels in the same payload beside the flag: the share of the visits REVIEWED IN THIS REGISTER that were not settled through Primer's own till. That is NOT a fiscalisation rate and must not be published as one — a salon may ring a visit up on a register this platform never sees, and only reviewed visits appear here at all, so the figure is silent about every visit nobody reviewed. What changed for paidVisit is therefore the ASSERTION, not the arithmetic: this platform no longer states, in signed bytes beside a named customer, that one particular visit did not go through a till. paymentMethod IS NULL ON EVERY REVIEW PUBLISHED FROM THIS BUILD, for every author, named as well as anonymous: how one business's takings divide between cash and card is that business's own affair, and no reader of one review needs it to judge the review. It is no longer derived at all — the till is asked whether a transaction exists, never which one or how it was paid. UNLIKE paidVisit THAT ONE IS A TOTAL REDUCTION: for the reviews published from this build the cash/card mix cannot be recovered from anything this register publishes, by counting or otherwise. THIS IS NOT A RULE CHANGE: both keys still exist and are still hashed, the rule did not move, and there is no rule after sha256-canonicaljson-v6 that touches THESE TWO FIELDS — only what this platform WRITES changed. Entries published BEFORE this build keep the values they committed to and re-derive byte-for-byte, because a payload is rebuilt from the review row and changing what an old entry publishes would break every proof already anchored. A register that mixes older entries naming a method with newer ones that do not is correct and expected. Both flags remain PLATFORM ASSERTIONS either way: this export carries no POSTransaction rows, so a third party can check that the value we committed to is the value we hash, never that we classified the visit honestly.","synthetic":"Each review published under hash rule sha256-canonicaljson-v5 or sha256-canonicaljson-v6 carries a 'synthetic' field in its signed payload: true when the row was written by a declared seed path, false on a real write. A production register can never carry true — the write door refuses a declared-synthetic write against a production tenant before the transaction. The field is ABSENT on every entry published under an earlier rule (v2, v3, v4), and absent means 'written before the flag existed', NEVER 'asserted genuine': back-filling it would rewrite payloads already committed and already anchored. It is a platform assertion, not a third-party-verifiable fact — you can verify that the value we committed to is the value we hash, not that we classified it honestly.","authorLanguage":"WHAT LANGUAGE A REVIEW IS IN, AND WHEN THIS REGISTER SAYS SO. Each review published under hash rule sha256-canonicaljson-v6 carries an authorLanguage field in its signed payload: a primary language subtag (en, ro, fr, hu, de, es) recorded AT THE WRITE DOOR from the page the author actually read and validated there, or null. The field is ABSENT on every entry published under an earlier rule (sha256-canonicaljson-v2, sha256-canonicaljson-v3, sha256-canonicaljson-v4, sha256-canonicaljson-v5) and it is never back-filled, because those rows genuinely do not know and a filled-in guess would rewrite payloads already committed and already anchored. ABSENT MEANS \"written before the field existed\"; NULL MEANS \"not recorded at that door\". NEITHER MEANS \"this review is in the salon's language\" — and that guess is exactly what this field replaces: before it, the machine-readable inLanguage on this platform's public pages was taken from the locale segment of whichever URL a page was fetched at, and from the salon's own configured language, so one review could be published as several different languages at the same time. FROM THIS BUILD, NO PUBLIC SURFACE PUBLISHES A LANGUAGE FOR A REVIEW THAT DOES NOT CARRY ONE: the key is omitted rather than guessed, and an omission is the honest reading. Like the economic flags and synthetic it is a PLATFORM ASSERTION, not a recomputable fact — nobody can check from a public export what language a human wrote in; what a reader can check is that the value we committed to is the value we hash. It is also NOT a claim about the review TEXT being translated: review text is never translated anywhere on this platform, in any direction.","signing":"This document is signed by the Primer platform key, which is separate from the key that signs per-salon documents. Its fingerprint is written into the reserved platform chain (see platformChain.keyAnchors), which is itself a leaf of the daily Merkle root.","anchor":"Daily Merkle root over the per-salon chain heads, submitted to public OpenTimestamps calendars. SUBMITTED means a calendar accepted the digest; it is NOT a Bitcoin confirmation. CONFIRMED means the proof carries a Bitcoin attestation naming a block height. Note for anyone checking by hand: GET <calendar>/timestamp/<digest> returns 404 for genuine digests — the calendar indexes the commitment at the pending attestation, not the file digest — so verification is done from the proof, never by re-querying the calendar. TWO CALENDARS, TWO ROLES, because one word is doing two jobs: the calendar field published beside this note is the SUBMISSION endpoint the digest was handed to, which is a POOL address; the ATTESTING calendar is the one named inside the .ots proof at its pending attestation, and it is routinely a different host, because a pool answers from one of its members. A verifier that finds the two disagreeing has found an ordinary hand-off, not a contradiction. We publish the submission endpoint because that is the fact we hold; the attesting calendar is READ OUT OF THE PROOF, which is the checkable artefact and is served at the otsUrl beside this block. Neither name is evidence on its own: what a proof commits to is a Bitcoin block, never a calendar.","signatureAbsence":"When this document cannot be signed it is served UNSIGNED and says so (signature: null, signatureUnavailable), never withheld and never faked. The reason is machine-readable and names the actual gap: NO_SIGNING_KEY_CONFIGURED means this deployment has no key at all; SIGNING_KID_NOT_CONFIGURED means it has one but no key id to publish it under; SIGNING_KEY_INVALID means the configured key is not base64(PKCS#8 DER) of an Ed25519 key. Three different things to go and fix, so they are three different codes. In every case the chain, the counters and the anchors below are unaffected and remain fully verifiable from the public export; only the origin binding is missing.","rateUnits":"meanResponseRateBp and negativeSurvivalRateBp are BASIS POINTS — integers in 0..10000, where 10000 means 100%. They are integers because these bytes are signed and the canonicalisation rule (sha256-canonicaljson-v2) admits only safe integers, so that a stranger can reproduce the signed bytes exactly. negativeSurvivalRateBp is null when the population contains no 1–3 star reviews at all — which is not the same as a rate of zero. ONE SCALE, TWO DIFFERENT BASES, said here rather than left to be assumed: meanResponseRateBp is a MEAN PER REGISTER — each register's own share of published reviews carrying a live reply, averaged over the registers that have published anything, every register weighted equally however large it is. It is a MACRO average and NOT a pooled rate: it is not replies divided by reviews across the fleet, and the smallest register moves it exactly as much as the biggest. negativeSurvivalRateBp is the other kind — POOLED over the whole population of final 1–3 star reviews at once, so there the biggest registers dominate it. Neither basis is recomputable from anything published here, which is why both are named in claimSources as our assertion.","recomputability":"Every key named in claimSources is OUR assertion: it is computed over Review or ledger rows this export does not carry — no document enumerates the network's salons — so a third party cannot recompute it from public data today. They are published labelled, and they are the numbers that would embarrass us if we were manipulating. Everything NOT named there is a different kind of claim: the per-salon chains, the daily heads, the leaves and the Bitcoin anchors ARE recomputable, and the standalone verifier recomputes them. One field is split, and the split is stated rather than glossed: \"chain\" is labelled because chain.salons and chain.entries are fleet-wide counts nobody outside this database can reproduce, while chain.head — the day, its Merkle root and its anchor status — is recomputable from the leaves published at endpoints.anchorsUrl, and should be checked there.","platformChainIsALeaf":"The reserved chain \"__platform__\" holds the platform key's KEY_ANCHOR entries. It is an ordinary leaf of the daily Merkle root, so a head's leafCount can exceed the number of SALONS by one. It is excluded from every salon statistic above, because it is not a salon.","platformChainTip":"platformChain.head is the CURRENT tip of that reserved chain (its latest {seq, entryHash}), NOT YET ANCHORED — distinct from chain.head, which is the last daily Merkle head submitted to OpenTimestamps and is null until the first anchoring run. So at cold start, when chain.head is null, platformChain.head is still an anchor a network verifier can validate from entry 1, recomputable from platformChain.exportUrl. Two different heads, labelled rather than left to look like a disagreement.","timeBasis":"State as of `generatedAt`; the aggregate these figures come from is recomputed at most every 3600 seconds, so the next refresh is at `nextAggregation`. This document is cached for that hour, so a disagreement with another signed document (the platform-host log, a per-salon log) generated inside this window is STALENESS, not a contradiction between two signed documents.","directory":"salons[] lists every register that has ever written a ledger entry and is not a seeded/ghost record — it ENTERS on its first entry and never leaves. Pausing collection does not remove a register from this list, and neither does being too young to have been anchored: each entry states its own anchorState (ANCHORED / NOT_YET_ANCHORED) and its wellKnownUrl, so absence of an anchor is DISCLOSED rather than expressed by absence from the document. Each entry's funnel and head are derived from the same append-only rows as that salon's own reviews-log.json and must match it; a divergence between the two surfaces is a fork signal (see the verifier's cross-origin inclusion step). salonsListedTruncated is true only if more registers qualify than one pass could walk.","directoryPopulation":"ledgerSalons is every register with at least one ledger entry (2); salonsListed is how many are enumerated in salons[] below (2). They differ for exactly two reasons: the directory hit its scan cap (salonsListedTruncated is false), or a register is excluded as a seeded/ghost record. Neither pausing collection nor never having been anchored removes a register from the list: a register that has never been anchored IS listed, with anchorState NOT_YET_ANCHORED — its head is attested by its own signed register document at that entry's wellKnownUrl, and by no daily Merkle root yet.","directoryClaims":"Every entry under salons[] mixes two kinds of field, and two kinds of UNIT: invited and responded inside each funnel are counts of DISTINCT PEOPLE, while the review counts (published, publishedFromInvitation, publishedOrganic, withdrawnReviews) beside them are not — so a response rate read off this entry is people over people. No absolute count of VISITS is published in an entry at all. The funnel counts are PLATFORM ASSERTIONS: they are computed over Appointment/Review rows no public export carries, so a third party cannot recompute them — which is why salons is labelled in claimSources. Inside each funnel, published is broken out as publishedFromInvitation and publishedOrganic (they sum to published): the organic door and legacy rows publish a review without an invitation, so published is NOT a subset of invited and this split is the explanation, not a new claim. Worked example, read off salons[0] of this very document: invited 22 / published 7, every one of them through the invitation door — publishedOrganic is 0 there. currentHead and the inclusion proof are CHECKABLE and are deliberately NOT labelled: currentHead against the salon's own export at endpoints.exportUrl, and membership against the OTS-anchored daily root via inclusionUrl. pilot is an honest disclosure: no register in this deployment is flagged pilot/demo, so it is false on every entry; a ghost/seed salon is never listed at all."},"documentOrigin":"https://primer.tech","signedAt":"2026-09-02T19:44:15.007Z","signedBy":{"scope":"platform","custody":"platform","kid":"primer-network-2026-08-prod"},"signature":{"alg":"EdDSA","kid":"primer-network-2026-08-prod","origin":"https://primer.tech","signedAt":"2026-09-02T19:44:15.007Z","canonicalization":"sha256-canonicaljson-v2","sig":"yQPPm0Vzi--yCUwseZskeWTCHerGD-XBPSe615BhIhFyGlWVGKr5xxqTcCPr4UBZOJgCJWT4SYkfgYxnC8DuAg"}}