Skip to content

Release CyteTypeR 0.6.0: evidence fields, timeouts, v5 layers, BSD-3 - #57

Merged
parashardhapola merged 4 commits into
masterfrom
release-0.6.0
Oct 18, 2026
Merged

parashardhapola merged 4 commits into
masterfrom
release-0.6.0

Conversation

@parashardhapola

Copy link
Copy Markdown
Member

Summary

Full details are in NEWS.md. Highlights:

Results

  • Evidence columns are populated again.
  • New table columns reviewerConfidence, isHeterogeneous and heterogeneityType, and a new <prefix>_reviewerConfidence_<group_key> meta.data column.
  • Failed clusters no longer crash CyteTypeR().
  • Other prefixes no longer overwrite misc$cytetype_results.

Waiting for jobs

  • timeout_seconds is enforced and raises cytetype_timeout_error.
  • Network errors are retried until the timeout.
  • GetResults(job_id=) returns NULL while a job is still running.
  • API failures raise cytetype_api_error with an error_code, and the server's error messages are kept.

Data preparation

  • Seurat v5 split layers and a non-RNA default assay work.
  • Missing cluster labels stop early with a clear error.
  • Coordinates fall back from umap to tsne to pca.
  • Raw counts are written only when they are whole numbers.
  • Gene-ID warnings now work.
  • DuckDB uses a private temp directory.

Other

  • visibility argument; the deepseek, nebius and together providers.
  • cytetyper login works, reading the key from stdin.
  • The rate-limit message is fixed.
  • duckdb, SeuratObject and withr are required; R >= 4.2.
  • BSD 3-Clause license; the docs moved to https://docs.nygen.io/CyteType/.

Testing

  • devtools::test(): 764 passed, 0 failed. The one skip is the installed-launcher test.
  • R CMD check --as-cran: 0 errors, 0 warnings, 0 notes. This was run locally on Linux only, with the qpdf and clock checks stubbed, so please watch the macOS and Windows CI runs.

Merge

Merging releases 0.6.0 to install_github users immediately. Merge on the day the docs site goes live, then push tag v0.6.0 and create the GitHub Release with the NEWS.md notes.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Release CyteTypeR 0.6.0 with restored evidence and reliable job handling

🐞 Bug fix ✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Restore result evidence, add reviewer fields, and retain annotations when clusters fail.
• Enforce polling timeouts, improve API errors, and support Seurat v5 split layers.
• Expand regression coverage and release documentation under the BSD 3-Clause License.
Diagram

graph TD
  A["Seurat object"] --> B["Data preparation"] --> C["Upload artifacts"] --> D["CyteType API"] --> E["Result normalization"] --> F["Seurat results"]
  G["GetResults"] --> D
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Normalize results only on the server
  • ➕ One authoritative implementation of evidence mapping.
  • ➖ Previously stored results and older server responses still need client-side compatibility handling.
  • ➖ R behavior would depend on server deployment timing.
2. Join Seurat layers on the caller's object
  • ➕ Simplifies repeated access to joined expression layers.
  • ➖ Mutates user data and can add memory and serialization costs.

Recommendation: Keep client-side, fill-only normalization and join split layers on a local copy. These choices support historical results without changing users' objects; maintain parity with the server and Python client as the rules evolve.

Files changed (42) +4737 / -1001

Enhancement (2) +417 / -154
cytetype.RIntegrate normalized results and improve job retrieval +414/-154

Integrate normalized results and improve job retrieval

• Adds visibility, prefix-safe result storage, reviewer metadata, failed-cluster handling, and job-ID recovery hints. GetResults checks status before fetching, returns NULL for unfinished jobs, and can skip JSON output; preparation uses aligned RNA data and coordinate fallbacks.

R/cytetype.R

schema.RAccept three additional LLM providers +3/-0

Accept three additional LLM providers

• Adds deepseek, nebius, and together to the accepted provider names.

R/schema.R

Bug fix (7) +1275 / -246
api.RPreserve API error details during result requests +44/-20

Preserve API error details during result requests

• Handles non-success responses explicitly, retaining server messages and error codes in typed conditions. Distinguishes network failures and leaves HTTP 202 responses available for processing-state handling.

R/api.R

artifacts.RGuard raw counts and isolate DuckDB writes +50/-9

Guard raw counts and isolate DuckDB writes

• Omits non-whole-number raw counts rather than truncating them. Uses a cleaned-up private spill directory and avoids a shared DuckDB home when supported.

R/artifacts.R

auth.RRead non-interactive login keys from stdin +70/-3

Read non-interactive login keys from stdin

• Allows Rscript and cytetyper login to accept typed or piped keys, disabling terminal echo where supported. Clarifies the dashboard fallback documentation.

R/auth.R

client.REnforce polling deadlines and classify fetch failures +117/-21

Enforce polling deadlines and classify fetch failures

• Measures elapsed time in seconds, raises a job-specific timeout condition, and retries network failures until the deadline. Propagates completed-job fetch errors and treats HTTP 202 as processing.

R/client.R

errors.RRetain server error codes and readable messages +110/-17

Retain server error codes and readable messages

• Extends cytetype_api_error with error_code and corrects its displayed condition call. Parses structured, plain-text, and validation-error responses and corrects rate-limit guidance.

R/errors.R

normalization.RNormalize historical and current cluster results +472/-0

Normalize historical and current cluster results

• Adds fill-only recovery of evidence from structured output, reviewer and heterogeneity fields, and preservation of raw annotations. Builds stable per-cluster tables while omitting clusters without annotations.

R/normalization.R

seurat_helpers.RSupport split RNA layers and safe result integration +412/-176

Support split RNA layers and safe result integration

• Joins Seurat v5 layers on a copy, validates cluster labels, improves gene-ID warnings and coordinate selection, and preserves the caller's random stream during sampling. Stores results by prefix and adds reviewer-confidence metadata.

R/seurat_helpers.R

Tests (14) +2402 / -8
helper-results.RAdd cross-generation result and Seurat fixtures +316/-0

Add cross-generation result and Seurat fixtures

• Provides legacy, structured, reviewed, malformed-cluster, JSON-round-trip, and small Seurat fixtures for regression tests.

tests/testthat/helper-results.R

test-api.RTest server errors and corrected rate-limit advice +160/-2

Test server errors and corrected rate-limit advice

• Covers structured, plain-text, and validation errors, network classification, code preservation, and submission/upload error messages.

tests/testthat/test-api.R

test-auth.RCheck unauthenticated dashboard fallback +18/-0

Check unauthenticated dashboard fallback

• Verifies that opening the dashboard without saved credentials targets the /dashboard URL.

tests/testthat/test-auth.R

test-cleanup.RTest artifact cleanup outcomes +23/-0

Test artifact cleanup outcomes

• Checks removal and repeat calls for built artifacts, plus the no-op return when files were not built.

tests/testthat/test-cleanup.R

test-cli.RExercise piped and terminal CLI login +196/-0

Exercise piped and terminal CLI login

• Tests stdin credentials, hidden terminal entry, empty input, interactive prompting, and a non-interactive subprocess. Includes an installed-launcher integration test when available.

tests/testthat/test-cli.R

test-client.RTest polling deadlines and failure handling +209/-1

Test polling deadlines and failure handling

• Uses mocked clocks and requests to cover seconds-based timeouts, network retries, five-error limits, HTTP 202, job-ID hints, and completed-job fetch failures.

tests/testthat/test-client.R

test-cytetype-build-upload.RTest visibility and interruption recovery +114/-0

Test visibility and interruption recovery

• Checks top-level visibility serialization and validation, default omission, and the job-ID hint on interruption.

tests/testthat/test-cytetype-build-upload.R

test-gene-symbols.RTest database gene-ID warnings +91/-0

Test database gene-ID warnings

• Covers Ensembl, RefSeq, numeric, and long identifiers, plus marker-table and RNA feature-metadata warning behavior.

tests/testthat/test-gene-symbols.R

test-get-results.RTest status-aware GetResults behavior +275/-0

Test status-aware GetResults behavior

• Verifies unfinished and missing jobs, HTTP 202, optional JSON output, normalized results, and typed status/results errors.

tests/testthat/test-get-results.R

test-normalization.RTest evidence and reviewer normalization +433/-0

Test evidence and reviewer normalization

• Covers legacy and newer result generations, fill-only and idempotent behavior, malformed fields, duplicate IDs, missing annotations, and preservation of raw data.

tests/testthat/test-normalization.R

test-prepare.RTest Seurat preparation and artifact correctness +298/-0

Test Seurat preparation and artifact correctness

• Exercises split and legacy assays, non-RNA defaults, missing clusters, coordinate fallbacks, sampling, whole-number counts, and private DuckDB spill cleanup.

tests/testthat/test-prepare.R

test-results-seurat.RTest per-cluster tables and per-cell annotations +245/-0

Test per-cluster tables and per-cell annotations

• Checks evidence and reviewer columns, failed-cluster defaults, table attributes, legacy columns, and isolation of alternate result prefixes.

tests/testthat/test-results-seurat.R

test-save-vars-h5.RRemove obsolete skipped HDF5 guard test +0/-5

Remove obsolete skipped HDF5 guard test

• Deletes a skipped test for the removed direct rhdf5filters availability guard.

tests/testthat/test-save-vars-h5.R

test-schema.RTest providers and visibility serialization +24/-0

Test providers and visibility serialization

• Checks the added provider names and preservation of top-level visibility in the prepared query.

tests/testthat/test-schema.R

Documentation (17) +587 / -551
LICENSEUpdate license attribution +3/-2

Update license attribution

• Sets the copyright period and identifies Nygen Analytics AB as the holder and organization.

LICENSE

LICENSE.mdReplace MIT terms with BSD 3-Clause terms +29/-37

Replace MIT terms with BSD 3-Clause terms

• Provides the BSD 3-Clause license text in place of the MIT license and embedded API-use notes.

LICENSE.md

NEWS.mdDocument the 0.6.0 release +164/-0

Document the 0.6.0 release

• Records changes to results, polling, data preparation, authentication, packaging, and documentation, including compatibility behavior.

NEWS.md

CyteTypeR-package.RAdd package-level workflow and license help +37/-0

Add package-level workflow and license help

• Introduces package documentation covering sign-in, preparation, submission, retrieval, the documentation site, and service licensing.

R/CyteTypeR-package.R

cli.RExplain stdin-based CLI login +4/-1

Explain stdin-based CLI login

• Updates login help to describe terminal echo behavior and provide a piped-key example.

R/cli.R

README.mdRefresh release requirements and documentation links +29/-8

Refresh release requirements and documentation links

• Updates R and license badges, describes the new results, links to the shared documentation site, and separates package licensing from service terms.

README.md

configurations.mdRedirect configuration guidance to shared documentation +6/-110

Redirect configuration guidance to shared documentation

• Replaces the local guide with links for sign-in, LLM setup, job settings, CLI use, and the R reference.

docs/configurations.md

get-started.mdRedirect the getting-started guide +7/-180

Redirect the getting-started guide

• Replaces the local walkthrough with links to the shared R quickstart, preparation, results, installation, and API reference.

docs/get-started.md

CleanUpArtifacts.RdDocument artifact cleanup return values +13/-1

Document artifact cleanup return values

• Explains which files are deleted and the invisible Boolean return value; adds a workflow example.

man/CleanUpArtifacts.Rd

CyteTypeR-package.RdGenerate package-level reference page +66/-0

Generate package-level reference page

• Adds generated help for the package workflow, external documentation, licensing, and related functions.

man/CyteTypeR-package.Rd

CyteTypeR.RdDocument submission options and result storage +64/-10

Document submission options and result storage

• Describes visibility, timeout behavior, reviewer confidence, prefix-specific storage, evidence, and recovery after polling failures.

man/CyteTypeR.Rd

GetResults.RdDocument status-aware result retrieval +55/-3

Document status-aware result retrieval

• Covers save_json, the different return forms, unfinished jobs, and typed API failures.

man/GetResults.Rd

LoginCyteTypeR.RdDocument non-interactive key entry +5/-1

Document non-interactive key entry

• Explains stdin input and platform-dependent terminal echo for login.

man/LoginCyteTypeR.Rd

OpenCyteTypeDashboard.RdCorrect the dashboard fallback URL +2/-1

Correct the dashboard fallback URL

• Specifies the /dashboard path used when credentials are absent.

man/OpenCyteTypeDashboard.Rd

PrepareCyteTypeR.RdDocument RNA and artifact preparation requirements +48/-16

Document RNA and artifact preparation requirements

• Clarifies split layers, required clusters and RNA data, coordinate fallbacks, whole-number counts, and the prepared payload.

man/PrepareCyteTypeR.Rd

cytetype_api_error.RdDocument typed API error fields +31/-5

Document typed API error fields

• Describes the optional server error code, error origin, condition behavior, and handling example.

man/cytetype_api_error.Rd

get-started.RmdShorten the installed getting-started vignette +24/-176

Shorten the installed getting-started vignette

• Replaces the long walkthrough with a brief, non-executed workflow and links to the shared R quickstart and reference.

vignettes/get-started.Rmd

Other (2) +56 / -42
DESCRIPTIONSet 0.6.0 release metadata and requirements +24/-12

Set 0.6.0 release metadata and requirements

• Bumps the version, expands package metadata and documentation links, and declares BSD licensing. Requires R 4.2, duckdb, SeuratObject, and withr while removing unused imports.

DESCRIPTION

NAMESPACERegenerate imports and API error method registration +32/-30

Regenerate imports and API error method registration

• Registers the API conditionCall method and removes imports no longer used after the Seurat and result-handling changes.

NAMESPACE

@qodo-code-review

qodo-code-review Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Job requests exceed the wait deadline 🐞 Bug ≡ Correctness
Description
.poll_for_results() checks elapsed time only before making a status-and-results request, using >
rather than >=, and does not check again before returning a completed result. A request that
starts just before timeout_seconds can finish after the deadline and still return successfully;
short timeouts also wait through the unconditional five-second initial sleep.
Code

R/client.R[R436-437]

+    # difftime() picks its units automatically; always compare seconds.
+    elapsed <- as.numeric(difftime(.now(), start_time, units = "secs"))
Evidence
The timer starts before the fixed initial sleep, but the loop checks it only before
.make_results_request(). The completed branch returns the response without another time check,
while the public documentation promises a maximum wait.

R/client.R[406-410]
R/client.R[434-445]
R/client.R[470-482]
R/cytetype.R[360-365]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The polling deadline is checked only before a request, so a completed response can be returned after `timeout_seconds`, and the initial sleep can exceed short timeouts.

## Fix Focus Areas
- R/client.R[406-410]
- R/client.R[434-445]
- R/client.R[470-482]

## Recommended Fix
Use an absolute deadline for the initial wait and each polling iteration. Limit waits and requests to the remaining time, check the deadline again before returning results, and treat reaching the deadline as a timeout.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗


2. A brief server hiccup at the end aborts the wait ✓ Resolved
Description
When a completed job's results request returns any HTTP error, including a temporary 502/503/504 or
a 429 rate limit, .make_results_request marks it "failed" unless condition$call is
"network". The "failed" branch of .poll_for_results then stops at once. The same transient
status on the status endpoint is retried up to five times, so one gateway blip after a long wait (up
to timeout_seconds, 7200s by default) ends CyteTypeR() with an error and no annotations, and the
user has to recover with GetResults() by hand.
Code

R/client.R[R279-286]

+          condition <- .as_fetch_error(e, "Error while fetching job results")
          make_response(
-            "failed",
-            message = paste("Job completed but results unavailable:", e$message),
-            raw = status_data
+            # Network errors are retried while waiting; others end the wait.
+            if (identical(condition$call, "network")) "error" else "failed",
+            message = conditionMessage(condition),
+            raw = status_data,
+            error_type = condition$call,
+            condition = condition
Evidence
.api_response_helper turns every non-2xx, non-404 response (including 5xx and RATE_LIMIT_EXCEEDED)
into cytetype_api_error(call = "api"). In .make_results_request, the results-fetch handler maps
every non-network condition to status "failed". In .poll_for_results, the "failed" branch calls
stop(status_response$condition) with no retry. The "error" branch, which handles the same errors
from the status endpoint, allows five consecutive attempts. The repo already treats 500/502/503/504
as transient for uploads (.CHUNK_UPLOAD_TRANSIENT_STATUSES).

R/api.R[78-98]
R/client.R[272-292]
R/client.R[481-501]
R/client.R[526-555]
R/api.R[9-11]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
When fetching the results of a completed job, any HTTP error that is not a network failure (for example 502/503/504 or 429) is marked as status "failed". `.poll_for_results` then stops immediately, while the same errors on the status endpoint are retried up to five times.

## Fix Focus Areas
- R/client.R[279-286]
- R/client.R[495-498]

## Recommended Fix
In the results-fetch error handler of `.make_results_request`, return status "error" (so the error counts toward `max_consecutive_errors`) when the condition is a network error, has `error_code == "RATE_LIMIT_EXCEEDED"`, or comes from an HTTP status in `.CHUNK_UPLOAD_TRANSIENT_STATUSES` (500/502/503/504). To support this, record the HTTP status on the `cytetype_api_error` in `.api_response_helper`, e.g. a `status_code` field. Keep "failed" for permanent errors such as 410 REPORT_DELETED. Update the NEWS and roxygen docs, which currently say a results-fetch error stops at once.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
Review mode: Auto: 🧠 Deep: Broad release changes span many independent, defect-prone logic paths.

Grey Divider

Tip of the day
💡 Did you know, you can move or hide resolved findings to focus on what still needs action

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread R/client.R Outdated
Comment on lines +436 to +437
# difftime() picks its units automatically; always compare seconds.
elapsed <- as.numeric(difftime(.now(), start_time, units = "secs"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Job requests exceed the wait deadline 🐞 Bug ≡ Correctness

.poll_for_results() checks elapsed time only before making a status-and-results request, using >
rather than >=, and does not check again before returning a completed result. A request that
starts just before timeout_seconds can finish after the deadline and still return successfully;
short timeouts also wait through the unconditional five-second initial sleep.
Agent Prompt
## Issue description
The polling deadline is checked only before a request, so a completed response can be returned after `timeout_seconds`, and the initial sleep can exceed short timeouts.

## Fix Focus Areas
- R/client.R[406-410]
- R/client.R[434-445]
- R/client.R[470-482]

## Recommended Fix
Use an absolute deadline for the initial wait and each polling iteration. Limit waits and requests to the remaining time, check the deadline again before returning results, and treat reaching the deadline as a timeout.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Dismiss ↗ | View ↗

Comment thread R/client.R
@parashardhapola parashardhapola mentioned this pull request Oct 18, 2026
@parashardhapola
parashardhapola merged commit 9ee3217 into master Oct 18, 2026
4 checks passed
@parashardhapola
parashardhapola deleted the release-0.6.0 branch October 18, 2026 22:55
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