Skip to main content
The Artifact Pool contains files published as queryable tables, and the data files of each Parable (A Parable’s data files). Each table has a namespace within its Workspace:
For example:
Workspace uploads use the reserved public namespace. The shorter artifacts.headcount is an alias for artifacts.public.headcount; it never searches other namespaces. Separate publications can use the same table name, such as artifacts.september.classifications and artifacts.october.classifications, without sharing data. Namespaces are stable SQL identities. Folders remain display organization and do not change a table’s SQL address.

Declared optional inputs

A Plot can declare an optional Artifact and its expected columns in its Perception contract. Only an absent declared table reads as an empty relation. A present table retains its rows and must satisfy the declared column types and nullability. Extra columns are allowed. Missing columns, incompatible types, unavailable publications, denied access, and explicit revision failures remain errors. A missing or incompatible column fails with QL-TB-005, and an unavailable publication or revision fails with QL-TB-006. Both are FAILED_PRECONDITION. An undeclared missing table remains an unknown relation. If the publication inventory cannot be read completely, Query Layer refuses optional fallback in publication namespaces until the inventory recovers. The fallback belongs to one Plot request. It does not appear in catalog listings or change another Plot’s input declaration. Generic SQL results carry known absent inputs in parable.warning.absent_optional_artifacts. Pane reads carry the same names in PlotDataMeta.absentOptionalArtifacts. Stored Reports keep the producer’s warning even when today’s Artifact inventory differs.

Publication revisions

Ordinary SQL, prepared statements, Flight metadata, and catalog discovery read each namespace’s active revision. A correction is a new revision of the same namespace. Queries keep reading the previous active revision until every table of the correction is ingested and someone activates it, so a failed replacement leaves the previous complete dataset in place. A Flight SQL request can read another revision instead, such as a staged correction waiting for QA, the verified tables of a failed revision, the previous revision, or one revision pinned across several queries. Name it in request metadata:
Separate several namespaces with commas. For that request, the named namespace’s tables resolve to the selected revision; other namespaces keep their active revision. A selection grants nothing: it resolves only among the revisions of the request’s Workspace, and the caller still needs access to the Artifact Pool. A revision the Workspace does not list fails as not found. A prepared statement runs only under the selection it was prepared with. A removed revision, and every revision of a deleted namespace, is no longer listed. A namespace keeps its active revision, the revision that was active before it, and every staged or failed revision until someone removes it. There is no expiry. When a revision is removed, its storage is deleted, except tables a kept revision still shares. Producers upload Arrow as their libraries write it. Parable converts every batch before it validates or writes a table: UTC or naive timestamps become microsecond timestamps without a time zone, UInt32 counts become Int64, and large and view strings become UTF-8. Values that would overflow or lose sub-microsecond precision, other time-zone labels, and types Parable cannot store fail the upload as an invalid schema. Parable derives each table’s schema from the converted data, and Reports read these timestamps as UTC. The JDBC 18.3.0 client must run with a UTC JVM default time zone to read these timestamps correctly.

Publish a complete dataset

Use these Workspace API operations to make an entire dataset available together:
  1. Call artifacts.reserveArtifactPublication with a namespace, revision ID, expected active revision, and every table’s name, row count, source size, format, and hash. Tables declare no schema: Parable derives it from the upload. A CSV table gets all-String columns, so send Arrow for typed columns. A table whose name, hash, and row count match the expected active revision’s table reuses its stored data: the receipt marks it reused, and it gets no upload URL.
  2. Upload each remaining CSV or Arrow IPC stream directly to its returned storage URL with the required headers.
  3. Call artifacts.finalizeArtifactPublication and poll artifacts.artifactPublicationReceipt. Each table’s outputSchema appears in the receipt once analysis derives it.
  4. Once every table is ingested, call artifacts.activateArtifactPublication. Until then, or until you activate it, the revision stays staged and QA can read it by selecting it. Activation checks the caller’s current permissions and switches the namespace to the complete revision in one transaction; it does not query the tables.
A failed replacement leaves the previous complete dataset available. Retry unchanged failed inputs with retryFailed; corrected inputs require a new revision ID in the selected namespace. Activation refuses a replacement whose expected active revision has changed. Activating a revision that is already READY returns its status and changes nothing, unless the request sets expectedActiveRevisionId to the current active revision: that switches back to it, which is how you roll back to the previous revision. artifacts.removeArtifactPublicationRevision removes a staged or failed revision that is not active and queues cleanup of its storage. artifacts.deleteArtifactPublication deletes the namespace: queries stop serving it, its slug becomes free for a new namespace, and durable cleanup of all its stored data is queued. Receipts of a removed revision or deleted namespace are no longer readable. Cleanup waits for issued upload URLs to expire.

Publish a table

An uploaded file becomes queryable in public after the Workspace:
  1. Reserves the upload with artifacts.prepareArtifactUpload, then sends the file directly to the returned signed storage URL using its required headers.
  2. Calls artifacts.completeArtifactUpload and waits for uploadStatus: ready. Parable verifies the file and saves a bounded sample and an all-String schema.
  3. Reviews that schema, optionally using artifacts.runArtifactSchemaInference or artifacts.updateArtifactDataSchema.
  4. Calls artifacts.publishArtifact with a new request ID, then polls the Artifact’s publishWork. The table becomes queryable only when that work succeeds. Values that cannot be converted to the reviewed schema fail publication; correct the schema or source and retry.
The app performs these steps and keeps processing status across page reloads. A repeated publication request with the same request ID and captured input returns its existing work. Unpublish hides the table and retains storage. Delete hides the Artifact and then removes its stored data. The upload and publication operations have no public reference page on this site. The developer site describes the requests, in Artifacts.

Schema inference and the model policy

runArtifactSchemaInference sends the CSV’s header row and up to five data rows to the model the Workspace’s model policy chooses for schema inference, on the AI processor that policy allows, and saves the column types it proposes. By default it runs on Gemini (gemini-3.5-flash-lite) in Google Vertex AI’s us multi-region, in the Workspace’s own Vertex AI project when it has one and a Parable-owned Google Cloud project otherwise. The result’s inference names the model and the processor that ran. When the policy allows no processor for schema inference, for example because a Workspace administrator switched Google Vertex AI off, nothing is sent to any processor. The call still succeeds: the Artifact’s schemaInferenceStatus becomes skipped_by_policy, the result’s inferenceRefusal names the reason, and the Artifact keeps the all-String schema from upload. Edit that schema with artifacts.updateArtifactDataSchema, then publish it as usual.

Upload limits

Each uploaded file can be up to 1 GB. Accepted formats are .csv, .xlsx, .xls, .numbers, .ods, and .zip. Only CSV supports preview, schema inference, and publication. Other formats remain storage-only uploads. An upload URL accepts only the reserved content type and exact size, and Parable checks the stored file before the Artifact is ready. Expired URLs require a new reservation. For an ordinary Workspace, file bytes go to the upload URL, not through the Workspace API.

Protected Workspaces

A protected Workspace keeps its files in a bucket that accepts only objects encrypted with the Workspace’s customer-supplied key (PARABLE-6436). The browser cannot hold that key, so prepareArtifactUpload returns the transport to use:
  • SIGNED_URL: send the file to the external signed URL with its required headers. Send no Parable cookies or credentials to it.
  • WORKSPACE_PROXY: uploadUrl is the same-origin path /api/sdk/workspace/<slug>/api/artifacts/uploads/<id>/content. Send the file there with PUT, the Content-Type header, and the normal session. The web-app proxy forwards the stream to uploadArtifactContent.
uploadArtifactContent accepts only a pending reservation of the same Workspace that the same caller made, before it expires. The caller must still act in the Workspace: active membership or bare admin. web-api counts the bytes itself because the proxy does not forward Content-Length. A body that is shorter or longer than the reserved size gets WA-AF-025, and nothing is kept. The write is create-only, so a replay gets WA-AF-026 and never replaces the stored bytes. web-api takes a short key lease from the key broker before it writes, with a svc=web-api-storage-keys service token, and asks for it again while the upload runs. When the broker refuses the first lease, the upload stops with the broker’s code: WA-SK-002 (protection not active, 409), WA-SK-003 (key refused, 403), or WA-SK-001 and WA-SK-005 (configuration fault, 409). When the key is unavailable, or the lease ends during the upload, the upload stops with 503 and WA-SK-004. Nothing is kept. No response contains the key or the lease. Each web-api pod admits at most eight protected uploads at once, before it requests a key lease. Their GCS chunk and read buffers use at most 66 MiB in total. A full pod returns 503 with Retry-After: 1 without reading the body or requesting a key. web-api selects WORKSPACE_PROXY only when the Workspace protection is ACTIVE and the protected upload gate is on. Otherwise a protected Workspace gets WA-AF-027 and no reservation. Ordinary Workspaces always get SIGNED_URL. The gate is PROTECTED_ARTIFACT_UPLOADS_ENABLED (default off). It requires STORAGE_KEY_BROKER_URL, the key broker web-api asks for leases. With the gate on and no URL, web-api stays not ready. The key broker is a web-api that runs with STORAGE_KEY_BROKER_ENABLED (default off). In local and ephemeral deploy values, the URL is populated and points to the main web-api over HTTP. With the broker flag off, protected leases still fail closed. Staging and production leave the URL unset. The ephemeral demo enables both flags explicitly and uses the shared ephemeral identity. The URL edges must move to an isolated broker workload before customer rollout. It serves leaseStorageKey to svc=query-runner, svc=query-layer, and svc=web-api-storage-keys callers only, and marks each response no-store. The svc=web-api-storage-keys token receives 403 outside /api/internal/storage-keys/. Only the protected upload path mints it, so a svc=web-api token that web-api sends to another service is never a lease credential. Any other web-api refuses every lease with WA-SK-004. query-runner and query-layer install their key provider from STORAGE_KEY_BROKER_URL before they open a store. Without it, every protected bucket fails closed. A protected Workspace never stores new plaintext sample rows in web-db and never serves stored ones, until the customer accepts that copy. For any Workspace with a protection row, in any state:
  • artifactDataPreview, parableArtifactPreview, and runArtifactSchemaInference refuse with WA-AF-027. They never serve or read stored sample rows. The Ponder file view uses the same Parable preview gate and omits the sample when it is refused.
  • The worker callback drops the sample rows of an analysis result. It keeps the row count and the schema, so the upload completes.
  • reserveArtifactPublication and finalizeArtifactPublication refuse with WA-AF-027. Publication producers are not supported for protected Workspaces.
The publication’s table name becomes {table} in that namespace. Artifacts can join other pools. For example, a published headcount plan can join Provider directory data on a compatible email column:
Use catalog discovery to inspect the published schema rather than inferring it from the source file.

A Parable’s data files

A CSV, Parquet, JSON Lines, or gzipped JSON Lines file that a person adds to a composed Parable becomes a table after its check, with no publish step:
{parable} is the Parable’s SQL name, the one in parables.{parable}.{plot}. {table} comes from the file name. The worker reads the whole file to choose each column’s type, and it calls no model. The developer site describes the names and the types, in Artifacts. Only SQL that runs in the Parable reads these tables. The Parable’s Plots read them for every person who can open the Parable. Its other SQL reads them only for a person who can edit its Plots. Query Layer refuses SQL in another Parable, and Workspace SQL outside every Parable. Catalog listings outside the Parable do not show its namespace. A Workspace publication cannot take a namespace that starts with parable_. Files do not travel with a Release or a Deploy. A Plot that must run in a Workspace with no such file declares the table as an optional input.

In Report runs

A Report run reads an artifact table as it reads a Provider table: at the last version published before the run’s AS OF time, so a publish while the run is queued is not read. Provider Policies do not apply to Artifact tables. See Reports.