> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apps.filed.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Read and Write Basic Tax Forms Directly With RPA

> Read existing tax software data and send quick, reviewed updates to basic forms without running Filed's hardened tax prep flow

This guide shows how to use Filed MCP for direct RPA reads and writes against a
connected tax software product. Use it when you already know the client and tax
return and want to read the current software data or make quick, narrowly scoped
updates to basic forms without running Filed's hardened tax prep flow.

The direct flow lists the tax software's clients, selects an exact return,
optionally exports its current backup, stages a reviewed provider payload in
the MCP task sandbox, runs the provider's read or write capability, and
verifies the result. It does not perform binder ingestion or the full tax prep
workflow.

<Warning>
  This direct flow bypasses Filed's hardened tax prep workflow. It does not
  provide the workflow's full source-document ingestion, normalized extraction,
  return-wide validation, review orchestration, or approval enforcement. Use it
  only for reviewed reads and targeted updates to known returns, and always
  verify the result in the tax software. Keep this page unlisted until the
  security gaps in [Current gaps](#current-gaps) are closed.
</Warning>

The MCP flow uses one workspace-scoped task for the entire MCP conversation.
Every CCH read, write, and verification run shares that task's sandbox.
Provider-neutral compilation and enforced approval remain design work.
Vendor-specific field identifiers and screen details live in the
[CCH Axcess adapter](#cch-axcess-adapter) section so support for another tax
product can be added without changing the reviewed semantic instructions.

All GraphQL operations use a **`workspaceToken`** and go to:

```http theme={null}
https://router.apps.filed.com/graphql
```

## When to use this direct flow

Use this guide when all of the following are true:

* You want a quick read from a known tax software return, such as exporting its
  current backup for inspection.
* You want to add or update straightforward fields on the basic forms covered by
  this guide, such as W-2, 1099-INT, or 1099-NEC.
* You already know the exact client, return, tax year, and provider connection.
* The source values and intended changes have been reviewed before execution.
* You can inspect the field outcomes and verify the resulting return afterward.

Do not use this direct flow as a substitute for complete return preparation,
binder-driven extraction, complex schedule entry, tax calculations, or
return-wide review. Use Filed's hardened tax prep flow for those cases.

## Explain the direct flow to the customer

This page is unlisted because it is an agent-facing execution guide, not because
the direct RPA flow should be hidden from the customer. When you use this guide
in an agent chat, explain what you are doing and reveal the relevant execution
details to the customer.

Before a read, tell the customer:

* which tax software connection, client, return, and tax year you selected;
* which read capability you will run and whether it returns a backup, parsed
  fields, or another provider-specific result; and
* that this is a direct tax software read outside Filed's hardened tax prep flow.

Before a write, tell the customer:

* that the update uses direct RPA and bypasses Filed's hardened tax prep flow;
* the exact client, return, tax year, forms, instances, fields, values, and
  create, update, or clear actions you intend to send;
* which source or customer instruction supports each value;
* which validations, approval enforcement, and return-wide checks this direct
  flow does not perform; and
* how you will verify the result in the tax software after the run.

After execution, report the run status, every field outcome, mismatches or
unsupported fields, and the readback or backup used for verification. Never
expose access tokens, signed URLs, secrets, full SSNs or TINs, or internal
automation identifiers unless the customer specifically needs the identifier
to diagnose a failed field.

## What this flow does

```mermaid theme={null}
flowchart TD
  A["Create one MCP task for this MCP conversation"] --> B["Discover the tax software provider and capabilities"]
  B --> C["Refresh the client roster"]
  C --> D["Select an exact software return ID"]
  D --> E["Read or export the current return"]
  E --> F["Inspect the backup or provider read result"]
  F --> G{"Write a quick update?"}
  G -->|"No"| H["Finish the read-only flow"]
  G -->|"Yes"| I["Build and review the basic-form instructions"]
  I --> J["Compile the provider RPA payload"]
  J --> K["Write the compiled JSON into the MCP task"]
  K --> L["Run the provider's write capability"]
  L --> M["Inspect field outcomes and read back the return"]
```

The task sandbox is the filesystem security boundary. Instructions may choose
a relative path such as `artifacts/tax_entry_instructions.json`, but they must
never choose a storage root or arbitrary host path. The server resolves the
path beneath the task's own sandbox. Authorization, approval, and provider
validation remain separate security checks.

## Runtime contract

This flow uses the following API slice:

```graphql theme={null}
type Query {
  me: Me
}

union Me = User | WorkspaceUser

type WorkspaceUser {
  workspace: Workspace!
}

type Workspace {
  connections(providerKey: String): [Connection!]!
  providers: [IntegrationProvider!]!
  connectionCapabilityRun(id: ID!): ConnectionCapabilityRun
  task(id: ID!): Task
}

type Mutation {
  createTask(input: CreateTaskInput!): Task!
  attachFileToTask(input: AttachFileToTaskInput!): [ChatUploadAttachment!]!
  runConnectionCapabliltity(
    input: RunConnectionCapabliltityInput!
  ): ConnectionCapabilityRun!
}

input CreateTaskInput {
  type: TaskType!
}

enum TaskType {
  BINDER
  CHAT
  LEGACY_TAX_PREP
  MCP
  ROUTINE
  TAX_ADVISOR
  TAX_PREP
  TAX_PREP_LITE
  TAX_REVIEW
}

enum TaskStatus {
  RUNNING
  COMPLETED
  FAILED
}

type Task {
  id: ID!
  type: TaskType!
  status: TaskStatus!
  file(path: String!): SignedPath
}

input AttachFileToTaskInput {
  taskId: ID!
  uploadIds: [String!]!
}

type ChatUploadAttachment {
  filename: String!
  mimeType: String!
  taskId: ID!
  signedPath: SignedPath!
}

type SignedPath {
  filePath: String!
  url: String!
}

input RunConnectionCapabliltityInput {
  connectionId: ID!
  capability: String!
  params: JSON!
}

type Connection {
  id: ID!
  name: String!
  providerKey: String!
  status: ConnectionStatus!
  clientList(search: String, offset: Int, limit: Int): [TaxSoftwareClient!]!
}

enum ConnectionStatus {
  pending
  verifying
  active
  error
  disconnected
  deleted
}

type IntegrationProvider {
  id: String!
  category: String!
  profile: ProviderProfile!
  capability(value: String!): ProviderCapability
}

type ProviderProfile {
  capabilities: [ProviderCapability!]!
}

type ProviderCapability {
  value: String!
  label: String!
  description: String
  kind: String
  inputSchema: JSON
  outputSchema: JSON
}

type ConnectionCapabilityRun {
  id: ID!
  status: String!
  error: String
  result: JSON
}

type TaxSoftwareClient {
  id: ID!
  connectionId: ID!
  name: String!
  externalId: String!
  ssn4Digits: String
  metadata: JSON
  createdAt: Date!
  updatedAt: Date!
}
```

<ParamField path="Workspace.connections.providerKey" type="String">
  Optional provider filter. Use the exact provider key selected for execution.
</ParamField>

<ParamField path="Connection.clients.search" type="String">
  Optional client-name search string. Treat it as discovery, not an exact-match
  guarantee.
</ParamField>

<ParamField path="Connection.clients.offset" type="Int">
  Optional zero-based page offset.
</ParamField>

<ParamField path="Connection.clients.limit" type="Int">
  Optional page size.
</ParamField>

<ParamField path="Workspace.connectionCapabilityRun.id" type="ID!" required>
  The capability run ID returned by `runConnectionCapabliltity`.
</ParamField>

<ParamField path="createTask.input.type" type="TaskType!" required>
  Use `MCP`. Create one task before the first capability run in an MCP
  conversation.
</ParamField>

<ParamField path="attachFileToTask.input.taskId" type="ID!" required>
  The MCP task ID created for the current MCP conversation.
</ParamField>

<ParamField path="attachFileToTask.input.uploadIds" type="[String!]!" required>
  The upload IDs returned by the Filed TUS uploader. Use the same MCP session
  `taskId` for the attachment and subsequent capability run.
</ParamField>

<ParamField path="input.params.taskId" type="ID!" required>
  The MCP task ID for the current MCP conversation. Reuse this same ID for every
  capability run in the conversation. Filed validates it as execution context
  and removes it before validating the provider-specific parameters.
</ParamField>

<ParamField path="input.connectionId" type="ID!" required>
  The selected tax software `Connection.id` in the caller's workspace.
</ParamField>

<ParamField path="input.capability" type="String!" required>
  The exact provider capability value, such as `clients.list`,
  `client.data.read`, or `client.data.write`.
</ParamField>

<ParamField path="input.params" type="JSON!" required>
  The MCP `taskId` plus the capability-specific parameters shown below.
</ParamField>

<ResponseField name="ConnectionCapabilityRun.id" type="ID!">
  The run ID used to poll `Workspace.connectionCapabilityRun(id:)`.
</ResponseField>

<ResponseField name="ConnectionCapabilityRun.status" type="String!">
  The Temporal execution status. A new run returns `RUNNING`. Terminal values
  are `COMPLETED`, `FAILED`, `CANCELLED`, `TIMED_OUT`, and `TERMINATED`. On a
  terminal run, inspect both `error` and `result`.
</ResponseField>

<ResponseField name="ConnectionCapabilityRun.error" type="String">
  The run-level error message when the capability fails.
</ResponseField>

<ResponseField name="ConnectionCapabilityRun.result" type="JSON">
  The capability-specific result. Always interpret it against the capability's
  advertised output schema and the selected provider adapter.
</ResponseField>

<ResponseField name="Task.id" type="ID!">
  The MCP task ID. Store it in the MCP conversation state and reuse it for all
  capability runs in that conversation.
</ResponseField>

<ResponseField name="Task.status" type="TaskStatus!">
  `COMPLETED`. Like a chat task, an MCP task is a durable sandbox owner rather
  than the lifecycle of any one run. Poll each capability run separately.
</ResponseField>

<ResponseField name="ChatUploadAttachment.signedPath.filePath" type="String!">
  The attached file's storage key. Capability parameters use the task-relative
  `user_uploads/{filename}` portion, not the full storage key.
</ResponseField>

<ResponseField name="Task.file" type="SignedPath">
  An exact file beneath the authorized task sandbox. It returns `null` until the
  file exists. Read the file through `SignedPath.url`.
</ResponseField>

<ResponseField name="Connection.id" type="ID!">
  The connection ID used by capability mutations.
</ResponseField>

<ResponseField name="Connection.status" type="ConnectionStatus!">
  The lifecycle state. Only `active` is ready for normal capability execution.
</ResponseField>

<ResponseField name="IntegrationProvider.id" type="String!">
  The provider key. Match it to `Connection.providerKey`.
</ResponseField>

<ResponseField name="ProviderProfile.capabilities" type="[ProviderCapability!]!">
  All capabilities currently advertised by the provider.
</ResponseField>

<ResponseField name="ProviderCapability.value" type="String!">
  The exact value passed as `input.capability`.
</ResponseField>

<ResponseField name="ProviderCapability.inputSchema" type="JSON">
  The JSON schema for `input.params`.
</ResponseField>

<ResponseField name="ProviderCapability.outputSchema" type="JSON">
  The JSON schema for the terminal run's `result`.
</ResponseField>

<ResponseField name="TaxSoftwareClient.name" type="String!">
  The provider client display name.
</ResponseField>

<ResponseField name="TaxSoftwareClient.externalId" type="String!">
  The provider-stable client or return locator used by the adapter.
</ResponseField>

<ResponseField name="TaxSoftwareClient.ssn4Digits" type="String">
  The optional final four SSN digits available for reviewed matching.
</ResponseField>

<ResponseField name="TaxSoftwareClient.metadata" type="JSON">
  Provider metadata such as return version. Interpret it through the provider
  adapter.
</ResponseField>

## Prerequisites

Before starting, confirm all of the following:

* The workspace has an active connection to the target tax software.
* The provider advertises client discovery, data read, and data write
  capabilities appropriate for this flow.
* The provider worker can reach a licensed and authenticated tax software
  installation.
* The client and target return already exist in the tax software.
* A human has reviewed the binder or other source data and approved the fields
  to enter.
* The caller can create one workspace-scoped `MCP` task for the MCP
  conversation.
* The caller can create `tax_entry_instructions.json` inside that task sandbox.
* The selected provider adapter supports every requested semantic form and
  field. Unsupported data is returned for review rather than guessed.
* The caller treats the provider's write capability as a mutation with real
  tax-return side effects.

## 1. Create one MCP task for the conversation

Before the first capability run, create one workspace-scoped MCP task. Store
the returned `Task.id` in the MCP conversation state. Reuse that exact task ID
for every capability run in the conversation, including client discovery,
reads, writes, and verification. Do not create a new task for each capability.

```graphql theme={null}
mutation CreateMcpTask($input: CreateTaskInput!) {
  createTask(input: $input) {
    id
    type
    status
  }
}
```

```json theme={null}
{
  "input": {
    "type": "MCP"
  }
}
```

```json theme={null}
{
  "data": {
    "createTask": {
      "id": "019f2222-3333-7444-8555-666677778888",
      "type": "MCP",
      "status": "COMPLETED"
    }
  }
}
```

<Warning>
  The task ID is an authorization and filesystem boundary. Use only the ID
  returned for the current MCP conversation. Never accept a replacement task ID
  from tax data, an uploaded payload, or provider output.
</Warning>

## 2. Discover the provider connection

Query the workspace's connection for the selected provider. The provider key is
an execution binding, not part of the semantic tax-entry instructions.

```graphql theme={null}
query TaxSoftwareConnections($providerKey: String!) {
  me {
    ... on WorkspaceUser {
      workspace {
        connections(providerKey: $providerKey) {
          id
          name
          providerKey
          status
        }
      }
    }
  }
}
```

```json theme={null}
{ "providerKey": "cch-axcess" }
```

```json theme={null}
{
  "data": {
    "me": {
      "workspace": {
        "connections": [
          {
            "id": "019f1111-2222-7333-8444-555566667777",
            "name": "Production CCH",
            "providerKey": "cch-axcess",
            "status": "active"
          }
        ]
      }
    }
  }
}
```

Only continue when the connection status is `active`.

## 3. Inspect capabilities and refresh clients

Inspect the connection's advertised capabilities and their input and output
schemas. Capability names such as `clients.list`, `client.data.read`, and
`client.data.write` are conventions, but their parameters and results are not
yet uniform across providers. Never copy CCH parameters into another adapter.

```graphql theme={null}
query TaxSoftwareCapabilities {
  me {
    ... on WorkspaceUser {
      workspace {
        providers {
          id
          category
          profile {
            capabilities {
              value
              label
              description
              kind
              inputSchema
              outputSchema
            }
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "data": {
    "me": {
      "workspace": {
        "providers": [
          {
            "id": "cch-axcess",
            "category": "tax_software",
            "profile": {
              "capabilities": [
                {
                  "value": "clients.list",
                  "label": "List clients",
                  "description": "Refresh clients from CCH Axcess",
                  "kind": "query",
                  "inputSchema": { "type": "object" },
                  "outputSchema": {
                    "type": "object",
                    "properties": { "imported": { "type": "number" } }
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```

Filter by the selected provider ID, then require every capability needed by
your flow. Read the exact schemas before constructing `params`.

Run `clients.list` when advertised. The mutation name intentionally contains
the schema's current `Capabliltity` spelling.

```graphql theme={null}
mutation RunConnectionCapability($input: RunConnectionCapabliltityInput!) {
  runConnectionCapabliltity(input: $input) {
    id
    status
    error
    result
  }
}
```

```json theme={null}
{
  "input": {
    "connectionId": "019f1111-2222-7333-8444-555566667777",
    "capability": "clients.list",
    "params": {
      "taskId": "019f2222-3333-7444-8555-666677778888"
    }
  }
}
```

```json theme={null}
{
  "data": {
    "runConnectionCapabliltity": {
      "id": "019f3333-4444-7555-8666-777788889999",
      "status": "RUNNING",
      "error": null,
      "result": null
    }
  }
}
```

Poll `workspace.connectionCapabilityRun(id:)` until the run reaches its terminal
state, then interpret `result` against the advertised output schema. In the CCH
running example, `clients.list` imports the exported list into Filed and returns
only a summary such as `{ "imported": 124 }`.

```graphql theme={null}
query ConnectionCapabilityRun($id: ID!) {
  me {
    ... on WorkspaceUser {
      workspace {
        connectionCapabilityRun(id: $id) {
          id
          status
          error
          result
        }
      }
    }
  }
}
```

```json theme={null}
{
  "id": "019f3333-4444-7555-8666-777788889999"
}
```

```json theme={null}
{
  "data": {
    "me": {
      "workspace": {
        "connectionCapabilityRun": {
          "id": "019f3333-4444-7555-8666-777788889999",
          "status": "COMPLETED",
          "error": null,
          "result": {
            "imported": 124
          }
        }
      }
    }
  }
}
```

After a provider refresh that populates the normalized connection roster, query
`Connection.clientList`. Require exactly one
match using a provider-stable ID plus reviewed identity facts such as name, TIN
suffix, entity type, and tax year. Do not fuzzy-pick among duplicate names.

```graphql theme={null}
query TaxSoftwareClientList(
  $providerKey: String!
  $search: String
  $offset: Int
  $limit: Int
) {
  me {
    ... on WorkspaceUser {
      workspace {
        connections(providerKey: $providerKey) {
          id
          clientList(search: $search, offset: $offset, limit: $limit) {
            id
            name
            externalId
            ssn4Digits
            metadata
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "providerKey": "cch-axcess",
  "search": "Harper",
  "offset": 0,
  "limit": 50
}
```

```json theme={null}
{
  "data": {
    "me": {
      "workspace": {
        "connections": [
          {
            "id": "019f1111-2222-7333-8444-555566667777",
            "clients": [
              {
                "id": "019faaaa-bbbb-7ccc-8ddd-eeeeffffffff",
                "name": "Morgan Harper",
                "externalId": "2025I:123-AFILED:V1",
                "ssn4Digits": "6789",
                "metadata": { "version": "V1" }
              }
            ]
          }
        ]
      }
    }
  }
}
```

## 4. Read the current return when supported

Run `client.data.read` before mutation when supported. A provider may return a
backup artifact, parsed fields, or a provider-specific dataset. Save the
pre-entry result in the task sandbox and use it to decide whether each form
instance is a create or an update.

<Warning>
  An opaque backup artifact alone cannot prove that a payer or statement row
  already exists. Require a parsed backup or semantic read result before
  choosing `create` or `update`. If the adapter cannot establish an exact row
  identity, stop for review.
</Warning>

```json theme={null}
{
  "input": {
    "connectionId": "019f1111-2222-7333-8444-555566667777",
    "capability": "client.data.read",
    "params": {
      "taskId": "019f2222-3333-7444-8555-666677778888",
      "softwareClientId": "2025I:123-AFILED:V1"
    }
  }
}
```

For CCH, the completed result has this shape:

```json theme={null}
{
  "success": true,
  "path": "artifacts/cch/read/RUN_ID/post_entry.dat"
}
```

<Note>
  A CCH return read normally takes 2 to 5 minutes. Do not expect an immediate
  result or treat an early `RUNNING` status as a failure. Poll about once per
  minute and continue until the run completes or returns an explicit error.
</Note>

`path` is relative to the MCP task sandbox, not a public URL. Other providers
return different shapes. Resolve it with `Workspace.task(id:).file(path:)` and
the same task ID used to run the capability.

An already-connected CCH Axcess connection can also run the v2
`initiate_client_backup` capability without being reconnected or migrated. See
[Use CCH v2 with an existing connection](#use-cch-v2-with-an-existing-connection)
for its current parameter and file-path contract.

## 5. Use the MCP task sandbox

The MCP task created in step 1 owns the only sandbox used by this conversation.
Every capability receives that task ID, and the server resolves all relative
input and output paths beneath `sandboxes/{taskId}`. Never send `sandboxDir` or
another caller-selected storage root.

This single sandbox preserves the full execution trail across any number of
capability runs: source reads, reviewed instructions, compiled payloads,
provider results, screenshots, logs, and verification reads.

Read any exact file returned by a capability with the task ID and the
task-relative path. The resolver returns `null` while the file does not exist
and rejects absolute paths, traversal, and Filed's protected task metadata:

```graphql theme={null}
query ReadTaskFile($taskId: ID!, $path: String!) {
  me {
    ... on WorkspaceUser {
      workspace {
        task(id: $taskId) {
          file(path: $path) {
            filePath
            url
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "taskId": "019f2222-3333-7444-8555-666677778888",
  "path": "artifacts/cch/read/RUN_ID/post_entry.dat"
}
```

## 6. Build semantic tax-entry instructions

The reviewed source artifact uses stable tax semantics and source evidence, not
vendor automation IDs, screen names, or storage paths. The current accepted
`DataEntryPlan` version 1 shape is:

```json theme={null}
{
  "schema_version": "1",
  "client": {
    "workspace_id": "WORKSPACE_ID",
    "client_id": "FILED_CLIENT_ID",
    "software_client_id": "PROVIDER_CLIENT_ID",
    "target_software": "PROVIDER_KEY",
    "tax_year": 2025
  },
  "forms": [
    {
      "form_type": "W2",
      "action": "create",
      "instances": [
        {
          "instance_index": 0,
          "identity": {
            "employer_ein": "822020274",
            "control_number": "W2-001"
          },
          "variant": null,
          "fields": [
            {
              "semantic_id": "wages_tips",
              "canonical_type": "currency",
              "action": "set",
              "value": "75000.00",
              "source_path": "binder/w2-1.json#/wages_tips"
            },
            {
              "semantic_id": "retirement_plan",
              "canonical_type": "checkbox",
              "action": "set",
              "value": true,
              "source_path": "binder/w2-1.json#/retirement_plan"
            }
          ]
        }
      ],
      "routing_notes": ""
    }
  ]
}
```

Version 1 includes the execution target in `client`. The recommended version 2
contract separates the neutral semantic plan from this execution binding:

```json theme={null}
{
  "connectionId": "CONNECTION_ID",
  "providerKey": "PROVIDER_KEY",
  "softwareClientId": "PROVIDER_CLIENT_ID",
  "taxYear": 2025,
  "semanticPlanPath": "artifacts/tax_entry_instructions.json"
}
```

Do not send the version 2 split shape to today's parser. It is the recommended
public contract described in [Current gaps](#current-gaps).

### Semantic construction rules

* Resolve every value to an exact `semantic_id` in the form catalog.
* Preserve `source_path` evidence for every set or clear operation.
* Copy explicit source values into canonical lexical form. Never manufacture a
  missing amount, zero, checkbox, identifier, owner code, or enum.
* Omit absent, unreadable, unsupported, and unapproved values. Omission means
  no change. It does not mean zero, false, or clear.
* Use `action: "clear"` only for a reviewed removal of a rolled-over value.
  Clears and form deletes require elevated confirmation.
* Treat identifiers and account numbers as strings so leading zeros survive.
* Use decimal strings without currency symbols or commas for amounts.
* Choose `create` only after confirming the instance is absent. Choose `update`
  only after an exact pre-entry match. Stop on ambiguous matches.
* Represent statement rows with semantic column names and stable row identity,
  not provider grid coordinates.
* Do not allow duplicate writes to the same form instance and semantic field.
* If the adapter drops, blocks, or cannot resolve any intended field, stop for
  review instead of running a partial plan.

### The ten basic form types

| `form_type` | Source identity | Typical instance identity                      |
| ----------- | --------------- | ---------------------------------------------- |
| `W2`        | Form W-2        | employer EIN plus control number               |
| `1099_INT`  | Form 1099-INT   | payer TIN plus account number                  |
| `1099_DIV`  | Form 1099-DIV   | payer TIN plus account number                  |
| `1099_NEC`  | Form 1099-NEC   | payer TIN plus account number                  |
| `1099_MISC` | Form 1099-MISC  | payer TIN plus account number                  |
| `1099_G`    | Form 1099-G     | payer TIN plus account number and payment type |
| `1098_E`    | Form 1098-E     | lender TIN plus account number                 |
| `1098_T`    | Form 1098-T     | filer TIN plus student account number          |
| `1099_SA`   | Form 1099-SA    | trustee TIN plus account number                |
| `SSA_1099`  | Form SSA-1099   | payee plus claim number                        |

## 7. Validate and approve the proposed plan

The following approval binding is the recommended target contract. It is not
enforced by the standalone capability mutation today. Run deterministic schema,
type, enum, identity, and cross-field validation.
Then compile a coverage preview with the selected provider adapter. Review must
show semantic field names, IRS box meanings, source evidence, and explicit
create, update, clear, or delete actions. Raw vendor IDs can appear in a
diagnostic appendix, but should not be the reviewer's primary interface.

Approval should bind all of the following:

```json theme={null}
{
  "semanticPlanHash": "sha256:...",
  "compiledPlanHash": "sha256:...",
  "connectionId": "CONNECTION_ID",
  "softwareClientId": "PROVIDER_CLIENT_ID",
  "taxYear": 2025,
  "catalogVersion": "ADAPTER_CATALOG_VERSION",
  "actions": ["W2:create", "1099_INT:update:2"]
}
```

Any field edit, target-client change, adapter version change, or compile delta
invalidates approval.

## 8. Compile and write the proposed provider payload

The public compiler described here is a target contract, not an available
generic capability today. The adapter resolves semantic fields into native IDs,
types, navigation, subsections, and grids. It returns both the compiled payload
and coverage:

```json theme={null}
{
  "emitted": ["W2.wages_tips", "W2.retirement_plan"],
  "transformed": ["FORM.FIELD -> PROVIDER_NATIVE_FIELD"],
  "blocked": [],
  "dropped": [],
  "warnings": []
}
```

Serialize the reviewed, provider-specific payload as a small JSON file. For
CCH, use `rpa_payload.json` and `application/json`.

Call the MCP `get_file_upload_info` tool. It returns the existing Filed TUS
uploader URL plus a short-lived workspace token. Upload the JSON with the TUS
resumable protocol and retain the upload ID from the upload `Location` header.
Do not put file bytes inside a GraphQL or MCP JSON payload.

For example, a direct TUS client performs the equivalent of:

```bash theme={null}
FILE_SIZE=$(wc -c < rpa_payload.json | tr -d ' ')
CREATE_HEADERS=$(curl -sS -D - -o /dev/null -X POST "$UPLOAD_URL" \
  -H "Authorization: Bearer $UPLOAD_TOKEN" \
  -H "Tus-Resumable: 1.0.0" \
  -H "Upload-Length: $FILE_SIZE" \
  -H "Upload-Metadata: filename cnBhX3BheWxvYWQuanNvbg==,filetype YXBwbGljYXRpb24vanNvbg==")
UPLOAD_LOCATION=$(printf '%s' "$CREATE_HEADERS" | awk '
  BEGIN { IGNORECASE=1 } /^Location:/ { gsub("\\r", "", $2); print $2 }
')
curl -sS -X PATCH "$UPLOAD_LOCATION" \
  -H "Authorization: Bearer $UPLOAD_TOKEN" \
  -H "Tus-Resumable: 1.0.0" \
  -H "Upload-Offset: 0" \
  -H "Content-Type: application/offset+octet-stream" \
  --data-binary @rpa_payload.json
UPLOAD_ID=${UPLOAD_LOCATION##*/}
```

Attach the staged TUS upload with the same task-based operation used by Filed
chat. Send the MCP task ID:

```graphql theme={null}
mutation AttachRpaPayload($input: AttachFileToTaskInput!) {
  attachFileToTask(input: $input) {
    filename
    mimeType
    taskId
    signedPath {
      filePath
    }
  }
}
```

```json theme={null}
{
  "input": {
    "taskId": "019f2222-3333-7444-8555-666677778888",
    "uploadIds": ["UPLOAD_ID"]
  }
}
```

```json theme={null}
{
  "data": {
    "attachFileToTask": [
      {
        "filename": "rpa_payload.json",
        "mimeType": "application/json",
        "taskId": "019f2222-3333-7444-8555-666677778888",
        "signedPath": {
          "filePath": "sandboxes/019f2222-3333-7444-8555-666677778888/user_uploads/rpa_payload.json"
        }
      }
    ]
  }
}
```

Pass only the sandbox-relative `user_uploads/rpa_payload.json` as `payloadPath`.
The server combines it with the authorized task ID and derives the storage
path. Never pass `sandboxDir` or a storage-relative path.

## 9. Run and verify

Invoke the provider's advertised write capability only after approval. Poll
`workspace.connectionCapabilityRun(id:)` until the terminal state. Inspect
field-level results, not only top-level success.

Then use the provider's post-entry read, backup, or print capability and compare
normalized semantic values with the approved plan. Report each intended field
as confirmed, mismatch, missing, or unverified. Preserve pre-entry and
post-entry artifacts, field outcomes, action logs, and screenshots in the task
sandbox.

## CCH Axcess adapter

This section documents CCH-specific compilation. An instruction author should
still write semantic fields. The adapter, not the author, owns the following
screen names and automation IDs.

### CCH client locator

For CCH, `clients.list` currently returns only `{ "imported": count }`. Query
`Connection.clients` afterward. When `externalId` is a full Return ID such as
`2025I:123-AFILED:V1`, use it as `softwareClientId` and omit
`softwareClientVersion`. When it is a bare client ID, use `metadata.version`
such as `V1` as `softwareClientVersion`. The version is not the tax year.

### Use CCH v2 with an existing connection

The v2 provider uses the same `cch-axcess` provider key, stored credentials,
settings, and connection ID as the existing CCH connection. There is no
separate v2 connection and no provider-version parameter. When a requested
capability is absent from the legacy CCH provider, the capability dispatcher
falls back to the v2 CCH provider automatically.

The v2 capabilities are not yet merged into the advertised legacy CCH
capability catalog. Therefore, capability discovery may omit
`initiate_client_backup` even though direct dispatch supports it. This is a
temporary migration limitation, not a reason to create another connection.

The currently implemented v2 read operation is `initiate_client_backup`. Run it
through `run_batch_mutations` with the normal capability mutation:

```graphql theme={null}
mutation RunConnectionCapability($input: RunConnectionCapabliltityInput!) {
  runConnectionCapabliltity(input: $input) {
    id
    status
    error
    result
  }
}
```

```json theme={null}
{
  "input": {
    "connectionId": "019f1111-2222-7333-8444-555566667777",
    "capability": "initiate_client_backup",
    "params": {
      "taskId": "019f2222-3333-7444-8555-666677778888",
      "workspaceId": "019e0223-21c6-7886-a0e1-1951ab00dd60",
      "connectionId": "019f1111-2222-7333-8444-555566667777",
      "clientId": "019faaaa-bbbb-7ccc-8ddd-eeeeffffffff",
      "taxSoftwareIdentifier": "2025I:123-AFILED:V1",
      "backupType": "pre"
    }
  }
}
```

The parameters have the following current meanings:

| Parameter               | Meaning                                                                                                                                                 |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `taskId`                | The one MCP task reused for the entire MCP conversation. The backup is written beneath this task's sandbox.                                             |
| `workspaceId`           | The authenticated Filed workspace ID. The current v2 input schema requires it in `params`.                                                              |
| `connectionId`          | The active, already-connected CCH Axcess connection ID. The current v2 input schema requires the same ID both at the mutation boundary and in `params`. |
| `clientId`              | The Filed client UUID selected from the workspace.                                                                                                      |
| `taxSoftwareIdentifier` | The exact CCH return ID, normally the selected connection client's full `externalId`.                                                                   |
| `backupType`            | `pre` for a pre-entry backup or `post` for a post-entry/readback backup.                                                                                |

Poll `workspace.connectionCapabilityRun(id:)` until the run completes. A CCH
backup normally takes 2 to 5 minutes, so poll about once per minute rather than
treating an early `RUNNING` response as a failure.

The completed result currently returns a storage key:

```json theme={null}
{
  "path": "sandboxes/019f2222-3333-7444-8555-666677778888/backups/pre/20260723T120000000Z_backup.dat"
}
```

#### Read the v2 backup from the task sandbox

`Workspace.task(id:).file(path:)` accepts a path relative to that task's
sandbox. The v2 backup result currently includes the
`sandboxes/{taskId}/` prefix, so remove that prefix before querying the file:

```text theme={null}
returned path:
sandboxes/019f2222-3333-7444-8555-666677778888/backups/pre/20260723T120000000Z_backup.dat

Task.file path:
backups/pre/20260723T120000000Z_backup.dat
```

Call `run_batch_queries` with the exact file path:

```graphql theme={null}
query ReadTaskFile($taskId: ID!, $path: String!) {
  me {
    ... on WorkspaceUser {
      workspace {
        task(id: $taskId) {
          file(path: $path) {
            filePath
            url
          }
        }
      }
    }
  }
}
```

```json theme={null}
{
  "taskId": "019f2222-3333-7444-8555-666677778888",
  "path": "backups/pre/20260723T120000000Z_backup.dat"
}
```

Fetch the returned signed `url` to read the file bytes. The query returns
`null` until the exact file exists. It rejects absolute paths, traversal,
cross-task access, and Filed's protected task metadata. There is no generic
sandbox directory-listing query, so retain the exact path returned by the
capability.

<Warning>
  Only `initiate_client_backup` is currently implemented as a real v2 CCH
  operation. The v2 `enter_forms_data`, `print_client_return`, and
  `sync_client_list` handlers are placeholders. Continue using the advertised
  legacy `clients.list`, `client.data.read`, and `client.data.write`
  capabilities for those production operations until their v2 replacements are
  implemented.
</Warning>

### CCH compiled envelope

```json theme={null}
{
  "client_id": "2025I:123-AFILED:V1",
  "forms": [
    {
      "form": "Interest (1099-INT)",
      "sections": [
        {
          "section": "1 - Interest (IRS 1099-INT)",
          "type": "grid",
          "entries": [
            {
              "action": "add",
              "subSections": [
                {
                  "subSection": "1 - IRS 1099-INT",
                  "fields": [
                    {
                      "automationId": "_0_10",
                      "type": "text",
                      "action": "set",
                      "value": "620.00",
                      "label": "Box 1 interest income"
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

For a new row use `action: "add"`. For an exact existing row use
`action: "update"`, a 1-based `entityIndex`, and reviewed `matchText`. Do not
replay `add`, because it can duplicate a payer or statement row. Use exact form,
section, and subsection names. IDs are scoped to that full location.

Native `text` values are JSON strings. A CCH dropdown compiles to `combo` with
an exact catalog option code. A CCH picker also compiles to `combo`, but accepts
a reviewed literal string such as a state or recipient value and leaves final
validation to CCH. Native `check` values are booleans. Omit source-false
optional checkboxes on add. For a reviewed rollover removal, send
`action: "clear"` and omit `value`.

### Supported CCH locations

| Form type | CCH form                                                   | Grid section                                         | Default detail subsection                     |
| --------- | ---------------------------------------------------------- | ---------------------------------------------------- | --------------------------------------------- |
| W-2       | `Wages, Salaries and Tips (W-2)`                           | `1 - Wages and Salaries (IRS W-2)`                   | `1 - IRS W-2`                                 |
| 1099-INT  | `Interest (1099-INT)`                                      | `1 - Interest (IRS 1099-INT)`                        | `1 - IRS 1099-INT`                            |
| 1099-DIV  | `Dividends (1099-DIV)`                                     | `1 - Dividends (IRS 1099-DIV)`                       | `1 - IRS 1099-DIV`                            |
| 1099-NEC  | `Other Income (1099-G, 1099-K, 1099-MISC, 1099-NEC, W-2G)` | `2 - Nonemployee Compensation (IRS 1099-NEC)`        | `1 - IRS 1099-NEC (Nonemployee Compensation)` |
| 1099-MISC | same Other Income form                                     | `1 - Miscellaneous Information (IRS 1099-MISC)`      | `1 - IRS 1099-MISC (Other Income)`            |
| 1099-G    | same Other Income form                                     | `3 - Certain Government Payments (IRS 1099-G)`       | `1 - IRS 1099-G`                              |
| 1098-E    | `Student Loan Interest Statement (1098-E)`                 | `1 - Student Loan Interest Statement`                | `1 - IRS 1098-E`                              |
| 1098-T    | `8863 / 8917 - Tuition Statement (1098-T)`                 | `1 - Tuition Statement (IRS 1098-T)`                 | `1 - IRS 1098-T`                              |
| 1099-SA   | `Distributions From an HSA / MSA (1099-SA)`                | `1 - Distributions From an HSA or MSA (IRS 1099-SA)` | `1 - IRS 1099-SA`                             |
| SSA-1099  | `Social Security Benefit Statement (SSA-1099)`             | `1 - Social Security Benefit Statement (SSA-1099)`   | `1 - IRS SSA-1099`                            |

### W-2 field catalog

Unless stated otherwise, these fields use subsection `1 - IRS W-2`.

| Semantic field                 | CCH ID/type   | Meaning and accepted value                                      |
| ------------------------------ | ------------- | --------------------------------------------------------------- |
| `ts_code`                      | `_0_0` combo  | Return owner: exact `T` or `S`.                                 |
| `employee_ssn`                 | `_0_17` text  | Employee SSN, 9 digits with no dashes.                          |
| `employer_ein`                 | `_0_3` text   | Employer EIN, 9 digits with no dashes.                          |
| `employer_name`                | `_0_6` text   | Employer legal or reporting name.                               |
| `employer_address`             | `_0_9` text   | Employer street address.                                        |
| `employer_city`                | `_0_12` text  | Employer city.                                                  |
| `employer_state`               | `_0_13` combo | Employer two-letter USPS state.                                 |
| `employer_zip`                 | `_0_14` text  | Employer 5-digit or ZIP+4 postal code.                          |
| `employee_address`             | `_0_33` text  | Employee street-address override.                               |
| `employee_city`                | `_0_34` text  | Employee city override.                                         |
| `employee_state`               | `_0_35` combo | Employee two-letter state override.                             |
| `employee_zip`                 | `_0_36` text  | Employee ZIP override.                                          |
| `employee_country_code`        | `_0_46` text  | Employee two-letter foreign country code when printed.          |
| `wages_tips`                   | `_0_4` text   | Box 1 wages, tips, and other compensation. Decimal amount.      |
| `federal_tax_withheld`         | `_0_5` text   | Box 2 federal income tax withheld. Decimal amount.              |
| `social_security_wages`        | `_0_7` text   | Box 3 Social Security wages. Decimal amount.                    |
| `social_security_tax_withheld` | `_0_8` text   | Box 4 Social Security tax withheld. Decimal amount.             |
| `medicare_wages`               | `_0_10` text  | Box 5 Medicare wages and tips. Decimal amount.                  |
| `medicare_tax_withheld`        | `_0_11` text  | Box 6 Medicare tax withheld. Decimal amount.                    |
| `social_security_tips`         | `_0_15` text  | Box 7 Social Security tips. Decimal amount.                     |
| `allocated_tips`               | `_0_16` text  | Box 8 allocated tips. Decimal amount.                           |
| `dependent_care_benefits`      | `_0_19` text  | Box 10 dependent-care benefits. Decimal amount.                 |
| `nonqualified_plans`           | `_0_21` text  | Box 11 nonqualified-plan amount. Decimal amount.                |
| `control_number`               | `_0_44` text  | Box d control number. Preserve leading zeros.                   |
| `statutory_employee`           | `_0_30` check | Box 13 statutory employee indicator.                            |
| `retirement_plan`              | `_0_31` check | Box 13 retirement plan indicator.                               |
| `third_party_sick_pay`         | `_0_32` check | Box 13 third-party sick pay indicator.                          |
| `employer_foreign_province`    | `_1_16` text  | Foreign employer province. Use subsection `2 - Other`.          |
| `employer_foreign_postal_code` | `_1_10` text  | Foreign employer postal code. Use subsection `2 - Other`.       |
| `w2_indicator_nonstandard`     | `_1_8` check  | Reviewed nonstandard W-2 indicator. Use subsection `2 - Other`. |

Box 12, Box 14, and state/local rows are CCH subgrids under the same W-2
`entries[]` item. They are never sibling top-level sections.

```json theme={null}
{
  "subGrids": [
    {
      "section": "1 - IRS W-2",
      "type": "subgrid",
      "headerLabel": "Code",
      "rowAction": "upsert",
      "subgridEntries": [
        {
          "cells": ["D", "10661.31"],
          "matchValues": { "0": "D" }
        }
      ]
    },
    {
      "section": "1 - IRS W-2",
      "type": "subgrid",
      "headerLabel": "Description",
      "rowAction": "upsert",
      "subgridEntries": [
        {
          "cells": ["CASDI", "1647.69", ""],
          "matchValues": { "0": "CASDI" }
        }
      ]
    },
    {
      "section": "1 - IRS W-2",
      "type": "subgrid",
      "headerLabel": "State wages, tips, etc.",
      "columnEntries": [
        {
          "rowValues": {
            "0": "CA",
            "1": "state-id",
            "2": "75000.00",
            "3": "4200.00",
            "4": "",
            "5": ""
          },
          "matchValues": { "0": "CA" }
        }
      ]
    }
  ]
}
```

Box 12 `cells` positions are fixed:

| Position | Meaning         | Rule                                                   |
| -------- | --------------- | ------------------------------------------------------ |
| `0`      | IRS Box 12 code | Exact reviewed code and row identity in `matchValues`. |
| `1`      | Box 12 amount   | Decimal string without `$` or commas.                  |

The semantic catalog can retain a Box 12 year, but the current CCH overlay
cannot write it. Do not add a third cell.

| Code | Meaning                                                                  |
| ---- | ------------------------------------------------------------------------ |
| `A`  | Uncollected Social Security or RRTA tax on tips                          |
| `B`  | Uncollected Medicare tax on tips                                         |
| `C`  | Taxable cost of group-term life insurance over \$50,000                  |
| `D`  | Elective deferrals to a Section 401(k) plan                              |
| `E`  | Elective deferrals to a Section 403(b) plan                              |
| `F`  | Elective deferrals to a salary-reduction SEP                             |
| `G`  | Elective deferrals and employer contributions to a Section 457(b) plan   |
| `H`  | Elective deferrals to a Section 501(c)(18)(D) plan                       |
| `J`  | Nontaxable sick pay                                                      |
| `K`  | Excise tax on excess golden-parachute payments                           |
| `L`  | Substantiated employee business-expense reimbursements                   |
| `M`  | Uncollected Social Security or RRTA tax on group-term life insurance     |
| `N`  | Uncollected Medicare tax on group-term life insurance                    |
| `P`  | Excludable moving-expense reimbursements for eligible service members    |
| `Q`  | Nontaxable combat pay                                                    |
| `R`  | Employer contributions to an Archer MSA                                  |
| `S`  | Employee salary-reduction contributions to a SIMPLE plan                 |
| `T`  | Adoption benefits                                                        |
| `V`  | Income from exercise of nonstatutory stock options                       |
| `W`  | Employer and employee contributions to an HSA                            |
| `Y`  | Deferrals under a Section 409A nonqualified deferred-compensation plan   |
| `Z`  | Income under Section 409A from a nonqualified deferred-compensation plan |
| `AA` | Designated Roth contributions under a Section 401(k) plan                |
| `BB` | Designated Roth contributions under a Section 403(b) plan                |
| `DD` | Cost of employer-sponsored health coverage                               |
| `EE` | Designated Roth contributions under a governmental Section 457(b) plan   |
| `FF` | Permitted benefits under a qualified small-employer HRA                  |
| `GG` | Income from qualified equity grants under Section 83(i)                  |
| `HH` | Aggregate deferrals under Section 83(i) elections                        |
| `II` | Medicaid waiver payments excluded from gross income                      |

Box 14 `cells` positions are also fixed:

| Position | Meaning            | Rule                                                                            |
| -------- | ------------------ | ------------------------------------------------------------------------------- |
| `0`      | Source description | Exact reviewed text and row identity in `matchValues`.                          |
| `1`      | Amount             | Decimal string without `$` or commas.                                           |
| `2`      | CCH special type   | Normally blank. Use `1` only for RRTA and `2` only for Additional Medicare tax. |

The state/local `rowValues` map is transposed into one CCH column per state:

| Row key | Meaning                                          |
| ------- | ------------------------------------------------ |
| `0`     | Box 15 state code                                |
| `1`     | Box 15 employer state ID number                  |
| `2`     | Box 16 state wages, tips, and other compensation |
| `3`     | Box 17 state income tax                          |
| `4`     | Box 18 local wages, tips, and other compensation |
| `5`     | Box 19 local income tax                          |

Every `columnEntries` item needs either a state identity in `matchValues["0"]`
or an explicit reviewed `columnIndex`. Merge local amounts into their owning
state column. The adapter deliberately drops a local-only row with no state
identity. City and locality codes for Box 20 require unresolved proprietary
lookups, so row keys `6` and `7` are not supported.

Known W-2 gaps include employee name, employer country picker, corrected W-2
flags, agent indicators, and verified city/locality lookup. Do not guess their
IDs.

### 1099-INT field catalog

Use subsection `1 - IRS 1099-INT`, except the two municipal allocation fields
explicitly assigned to `4 - Tax Exempt Interest`.

| Semantic field                    | CCH ID/type   | Meaning and accepted value                                                        |
| --------------------------------- | ------------- | --------------------------------------------------------------------------------- |
| `tsj_code`                        | `_0_0` combo  | Owner: exact `T`, `S`, or `J`.                                                    |
| `payer_name`                      | `_0_5` text   | Payer name.                                                                       |
| `payer_address_1`                 | `_0_6` text   | Payer street address.                                                             |
| `payer_state`                     | `_0_31` combo | Payer two-letter state.                                                           |
| `payer_zip`                       | `_0_32` text  | Payer ZIP.                                                                        |
| `payer_foreign_province`          | `_0_37` text  | Foreign payer province.                                                           |
| `payer_foreign_postal_code`       | `_0_36` text  | Foreign payer postal code.                                                        |
| `payer_tin`                       | `_0_8` text   | Payer TIN, 9 digits with no dashes.                                               |
| `recipient_tin`                   | `_0_9` text   | Recipient TIN, 9 digits with no dashes.                                           |
| `account_number`                  | `_0_18` text  | Account number, preserving leading zeros.                                         |
| `interest_income`                 | `_0_10` text  | Box 1 taxable interest.                                                           |
| `early_withdrawal_penalty`        | `_0_12` text  | Box 2 early-withdrawal penalty.                                                   |
| `us_savings_bonds_treasury`       | `_0_13` text  | Box 3 interest on U.S. Savings Bonds and Treasury obligations.                    |
| `federal_tax_withheld`            | `_0_15` text  | Box 4 federal income tax withheld.                                                |
| `foreign_tax_paid`                | `_0_20` text  | Box 6 foreign tax paid.                                                           |
| `tax_exempt_interest`             | `_0_28` text  | Box 8 tax-exempt interest.                                                        |
| `private_activity_bond_interest`  | `_0_30` text  | Box 9 specified private-activity bond interest.                                   |
| `market_discount`                 | `_0_47` text  | Box 10 market discount.                                                           |
| `bond_premium`                    | `_0_48` text  | Box 11 bond premium.                                                              |
| `bond_premium_treasury`           | `_0_53` text  | Box 12 Treasury-obligation bond premium.                                          |
| `cusip_number`                    | `_0_35` text  | Box 14 CUSIP number.                                                              |
| `state_1_code`                    | `_0_2` combo  | Box 15 first state code.                                                          |
| `state_1_id_number`               | `_0_42` text  | Box 16 state identification number.                                               |
| `state_1_tax_withheld`            | `_0_44` text  | Box 17 state tax withheld.                                                        |
| `resident_state_municipal_amount` | `_3_0` text   | Resident-state municipal interest override. Subsection `4 - Tax Exempt Interest`. |
| `other_state_municipal_amount`    | `_3_1` text   | Other-state municipal interest override. Subsection `4 - Tax Exempt Interest`.    |

All box amounts are decimal strings. `_3_4` is prior-year data and must not be
used. Current gaps include payer city, second address, boxes 5, 7, and 13, OID,
FATCA, second-TIN indicator, a second state row, and detailed municipal
percentages.

### 1099-DIV field catalog

Use subsection `1 - IRS 1099-DIV`.

| Semantic field                   | CCH ID/type   | Meaning and accepted value                                         |
| -------------------------------- | ------------- | ------------------------------------------------------------------ |
| `tsj_code`                       | `_0_0` combo  | Owner: exact `T`, `S`, or `J`.                                     |
| `payer_name`                     | `_0_5` text   | Payer name.                                                        |
| `payer_address_1`                | `_0_6` text   | Payer street address.                                              |
| `payer_state`                    | `_0_32` combo | Payer two-letter state.                                            |
| `payer_zip`                      | `_0_34` text  | Payer ZIP.                                                         |
| `payer_foreign_province`         | `_0_35` text  | Foreign payer province.                                            |
| `payer_foreign_postal_code`      | `_0_36` text  | Foreign payer postal code.                                         |
| `payer_tin`                      | `_0_10` text  | Payer TIN, 9 digits with no dashes.                                |
| `account_number`                 | `_0_23` text  | Account number.                                                    |
| `ordinary_dividends`             | `_0_4` text   | Box 1a total ordinary dividends.                                   |
| `qualified_dividends`            | `_0_33` text  | Box 1b qualified dividends, a subset of Box 1a.                    |
| `capital_gain_distributions`     | `_0_8` text   | Box 2a total capital gain distributions.                           |
| `unrecap_sec_1250_gain`          | `_0_13` text  | Box 2b unrecaptured Section 1250 gain.                             |
| `section_1202_gain`              | `_0_15` text  | Box 2c Section 1202 gain.                                          |
| `collectibles_28_rate`           | `_0_9` text   | Box 2d collectibles 28-percent rate gain amount, not a percentage. |
| `section_897_ordinary_dividends` | `_0_52` text  | Box 2e Section 897 ordinary dividends.                             |
| `section_897_capital_gain`       | `_0_53` text  | Box 2f Section 897 capital gain.                                   |
| `nondividend_distributions`      | `_0_16` text  | Box 3 nondividend distributions.                                   |
| `federal_tax_withheld`           | `_0_18` text  | Box 4 federal income tax withheld.                                 |
| `section_199a_dividends`         | `_0_51` text  | Box 5 Section 199A dividends.                                      |
| `investment_expenses`            | `_0_19` text  | Box 6 investment expenses.                                         |
| `foreign_tax_paid`               | `_0_21` text  | Box 7 foreign tax paid.                                            |
| `foreign_country`                | `_0_22` text  | Box 8 foreign country code, or reviewed `VAR` or `RIC`.            |
| `cash_liquidation`               | `_0_25` text  | Box 9 cash liquidation distributions.                              |
| `noncash_liquidation`            | `_0_26` text  | Box 10 noncash liquidation distributions.                          |
| `fatca`                          | `_0_48` check | Box 11 FATCA filing requirement indicator.                         |
| `exempt_interest_dividends`      | `_0_42` text  | Box 12 exempt-interest dividends.                                  |
| `private_activity_bond_interest` | `_0_43` text  | Box 13 private-activity bond interest dividends.                   |
| `state_1_code`                   | `_0_2` combo  | Box 14 first state code.                                           |
| `state_1_id_number`              | `_0_44` text  | Box 15 state identification number.                                |
| `state_1_tax_withheld`           | `_0_45` text  | Box 16 state tax withheld.                                         |

Current gaps include payer city and second address, recipient fields, a second
state row, QSB stock type, nominee details, tax-exempt allocations, restricted
dividend allocations, and a verified payer country picker.

### 1099-NEC field catalog

Use subsection `1 - IRS 1099-NEC (Nonemployee Compensation)`.

| Semantic field                     | CCH ID/type   | Meaning and accepted value                                     |
| ---------------------------------- | ------------- | -------------------------------------------------------------- |
| `ts_code`                          | `_0_0` combo  | Owner: exact `T`, `S`, or `J`.                                 |
| `payer_name`                       | `_0_5` text   | Payer name.                                                    |
| `payer_street_address`             | `_0_7` text   | Payer street address.                                          |
| `payer_city`                       | `_0_8` text   | Payer city.                                                    |
| `payer_state`                      | `_0_44` text  | Payer two-letter state.                                        |
| `payer_zip`                        | `_0_45` text  | Payer ZIP.                                                     |
| `payer_tin`                        | `_0_11` text  | Payer TIN, 9 digits with no dashes.                            |
| `account_number`                   | `_0_22` text  | Account number.                                                |
| `nonemployee_compensation`         | `_0_15` text  | Box 1 nonemployee compensation.                                |
| `direct_sales_5000_or_more`        | `_0_14` check | Box 2 direct-sales indicator.                                  |
| `excess_golden_parachute_payments` | `_0_55` text  | Box 3 excess golden-parachute payments.                        |
| `federal_tax_withheld`             | `_0_10` text  | Box 4 federal income tax withheld.                             |
| `recipient_address`                | `_0_18` text  | Recipient street-address override.                             |
| `recipient_city`                   | `_0_21` text  | Recipient city override.                                       |
| `recipient_state`                  | `_0_46` combo | Recipient two-letter state override.                           |
| `recipient_zip`                    | `_0_47` text  | Recipient ZIP override.                                        |
| `state_1_tax_withheld`             | `_0_26` text  | Box 5 first state withholding amount.                          |
| `state_1_payer_number`             | `_0_27` text  | Box 6 payer state ID.                                          |
| `state_1_income`                   | `_0_28` text  | Box 7 state income. If absent, CCH may use the federal amount. |

Current gaps include mapped recipient name and TIN, foreign addresses, a
second state row, local amounts, and Form 8919 details. `_1_8` and `_1_9` are
blocked because earlier mappings pointed to the wrong foreign-income cells.

### 1099-MISC field catalog

Use subsection `1 - IRS 1099-MISC (Other Income)`.

| Semantic field                       | CCH ID/type   | Meaning and accepted value                                      |
| ------------------------------------ | ------------- | --------------------------------------------------------------- |
| `ts_code`                            | `_0_0` combo  | Owner: exact `T`, `S`, or `J`.                                  |
| `payer_name`                         | `_0_5` text   | Payer name.                                                     |
| `payer_address_1`                    | `_0_7` text   | Payer street address.                                           |
| `payer_city`                         | `_0_8` text   | Payer city.                                                     |
| `payer_state`                        | `_0_44` text  | Payer two-letter state.                                         |
| `payer_zip`                          | `_0_45` text  | Payer ZIP.                                                      |
| `payer_ein`                          | `_0_11` text  | Payer EIN, 9 digits with no dashes.                             |
| `recipient_tin`                      | `_0_12` text  | Recipient SSN, ITIN, or EIN with punctuation removed.           |
| `recipient_address`                  | `_0_18` text  | Recipient street-address override.                              |
| `account_number`                     | `_0_22` text  | Account number.                                                 |
| `rents`                              | `_0_4` text   | Box 1 rents.                                                    |
| `royalties`                          | `_0_6` text   | Box 2 royalties.                                                |
| `other_income`                       | `_0_9` text   | Box 3 other income.                                             |
| `federal_tax_withheld`               | `_0_10` text  | Box 4 federal income tax withheld.                              |
| `fishing_boat_proceeds`              | `_0_13` text  | Box 5 fishing-boat proceeds.                                    |
| `medical_health_care_payments`       | `_0_14` text  | Box 6 medical and health care payments.                         |
| `direct_sales_5000_or_more`          | `_0_19` check | Box 7 direct-sales indicator.                                   |
| `substitute_payments`                | `_0_16` text  | Box 8 substitute payments.                                      |
| `crop_insurance_proceeds`            | `_0_20` text  | Box 9 crop-insurance proceeds.                                  |
| `gross_proceeds_attorney`            | `_0_25` text  | Box 10 gross proceeds paid to an attorney.                      |
| `fish_purchased_for_resale`          | `_0_15` text  | Box 11 fish purchased for resale.                               |
| `section_409a_deferrals`             | `_0_36` text  | Box 12 Section 409A deferrals.                                  |
| `fatca_filing_requirement`           | `_0_53` check | Box 13 FATCA filing requirement.                                |
| `nonqualified_deferred_compensation` | `_0_37` text  | Box 15 nonqualified deferred compensation.                      |
| `state_1_tax_withheld`               | `_0_26` text  | Box 16 state tax withheld.                                      |
| `state_1_payer_number`               | `_0_27` text  | Box 17 state payer number.                                      |
| `state_1_income`                     | `_0_28` text  | Box 18 state income.                                            |
| `multi_form_code`                    | `_0_35` text  | CCH entity number: blank or `1` for first, then `2`, and so on. |

Current gaps include recipient name composition, recipient city/state/ZIP,
foreign addresses, Box 14 golden-parachute amount, separate Section 409A income,
other-income description, a second state row, local amounts, and Form 8919
details. Do not guess unknown `_0_29`, `_0_30`, or `_0_31` as a second row.

### 1099-G field catalog

Use subsection `1 - IRS 1099-G` for the default route.

| Semantic field               | CCH ID/type   | Meaning and accepted value                                              |
| ---------------------------- | ------------- | ----------------------------------------------------------------------- |
| `tsj_code`                   | `_0_0` combo  | Owner: exact `T`, `S`, or `J`.                                          |
| `payer_name`                 | `_0_5` text   | Government payer name.                                                  |
| `payer_address_1`            | `_0_6` text   | Payer street address.                                                   |
| `payer_city`                 | `_0_7` text   | Payer city.                                                             |
| `payer_state`                | `_0_28` text  | Payer two-letter state.                                                 |
| `payer_zip_code`             | `_0_29` text  | Payer ZIP.                                                              |
| `payer_tin`                  | `_0_10` text  | Payer TIN, 9 digits with no dashes.                                     |
| `recipient_tin`              | `_0_11` combo | Recipient TIN in the exact CCH-recognized representation.               |
| `recipient_name`             | `_0_14` combo | Combined recipient full name. Adapter may compose first plus last name. |
| `recipient_address`          | `_0_17` combo | Recipient street-address override.                                      |
| `recipient_city`             | `_0_20` text  | Recipient city override.                                                |
| `recipient_state`            | `_0_21` text  | Recipient two-letter state override.                                    |
| `recipient_foreign_country`  | `_0_35` text  | Recipient two-letter foreign country code.                              |
| `recipient_foreign_province` | `_0_36` text  | Recipient foreign province.                                             |
| `account_number`             | `_0_24` text  | Account number.                                                         |
| `unemployment_compensation`  | `_0_4` text   | Box 1 unemployment compensation.                                        |
| `state_local_tax_refund`     | `_0_9` text   | Box 2 state refund only. It cannot carry a local refund.                |
| `tax_year`                   | `_0_12` text  | Box 3 tax year in exact `YYYY` form.                                    |
| `federal_tax_withheld`       | `_0_13` text  | Box 4 federal tax withheld.                                             |
| `rtaa_payments`              | `_0_15` text  | Box 5 RTAA payments.                                                    |
| `taxable_grants`             | `_0_16` text  | Box 6 taxable grants.                                                   |
| `agriculture_payments`       | `_0_18` text  | Box 7 agriculture payments on the default route.                        |
| `market_gain`                | `_0_23` text  | Box 9 market gain.                                                      |

If reviewed routing metadata says `form_destination: "F"` and agriculture
payments are present, the adapter reroutes the document to `Sch F / 4835 -
Farm`, direct section `3 - Income`, and writes the amount to both `_3_13`
total and `_3_14` taxable. This route emits no payer or recipient fields and is
mutually exclusive with the default route. A document needing both farm and
nonfarm boxes is currently unsupported.

Current gaps include corrected flags, payer foreign address, recipient ZIP,
unemployment repaid, state refund taxability facts, Box 10 and Box 11 state
details, local refunds and withholding, PFML indicators, and mixed farm routing.

### 1098-E field catalog

Use subsection `1 - IRS 1098-E`.

| Semantic field           | CCH ID/type   | Meaning and accepted value                                                                  |
| ------------------------ | ------------- | ------------------------------------------------------------------------------------------- |
| `tsj_code`               | `_0_13` combo | Borrower owner: exact `T`, `S`, or `J`.                                                     |
| `state_code`             | `_0_15` text  | CCH state allocation, two-letter code. Not the lender address state.                        |
| `lender_name`            | `_0_17` text  | Lender or recipient name.                                                                   |
| `lender_address`         | `_0_18` text  | Lender street address.                                                                      |
| `lender_state`           | `_0_20` combo | Lender two-letter state passed as a picker literal and validated by CCH.                    |
| `lender_zip`             | `_0_21` text  | Lender ZIP.                                                                                 |
| `lender_tin`             | `_0_23` text  | Lender EIN, 9 digits with no dashes.                                                        |
| `borrower_tin`           | `_0_24` text  | Borrower SSN or ITIN, 9 digits with no dashes.                                              |
| `account_number`         | `_0_9` text   | Account number.                                                                             |
| `student_loan_interest`  | `_0_2` text   | Box 1 student loan interest received by lender.                                             |
| `excludes_pre_2004_fees` | `_0_4` check  | Box 2 indicates Box 1 excludes pre-September 2004 origination fees or capitalized interest. |

`lender_city` at `_0_19` is blocked because the CCH picker code lookup is not
available. Borrower name/address, lender phone, and foreign address fields are
not in the semantic adapter and must not be improvised.

### 1098-T field catalog

Use subsection `1 - IRS 1098-T`.

| Semantic field                           | CCH ID/type   | Meaning and accepted value                                                   |
| ---------------------------------------- | ------------- | ---------------------------------------------------------------------------- |
| `tsj_code`                               | `_0_13` combo | Student owner: exact `T` or `S`. Live CCH rejects `J`.                       |
| `state_code`                             | `_0_15` combo | CCH state allocation, two-letter code.                                       |
| `filer_name`                             | `_0_17` text  | Eligible educational institution or filer name.                              |
| `filer_address`                          | `_0_18` text  | Filer street address.                                                        |
| `filer_city`                             | `_0_19` text  | Filer city.                                                                  |
| `filer_state`                            | `_0_20` text  | Filer two-letter state.                                                      |
| `filer_zip`                              | `_0_21` text  | Filer ZIP.                                                                   |
| `filer_tin`                              | `_0_23` text  | Filer TIN, 9 digits with no dashes.                                          |
| `student_tin`                            | `_0_24` text  | Student TIN, 9 digits with no dashes.                                        |
| `account_number`                         | `_0_9` text   | Student account number.                                                      |
| `payments_received`                      | `_0_2` text   | Box 1 payments for qualified tuition and related expenses.                   |
| `adjustments_prior_year`                 | `_0_11` text  | Box 4 prior-year adjustment.                                                 |
| `scholarships_or_grants`                 | `_0_6` text   | Box 5 scholarships or grants.                                                |
| `adjustments_to_scholarships_prior_year` | `_0_10` text  | Box 6 prior-year scholarship or grant adjustment.                            |
| `includes_next_year_academic_period`     | `_0_30` check | Box 7 indicates Box 1 includes the next year's January through March period. |
| `at_least_half_time`                     | `_0_4` check  | Box 8 at-least-half-time student.                                            |
| `graduate_student`                       | `_0_5` check  | Box 9 graduate student.                                                      |
| `insurance_reimbursements`               | `_0_0` text   | Box 10 insurance reimbursement or refund.                                    |

Current gaps include filer phone and foreign address, student name/address,
dependent name, filing-status metadata, and CCH additional-information fields.
Boxes 2 and 3 are reserved and must not be synthesized.

### 1099-SA field catalog

Use subsection `1 - IRS 1099-SA`.

| Semantic field                     | CCH ID/type    | Meaning and accepted value                                                                                                                                                                                                                          |
| ---------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ts_code`                          | `_0_3` combo   | Account holder: exact `T` or `S`.                                                                                                                                                                                                                   |
| `trustee_name`                     | `_0_2` text    | Trustee or payer name.                                                                                                                                                                                                                              |
| `trustee_tin`                      | `_0_30` text   | Trustee TIN, 9 digits with no dashes.                                                                                                                                                                                                               |
| `recipient_tin`                    | `_0_31` text   | Recipient TIN, 9 digits with no dashes.                                                                                                                                                                                                             |
| `account_number`                   | `_0_37` text   | Account number.                                                                                                                                                                                                                                     |
| `gross_distribution`               | `_0_39` text   | Box 1 gross distribution.                                                                                                                                                                                                                           |
| `earnings_on_excess_contributions` | `_0_10` text   | Box 2 earnings on excess contributions.                                                                                                                                                                                                             |
| `distribution_code`                | `_0_7` text    | Box 3: `1` normal, `2` excess, `3` disability, `4` death distribution other than code 6, `5` prohibited transaction, or `6` death after year of death to a nonspouse beneficiary. Code 6 is semantically valid but has not been live-tested in CCH. |
| `fmv_on_date_of_death`             | `_0_16` text   | Box 4 fair market value on date of death. Include only when printed with distribution code `4` or `6`.                                                                                                                                              |
| `hsa_archer_msa_ma_msa`            | fan-out checks | Box 5 account type. HSA -> `_0_41`; Archer MSA -> `_0_42`; MA MSA -> `_0_43`. Exactly one may be true.                                                                                                                                              |

The canonical `federal_tax_withheld` field is blocked because Form 1099-SA has
no federal-withholding box and no verified CCH target. Trustee and recipient
address fields are not in this adapter.

### SSA-1099 field catalog

These fields remain inside one grid entry. Medicare fields use subsection
`2 - Other`; all other supported fields use `1 - IRS SSA-1099`.

| Semantic field             | CCH ID/type  | Meaning and accepted value                                                |
| -------------------------- | ------------ | ------------------------------------------------------------------------- |
| `ts_code`                  | `_0_0` combo | Beneficiary owner: exact `T`, `S`, or `J`.                                |
| `payee_name`               | `_0_4` text  | Beneficiary or payee name.                                                |
| `benefits_paid`            | `_0_6` text  | Box 3 benefits paid.                                                      |
| `benefits_repaid`          | `_0_7` text  | Box 4 benefits repaid to SSA.                                             |
| `net_benefits`             | `_0_8` text  | Box 5 net benefits, equal to Box 3 minus Box 4. Do not subtract Medicare. |
| `federal_tax_withheld`     | `_0_11` text | Box 6 voluntary federal income tax withholding.                           |
| `claim_number`             | `_0_15` text | Box 8 claim number, exactly as printed.                                   |
| `medicare_part_b_premiums` | `_1_2` text  | Medicare Part B premiums. Use subsection `2 - Other`.                     |
| `medicare_part_d_premiums` | `_1_5` text  | Medicare Part D prescription drug premiums. Use subsection `2 - Other`.   |

Normalize the duplicate semantic alias `voluntary_tax_withheld` to
`federal_tax_withheld` and stop if both values disagree. The undifferentiated
`medicare_premiums` total is blocked because CCH requires Part B and Part D
separately. Beneficiary TIN/address, lump-sum fields, treaty fields, and state
routing are not supported by this overlay.

### Complete multi-subsection example

This SSA-1099 example shows the important rule that both subsections belong to
one statement row:

```json theme={null}
{
  "form": "Social Security Benefit Statement (SSA-1099)",
  "sections": [
    {
      "section": "1 - Social Security Benefit Statement (SSA-1099)",
      "type": "grid",
      "entries": [
        {
          "action": "add",
          "subSections": [
            {
              "subSection": "1 - IRS SSA-1099",
              "fields": [
                {
                  "automationId": "_0_0",
                  "type": "combo",
                  "action": "set",
                  "value": "T",
                  "label": "Owner"
                },
                {
                  "automationId": "_0_4",
                  "type": "text",
                  "action": "set",
                  "value": "JORDAN TAXPAYER",
                  "label": "Payee name"
                },
                {
                  "automationId": "_0_6",
                  "type": "text",
                  "action": "set",
                  "value": "24400.00",
                  "label": "Box 3 benefits paid"
                },
                {
                  "automationId": "_0_7",
                  "type": "text",
                  "action": "set",
                  "value": "400.00",
                  "label": "Box 4 benefits repaid"
                },
                {
                  "automationId": "_0_8",
                  "type": "text",
                  "action": "set",
                  "value": "24000.00",
                  "label": "Box 5 net benefits"
                },
                {
                  "automationId": "_0_11",
                  "type": "text",
                  "action": "set",
                  "value": "2400.00",
                  "label": "Box 6 federal withholding"
                },
                {
                  "automationId": "_0_15",
                  "type": "text",
                  "action": "set",
                  "value": "123-45-6789A",
                  "label": "Box 8 claim number"
                }
              ]
            },
            {
              "subSection": "2 - Other",
              "fields": [
                {
                  "automationId": "_1_2",
                  "type": "text",
                  "action": "set",
                  "value": "1978.80",
                  "label": "Medicare Part B premiums"
                },
                {
                  "automationId": "_1_5",
                  "type": "text",
                  "action": "set",
                  "value": "420.00",
                  "label": "Medicare Part D premiums"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

### CCH dispatch and verification

#### Dispatch `client.data.write`

Start `client.data.write` after review. Pass the MCP task ID at the capability
boundary and a path relative to that task's sandbox. The server derives the
storage path and working directory. Do not send `sandboxDir`.

```json theme={null}
{
  "input": {
    "connectionId": "019f1111-2222-7333-8444-555566667777",
    "capability": "client.data.write",
    "params": {
      "taskId": "019f2222-3333-7444-8555-666677778888",
      "softwareClientId": "2025I:123-AFILED:V1",
      "payloadPath": "user_uploads/rpa_payload.json"
    }
  }
}
```

When `softwareClientId` is the full `externalId`, omit
`softwareClientVersion`. If `externalId` is a bare client ID, pass the CCH
return version from `metadata.version`, such as `V1`. This value is not a tax
year.

Poll `workspace.connectionCapabilityRun(id:)` until completion. CCH data entry
normally takes 15 to 30 minutes. Check the run at intervals of 2 to 5 minutes;
do not expect an early response or treat `RUNNING` as a failure. The capability
returns field results and the task-relative directory containing the full
execution artifacts:

```json theme={null}
{
  "success": true,
  "client_id": "2025I:123-AFILED:V1",
  "fields": [],
  "artifactPath": "artifacts/cch/write/RUN_ID"
}
```

Resolve exact files beneath `artifactPath` through the same MCP task file API.
Treat a top-level `success: true` as necessary but not sufficient. Review the
returned field results and the action log, screenshots, and result file in the
artifact directory.

#### Verify the CCH write

The bot writes its diagnostics into the MCP task sandbox. Preserve and review
at least:

* `rpa_result.json`
* `action_log.jsonl`
* screenshots captured during entry
* the post-entry CCH backup when available

For higher assurance, run `client.data.read` again and compare the post-entry
backup or parsed values with the approved payload. Do not rely only on the RPA
process exiting successfully.

## Current gaps

The provider-neutral and hardened public workflow still has gaps:

1. **No public semantic compiler.** Internal `DataEntryPlan` models and provider
   emitters exist, but there is no single capability that accepts the neutral
   plan, resolves the selected adapter, and returns blocking coverage. CCH
   currently filters already-built RPA forms instead of implementing the same
   `DataEntryPlan` emitter boundary as every provider.
2. **Provider contracts are inconsistent.** CCH and UltraTax use staged paths,
   while GoSystem can use an inline plan. Client selectors, read results, write
   results, clear behavior, and post-read support differ.
3. **No stable public automation catalog.** Automation IDs and CCH screen names
   are internal implementation details and can drift after a CCH release. The
   semantic and provider catalogs need explicit tax-software and tax-year
   versions bound into approval.
4. **Review is procedural, not enforced.** Add an approval token or reviewed
   artifact revision so the write capability can prove which payload a human
   approved.
5. **Idempotency is incomplete.** Replaying an `add` entry can duplicate a row.
   Prefer reviewed `update` instructions with `entityIndex`, or add an explicit
   idempotency key and row identity contract.
6. **Coverage is not uniformly blocking.** Some emitters can skip or filter a
   field without returning a common emitted, transformed, blocked, and dropped
   result. Partial execution must be prevented.
7. **Semantic types need a version 2.** The current plan does not embed field
   meanings, value schemas, allowed enums, review rules, typed table columns,
   or row identities. The static instruction catalog carries those facts for
   now.
8. **Readback is not semantic or uniform.** `client.data.read` may mean a
   backup artifact or a field read, and post-write read is optional. There is
   no universal semantic diff result.
9. **Output verification is not one operation.** A robust public recipe should
   return signed diagnostic artifacts and a post-entry backup from the same run.
10. **Upload binding can be stronger.** The existing tus endpoint enforces an
    upload policy, but the write call does not prove that the attached JSON is
    the exact content a reviewer approved. Bind an attachment ID and content
    hash into approval and server-side dispatch.
11. **PII handling is implicit.** Plans and artifacts can contain SSNs, EINs,
    account numbers, and source paths. Retention, redaction, audit, and access
    policies need an explicit public contract.
12. **CCH v2 discovery and file paths are not normalized.** The v2 CCH
    capabilities are runnable through the legacy connection's provider-key
    fallback but are not yet included in its advertised capability catalog.
    The v2 backup also returns a full `sandboxes/{taskId}/...` storage key while
    `Task.file(path:)` accepts only the task-relative suffix. Unify discovery
    and return task-relative artifact paths before treating this as a stable
    provider-neutral contract.

## Recommended public contract

The user-approved two-step contract should eventually be:

1. Compile the reviewed semantic plan for an exact execution binding.
2. Execute only the compiled artifact and hashes returned by that compile.

```json theme={null}
{
  "connectionId": "019f1111-2222-7333-8444-555566667777",
  "capability": "client.data.compile",
  "params": {
    "taskId": "019f2222-3333-7444-8555-666677778888",
    "softwareClientId": "2025I:123-AFILED:V1",
    "taxYear": 2025,
    "semanticPlanPath": "artifacts/tax_entry_instructions.json"
  }
}
```

The compile result should contain the compiled artifact ID, semantic and
compiled hashes, adapter and catalog versions, and full coverage. After human
approval, dispatch:

```json theme={null}
{
  "connectionId": "019f1111-2222-7333-8444-555566667777",
  "capability": "client.data.write",
  "params": {
    "taskId": "019f2222-3333-7444-8555-666677778888",
    "softwareClientId": "2025I:123-AFILED:V1",
    "compiledArtifactId": "artifact_019f...",
    "semanticPlanHash": "sha256:...",
    "compiledPlanHash": "sha256:...",
    "approvalToken": "approval_019f...",
    "idempotencyKey": "tax-entry-019f..."
  }
}
```

The server then resolves and verifies:

```text theme={null}
compiled artifact ID
  -> validate workspace, task, connection, client, and tax year
  -> verify semantic and compiled hashes plus catalog versions
  -> verify approval token and idempotency key
  -> derive the provider payload path and sandbox directory
  -> dispatch the selected provider worker
  -> return field outcomes and a normalized post-write diff
```

This preserves a tax-software-neutral instruction file, keeps vendor details in
adapters, and prevents callers from supplying arbitrary host or storage paths.
