# Submit task evidence

Install `openpond-sdk` and use `OpenPondLearningClient` from
`openpond-sdk/learning`. Task definitions, reusable Rewards, grading, review,
batching and HTTP schemas are owned by `@openpond/evals/learning`; see that
package's `LEARNING.md` for the full contract and host responsibilities.

The runnable examples in `examples/learning` submit one JSON record through an
existing source. Create a task format and source in Models → Tasksets → Task
formats first. The sample uses an input object with `question` and an output
object with `answer`; adapt the record to your published format. The scripts read
the source's exact task-definition reference from the server.

Set `OPENPOND_API_KEY`, `OPENPOND_API_URL` and `OPENPOND_LEARNING_SCOPE` in your
shell, then run one of:

```sh
node --experimental-strip-types submit.ts SOURCE_ID example.json
python3 submit.py SOURCE_ID example.json
```

Use the URL of the execution owner: a local OpenPond server or the hosted API
where the learning service is deployed. The server authorizes the requested
profile/team scope. The SDK and Python example send the selected scope in
`X-OpenPond-Team-Id` so hosted requests select that team before authorization;
the local server uses the profile scope in the request body. These variables are example configuration, not arguments
that should be committed with credentials.

Assign stable example/attempt identities and preserve `idempotencyKey`, timestamp
and content on retries. A different record must use a different key. Submission
records evidence; it does not approve the task or observed response for training.
The failed observed answer in the sample is intentional. Grade it, propose the
correct target, grade that target separately, and approve it in Example review.

For feedback, call `client.submitFeedback` with a
`openpond.taskFeedback.v1` envelope. Preserve source/example/attempt identity,
use a separate stable idempotency key, and set `expectedEvidenceHash` to the
evidence hash when targeting a specific revision. Feedback may arrive before
the example and stays pending until review. Corrections do not mutate sealed
historical batches.

All client requests support an optional `AbortSignal`. Aborting a request does
not cancel remote compute; use `cancel_grade` and read the authoritative terminal
job state. Page through list responses with `nextCursor` as `afterId`.

## Configure hosted learning

Use `hostedLearningPolicyReferences(project)` from `openpond-sdk/learning` with
the Model summary returned by the authenticated Model Projects API. It derives
the exact recipe, training-parent and retained-evaluation references used by the
hosted policy snapshot. The recipe identifier binds the Model's reviewed etag,
including its Harness and data settings; the content hash binds the recipe.
Missing recipe, starting model or retained evaluation is a configuration error.

Keep those references when changing a policy's pause state, schedule or limits.
Recompute them only when explicitly applying a newly reviewed Model configuration.
The server verifies the references when publishing the policy and retains the
immutable configuration for later preparation. Use `client.inspectPolicy(ref)`
for shared readiness counts and blockers without reserving or launching work.

## Connect an application

In the task format, open **Connect an application** and create a source credential.
Copy it into the application's secret store before closing the panel. Credentials
expire within 90 days and can be revoked from the same panel. The list contains
metadata and key prefixes only; hosts store secret hashes.

Use that credential as `OPENPOND_API_KEY` in the examples above. It authorizes
`submitExample`, `submitFeedback` and `sourceConfiguration(sourceId)` for exactly
one source and scope. Configuration returns the source and task-definition
references, allowed splits and enabled status. It does not expose private
evidence. Reading resources, grading, review, publication, training and credential
management require the owning user's authenticated client.

Owners can also manage credentials through the SDK:

```ts
import { createSourceCredentialRequest } from "openpond-sdk/learning";

const request = createSourceCredentialRequest({
  sourceId,
  name: "Application intake",
  expiresAt: new Date(Date.now() + 30 * 86_400_000).toISOString(),
});
const issued = await ownerClient.createSourceCredential(request);
// Store issued.apiKey securely. Never log it or commit the prepared request.
const page = await ownerClient.listSourceCredentials(sourceId, { limit: 30 });
await ownerClient.revokeSourceCredential(sourceId, issued.credential.id);
```

Keep the prepared request in memory for a transport retry: the same operation ID
and content returns the same credential, while changed content conflicts.
Revocation is idempotent; repeating creation does not reactivate a revoked key.
Use a new prepared request for a new credential. Disabling a source also prevents
new evidence submission. Hosts enforce authentication, expiry and source scope
on every request.

## Publish a reviewed batch to a hosted model

Call `learning.publishBatch({ batchId, modelProjectId })` against the hosted API after sealing an approved batch. This stores its immutable Taskset package and attaches the exact release to the model. It does not start training. The service authorizes the model and batch in the same team and deduplicates publication by release identity.

Model configuration can save `trainingSetup.rewardBindingRef` before selecting a Taskset. The reference pins a binding ID, revision and content hash; task compatibility and training readiness remain separate checks. Use `createModelProjectSaveRequest` with `createModelProjectsClient().checkConfiguration()` / `.saveConfiguration()` for hosted configuration operations, and `configurationCandidates()` for available starting models. Keep one request identity for transport retries.

## Durable authoring drafts

Reward, combined Reward and task-format editors save incomplete work separately from published releases. Use `AuthoringDraftInputSchema` with the corresponding typed fields schema. Drafts preserve incomplete JSON and JavaScript as strings; publishing still validates the finished resource. Drafts belong to the workspace and are not available to source credentials.

Send `save_draft` with a stable `operationId`, the draft input and its `expectedRevision` (zero for a new draft). Retry the identical command after an uncertain response. Distinct edits against the same revision conflict rather than overwriting each other. List with `client.list("draft", { parentId: "reward", status: "draft", limit: 20 })`; the other target kinds are `definition` and `binding`.

A draft's target and exact base release remain fixed. To publish, include `finalizeDraft: { draft: learningRef(savedDraft), targetKind: savedDraft.targetKind, release: learningRef(publishedRelease) }` in the `publish` or `publish_resources` command. The release and the draft's published status commit in one transaction; stale draft finalization rolls back publication. Archive unfinished work with `archive_draft` and its exact draft reference. Archived and published drafts cannot accept further edits.

### Reviewed Work batches

Task Definitions can pin `requiredOutputs` using the same output contracts as
Taskset rows. Evidence grading and batch sealing include those outputs in the
task hash. `prepareReviewedLearningBatch` preserves the Work environment,
released tools, output contracts and private Reward binding. Supply exact input
bytes in `assetBytes`, keyed by immutable asset ID; missing or changed bytes fail
preparation. The returned `tasksetAssetBytes` map uses task-scoped paths and is
passed to `buildTasksetTrainingBundle` or materialized beside the local Taskset.
Input content participates in the existing privacy scan. File state is reset and
cleaned up between attempts; a Work environment may hold state during an attempt.

### Simple continual-learning creation

Hosted creation can pass `learning` to `createModelProjectSaveRequest` as its
third argument, or in `createModelStarterCreationRequest`. The intent contains
`mode` (`nightly` or `approved_count`), `minimumTasks`, `localTime`, `timeZone`,
`maximumSpendUsd` and `maximumDailySpendUsd`. It participates in the operation
hash. The hosted owner commits the Model, exact task source, enabled policy and
receipt together; a failed policy cannot leave a partially created Model.
Local creation rejects this hosted intent. Existing Models edit the authoritative
policy with Learning commands instead of resubmitting creation preferences.

`createHostedLearningPolicyContent` accepts an explicit `settings.trigger` for
nightly, task-count, interval or manual policies. New settings default to ten
tasks; existing policy limits remain unchanged. Candidates still require explicit
acceptance and serving selection. `learning.inspectTaskQueue(modelProjectId?)`
returns the shared eligible, unconsumed task count, or explicit issues when the
count cannot be determined.

### Source coverage for task preparation

`openpond-sdk/dataset-workspaces` exports `DatasetPreparationSourceSchema` and
`reconcilePreparationSourceCoverage`. A policy's `source.excludedSessions`
records exact unreadable source revisions with a connection ID, source-key hash,
native revision hash, retained failure reason and explanation. Hosted preparation
checks the original owner-scoped attestation and eligible Dataset membership.
Exclusions cannot bypass unfinished listing, pending uploads, unknown event times
or known eligible boundaries. Changed originals require a new policy.

`coverage.complete` reports reconciled eligible membership;
`coverage.sourceComplete` reports complete original-source coverage and remains
false when unreadable originals are excluded. `coverage.excludedSessions` retains
their count. These fields establish inventory reconciliation only; reconstructed
tasks still need their own starting-state and grader qualification.

### Bounded tool episode records

`openpond-sdk/tool-learning` exports `assembleToolLearningEpisode`. Episode reads
retain the original events plus an `assembly` with structural application/tool
version groups and an explicit `incomplete`, `ambiguous`, or
`awaiting_owner_review` state. Missing observations stay incomplete; contradictory
terminal observations or mismatched call references stay ambiguous. Delivery
order does not select a preferred outcome. The SDK checks assembly against the
returned events. These records grant neither verification nor learning authority;
owner review and canonical grading/admission remain separate.
