Skip to content

Casabio integration handoff: green build/tests + complete SearchResult migration - #1

Open
capebio wants to merge 35 commits into
mainfrom
alex/casabio-integration
Open

capebio wants to merge 35 commits into
mainfrom
alex/casabio-integration

Conversation

@capebio

@capebio capebio commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

Prepares JOSE (implementation, the NestJS backend) for Casabio integration handoff. Brings main's 34 unpushed commits + this branch to a green typecheck/build/test state, and commits the phylogeny module that was wired into app.module.ts but left untracked (a fresh clone would not have built).

Root cause of the red state was one half-finished refactor: feat/elastic-facets changed SearchPort.search() from SearchDoc[]SearchResult { hits, total, facets } but not every consumer was migrated.

Changes

  • desk.service.ts — spread .hits instead of the SearchResult object. This was a real runtime bug: [...SearchResult] throws (non-iterable), so the Desk endpoint failed live, not only in tests.
  • search.spec — destructure .hits from query().
  • federation.specawait resolvePerson (now async); wire ConfigService + persistence context (FederationModule now imports KnowledgeObjectModule for preprint ingest).
  • export.spec / review.spec — pass the new 4th constructor dependency (KnowledgeObjectRepo / KnowledgeObjectService).
  • phylogeny/ — commit the backend + frontend module (app.module.ts already imported it) so the repo builds from a clean clone; provide ConfigService in its spec.
  • Deferred implementation plans added.

Verification

  • tsc --noEmit -p tsconfig.json — clean
  • tsc -p tsconfig.build.json — clean
  • jest20 suites / 138 tests pass (was 7 suites / 6 tests failing)

Notes

  • The author.casabio.org deploy target is the separate jose-author app (Bun/SQLite), now at private repo capebio/jose-author — not this repo.
  • Production deploy work (OAuth, reverse proxy, persistent storage, Litestream, secrets, live smoke) remains and belongs to jose-author.

🤖 Generated with Claude Code

capebio and others added 30 commits July 13, 2026 00:57
…n ExternalIdsDto

- Add altText?: string to ContentBlock (types.ts) and MediaObjectMeta (ports.ts)
  with WCAG 1.1.1 JSDoc; mirrors the authored-field-wins pattern.
- Add altText?: string to UploadMediaDto (media.dto.ts) with @IsOptional/@IsString.
- LightboxViewer: accept altText prop; when present it wins over the
  caption/taxon-derived fallback (backward compat preserved).
- Add ror, rrid, lsid optional string fields to ExternalIdsDto (identity-trust.dto.ts)
  with descriptive JSDoc; update IdentityRecord.externalIds comment in types.ts.
- Extend NomName.registration comment to include mycobank|lsid; same in
  CreateNameDto (taxonomy.dto.ts).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds structural synonym linkage — a junior/invalid name now points
directly to its accepted name and basionym. Previously "synonymy"
existed only as a free-text actType string on NomenclaturalAct.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ogeny wiring

D1 (RESOLVED 2026-07-11 a): AccessGrant gains an explicit scope field
(AccessGrantScope) supporting per-KO working-set grants over a list of
observationIds. activeGrants in pg + memory repos match scope.observationIds.
Migration 003_access_grant_scope.sql adds the scope JSONB column.

D2: ContentBlock.aiOriginalHash pins the sha256 of AI-authored text at
first recording; origin.ts houses the D2 swap-point logic.

Map: locality.service.ts map() now includes micro-observations sharing
the treatment's taxon concept (not only direct ko matches), so the
flagship distribution map populates from linked micro-obs KOs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- altText on ContentBlock + MediaObjectMeta + UploadMediaDto + LightboxViewer
- ror/rrid/lsid fields on ExternalIdsDto (WCAG 1.1.1 + research resource PIDs)
- NomName.registration comment expanded to include mycobank|lsid
- IdentityRecord.externalIds comment updated with ror/rrid/lsid

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolved conflict: kept mycobank|lsid in registration comment (from
type-model-additions) and added synonymyOf/basionymOf fields (from
synonymy-linkage). Additive, non-overlapping changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds DwcRecord type + renderDwc() producing GBIF-compatible occurrence
records from ObservationPublic projections. Endpoint supports ?format=json
(default) and ?format=tsv. Coordinates are QDS-cell centroids (~14km
uncertainty) — precise coords never leave the system.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces post-hoc soft filtering with proper Elastic bool+filter queries
and terms aggregations. SearchResult now includes hits + total + facets
(koType, tier, status, locality buckets). New filter params: tier, taxon,
localityQDS. Fixes localityQDS + tier population at index time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
GBIF-compatible occurrence export from ObservationPublic projections.
Supports ?format=json (default) and ?format=tsv. Coordinates are QDS
cell centroids (~14km uncertainty). Endpoint is @public (no JWT needed
for harvesters). scientificName + recordedBy TODO pending repo injections.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replaces top-1000 soft-filter with bool+filter Elastic queries and
terms aggregations. SearchResult now includes hits/total/facets
(koType, tier, status, locality buckets). New filter params: tier,
taxon, localityQDS (prefix match). Fixes localityQDS+tier population
at index time for micro-observation and method KOs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds BOLD (barcode/BIN), eBird observation, bioRxiv/EcoEvoRxiv/OSF
preprint, and MycoBank taxon stubs. All follow the offline-stub pattern;
live fetches gated behind federation.live (off in v1).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds CreditRole union (14 CRediT types) and contributions field on
KnowledgeObjectContent. Adds ontologyTerms on Claim and TaxonConcept
for ENVO/PATO/GO controlled vocabulary binding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the DwC-aligned Specimen type, SpecimenRepo port, Pg and Memory
adapters, DB migration 005, and the /specimens module with upsert
semantics on (institutionCode, catalogNumber).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Aggregates exportCount and citationCount from the provenance ledger
('exported' and 'cited' events). Public endpoint GET /ko/:id/stats
returns KoStats. Desk stats extended with totals.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Capture.tsx now queues observations in a local PouchDB outbox when
offline or when the API call fails. Auto-syncs on reconnect. Closes
the gap where UI promised local queuing but posted directly to the API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds GET /citation/cited-by?ref=ko:… querying provenance 'cited' events
for inbound citations. CitationRepo gains citedBy() on both pg and memory
implementations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tors

BOLD (barcode/BIN), eBird, bioRxiv/EcoEvoRxiv/OSF preprints, MycoBank.
All offline stubs; live fetches gated behind federation.live (off v1).
PreprintParamDto + GET /federation/preprint/:system/:id endpoint.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Capture.tsx now queues observations locally when offline or on API
failure. jose_outbox PouchDB db. Auto-syncs on online event, component
mount, and app startup. Closes gap where UI promised local queuing but
posted straight to the API.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
KoStats interface (exportCount, citationCount, viewCount, lastActivity).
statsForKo() fans out to provenance events per version. Public endpoint
GET /ko/:koId/stats. Desk stats extended with totalExports + totalCitations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CitedByEntry type + citedBy() on CitationRepo (pg + memory). GET
/citation/cited-by?ref=ko:… (query param avoids colon routing issues).
createSnippet now stores citingKo+citingVersion in provenance detail.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
CreditRole union type (14 terms), contributions on KnowledgeObjectContent,
ontologyTerms on TaxonConcept (stored in circumscription JSONB, no migration).
SetContributionsDto + ContributorRolesDto; taxonomy DTOs/service/controller pass
ontologyTerms through.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Specimen type + SpecimenRepo port + PgSpecimenRepo/MemorySpecimenRepo adapters.
SpecimenModule: POST /specimens (verified), GET /specimens/:id and ?institution=CODE (public).
DB migration 005_specimen.sql. Wired into persistence.module.ts + app.module.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
JATS output gains <contrib-group> with <role vocab="credit"> elements per
CRediT spec (NISO). Markdown export appends a "Contributor roles" line.
Uses version.content.contributions (Record<authorRef, CreditRole[]>).
JATS output gains <contrib-group> with <role vocab="credit"> per NISO spec.
creditTermUrl() maps role name to NISO URI. Markdown appends contributor
roles line. Uses version.content.contributions Record<authorRef, CreditRole[]>.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… descendants

Adds KnowledgeObjectRepo.listForkDescendants(). VersioningService.retract()
now fans out 'cited-retracted' and 'fork-source-retracted' provenance events
to all KOs that cited or forked from the retracted content. Two new
ProvenanceAction values added to the union type.
… forks

listForkDescendants() on KnowledgeObjectRepo (memory + Couch adapters).
retract() fans out 'cited-retracted' and 'fork-source-retracted' provenance
events to all KOs that cited or forked from the retracted content.
Two new ProvenanceAction values added to the union type.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…w-as-KO

DoiRegistrar port (stub + live DataCite API v2). VersioningService.tagVoR
calls registrar after transaction commits. GET /ko/:id/schema.org returns
JSON-LD ScholarlyArticle/Dataset. POST /reviews/:id/mint-ko mints peer
reviews as citable KOs.
… Review-as-KO

DoiRegistrar port with DataCiteRegistrar (live) and NoopDoiRegistrar (test).
tagVoR calls registrar outside the UoW transaction so a DataCite failure
never rolls back the DB. GET /export/:koId/schema.org returns JSON-LD
ScholarlyArticle/Dataset. POST /reviews/:id/mint-ko mints peer reviews as
citable KOs of type 'review'.

Conflict resolved: versioning.service.ts imports CitationRepo + DoiRegistrar
(both branches added distinct injections — merged additively).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
plan-vector-search.md: pgvector semantic search with embedding service
plan-casa-wasm.md: WASM media pipeline (EXIF strip + JXL derivatives)
plan-ai-triage.md: async AI review triage + species ID via vision model
plan-preservation.md: CLOCKSS SFTP deposit after tagVoR

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…egister

Adds 'preregistered' to VersionStatus and ProvenanceAction unions.
VersioningService.preregister() mints a public timestamped version with
status='preregistered' -- the immutable registered report record.
POST /ko/:id/preregister endpoint added (verified assurance required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FederationService gains ConfigService injection. resolvePerson() goes live
for ORCID when federation.live=true, calling pub.orcid.org/v3.0/{id}/record.
Falls back gracefully to stub with liveAttempted:true on API failure.
GET /identity/verify-orcid/:id added (verified assurance required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
capebio and others added 5 commits July 14, 2026 03:54
'preregistered' added to VersionStatus and 'preregister' to ProvenanceAction.
VersioningService.preregister() mints a public immutable version with
status='preregistered'. POST /ko/:id/preregister added (verified required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
FederationService gains ConfigService. resolvePerson() goes live for ORCID
when federation.live=true, fetching pub.orcid.org/v3.0/{id}/record.
Graceful fallback to stub with liveAttempted:true on API failure.
GET /identity/verify-orcid/:id added (verified assurance required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…m/:id/ingest

buildPreprintContent() produces stub KnowledgeObjectContent from a preprint
reference. POST endpoint mints a private Commons KO of type ''article'' from
the stub, returning federatedRef + entity + version. Requires verified
assurance.
…/preprint/:system/:id/ingest

buildPreprintContent() produces stub KnowledgeObjectContent from a preprint
reference. POST endpoint mints a private Commons 'article' KO from the stub,
returning federatedRef + entity + version. Requires verified assurance.
KnowledgeObjectModule imported into FederationModule via forwardRef.

Conflict resolved: federation.service.ts imports ConfigService (orcid-live)
+ KnowledgeObjectContent type (preprint-ingest) — both additive.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… build/tests)

The elastic-facets change made SearchPort.search() return SearchResult
{hits,total,facets} instead of SearchDoc[], but not all consumers were
migrated, leaving main red (typecheck + build + 7 failing test suites).

- desk.service.ts: spread .hits (was spreading a non-iterable SearchResult
  -> the Desk endpoint threw at runtime, not only in tests)
- search.spec: destructure .hits from query()
- federation.spec: await resolvePerson (now async) and wire ConfigService +
  persistence context (FederationModule now imports KnowledgeObjectModule)
- export.spec / review.spec: pass the new 4th constructor dependency
  (KnowledgeObjectRepo / KnowledgeObjectService)
- commit the phylogeny module (backend + frontend) that app.module.ts already
  imported but was left untracked, so a fresh clone builds

Result: tsc --noEmit clean, tsc -p tsconfig.build.json clean,
jest 20 suites / 138 tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant