fix(daemon): answer 404 for an expired or unknown resource id
Summary
A GET of /artifacts/<id> for an artifact that was already downloaded, has expired, or never existed answered HTTP 500 with COMMAND_FAILED. Expired upload ids on /upload/direct and /upload/finalize did the same. Nothing failed on the host, but proxies and gateways logged each one as a server fault.
statusCodeForNormalizedError now reads the normalized error's details. It maps COMMAND_FAILED with details.reason: "RESOURCE_EXPIRED" to 404. The human_control_active 423 rule moved into it, so /rpc and REST use one mapper, and the statusCodeForDaemonError wrapper is gone. REST error bodies add reason when the error has one, and a hint (usually present, since the normalized error fills in a default hint for most codes). Full details is still never sent. The code stays COMMAND_FAILED. The PR includes a changeset and a note in remote-proxy.md.
The 423 rule used to apply only to a failed response that a /rpc handler returned. It now also covers the REST routes and thrown /rpc failures, which answered 500 before. A PUT /admin/leases/<id> refused during a human-control hold now answers 423. So does a non-streamed /rpc call whose handler throws human_control_active.
The status is 404, not 410, because a TTL registry cleans up silently and cannot tell an expired id from one that never existed. A /rpc call that streams progress (the CLI without --json) has already answered 200, so it keeps 200 and carries the failure in its final envelope.
Wire compat: the three http-errors.ts declarations are re-recorded in the ledger with compatibleChanges acks. The acks state the 404 and 423 moves. No client branches on these statuses on the affected routes, and the body fields are additive optional fields. rpcProtocolVersion is unchanged.
Possible follow-up: the cross-tenant 401 ("belongs to a different tenant") still confirms that an id exists.
Validation
Tested at 8103182, merge base 45125d7. pnpm check:affected --run --head HEAD passed with exactCommit: true: format, lint, typecheck, layering, fallow, build, vitest-related (579 tests), daemon-wire-compat (protocol unchanged), and the docs checks. With the old mapper restored, the new and flipped tests fail, including the new /admin/leases 423 test. GitHub still owns the device and integration lanes. No device run, because this changes no device behavior.