Skip to content

Root identity: hash-pin every raw microdata input and reference its Chronicle registration (#848) - #853

Open
MaxGhenis wants to merge 13 commits into
mainfrom
root-identity-848
Open

Root identity: hash-pin every raw microdata input and reference its Chronicle registration (#848)#853
MaxGhenis wants to merge 13 commits into
mainfrom
root-identity-848

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #848.

A build graph should have no anonymous roots. Today Microcosm pins raw
microdata in per-country manifests, checkpoint metadata, code constants, and
command-line arguments, with no shared registry, no licence record, and no
timestamp anyone outside the build can check. This makes every raw microdata
input declare the SHA-256 of the exact file its stage reads plus the one
Chronicle registration that witnesses it, refuses to build when the bytes on
disk disagree, and lists the roots that cannot be pinned yet in one ratcheted
allowlist.

This is the consumer half of the contract shared with chronicle#221 and the
Chronicle ADR "Raw microdata in Chronicle is identity, not content."

The contract

Every artifact entry whose kind is one of public_microdata,
licensed_microdata, restricted_microdata, private_microdata, or
versioned_derived_microdata carries either

  • sha256 (64 lowercase hex) of the file the stage reads, plus
    chronicle_artifact {source_id, package_id, year, sha256, filename, access}
    — where the R2 key raw/{source_id}/{package_id}/{year}/{sha256}/{filename}
    exists only for access: public; or
  • one reviewed row in
    packages/microcosm-build/src/microcosm/build/microdata_pins_pending.json
    with country, stage, locator, reason, issue.

Three invariants make the reference hard to get wrong, so review is about
whether the registration is right rather than whether it is well-formed:

  1. The access class is derived, not chosen. licensed_microdata
    licensed; private_microdata and restricted_microdatarestricted
    (the conservative side — no bytes in any Chronicle store);
    public_microdatapublic. versioned_derived_microdata has no mapping
    at all: a Microcosm-derived HDF5 is not a publisher release, so it must be
    allowlisted rather than registered.
  2. The year must be one the entry already declares — exactly
    tax_year_start where present, otherwise a four-digit year appearing in
    vintage.
  3. One file, one registration. Entries sharing a SHA-256 must resolve to
    the same registration; the FRS adult tab feeds five UK stages and the SIPP
    public-use file feeds four US stages, and identity belongs to the bytes.

Where archive and member are already distinguished (weeks_unemployed_input,
scf_wealth), member_sha256 is kept unchanged and the registration witnesses
the distributed archive — the file a publisher actually released and the only
thing Chronicle can register — while the member pin remains Microcosm's extra
reach inside it.

The fail-closed gate

microcosm.build.source_runtime gains:

  • verify_microdata_files — hashes every raw microdata file a run was
    handed and refuses to continue unless the bytes are the pinned ones. The
    refusal names the publisher, the vintage, the locator, the path, and both
    digests, so an operator can tell a reissued vintage from a corrupted download
    without rerunning anything. Keys resolve against the locator and the
    declared filename, because a caller-supplied private input's locator is the
    shared placeholder "caller-supplied local input"; a key that resolves to
    several differently-pinned files is refused as ambiguous rather than
    arbitrarily matched.
  • verify_recorded_microdata_pins — the cheap path when a producing run
    already hashed its inputs. Disagreement is fatal; absence is not: a locator
    the manifest declares no pin for is reported as unregistered, because that is
    exactly what the allowlist records, and this check must not invent a
    registration the repository has not made.

Wired into the three places raw microdata actually enters a build:

where what it does
tools/build_uk_frs_spine.py hashes all 14 FRS tabs and every caller-supplied licensed input before any stage reads a table; records the resolved registrations in the spine sidecar under microdata_registrations
us_runtime/asec_checkpoint.py cross-checks the ASEC raw-stage checkpoint's recorded sha256/member_sha256 source pins against the US manifest instead of re-hashing hundreds of megabytes per archive; the checkpoint metadata contract is unchanged
tools/build_us_fiscal_refresh_release.py writes a microdata_registrations block next to the existing Chronicle consumer-artifact pin, carrying both the resolved registrations and the pending rows, so a release manifest states its own unwitnessed surface

Registration ids chosen

Chronicle's live db/data/*/manifest.yaml uses a publisher-slug source_id
and a kebab-case, publisher-prefixed package_id (hmrc /
hmrc-spi-income-bands-2023-24), and files[year] holds exactly one file per
(package, year). So this uses one package per distributed file rather
than one per study — the same granularity Chronicle already uses for
soi-table-1-1 vs soi-table-1-2. That is a deviation from the tentative
dwp/frs-2023-24 and hmrc/spi-<vintage> in the brief, and it is what the
key shape requires.

Note for chronicle#221: the FRS this build reads is 2024-25, UKDS
SN 9563
(tax_year_start: 2024), not 2023-24, and the UK manifest carries
21 licensed references over 14 distinct tabs.

Pin / allowlist table

Pinned — 32 entries resolving to 21 distinct registrations. UK is fully
pinned, so its ratchet contribution is zero.

country stage locator status registration
uk frs_spine accounts.tab pinned dwp / dwp-frs-2024-25-accounts @ 2024 (licensed)
uk frs_spine adult.tab pinned dwp / dwp-frs-2024-25-adult @ 2024 (licensed)
uk frs_spine benefits.tab pinned dwp / dwp-frs-2024-25-benefits @ 2024 (licensed)
uk frs_spine benunit.tab pinned dwp / dwp-frs-2024-25-benunit @ 2024 (licensed)
uk frs_spine child.tab pinned dwp / dwp-frs-2024-25-child @ 2024 (licensed)
uk frs_spine chldcare.tab pinned dwp / dwp-frs-2024-25-chldcare @ 2024 (licensed)
uk frs_spine extchild.tab pinned dwp / dwp-frs-2024-25-extchild @ 2024 (licensed)
uk frs_spine househol.tab pinned dwp / dwp-frs-2024-25-househol @ 2024 (licensed)
uk frs_spine job.tab pinned dwp / dwp-frs-2024-25-job @ 2024 (licensed)
uk frs_spine maint.tab pinned dwp / dwp-frs-2024-25-maint @ 2024 (licensed)
uk frs_spine mortgage.tab pinned dwp / dwp-frs-2024-25-mortgage @ 2024 (licensed)
uk frs_spine oddjob.tab pinned dwp / dwp-frs-2024-25-oddjob @ 2024 (licensed)
uk frs_spine penprov.tab pinned dwp / dwp-frs-2024-25-penprov @ 2024 (licensed)
uk frs_spine pension.tab pinned dwp / dwp-frs-2024-25-pension @ 2024 (licensed)
uk frs_employment adult.tab pinned dwp / dwp-frs-2024-25-adult @ 2024 (licensed)
uk frs_council_tax househol.tab pinned dwp / dwp-frs-2024-25-househol @ 2024 (licensed)
uk frs_education adult.tab pinned dwp / dwp-frs-2024-25-adult @ 2024 (licensed)
uk frs_education child.tab pinned dwp / dwp-frs-2024-25-child @ 2024 (licensed)
uk frs_legacy_proxies adult.tab pinned dwp / dwp-frs-2024-25-adult @ 2024 (licensed)
uk frs_hmrc_spine_leaves adult.tab pinned dwp / dwp-frs-2024-25-adult @ 2024 (licensed)
uk frs_hmrc_spine_leaves benefits.tab pinned dwp / dwp-frs-2024-25-benefits @ 2024 (licensed)
uk was_wealth caller-supplied local input pinned ons / ons-was-round-8-household @ 2018 (restricted)
uk lcfs_consumption caller-supplied local input pinned ons / ons-was-round-8-household @ 2018 (restricted)
uk lcfs_consumption dvhh_ukanon_v2_2023.tab pinned ons / ons-lcfs-2023-24-household @ 2023 (restricted)
uk lcfs_consumption dvper_ukanon_202324_2023.tab pinned ons / ons-lcfs-2023-24-person @ 2023 (restricted)
uk etb_vat householdv2_1977-2024.tab pinned ons / ons-etb-1977-2024-household @ 1977 (restricted)
uk etb_services householdv2_1977-2024.tab pinned ons / ons-etb-1977-2024-household @ 1977 (restricted)
uk hmrc_spi_income_spine caller-supplied local input pinned hmrc / hmrc-spi-public-use-tape-2022-23 @ 2022 (restricted)
uk hmrc_spi_income caller-supplied local input pinned hmrc / hmrc-spi-public-use-tape-2022-23 @ 2022 (restricted)
uk (frozen replay) hmrc_spi_income caller-supplied local input pinned hmrc / hmrc-spi-public-use-tape-2022-23 @ 2022 (restricted)
us weeks_unemployed_input …/cps/datasets/2023/march/asecpub23csv.zip pinned census_cps / census-cps-asec-2023 @ 2023 (public)
us scf_wealth …/econres/files/scfp2022s.zip pinned federal_reserve / federal-reserve-scf-2022-summary-extract @ 2022 (public)

Pending — 39 rows, the committed ratchet baseline. Grouped by what
specifically blocks the pin; each row in the file states its own reason.

n country stages why not pinned yet
24 us education_inputs, retirement_contributions, childcare_inputs, adult_care_inputs, energy_subsidy, child_support_inputs, disability_benefits_input, workers_compensation_input, ssi_take_up, meps_esi_premiums, prior_year_income, immigration_status, hours_worked, snap_take_up, snap_state_take_up, relationship_inputs, medicare_take_up_input, retirement_distributions, eligibility_inputs, pregnancy, snap_abawd_discretionary_exemption, aca_marketplace_inputs, medicaid_take_up, other_health_insurance_premiums The entry names a CPS ASEC column universe pooled across build-selected income years, not one distributed file, so no single SHA-256 witnesses it. Pinning needs one artifact entry per pooled survey-year archive; the 2023, 2024, and 2025 zips are already hash-pinned in us_runtime/education_assistance_source.py, so this is a manifest-shape change, not a discovery problem.
5 us scf_wealth, ssi_disability_criteria, sipp_head_start, vehicle_assets, voluntary_filing_input The declared SHA-256 witnesses the retired pipeline's Hugging Face mirror revision 21280dca…, not the Census-distributed SIPP 2023 release. Chronicle registers the publisher artifact, whose own hash needs one network-enabled fetch.
1 us sipp_tips pu2023_slim.csv is a PolicyEngine-derived column subset of SIPP 2023 with no publisher release of its own; registration must reference the Census file behind it.
2 us puf_tax_detail, education_inputs IRS SOI Public Use File: the entry names the 2015 PUF field set with no distributed-file hash, and the IRS withdrew the file, so a registration must witness the licensed copy the build reads.
2 us puf_tax_detail, acs_rent puf_2024.h5 and acs_2022.h5 are versioned_derived_microdata produced by the retired pipeline, not publisher releases, so they have no Chronicle access class. acs_2022.h5 is hash-pinned; its official PUMS zips are named in the entry and unhashed.
1 us acs_rent Locator names SHA-locked CPS ASEC person and household tables pooled over 2022-2024 rather than one distributed file; needs the same per-archive split as the ASEC column entries above.
1 us scf_wealth (scf2022s.zip) Full-file SHA-256 pending one network-enabled provisioning fetch, as the entry's own integrity_note already records.
1 us org_wages Reads twelve CPS basic monthly files (jan24pubdec24pub); the entry pins the generated cache's content hash, not the twelve distributed archives.
1 be silc_load Statbel BE-SILC scientific-use files (D/R/H/P) are restricted and not yet provisioned; the entry names four files with no hashes.
1 am load_populace_us_support_pool Armenia is a spec-only package; the policyengine/populace-us support pool has no certified revision, filename, or SHA-256 yet — its own integrity_note makes those a harvest item.

24 + 5 + 1 + 2 + 2 + 1 + 1 + 1 = 37 US rows, plus one BE and one AM row, is
the 39-row baseline. education_inputs and acs_rent each appear in two
groups because each declares two microdata artifacts.

One allowlist, not one per country

The brief's example path was build/us/microdata_pins_pending.json. A file
inside a country package is a declared package resource, so adding one to am/
and be/ moves their CountrySpec fingerprints and resource_hashes, which
would require regenerating tests/golden/{am,be}_country_spec.json — expressly
out of scope here. The allowlist is therefore a single country-tagged file one
directory up, at microcosm/build/microdata_pins_pending.json. That also makes
the ratchet a single number a reviewer can watch (39) instead of four.

Contract tests

packages/microcosm-build/tests/test_microdata_root_identity.py (37 tests,
shared-spec group, tools/ci_test_groups.py --verify green, fully hermetic —
the gate tests build synthetic files in tmp_path):

  • pinned-or-listed for am/be/uk/us and the frozen UK replay manifest;
  • the ratchet: never above baseline, every row names a live unpinned root,
    every row states a reason and an issue, an over-baseline file is refused, and
    stale and orphan rows are reported as gaps;
  • validation: derived access class, public-only R2 key, registration/pin
    agreement, one registration per file, and the refusals for a mismatched
    digest, an unknown access class, an access class the kind does not imply, a
    public registration without a filename, a registration without a pin, an
    uppercase digest, an undeclared year, and a derived artifact carrying a
    registration;
  • the gate: matching bytes pass and resolve their registration, different bytes
    raise with publisher/vintage/locator/expected/actual in the message, unknown
    keys and missing files are refused, a caller-supplied input resolves by its
    declared filename, the shared placeholder locator is refused as ambiguous,
    and the real UK manifest rejects a tampered adult.tab across all five
    stages that read it;
  • the recorded-pin cross-check: agreeing pins resolve, a disagreeing archive or
    member digest raises, and an unregistered locator is reported rather than
    refused.

Digests that moved

Byte pins over the manifests this PR edits, re-pinned in the same commits that
changed the bytes. No dataset golden was regenerated and no on-disk, artifact,
or diagnostic key was renamed (#639).

  • us/spec/sources.yaml stage_asset.sha256 and its two test copies, plus the
    FROZEN_LEGACY_RESOURCE_SHA256 constant in
    tools/generate_us_bundle_from_constants.py; the US bundle YAML was
    regenerated by that tool rather than hand-edited.
  • FROZEN_SOURCE_STAGES_SHA256 in test_uk_source_stages.py — the frozen
    HMRC/SPI replay manifest is a live runtime resource
    (uk_runtime/hmrc_source_contract.py), so it carries its registration in
    lockstep with the canonical copy, as the lockstep test already requires.
  • uk/release_input_coverage_manifest.json, regenerated with
    tools/build_uk_release_input_coverage_manifest.py.
  • Four spec_sha256 vectors (am, be, uk, and the synthetic loader golden
    vector). These move for two reasons, both by design: they attest the schema
    set, which gains the chronicle_artifact definition; and
    microcosm.build.source_runtime is a _DIRECT_KERNEL_MODULE in
    spec_engine/seeds.py, so its source is attested by every country's spec
    identity. Any later change to the gate's code moves these four again — they
    were re-pinned last, against the final code.

Scope

No publish, promotion, or HF destination change; no golden regeneration; no key
renames. PR CI stays secrets-free — every new test is hermetic and none touches
restricted microdata.

Residual risks

  • Registration ids are unconfirmed against chronicle#221. That lane had not
    committed its manifests when this was written; if it lands different ids,
    each is a one-line change per entry, and the contract tests pin the shape,
    not the names.
  • ons-was-round-8-household @ 2018 and ons-etb-1977-2024-household @ 1977
    take their year from the vintage the entry declares (2018_20, 1977_24),
    which is the series/reference start rather than the edition year. If
    Chronicle keys those files by edition year instead, the year field moves.
  • The UK gate is wired but unexercised on real data here — it needs
    licensed FRS tabs, which PR CI deliberately cannot see. Its behaviour is
    covered by hermetic tests and by rejecting a tampered adult.tab against the
    real manifest pins.

🤖 Generated with Claude Code

MaxGhenis and others added 13 commits September 2, 2026 12:35
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ader

Every artifact entry whose kind names microdata now has to say which exact
bytes a stage reads and which single Chronicle registration witnesses them.
source_manifest validates that shape at load: lowercase 64-hex sha256, a
chronicle_artifact object carrying source_id/package_id/year/sha256/access
(plus filename, required whenever access is public because only public
registrations have an R2 object key), agreement between the entry's sha256
and the registration's, and no repeated locator inside a stage. Unknown
access classes and unknown keys fail loudly rather than being ignored.

Alongside the validation this adds the reader side the rest of microcosm#848
builds on: microdata_artifact_entries to enumerate the roots of a manifest,
resolved_chronicle_registrations to collect the deduped registrations a build
actually consumed, load_microdata_pin_allowlist for the per-country
microdata_pins_pending.json ratchet, and audit_microdata_pins to report the
entries that are neither pinned nor allowlisted. No manifest declares a
registration yet, so this commit is inert on the real manifests.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…registration per file

Three invariants turn the registration reference from free text into something
a reviewer cannot get wrong:

- access class is derived, not chosen: licensed_microdata registers as
  licensed, restricted_microdata and private_microdata as restricted (the
  conservative side — no bytes in any Chronicle store), public_microdata as
  public. versioned_derived_microdata has no mapping at all: a
  Microcosm-derived HDF5 is not a publisher release, so it belongs in the
  pending allowlist rather than in a registration.
- the registration year must be one the entry already declares — exactly
  tax_year_start where present, otherwise any four-digit year in vintage.
- entries sharing a SHA-256 must resolve to the same registration. The FRS
  adult tab feeds five UK stages and the SIPP public-use file feeds four US
  stages; identity belongs to the bytes, so one file cannot enter a build
  graph as two differently named roots.

Also add load_country_microdata_pin_allowlist, which returns the empty
zero-baseline allowlist for a country that ships no pending file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the rest

The UK side is now fully witnessed: all 29 microdata entries in
uk/source_stages.json plus the frozen HMRC/SPI replay manifest carry a
chronicle_artifact, so the UK ratchet baseline is zero. The US side pins the
two roots that name a publisher-distributed file with a verified hash — the
2023 CPS ASEC archive and the SCF 2022 summary extract — and lists the other
37 with a reviewed reason.

Registration ids follow Chronicle's live db/data convention (source_id a
publisher slug, package_id kebab-case and publisher-prefixed) and one package
per distributed file, because a Chronicle manifest holds one file per
(package, year):

  dwp/dwp-frs-2024-25-<tab>            licensed    14 FRS 2024-25 tabs, SN 9563
  ons/ons-was-round-8-household        restricted  WAS round 8 EUL
  ons/ons-lcfs-2023-24-{household,person}  restricted
  ons/ons-etb-1977-2024-household      restricted
  hmrc/hmrc-spi-public-use-tape-2022-23  restricted  SN 9422
  census_cps/census-cps-asec-2023      public      asecpub23csv.zip
  federal_reserve/federal-reserve-scf-2022-summary-extract  public

The pending allowlist is one file for the whole workspace,
build/microdata_pins_pending.json, with a country tag per row, so the ratchet
is a single reviewable number (39) rather than one per country. Rows say what
specifically blocks each pin: 24 US entries name a pooled ASEC column universe
rather than one file, 6 pin the retired pipeline's Hugging Face mirror rather
than the Census release, 2 are Microcosm-derived HDF5s with no publisher
release behind them, and the rest are named individually.

sources.schema.json gains the chronicle_artifact definition, with filename and
access annotated operational to match how the artifact-level keys of those
names are already classified. Byte pins over the changed manifests move with
them: the US stage_asset digest and its two test copies, the UK frozen replay
digest, the regenerated UK release_input_coverage_manifest, and the four
spec_sha256 vectors that attest the schema set.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… ones

source_runtime gains the fail-closed root-identity gate. verify_microdata_files
hashes each raw microdata file a run was handed and refuses to continue unless
the bytes are the pinned ones; the refusal names the publisher, the vintage,
the locator, the path, and both digests, so an operator can tell a reissued
vintage from a corrupted download without rerunning anything. Keys resolve
against both the locator and the declared filename, because a caller-supplied
private input's locator is the placeholder "caller-supplied local input".

verify_recorded_microdata_pins is the cheap path for a producing run that
already hashed its inputs. The ASEC raw-stage checkpoint records a
sha256/member_sha256 pin per archive, so load_asec_raw_stage_checkpoint now
cross-checks those against the US manifest instead of re-reading hundreds of
megabytes per archive. Disagreement is fatal; absence is not — a locator the
manifest declares no pin for is reported as unregistered, which is exactly what
microdata_pins_pending.json records, and the checkpoint metadata contract is
unchanged.

Both builds record what they resolved. build_uk_frs_spine verifies every FRS
tab and caller-supplied licensed input before any stage reads a table and
writes the resulting registrations into the spine sidecar;
build_us_fiscal_refresh_release writes a microdata_registrations block beside
the existing Chronicle consumer-artifact pin, carrying both the resolved
registrations and the pending rows, so a release manifest states its own
unwitnessed surface.

test_microdata_root_identity is the contract: pinned-or-listed for all four
countries and the frozen UK replay manifest, the allowlist ratchet and its
stale/orphan row failures, the derived access class, the public-only R2 key,
the registration/pin agreement, and both gate paths including the exact
diagnosable message.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ment

DESIGN.md's process rules gain "build graphs have no anonymous roots": what a
microdata root must declare, why licensed and restricted releases register
hash-only, that the build gate is fail-closed, and that the pending allowlist
is a ratchet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Records what was built, the Chronicle registration ids chosen and why, the
39-row ratchet baseline, and the note chronicle#221 needs: the FRS the UK build
reads is 2024-25 / SN 9563, not 2023-24.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
"caller-supplied local input" is the locator every UK private root shares, so
resolving a supplied file by that key would compare one file against the WAS,
LCFS, ETB, and SPI pins at once and report three spurious mismatches. The gate
now names the ambiguity and points at the declared filename, which is what the
UK builder already keys by.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Main moved the UK source manifest and the release input-coverage manifest, so
the byte pins over both had to be recomputed on the rebased tree rather than
carried across: the regenerated uk/release_input_coverage_manifest.json and the
four spec_sha256 vectors that attest the schema set. No contract changed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
python -O strips asserts, so a bare assert is the wrong guard inside a
fail-closed check. The ambiguity check just above already proves every match
shares one pinned digest, so read that value directly and raise if it is
somehow absent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…pping

The allowlist spans every country, so auditing the frozen UK replay manifest —
read as JSON rather than through the loader — would have reported all 37 US
rows as orphans of it. A SourceManifest names its own country; anything else
must now be told, and the audit takes an explicit country override.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…spec digests

microcosm.build.source_runtime is a _DIRECT_KERNEL_MODULE in
spec_engine/seeds.py, so its source is attested by every country's
spec_sha256: the am, be, uk, and loader golden vectors move whenever the gate's
code changes, by design. This re-pins them once against the final code, and
drops the quotes the registration blocks in uk/spec/sources.yaml were written
with so they read like the surrounding entries and like the generator's output
in us/spec/sources.yaml.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Anyone editing the gate again will move four spec_sha256 vectors with it;
say so once rather than let the next editor rediscover it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Cross-PR convention ruling (chronicle#227 ↔ microcosm#853), so both sides land on one shape:

  1. One Chronicle package per publisher release, files listed under the vintage. Chronicle's kind: microdata_release manifests hold a list under files[year] precisely so several distributed files share one registration (14 FRS tabs = one UKDS study). The consumer reference {source_id, package_id, year, sha256, filename, access} already disambiguates files inside a package by filename + sha256. So the ids are dwp / dwp-frs-2024-25 (year 2024, 14 tabs) and hmrc / hmrc-spi-public-use-tape-2022-23 (year 2022, put2223uk.tab), not one package per tab.
  2. Vintage: FRS 2024-25 (UKDS SN 9563). Microcosm main moved to the 2024-25 tabs today (UK spine: condition SPI UC receipt on benefit-unit composition and add a UC-specific child count #832); chronicle#227 registered the 2023-24 hashes from a stale checkout, so only 1 of its 15 hashes still matches main. The Chronicle side regenerates from microcosm origin/main (emit against a fresh checkout) and adds the other licensed/private roots main pins (WAS round 8, LCFS 2023-24 and 2018-20, ETB 1977-2024, SPI PUT): 19 hashes today.
  3. Access class derived from the Microcosm kind as Root identity: hash-pin every raw microdata input and reference its Chronicle registration (#848) #853 does (licensed_microdata → licensed; private_microdata/restricted_microdata → restricted; public_microdata → public), with byte custody additionally requiring the licence allowlist (ADR round 2). versioned_derived_microdata is never registered.

Chronicle's #227 fix round and a small #853 follow-up apply this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Root identity: every raw microdata input hash-pinned and referenced to its Chronicle registration

1 participant