# Domain favicon and staged file upload
> Current behavior: `domain_favicon_apply` and `domain_register` take the favicon only as an upload from the user's
> computer. The tool signs one presigned PUT for the console's favicon grant, then the completed upload is saved.
> The server never receives the file or downloads a link. The staged-file and link sections below are history.
Workflow: `account.domains`. Tool: `domain_favicon_apply`. Task type: `domain-favicon`.
It reuses `domains_get` for selection and readback. It does not add favicon clearing, file-template/channel-icon/logo/profile uploads, pApp uploads, or a combined create-record-with-favicon wizard. Those remain separate gaps. No real publ, storage, browser, or UI execution was performed by the implementer. Human upload availability and live publ/S3, rendered UI, Hermes, hosted authorization, and DB/deployment verification remain on hold.
## Human upload and host contract
It is not an MCP tool or an HTTP route. After authenticating the person and verifying the selected target, the host constructs `{connectionId,sellerId,operation:"domain-favicon",domainId,recordId?}` itself and returns only the resulting `assetId` to the agent. A hosted route must never accept these identity claims verbatim from the browser. Hosts must partition state by principal and environment, enforce request size/quota/CSRF requirements, and use the same credential-connection lock as the MCP runtime.
The current stdio server reads staged files under `<stateDirectory>/assets`. It does not provide a human upload entry point. Without an integrating host, the agent must direct the person to the returned console link. Do not manually collect paths, file bytes, URLs, account passwords, or tokens through MCP.
The private store uses opaque IDs, a 0700 directory, 0600 files, no-follow reads, a 24-hour staging lifetime, a byte checksum, and account/operation/target binding. The bridge accepts ICO files up to 1 MiB with 1–32 frames. Each frame is at most 192 × 192 and must be PNG or an uncompressed Windows DIB with supported 1/4/8/24/32-bit depth. This is a bridge bound, not a claimed server size limit. Frame boundaries and embedded dimensions are checked; pixels are not decoded, PNG CRCs are not validated, and this is not a malware scan. Expired staging files and unreferenced S3 objects are not automatically deleted. Host retention and operator cleanup remain required.
## Runtime configuration and upload
Configure all three together in the selected environment profile: `resourceGatewayApiOrigin`, `uploadBucket`, `uploadRegion`. Environment overrides are `PUBL_RESOURCE_GATEWAY_API_ORIGIN`, `PUBL_UPLOAD_BUCKET`, and `PUBL_UPLOAD_REGION`. The resource gateway is a distinct origin from the DNS service and general API. Custom API origins inherit none of another environment's auxiliary settings. No real service address, bucket, region, or credentials are guessed or bundled.
Account-owner credentials authorize the resource request and DNS writes. The bridge verifies the returned bucket and region against host configuration, requires a generated object key and an unexpired grant, and uses temporary credentials only in memory. The generated object identity is journaled before upload; the credentials never enter task files or MCP results.
AWS SDK v3 performs one `PutObject` using an explicit regional S3 endpoint, path-style bucket addressing, no ambient credential provider, no automatic retries or region redirects, and a 30-second abort signal. The body includes its SHA-256 checksum; acknowledgement requires HTTP 200 and the matching response checksum. The workflow does not request an ACL change, multipart upload, public GET, or object deletion. This uses the official [PutObject contract](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/command/PutObjectCommand/) and [S3 checksum guidance](https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/s3-checksums.html).
## Workflow and recovery
1. Select the domain detail or CHANNEL row with `domains_get`. Copy its revision; a record-view revision is not a row revision.
2. Provide `requestId`, `domainId`, optional `recordId`, `expectedRevision`, and the host-issued `assetId` in one call. For a new task, `dryRun:true` reads and validates without credentials, storage upload, favicon PUT, or a task record. Existing-task replay follows the saved-history rule below.
3. Recheck target identity, account owner, staged bytes, and revision. Persist `issuing` before requesting a grant and `uploading` with the generated object identity before S3 PUT. Persist `uploaded` after acknowledgement.
4. Recheck the original target revision after upload. Persist `sent`, write only the source `fileSrc` body, then observe the exact domain or record and connected-channel identity.
5. Success requires a matching saved favicon URL and the acknowledged upload receipt. Return a fresh target revision.
An uncertain credential request or upload stops for operator inspection and possible orphan reconciliation. Resume never requests a second grant or reuploads bytes for that task. No upload retry is inferred from an absent/malformed receipt. A definite favicon rejection may retry the PUT using the acknowledged object; an uncertain sent PUT is read back only. Revision conflicts after upload retain the object and stop before writing. The source API supplies no server-side conditional update or transaction, so a separate concurrent actor can still race between the final read and PUT. No rollback or cleanup is attempted automatically.
Use `task_status` and `task_resume` with `taskType:"domain-favicon"`. A completed task result is historical. Keep the original task ID, connection, target, asset, and revision on repeated calls.
## Account response context
Grant issuance, object upload and both favicon save endpoints bind their responses to the current account owner, connection, token and full credential bundle. Configured renewal completes before pinning that context. A context change after dispatch is `DOMAIN_CONTEXT_CHANGED` with an unknown outcome, including failed HTTP responses and lost storage acknowledgements. Do not start a new task to bypass it. Grant/upload stages stay held for inspection without reissue/reupload; a sent save is reconciled by reading its existing effect. Source status and checksum requirements are unchanged.
## Saved plan replay
For an existing task ID, `dryRun` returns saved history with `historical: true`,
`replayed: true` and false current verification. It does not freshly validate the
target or asset, repeat a business request, or change the saved journal. No current
console or action link is attached. Follow `nextStep` to read current state; retain
the same task ID for status/resume or inspection of an uncertain result. A new task
ID still follows the normal fresh-plan rules. Do not bypass an uncertain outcome
by inventing another request ID.
See the [tool reference](../tools/publ_domain_favicon_apply.md) for the current saved-plan contract.