# RNA-seq Sample-sheet Preflight (`l3digital/rnaseq-samplesheet-preflight`) Actor

Experimental checks on authorized inline RNA-seq CSV: row findings, exact sample-group conflicts and explicit coverage. Finite profile informed by nf-core/rnaseq 3.27.0; no FASTQ access, native validator execution or pipeline-readiness certification.

- **URL**: https://apify.com/l3digital/rnaseq-samplesheet-preflight.md
- **Developed by:** [L3Digital](https://apify.com/l3digital) (community)
- **Categories:** Developer tools, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.05 / useful rna-seq metadata receipt

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## RNA-seq Sample-sheet Preflight

Find metadata problems and conflicting rows for the same exact sample ID before
reviewing an RNA-seq sample sheet for a run. Supply a small authorized inline
CSV; one bounded report localizes row findings and sample-group conflicts with
explicit coverage, without opening FASTQ files or running a pipeline.

This experimental profile is informed by
[nf-core/rnaseq 3.27.0](https://github.com/nf-core/rnaseq/tree/3.27.0) and its
[nf-schema 2.7.2 pin](https://github.com/nextflow-io/nf-schema/tree/2.7.2).
It is not their native validator, an official endorsement, a complete
compatibility check or a pipeline-readiness certificate. Existing nf-schema,
workflow and local validation tools are strong substitutes; customer demand
and savings from this managed call remain unvalidated.

### Input

Use the always-uncharged synthetic demo:

```json
{"demo": true}
```

For real metadata, provide these exact keys:

In the Console form, turn off **Synthetic demo** before entering real metadata.

```json
{
  "processingPermission": true,
  "profile": "rnaseq-3.27.0-metadata-v1",
  "csvText": "sample,fastq_1,fastq_2,strandedness\n001,lane1_R1.fastq.gz,lane1_R2.fastq.gz,auto\n"
}
```

`demo` and `processingPermission` are actual booleans, default false. Real input
requires permission true and the exact profile. Demo requires profile and CSV
to be absent, even if empty/null, with permission false or absent. Unknown
keys, nulls, coercion, mixed modes, NUL and malformed Unicode are refused.
Only authorized metadata is accepted. No files, URLs, schemas, shell commands,
credentials or customer code are fetched or executed. Paths are inert strings.

Required headers are `sample`, `fastq_1`, `fastq_2`, `strandedness`, with optional
`seq_platform`, `seq_center`, in any order. Headers must be exact, unique and
unmodified; additional BAM or percent-mapped columns are outside this profile.
All data records must have the header width. Invalid structure refuses the
whole sheet, including any earlier well-formed rows.

Python's strict comma/double-quote CSV parser accepts LF/CRLF and quoted fields.
One leading UTF-8 BOM is removed and recorded; identifiers and cell values are
never trimmed, normalized, case-folded or numerically converted. Genuinely empty
records are skipped, while whitespace-filled records remain records. Record
numbers are logical data records starting at one, excluding the header and
skipped empty records; quoted newlines do not become additional records.
This chosen parser does not certify complete RFC grammar conformance.

### Selected checks and group coverage

Empty sample IDs fail `sample_required`; nonempty IDs with Unicode whitespace
fail `sample_whitespace`. C0/DEL controls anywhere in a cell fail `cell_control`,
including quoted newline/tab text. Invalid sample rows remain accounted for,
but are excluded from sample grouping. No ASCII-only or biological-identity
rule is applied. `001`, `1`, composed/decomposed Unicode and case variants remain
exact distinct identifiers.

The first read is required. Nonempty read filenames must end in case-sensitive
`.fq`, `.fastq`, `.fq.gz` or `.fastq.gz`, with no whitespace or slash in the
filename portion. Directory spaces can match the selected tagged filename
syntax. The mate can be empty for single-end metadata. Cell controls suppress
additional suffix findings for that cell. Filenames never establish actual
read pairing, read contents or file access. The selected tagged schema allows
uncompressed FASTQ and disallows sample whitespace; guide wording elsewhere
may differ. Native coercions and workflow behavior are unchecked.

Strandedness must be exactly `auto`, `forward`, `reverse` or `unstranded`.
Nonempty optional platform/center values must contain no Unicode whitespace.
Controls are checked separately. Empty optional values and absent optional
columns contribute the same empty metadata value.

Each eligible exact sample ID forms one group across its records. Groups are
ordered by first occurrence. Five fields are inspected: strandedness, platform,
center, endedness and compression. Valid contributing values produce
`consistent` or `conflict`; a relevant row finding in any contributing cell
produces `not_checked`. Endedness and compression depend on both read cells.
Compression checks both nonempty mates, so mixed compressed/uncompressed paths
within one record can conflict. Each conflict emits one group finding with all
of that group's logical record numbers. Every row and group field has explicit
coverage; excluded rows are never presented as group-checked.

No cross-sample path uniqueness, lane inference, biological replicate,
actual strandedness or clinical correctness check is performed.

### Full receipt and failures

After successful delivery, `REPORT` in the default key-value store and the one
full default dataset item contain identical JSON. Use the Output tab's
**Complete REPORT JSON** link, or retrieve
`GET /v2/key-value-stores/{defaultKeyValueStoreId}/records/REPORT` with appropriate
Apify authorization. Dataset table views summarize the receipt; the full JSON
contains row checks, findings, exact sample IDs, groups and coverage counters.
Raw paths and arbitrary exception strings are omitted. This is not anonymization.

Statuses are `complete`, `refused` and `failed`. A complete receipt means all
selected applicable checks finished, including explicitly excluded and
`not_checked` coverage. Findings yield `review_findings`; a receipt without
findings yields `no_findings_in_completed_checks` with its unchecked scope.
Refusals/failures yield `not_inspected` and a fixed reason. None of these outcomes
means valid, conformant, safe, ready or successful pipeline execution.

### Recover and retain this run's evidence

1. Use your authorized Apify caller to [start asynchronously](https://docs.apify.com/api/v2/actors-runs-post). Save the returned run `id` and a caller-generated request key in your own records before proceeding; retain `defaultKeyValueStoreId` and `defaultDatasetId` from the run response.
2. Check `GET /v2/actor-runs/RUN_ID` with that saved ID ([run API](https://docs.apify.com/api/v2/actor-run-get)). If a wait or retrieval times out, check the same run again. A failed or timed-out run can still have stored output; inspect it before deciding what to do.
3. Retrieve the authoritative full receipt with `GET /v2/key-value-stores/STORE_ID/records/REPORT`, using that run's `defaultKeyValueStoreId` as `STORE_ID` ([record API](https://docs.apify.com/api/v2/key-value-store-record-get)). Its equal dataset item is available at `GET /v2/datasets/DATASET_ID/items?format=json`, using `defaultDatasetId` ([dataset items API](https://docs.apify.com/api/v2/dataset-items-get)). Check `REPORT` during failure recovery even if dataset delivery failed.
4. Export the full typed JSON, parse it and verify the input binding and decision-required evidence before acting or cleaning up. Keep `catalogVersion`, `profile`, `input.sha256`, exact sample IDs, row/group findings and coverage. Preserve IDs such as `001` as strings. `complete` can include excluded rows and `not_checked` group fields; this contract has no `partial` status.

Do not silently POST again after a failed retrieval. If the initial start response was lost and no run ID is known, reconcile your authorized run history against your recorded request and input before considering a paid restart. A missing response does not prove no run started; this workflow promises no universal start idempotency.

A table or optional dataset field projection can support a limited notification, but it is not the full report. Retain the run/storage IDs, the identity and version/profile fields above, and relevant coverage; retrieve omitted detail from this same run before making a detailed decision.

#### Selective cleanup

After the run is terminal, no restart is planned and your exported evidence has been parsed and verified, you may remove authorized copies you no longer need. Use your saved exact storage IDs, never a latest-run shortcut or an assumed shared store. See Apify's [record deletion](https://docs.apify.com/api/v2/key-value-store-record-delete) and [dataset deletion](https://docs.apify.com/api/v2/dataset-delete) references for platform operations, which were not exercised in this Actor's QA: deleting `INPUT` leaves `REPORT`; deleting `REPORT` does not delete the dataset. Input records, REPORT records, dataset items and external copies are separate. Removing one does not erase logs, exports, saved task input, source files or customer copies, or guarantee provider-wide erasure.

### Limits, storage and price

| Bound | Maximum |
| --- | --- |
| Original UTF-8 CSV | 256 KiB (262,144 bytes) |
| Logical data records / columns | 2,000 / 6 |
| Sample and other metadata cells | 128 characters |
| Each read path cell | 4,096 characters |
| Serialized UTF-8 report | 1 MiB (1,048,576 bytes) |
| Adapter cancellation deadline / recommended platform timeout | 55 / 60 seconds |
| Candidate platform memory | 256 MiB |

If output exceeds its cap, the whole receipt is refused as `output_limit`;
no partial receipt is charged. Bounds are design choices, not measured maximum
resource or scalability guarantees. No native process, Java or Nextflow is needed.
SDK shutdown cleanup can continue after the 55-second cancellation deadline;
the separately configured platform timeout bounds the hosted run.

The current price is **$0.05 per useful report**. Useful means real, non-demo, complete
selected metadata checking with at least one parsed row. Metadata conflicts
and excluded-row findings can be useful results. Demo, refused and failed
receipts are uncharged. Equal REPORT and dataset copies precede at most one
eligible `report-produced` event. Storage, charge or deadline failures fail the
run without application replay; dataset redirects are disabled. SDK/platform
behavior remains outside any exactly-once storage guarantee.

Authorized input and output may persist in normal Apify storage. No automatic
deletion, original-input redaction, erasure or nonretention is promised.

# Actor input Schema

## `demo` (type: `boolean`):

Always uncharged; omit profile/csvText and leave permission false.

## `processingPermission` (type: `boolean`):

Required true for authorized real inline metadata.

## `profile` (type: `string`):

Required for real input. Selected checks informed by nf-core/rnaseq3.27.0; no native parity claim.

## `csvText` (type: `string`):

Required real input: exact sample,fastq_1,fastq_2,strandedness headers, optionally seq_platform/seq_center, in any order. Paths remain inert text.

## Actor input object example

```json
{
  "demo": true,
  "processingPermission": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

One full receipt after successful delivery, including explicit coverage gaps.

## `report` (type: `string`):

The same object as the dataset receipt.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "demo": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("l3digital/rnaseq-samplesheet-preflight").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "demo": True }

# Run the Actor and wait for it to finish
run = client.actor("l3digital/rnaseq-samplesheet-preflight").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "demo": true
}' |
apify call l3digital/rnaseq-samplesheet-preflight --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,l3digital/rnaseq-samplesheet-preflight"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fg9yUXib7JtLlFNIg/builds/yNcaOtQuyfvytoLdH/openapi.json
