Repository navigation
Releases
v0.9.0
Added
- Lossless continuous judgments. The generated
Judgmentmodel now carries
the Layers 0.11.0continuousValuearm as a typedDecimalValuecoefficient
and exponent, whileExperimentDef.taskTypelistscontinuousamong its
known values.JudgmentStudy.judgments()exposes that response as
JudgmentRow.continuous_value: Decimal | None, preserving participant and
item identity and keeping continuous responses distinct from the existing
integerscalar_value. The long-format Arrow and Parquet view stores the
exact decimal text in acontinuous_valuecolumn rather than converting it
to binary floating point.
Changed
- Vendored Layers lexicons 0.11.0. The vendored release is pinned to commit
da20595e19874358f5c0fcd37462d8e457ec0cdb; the regenerated lexicon tree hash
is87f116cc92d112e697e0fde39368185a8301a1a422e9cfcf20d911b940f8615f.
Generated integer fields now validate through a strict converter, so
malformed and nonfinite continuous components raisedx.ValidationErrorat
the typed boundary.
v0.8.1
Fixed
- CoNLL-U token spans index the text the sentence declares. A sentence
that carries a# textcomment keeps that text, but spans were still
computed as though the text were the forms joined by single spaces. Every
corpus that writesSpaceAfter=Notherefore drifted one byte per run-on
token, and a reader validating spans against the text rejected the file:
Universal Dependencies English-EWT failed on its first sentence, whose
spans ran seven bytes past a 129-byte text. Spans now locate forms in the
declared text and retain UTF-8 byte offsets whatever the corpus's spacing.
Multiword range rows are preserved by both parser paths and through Layers
records: each component word shares the range's complete surface span, as in
the published Layers UD data. A form that cannot be aligned receives no span
rather than a fabricated or out-of-bounds one.
v0.8.0
Fixed
- Repository history reads work on repositories committed under panproto
0.73 or later. panproto 0.73 changed the committed-data carrier from the
source JSON bytes to canonical MessagePack, soRepository.content_atcould
no longer decode committed values and the byte-equality tombstone check never
matched, resurfacing forgotten records.content_atanddiffnow read
committed values through panproto's schema-awaredecoded_data_at, which
decodes both the historical JSON carrier and the current canonical one, and
tombstones are recognized semantically after decoding.content_atstill
returns plain JSON values keyed by AT-URI with tombstoned records excluded.
The ancestry fold also rejects malformed keyed data sets and preserves
non-ASCII record content. The test suite pins fixture repositories committed
under panproto 0.71, 0.72.1, and 0.74.3 with the same history and checks that
all three read back identically. - Commit identifiers are stable across panproto releases. The identifiers
returned byRepository.log()are now the stored object identifiers, the
same oneshead()andresolve()return, rather than a re-hash of the
commit projected through the current commit shape. A repository committed
under panproto 0.71 or 0.72, whose commit objects lack fields the current
shape gives defaults, reports the identifiers it was written with, so
log()identifiers can be relied on for pinning. Identifiers are checked
against the persisted bytes on every read: a stored commit or data object
whose bytes no longer hash to its identifier failslog()andcontent_at
with aVcsError, for historical and current repositories alike.
Changed
- The
panprotofloor is now>=0.74.3, the first release carrying
decoded_data_atand the stored-identifier log traversal, and thedidactic
floor is now>=0.15.0. Repositories written under this floor use the
canonical MessagePack carrier and need lairs 0.8.0 or later to read.
v0.7.1
Changed
lairs toc --countscounts a repository in onegetRepopass. Counting
no longer drains every collection with pagedlistRecords; it fetches the
repository CAR once and tallies Merkle-search-tree keys per collection without
decoding record values, falling back to paged counting only whengetRepois
unavailable. On a repository with hundreds of thousands of records this turns
thousands of sequential requests into a single download (PdsClient.count_records
andcount_repo_carexpose the same path). An exact count of a very large
repository still transfers the whole repository, since ATProto exposes no
cheaper exact count, but it is now one streamed request rather than per-page
latency.
Added
lairs toc --max-count N(andtable_of_contents(count_cap=...)) caps each
collection's count atNand stops early, so a very large repository is not
transferred in full to be counted. A collection with more thanNrecords is
reported as capped and prints asN+.
v0.7.0
Added
- Federated project domains.
repo.decomp.io(Universal Decompositional
Semantics) andrepo.megaattitude.io(MegaAttitude) are live PDS endpoints and
ship as built-in discovery sources alongsiderepo.layers.pub, so all three
project domains are browsable out of the box.lairs sources listshows all
three; the index dedups by dataset URI, so crawling every source stays
idempotent while they share a PDS. - Catalogue-collection datasets in the global browse.
lairs index search
and the TUI Explore pane surface catalogue-collection datasets (UniMorph,
VerbNet, WordNet, MegaAttitude), not only corpora, through a new
search_collectionsandCollectionHit. Corpus-only facets (expression
bounds, quality metric, annotation rounds) match no collection. - Collection datasets in the Discover tab. The TUI Discover crawl lists
collection-shaped datasets alongside corpora, tags each row with its type
(corpusor the collection's kind), and indexes or mutes either card type;
DiscoveryIndex.muteaccepts a collection card, keyed by URI as before. - Judgment-study browsing.
lairs.data.JudgmentStudyand
load_judgment_studyload an experiment definition and its judgment sets and
expose the study the way it is explored: its response scale, its participants,
its items (with resolved text), the raw participant-by-item judgments, and
per-item and per-participant distributions.lairs judgments <uri>prints the
scale, each item's response distribution, and the participants. Item text
resolves by bulk-loading the stimulus expression accounts the judgments
reference rather than one fetch per item. - Judgment materialization.
JudgmentStudy.to_arrowand.materialize
write the judgments as a long-format participant-by-item table (each row
carrying the scalar or categorical response, confidence, and reading/response
time) plus per-item and per-participant views, andlairs judgments <uri> --out <dir>writes
judgments.parquet,items.parquet, andparticipants.parquet, so a study is
queryable with DuckDB and the explorer's Query tab. - Judgment views in the explorer's Browse tab. A judgment set renders its
participant's response distribution as a per-value histogram with the mean and
range for scalar tasks (in addition to the per-label counts for categorical
tasks) plus the median reading/response time, and an experiment definition
shows its scale and guidelines. - Signal (neural recording) view in the Browse tab. A media record carrying
a signal block gains a Signal view with the recording's parameters (modality,
device, sampling frequency, duration, channel count, reference and placement
schemes) and its channel and sensor layout. The sampled waveform lives in the
carrier blob, which the index never stores, so the view shows the layout, not
the samples. - Region reading times.
JudgmentStudy.region_responsesflattens every
per-region measure a judgment carries: the region's analysis role
(region_role), the reading and eye-movement measures (reading_time_ms,
first_fixation_ms,gaze_duration_ms,go_past_ms,total_time_ms,
regressions_out,regressions_in,fixation_count), and any per-region
response (response_time_ms,scalar_value,categorical_value).
materializewrites them asregion_responses.parquet, and the Browse
judgment Distribution view summarizes them as a region count and median
reading time. Requires Layers lexicon 0.10.0 (see below).
Changed
- Vendored Layers lexicon 0.10.0, which adds an optional
regionResponses
array topub.layers.judgment.defs#judgmentso region-level reading and
eye-tracking measurements have a home. Additive and backward compatible. - Documentation. Clarified the guides, concepts, reference, and tutorials, and
fixed the README quickstart to pass aPdsClientso it runs as written.
v0.6.0
Added
-
Data-access surfaces. Typed read surfaces over a repository's
pub.layers.*
records:Corpus,Acquisition,Collection, and signal-bearingMedia, plus
the lazyDatasetview, all built on a shared PDS graph loader (lairs.data)
that enumerates an authority's collections and follows AT-URI references across
account boundaries into a model pool keyed by AT-URI. -
Single-actor collection discovery.
lairs.discovery.collectionslists an
actor'spub.layers.catalog.collectionrecords asCollectionSummaryrows,
preferring a configured appview's server-side facets and falling back to a direct
PDS read. -
DNS handle resolution.
IdentityResolver.resolve_handlenow races the
_atprotoDNS TXT record against the.well-known/atproto-didHTTP method and
returns the firstdid:, so a handle served only over DNS resolves without an
injected client. Adds adnspythondependency and adns_timeoutsetting. -
lairs index builddefaults to the Layers PDS.--endpointand
--sourceare no longer a required choice: with neither flag, the crawl
targets the first enabled configured source, which on a default install is
the built-in Layers PDS (repo.layers.pub).lairs index build --into ./index
is now enough to index the public corpus. A user who re-points or disables the
built-in insources.tomlmoves the default with it; when every source is
disabled, the command reports that and exits non-zero rather than crawling
nothing. The newlairs.discovery.default_sourceexposes the same resolution
to library callers. -
Incremental re-crawls.
com.atproto.sync.listReposreports each
repository's current commit revision, and the new
PdsClient.list_repo_listingssurfaces it as aRepoListingalongside the
head CID (list_reposremains as a DID-only view).build_indexaccepts a
revsmapping and skips any repository whose revision matches the one
recorded at the last crawl, reported asrepos_unchangedon the
CrawlReportand stored asRepoCrawlState.last_seen_rev.lairs index buildsupplies the mapping whenever it enumerates the service itself, so a
re-crawl costs onelistRepospass plus adescribeRepofor only the
repositories that actually moved. An explicit--seed-didlist carries no
revisions, so those repositories are always described.
Changed
- Dependency floors raised to
didactic>=0.9.1andpanproto>=0.71.0,
picking up upstream fixes. - The adapter registries are concretely parameterized.
Registry[Codec],
Registry[Exporter], andRegistry[KnowledgeBase]used the protocols bare,
so all eight type arguments were implicitly unknown. Every codec is
Codec[CorpusFragment, FragmentRecord]and every knowledge base is
KnowledgeBase[Entity, Candidate, Edge], so those are now exact; an
exporter's view is alwayspyarrow.Tablewhile its spec and result differ per
adapter, so those are closed unions over the shipped adapters. A third-party
exporter introducing a new spec or result type widens the aliases. With the
registries typed, ty'smissing-type-argumentrule is promoted to an error,
leavingpossibly-missing-attributeas the one rule at its default. --sourcerenamed to--source-typeondatasets,toc, andsearch.
On those commands the flag selects the discovery mechanism (auto,pds,
orappview), which collided with--sourceonlairs index build, where it
names a configured source. The two meanings now have two names. Because
argparse accepts unambiguous prefixes, existing--source pdsinvocations
keep working on the renamed commands, but scripts should move to
--source-type.
Fixed
- The
tfdataexporter validates before it requires tensorflow.export
imported tensorflow before reading the Arrow view, so a bad column raised
ModuleNotFoundErrorinstead of the intended lairs error whenever the
optional extra was absent, contradicting the method's own documented
contract. The Arrow read and its null-column check now run first.
v0.5.0
Added
- Configured dataset sources. A
Sourcemodel and asources.tomlconfig
(under the XDG config directory, overridable withLAIRS_SOURCES_FILE) name
the PDS and relay endpoints lairs crawls for datasets, so a PDS that is
deliberately off the firehose stays discoverable. lairs ships a built-in
default for the public Layers PDS (repo.layers.pub); a user can add sources
or override a built-in, including disabling it.lairs index buildaccepts
--source <name>as an alternative to--endpoint, andlairs sources list
shows the configured sources. - Discover tab in the TUI. A new Discover tab (
4) browses the configured
sources and crawls a chosen source in the background, listing each dataset with
its state (indexed,new, ormuted). Pressingenterorspaceon a row
indexes a new dataset (so it appears on Explore) or permanently mutes an
indexed one. The crawl reuses the samelistRepospath aslairs index build
through a new streamingdiscoverfunction inlairs.discovery. - Auto-index on launch. With no
--index, the TUI uses a default index
location (under the XDG state directory, overridable withLAIRS_INDEX_DIR)
and, on launch, crawls the enabled sources and indexes every newly discovered
dataset that is not muted, so Explore fills in on its own.lairs tui --no-auto-indexskips the launch crawl. - Permanent muting with review. A muted dataset is recorded as a
MutedDatasetin the index and excluded from auto-indexing until unmuted. A
settings modal (ctrl+s) lists the configured sources and every muted dataset,
with an unmute action so a later crawl can pick it up again.
v0.4.1
Fixed
- Querying a materialized dataset with no annotations. A dataset without
annotation layers materialized anannotations.parquetwith no columns, which
DuckDB cannot read, so the Query tab andQueryEnginefailed to open the
dataset (andtui --datacrashed).materializenow skips a column-less view
rather than writing an unreadable Parquet, andQueryEngine.openskips any
Parquet it cannot register (raising only when none are readable), so querying
an annotation-less dataset works.
v0.4.0
Added
- Cross-account materialization.
load_corpus(and thelairs materialize
andlairs inspectcommands built on it) now follow AT-URI references across
account boundaries, transitively, to pull in the component records a dataset is
built from (its expressions, and the records those reference in turn), since a
Layers dataset typically fans out across many single-purpose accounts rather
than living in one. A newfollow_refsparameter, exposed on the CLI as
--follow-refs/--no-follow-refs(enabled by default), controls this, for
example to read only the corpus's own account when the components are already
materialized. References are fetched by exact AT-URI, so only the records the
corpus actually cites are loaded.
Fixed
- Reading records back from a PDS.
lairs pullandload_corpus(and the
materializeandinspectcommands) validated each record with the wire
$typefield that the generated models do not declare, so every real PDS
record failed validation and was silently skipped (pullreported zero
records;materializewrote empty views). They now strip$typebefore
validation through the shareddecodehelper, so records read back correctly.
v0.3.0
Added
- Aggregate per-dataset changelog entries.
build_aggregate_entryassembles
a singlepub.layers.changelog.entryfor a dataset anchor from the diffs of the
many component records that make up that dataset (a newComponentChangevalue
type), grouping changes intoChangeSections by each component's category and
pointingChangeItem.targetsat the changed components. The version is bumped
once from the whole aggregate, monotonic from the supplied previous version, and
an aggregate with no real change does not bump. A scale guard keeps each item's
true count in itsdescriptionand caps the enumeratedtargetsat
targets_per_item, so a change touching many records is summarised, never
silently truncated.