# Figure galleries

The figure gallery groups editable Typst and Mermaid diagrams by scientific
topic. It preserves alternatives for comparison and records preferences without
changing the active thesis. The catalog is
[`catalog.toml`](catalog.toml); generated PDFs, thumbnails, comparison sheets,
fingerprint snapshots, and thesis-usage receipts are ignored artifacts beneath
`.cache/ci-renders/figure-galleries/`.

## Commands

From the repository root:

```sh
make figure-gallery-check
make figure-galleries
make figure-galleries GALLERY=target-selection

python3 scripts/figure_gallery.py check
python3 scripts/figure_gallery.py check --inventory
python3 scripts/figure_gallery.py show <gallery-id> --json
python3 scripts/figure_gallery.py find '<scientific term>' --json
python3 scripts/figure_gallery.py find frustum --records all --format summary
python3 scripts/figure_gallery.py show CAP:cap-s2 --json
python3 scripts/figure_gallery.py related CAP:cap-s2 --relation outputs --json
python3 scripts/figure_gallery.py related FIG:report-s2-pilot-s2-figure-s01-frustum --relation uses --json
python3 scripts/figure_gallery.py related USE:use-thesis-s2-frustum --relation uses --json
python3 scripts/figure_gallery.py build --gallery target-selection
python3 scripts/figure_gallery.py compare <candidate-id> <candidate-id> [...]
python3 scripts/figure_gallery.py select \
  --slot <thesis-figure-slot> \
  --candidate <candidate-id> \
  --reason "<concise decision rationale>"
python3 scripts/figure_gallery.py status
python3 scripts/figure_gallery.py usage --document thesis
```

`build` also accepts `--output <directory>`. `show` resolves an exact figure ID,
including aliases, while `find` searches IDs, questions, descriptions, and
tags. `show` and `find` expose missing descriptions as `description needed` and
retain the `provisional` status of unfinished explanations. `check --inventory`
permits missing or provisional descriptions. Plain `check` validates the declared
curation scope and rejects provisional descriptions: report figures and individually
migrated records require resolved descriptions; `curation_version = 1` explicitly
migrates the whole catalog. Adding one description or bundle leaves other legacy
records unmigrated. `check --publication-ready` requires resolved descriptions for
every record and rejects provisional ones. Lookup and all check modes validate
catalog structure, supplied descriptions, frozen bundles, and source coverage
without requiring successful renders.
Kind-specific requirements, including authored Streamlit descriptions, still apply.
A build reports a renderer failure with an error card and nonzero exit status, so an old thumbnail
cannot look current.

Source-only catalogs and their gallery tests need only the Python standard
library. Catalogs with `report_bundles` use the canonical package reader and
require the package environment. Their eighteen integration tests run through
`make package-smoke` and the full `make package-ci` contract.

The generated HTML entry point is a thesis-first usage index:

- `index.html` shows thesis-owned figures, grouped by scientific topic and with
  chapter/section placement read from the canonical directory path;
- `seminar.html` keeps historical seminar figures separate from the thesis;
- `archive.html` shows explicitly superseded material;
- `all.html` provides the complete catalog when cross-publication discovery is
  useful.

Each card links to its source, fresh render when available, usage evidence, and
the evaluated development-thesis PDF when inclusion is verified. The index also
lists evaluated image dependencies that are absent from the catalog, so missing
metadata cannot make an included asset disappear from the audit.

Use completion validation only for an existing autoresearch artifact:

```sh
python3 scripts/figure_gallery.py validate-completion <path> \
  --mode prompt-architect-artifact
```

The other supported mode is `mission-validator-script`; the modes are mutually
exclusive within one mission.

## Topics and records

Catalog version 2 adds independent `capabilities` (source-bound public producers)
and `publication_uses` (authored placement intentions) alongside existing
`figures`. The updated reader also accepts version 1. Legacy `find` stays
figure-only JSON, even without `--json`; legacy `show --json` remains a
one-element list with the same fields. `--records all|figure|capability|publication-use`
opts into mixed discovery; `--format summary` opts into compact handles. `CAP:`
and `USE:` select typed records, while `FIG:` retains existing figure identities.
`--topic dataset` includes its curated descendants; `--tag pipeline` selects a
facet. Lookup treats case, whitespace, hyphens and underscores equivalently within an
ordered phrase. Exact typed handles and topic/tag filters remain exact. Lookup
does not create a cache directory, import producers or render.

Capabilities specify source, exact public or internal definition, input/output contracts,
renderer and tests. Python definitions are checked statically; authored diagram
entrypoints use `symbol = "source"`. A figure can link several capabilities;
an empty-output capability is valid. Examples must link back to their producer.
`related --relation produced-by|outputs|uses` derives reciprocal typed edges from
those authored links. It does not infer a connection from topic similarity.
Topic parents must reference an existing topic and cannot form cycles.

Optional figure `provenance` tables expose origin and source locators, and
separate creation, evidence and review dates. Dates are ISO `YYYY-MM-DD` or
`unknown`; malformed dates fail validation. These values participate in phrase
search and appear on rendered HTML cards. Provenance does not establish
scientific acceptance, render freshness or evaluated publication inclusion.
Authored sources under `docs/figures/shared/` join the existing source inventory.

The three S2 results are cold-read from the unchanged frozen pilot bundle. Their
existing development placements are recorded as intent only: neither registration
nor the cold reader establishes publication admission or evaluated occurrence.
The pilot retains its unresolved source-provenance caveat. Adding this bundle
retains its per-record description requirements: `check` and `check --inventory`
pass. The historical 147-record curation snapshot received source-grounded reading
guides, including eight aliases inheriting canonical descriptions.
`check --publication-ready` passed at that stage; newly inventoried uncurated
assets now require separate editorial review before whole-library publication
readiness. This establishes description completeness, not
scientific admission, successful rendering of every asset, or evaluated inclusion.
Historical screenshots and constructed alternatives retain their explicit limits.

The catalog links source-bound producer capabilities and destination-use intentions
to concrete/authored figures. Use typed lookup for records and the independent
coverage command for the current source census. Capability topics nest scene geometry,
pose feasibility, rendering, reconstruction, dataset statistics, model diagnostics,
training histories and reporting beneath the existing broad topics. Facets select
pipeline roles across those branches. Empty output lists deliberately identify
reusable functionality without inventing an experiment result.

The family routes below orient source review. Public factories, internal drawing
helpers and plotting methods require their own exact capability bindings:

| Family | Current disposition and remaining work |
| --- | --- |
| utils/geometry, pose_generation, rendering, rri_metrics | Scene/trajectory, candidate shell, view-jitter, proposal-sequence, paired-gaze, depth histograms and directional point-mesh accuracy/completeness producers. Transforms, colors and private drawing helpers stay under those owners; no geometric support plot establishes useful reconstruction gain. |
| oracle/evaluated pipelines, rollouts | Evaluated reward/candidate builders, S2, rollout distribution, support and budget-coverage producers; reducers and collection recipes are inputs rather than independent plot producers. |
| vin/QH/experimental diagnostics | QH, geometry/backbone/candidate-encoding, pose-grid/PCA/LFF/alignment and benchmark producers. Experimental output keys are qualified; additional projection/transform plots remain source-discoverable rather than promised stable. |
| reporting/W&B | Public report builder, real pilot links, and acquired W&B curves/bars/scatter plus selector, score-floor and renderer exports. W&B acquisition remains an input seam. Frozen result identity differs from live history or a descriptive benchmark. |
| app, data_handling, lightning | Curated Streamlit records, root-store, rollout candidate-flow and Optuna pages plus the typed target-inventory report. Loaders, caches and trainers are not producers; source-only pages do not establish a retained measurement output. |
| rerun_inspector | Public offline and rollout logger classes route to their session/README owners. Logging contract tests are not native viewer proof; no `.rrd` or static output is fabricated. |
| scripts, experiments, docs | Authored architecture, package-dependency generator and frozen measured-transition renderer. Helpers/templates/history remain qualified; renderer receipt tests do not prove a fresh browser/export execution. |
| #524 leads | Historical branch-only leads are not admitted as current functionality without current-source proof. |

Agent discovery should start with mixed `find`, inspect a typed `show`, follow
`related`, then open the producer and its tests. Scientific claims remain with
the data/code owner; figure editing and publication integration remain with the
format and thesis owners. A later optional graph adapter must preserve these exact
edges and freshness identities; no global graph is required for these commands.

Each candidate has one primary topic and may have cross-tags:

- model;
- dataset and storage;
- target selection;
- view generation and policy;
- oracle, labels and learning;
- code architecture.

Candidate records point to source and dependency owners. They distinguish
protocol status (`current`, `proposed`, or `historical`) from evidence kind
(`measured`, `constructed`, `derived`, or `not-applicable`). Collections are
ordered views over candidate IDs; aliases retain duplicate or example paths
without creating a second metadata owner.

Each curated record's `description` separates `subject` (what is shown),
`encoding` (how marks and axes work), `reading_guide` (how to answer the reader
question), and `limits` (what the visual cannot establish). Aliases inherit the
canonical description; a variant may inherit it when it records a
`description_delta`. An alias cannot define a competing local description.

`[[report_bundles]]` registers a sealed report bundle once. Its validated
`ReportSnapshot` figures become distinct gallery records, and authored overlays
can classify and describe individual results. The stable gallery ID is derived
from the bundle and result IDs. `snapshot_sha256`, result support IDs, and the
canonical static export remain visible as evidence metadata. Bundle admission
uses the reporting package's cold reader, including typed snapshot and asset
validation; updating a manifest digest cannot make altered report content valid.
Overlays may add editorial classification and reading guidance, but cannot
replace the cold-derived snapshot, manifest, support IDs, asset paths, or kind.

Selection records map a thesis figure slot to a preferred candidate and a
reason. Preference does not imply scientific approval or active inclusion, and
it never rewrites an include. Optional review pointers and reviewed fingerprints
are evidence references; the gallery can report them current, stale, missing,
or unavailable but cannot authenticate a reviewer or advance workflow state.

## Status and inclusion

`status` derives render and fingerprint freshness from the candidate source,
declared data and notation dependencies, renderer configuration, and inspected
output. A source or relevant dependency change makes prior render/review evidence
stale. Unresolved dependency coverage remains visible instead of being reported
fresh.

Active inclusion is evaluated separately through `usage --document thesis` and
`usage --document slides`. Each command compiles the real publication with Typst
dependency output and writes an ignored receipt for the assets used by that
evaluation. A report result maps only to its selected static export. Inclusion
remains `unknown` or `stale` until a matching receipt exists. A catalog
preference, prospective section, figure label, or text search is not inclusion
proof. Inclusion IDs are recomputed from the receipt's verified dependency paths
and the current mapping; the receipt's stored ID list is checked rather than
trusted.

Native compositions inside a chapter use `usage_identity = "metadata"`:
explicit `usage` queries their evaluated `aria-figure-gallery` metadata and binds
that JSON alongside the PDF and dependency digests. Reading the chapter alone
cannot establish that either of two visual slots in it was emitted. Readback
checks these saved outputs and recomputes included identities without compiling;
old or altered proof stays unknown/stale. The three inline compositions are
source-only FIG records using the existing nonrender `helper` role; they are
chapter visuals, not reusable primitives or standalone render entrypoints. Their
full publication PDF supplies occurrence proof. Development badges are optional;
clean/submission output retains the original figure body without a visible badge.

The original research-update slide source is currently absent from main.
`usage --document slides` therefore fails with `source-missing`, without invoking
the compiler; inclusion stays unknown rather than becoming a negative result.
The historical deck PDF and its immutable source-commit link are retained in
[`pr458-publication-archive`](../../../experiments/archives/pr458-publications/README.md).
The advisor-meeting deck is a different publication and is not substituted.

With a fresh receipt, cards distinguish inclusion independently for the thesis
and slide deck. An absent receipt is `unknown`; changed dependencies, mappings,
or the evaluated PDF make it `stale`. Development inclusion does not establish
submission inclusion, which has a separate evidence gate.

Publication ownership follows the canonical source roots beneath
`docs/figures/`: `thesis/`, `seminar/`, and `archive/`. Thesis figure paths use
the chapter and section slugs from `docs/typst/thesis/sections/`; an optional
format segment such as `vector/` does not affect the displayed placement.

## Iteration and integration

Edit `.mmd` candidates through `aria-nbv-mermaid` and Typst candidates through
`typst-authoring`. Use a new variant ID when the scientific message or alternative
changes; use Git history for small visual revisions. Compare candidates at the
same intended thesis width and inspect critical encodings in grayscale.

When a favorite should enter the thesis, update the exact chapter include,
caption, alt text, label, and surrounding prose through `typst-authoring`; add
`academic-writing` when the lesson or claims change. Compile and inspect the
destination page, rerun `usage`, and reconcile the evaluated receipt. Proposed
protocols must remain identified as proposed until their executable owners say
otherwise.

For professor/student autoresearch iterations, use the mission template in
[`figure-gallery`](../../../.agents/skills/figure-gallery/SKILL.md). The installed
autoresearch workflow owns its lifecycle and architect approval; gallery
completion validation checks only result shape and output-file existence.

Build outputs must stay under the repository `.cache/` directory. Gallery
thumbnails use first-page SVG previews converted by Poppler `pdftocairo` from
the exact rendered PDF. Vector marks remain vector; raster image layers remain
embedded raster images. Mermaid uses the existing renderer’s native PDF output
to preserve HTML and math labels. The full PDF remains available for export,
including all pages. Render receipts hash both outputs, record the preview
format/page and converter version, and invalidate older PNG preview caches.
Completion validation checks structure and file existence; use `status`
separately to check current render and review fingerprints.


## Complete library accounting and consumer evidence

```sh
python3 scripts/figure_gallery.py audit
python3 scripts/figure_gallery.py app-usage --route aria_nbv/aria_nbv/app/panels/generation/candidate_proposals.py:render_candidate_proposals_page
python3 scripts/figure_gallery.py usage --document thesis
python3 scripts/figure_gallery.py build --gallery shared-ase-library
```

Use the provisioned repository environment. `audit` writes a reproducible
`library-audit.json` under the ignored gallery cache. It combines tracked paths
(including missing files), non-ignored untracked files, resolved catalog sources,
exports, supporting context, inputs and producer/test references. Report visuals
remain at their sealed owners. Pass `--additional-path` for explicitly discovered
consumer dependencies outside this scope; dynamic application execution and raw
datasets are not exhaustively inventoried. Unknown ownership fails accounting;
unknown scientific provenance or dates do not.

`--baseline <audit.json> --migrations <lineage.json>` reconciles a frozen inventory.
Lineage records use `old_path`, `new_path` and `action`: `git-mv`,
`untracked-move`, `duplicate-consolidation`, or a separately documented
`intentional-edit`. The latter requires unchanged pathname, exact old/new payload
hashes and a reason. Moves preserve content; tracking changes and content changes
are distinct evidence. These projections do not become another metadata registry.

The catalog includes retained assets whose scientific descriptions have not been
curated. Their `retained-uncurated` topic and `inventory-only` tags prevent
registration from implying recommendation or scientific acceptance. Preferred
collections remain independently authored. File, FIG and CAP counts differ.

`exports` lists retained alternate-format or legacy visual files owned by a FIG.
`context_files` records supporting family context; it does not assert that those
files generated the visual. `inputs` remains the actual dependency relation.
CAP records for command-line programs without a callable entrypoint explicitly
use `invocation = "script"` and `symbol = "__main__"`; AST validation does not run
the program.

Publication usage now binds evaluated figure metadata **and emitted image
sources** to the compiled publication. Dependency access alone cannot establish
emission. Typst image tokens are reconciled conservatively with dependencies;
ambiguous names or unresolved ownership remain unknown. Uninstrumented Typst
compositions can remain unknown even when other assets are resolved. Changed
image-query evidence invalidates the receipt.

App receipts bind explicitly selected source routes, identity mappings and
source hashes. They can establish source integration of literal assets or
identified producer outputs at display calls. Runtime display, global dispatch
reachability and unmatched route absence remain unassessed. Repeat `--route` for
a declared route set; a changed route or identity invalidates its receipt.

FIG cards and typed lookup show thesis and app evidence independently. Combined
views are both, thesis-only, app-only, neither-within-verified-scope or unresolved;
they require adequate evidence in both dimensions. CAP lookup describes producer
integration and treats direct publication occurrence as not applicable.

## Producer identity and completeness

`CAP:` identifies plotting functionality (including internal functions, classes
and contributing methods); `FIG:` identifies a concrete retained result or an
authored visual definition. A CAP may have no retained outputs. Export formats,
filter values and scene IDs do not mint capabilities. Class registration never
substitutes for registering its plotting methods. `USE:` remains authored placement
intent; evaluated thesis inclusion still requires a fresh `usage` receipt.

The catalog is the sole authored metadata owner. Each capability's exact
`source`/`symbol`, finite `output_keys` and `consumers` connect implementation to
view placements. Consumer rows name source, lexical symbol, kind, and the exact
display `line`/`end_line`; multi-output sites also declare `output_key`.
`output_figures` optionally narrows known FIG relationships by view key.
Private definitions use `visibility = "internal"`; registration does not make
them public interfaces. Explicit `coverage_classifications` explain individual
non-producing candidates, fixtures, non-plot documents and generated adapters.
They are exact locators with reasons, not folder-wide exemptions.

From the repository root with its prepared Python environment:

```sh
python scripts/figure_gallery.py identity CAP:cap-population-target-distance
python scripts/figure_gallery.py identity CAP:cap-s2 --output-key frustum
python scripts/figure_gallery.py identity-resource
python scripts/figure_gallery.py identity-resource --check
python scripts/figure_gallery.py coverage --check --output /tmp/figure-coverage.json
```

The coverage command independently enumerates producer candidates, Streamlit
displays and retained/authored visuals across tracked and nonignored project
files, including scripts, experiments and notebooks. Use repeatable
`--additional-path` for intentional ignored inputs. Nonignored agent execution
artifacts are reported separately as outside project scope. Static recognizers
and exact source review establish this declared census; arbitrary Python dynamic
execution is not proved. Parse failures, missing identities, missing view keys,
wrong/missing display adapters and stale classifications fail `--check`.
Descriptions and scientific acceptance remain separate editorial gates.

The generator produces package-local
`aria_nbv/reporting/_figure_identity.json`, a derived projection, never another
authored registry. Commit it with catalog/source changes and check freshness.
The installed runtime reads metadata lazily without importing plotting modules or
loading stores. `plot_identity(function_or_class, output_key=...)` resolves exact
defining callables; `source_identity(source, symbol, output_key=...)` handles
explicit nonimportable origins. Bound/inherited methods, partials, class/static
methods and transparent wrappers follow the documented source contract; ambiguous
copied wrapper names fail instead of silently selecting another producer.

Streamlit consumers pass `producer=` and `output_key=` to `render_plot`, or call
`render_plot_identity` before native displays. This caption seam preserves chart
payloads, data selection and lazy dispatch. Sealed report identities match both
snapshot hash and result ID; current-builder live reports use source-owned exact
section/result bindings. Historical unknown lineage remains unknown. Restart a
running validation app after regenerating its loaded metadata resource.

Reviewed coverage classifications include an `evidence_sha256` witness: a
location-free, explicitly normalized AST for a producer or display scope, or a logical asset-payload
hash (the LFS OID when unmaterialized). A changed helper cannot reuse an old
non-producer classification. Ordinary generation never refreshes these authored
witnesses; review the source and its reason before deliberately updating one.
The AST representation preserves meaningful fields while normalizing optional
version-only fields, so identical source has the same witness on supported
Python versions. A hash-format migration must first verify the old witness
against unchanged reviewed source; it is not an automatic refresh operation.

Retained `*.plotly.json` is included in visual accounting. Same-Figure serialized
exports share their manifest/publisher-proven FIG. Independent Matplotlib and
interactive Plotly representations remain distinct FIGs, even when they show
the same declared camera coordinates. Byte-equal copies preserve their locations
and qualified provenance; equality alone does not prove independent or identical
scientific inputs. Explicit gallery builds render serialized assets through the
existing report static renderer into the ignored cache; cold lookup never does.

The shared reporting decoder can adapt unsupported, unused legacy Plotly
template defaults in memory. Active data/styles still undergo strict validation;
saved JSON and bundle hashes stay unchanged. Build logs name omissions, and the
renderer fingerprint includes the compatibility policy and decoder source.

The standard local `make figure-gallery-check` target runs `figure-identity-check`
first, so new producer, display and retained-asset gaps cannot bypass the normal
gallery verification route. No hosted workflow is dispatched by these targets.
