# Handoff — Onda 2.A core MERGED + 2 of 3 follow-ups MERGED/OPEN, 1 remaining

**Data:** 2026-04-26 (end of focused Onda 2.A session)
**Worktree:** `/Users/luizpenha/monetarie/.worktrees/sta-paridade`
**Last branch worked on:** `sta/onda2a-resume-upload` (PR #36 OPEN, awaiting merge)
**Next continuation point:** see `## Resumption checklist` and `## Decision tree at session start` below

> **READ THIS DOC FIRST in the next session, before any code or commands.** It captures every commit, every PR state, the touchstones invariants, the deferred work, the pre-existing issues we hit, and the exact decision tree for picking up cleanly.

---

## TL;DR (one paragraph)

Onda 2.A (resilient transfer — chunked upload + ranged download + ETag) shipped as PR #30 (8 commits, 33 new tests) on 2026-04-26. Two of three documented follow-ups followed: PR #34 (worker chunked-upload wiring + `bytes_uploaded` persistence, MERGED) and PR #36 (`Operations.resume_upload/3` public restart-after-crash entry point, **OPEN at time of writing**). One follow-up remains: **ranged-resume on transient mid-download failure** (~2-3h, needs Manual §6.4 re-read for `bytes=N-` open-ended Range form). Onda 2.A core acceptance criteria are met in production; the remaining follow-up improves resilience under specific transient-failure paths but is not a blocker for any ATM downstream consumer.

---

## What's in main (chronologically)

| # | Commit on main | Purpose | Test count delta |
|---|---|---|---|
| 1 | `301503ec` | PR #24 — Onda 1 (parent) MERGED prior to this session | baseline |
| 2 | `3af17964` | PR #30 — **Onda 2.A core** (Tasks 1-7) | +33 tests |
| 3 | `ed03ce39` | PR #34 — **Follow-up #1**: Worker chunked-upload wiring + bytes_uploaded persistence | +6 tests |
| 4 | `1d50adfd` | PR #35 — Unrelated SPB chore (test sweep) | — |
| 5 | (PR #36 pending) | Follow-up #3: `Operations.resume_upload/3` | +6 tests pending |

**Origin/main HEAD at session end:** `1d50adfd` (will advance to PR #36 merge commit when that lands).

### Detailed commit-level inventory (PR #30 + #34 + #36)

**PR #30 (Onda 2.A core, MERGED at `3af17964`)** — 10 commits preserved in regular merge:
- `5bae4f12` docs(sta): Onda 2.A bite-sized plan + Task 0 Manual Verification report
- `e4b53ceb` docs(sta): handoff for Onda 2.A pause — Task 0 done, Tasks 1-7 pending
- `34104351` feat(sta): Client.posicao_upload + RangesRecebidos parser (**Task 1**)
- `31283d37` feat(sta): Client.upload_part with Content-Range (**Task 2**)
- `15dbf667` feat(sta): Client.download_part + ETag/X-Content-Hash plumbing (**Task 3**)
- `9f214a2e` feat(sta): outbound_files migration for resilient transfer columns (**Task 4**)
- `d00c965c` feat(sta): Operations.upload_with_retry chunked upload + reconciliation (**Task 5**)
- `ce29550d` feat(sta): Operations.download_with_retry + ETag/X-Content-Hash verify (**Task 6**)
- `5baad8df` docs(sta): handoff update — Onda 2.A Tasks 1-6 complete
- `cacc0ecc` docs(sta): handoff — record PR #30 URL

**PR #34 (Follow-up #1, MERGED at `ed03ce39`)** — single commit:
- `bacc5a07` feat(sta): wire Outbound.Worker to chunked-upload + bytes_uploaded persistence

**PR #36 (Follow-up #3, OPEN)** — single commit + this handoff doc:
- `9ff657fa` feat(sta): Operations.resume_upload/3 — restart-after-crash entry point

**PR #36 will likely become 2 commits** if this handoff doc gets committed onto the same branch before merge.

---

## Public API surface added by Onda 2.A (post-merge state)

### `StaConnector.Sta.Client` (lib/sta_connector/sta/client.ex)

| Function | Manual ref | Purpose |
|---|---|---|
| `posicao_upload/2` | §5.3.1 | Query `<RangesRecebidos>` + `<Situacao>` for a protocol |
| `upload_part/2` | §5.6 | PUT a chunk with `Content-Range` header |
| `download_part/2` | §6.4 | GET a byte range with optional `If-Match` / `If-Unmodified-Since` |
| `download_file/2` | §6.1 | Full download (existing — now extracts ETag, Last-Modified, X-Content-Hash) |

### `StaConnector.Sta.Operations` (lib/sta_connector/sta/operations.ex)

| Function | Purpose | DB-coupled? |
|---|---|---|
| `upload_with_retry/4` | Request protocol + upload (single PUT or chunked + reconcile) with retries/circuit breaker/rate limiter | No |
| `upload_content/3` | Chunked upload primitive given an already-issued protocol; fires `on_chunk_progress` per chunk | No |
| `resume_upload/3` | Restart-after-crash; queries `posicao_upload` first, uploads only missing chunks | No |
| `download_with_retry/2` | Full download with retries + circuit breaker + X-Content-Hash integrity verify | No |
| `verify_file_integrity/2` | Pre-existing (Onda 1) | No |

### `StaConnector.Sta.Types` (lib/sta_connector/sta/types.ex)

| Struct | New in Onda 2.A | Notes |
|---|---|---|
| `Types.PosicaoUpload` | ✅ NEW (Task 1) | `protocol_number`, `ranges_received: [{start, end_inclusive}]`, `situacao: :nao_iniciada \| :pendente \| :finalizada` |
| `Types.UploadResult` | (extended Task 5) | Same shape; surfaces `nil` protocol_number on chunked path so caller's `||` fallback uses request-side protocol |
| `Types.DownloadResult` | (extended Task 3+6) | New optional fields: `:etag`, `:last_modified`, `:x_content_hash`. Pre-existing `:hash` kept for backwards compat |

### `StaConnector.Outbound` (lib/sta_connector/outbound.ex)

| Function | Purpose |
|---|---|
| `set_bytes_uploaded/2` | Persist chunked-upload progress; idempotent (accepts repeated and non-monotonic writes) |

### `StaConnector.Files.OutboundFile` schema (lib/sta_connector/files/outbound_file.ex)

| Column | Type | Default | Purpose |
|---|---|---|---|
| `etag` | `string` | nil | RFC 7232 ETag for download `If-Match` preconditions |
| `last_modified` | `utc_datetime` | nil | RFC 7232 timestamp for `If-Unmodified-Since` |
| `bytes_uploaded` | `bigint NOT NULL` | 0 | Cumulative bytes BCB has acked per posicao_upload |

Migration: `priv/repo/migrations/20260426150000_add_resilient_transfer_columns.exs` (applied to dev DB on port 15432 + test DB).

---

## Touchstones (post Onda 2.A core; pre PR #36 merge)

All measured on `9ff657fa` (current branch HEAD):

```
$ mix compile
5 baseline warnings — UNCHANGED from pre-Onda-1 state

$ mix test test/sta_connector/sta/client_test.exs
55 tests, 6 failures
# All 6 failures are pre-existing Soap.parse_response baseline (orthogonal)

$ mix test test/sta_connector/sta/operations_test.exs
51 tests, 0 failures
# +6 from PR #36 (resume_upload) on top of the 45 from PR #30+#34

$ mix test test/sta_connector/files/outbound_file_test.exs
7 tests, 0 failures

$ mix test test/sta_connector/application_test.exs
3 tests, 0 failures

$ mix test test/sta_connector/outbound_test.exs --only describe:"set_bytes_uploaded/2 (Onda 2.A worker chunked-wiring follow-up)"
4 tests, 0 failures (33 excluded)

# Suite-level outbound_test has 9 PRE-EXISTING :utc_datetime/usec mismatch failures
# unrelated to any Onda 2.A work — confirmed via `git stash` on the same code state
# (see "Pre-existing issues" section below).
```

**Combined Onda 2.A test suite:** 116 tests, 6 baseline failures (Soap.parse_response). 39 net new tests from PR #30 + #34 + #36.

---

## Pattern: Manual Verification — gate status

The Pattern: Manual Verification gate (`sta/docs/plans/2026-04-26-sta-conformance-rollout.md#pattern-manual-verification`) requires every Onda 2-4 sub-PR to inventory wire-format / endpoint / response-code / field-name / numeric-threshold claims and tag each `[VERIFIED §X.Y]`, `[STUDY-CONJECTURE]`, or `[NEEDS-OPERATOR-CONFIRM]`.

**PR #30** had a comprehensive Task 0 that read Manual STA v1.5 §2.6, 5.3-5.6, 6.1-6.4, 7, 8, and Tabela 3. It caught **4 misdiagnoses** and **5 new findings** against the parent plan. All findings are documented in PR #30 body, the Onda 2.A bite-sized plan, and the original handoff doc.

**PR #34 and #36** are pure internal-wiring follow-ups — they introduce no new wire-format claims, so the Pattern gate's Task 0 inventory does not apply. Manual citations in their docstrings reuse the contracts pinned in PR #30 Tasks 0-6.

### The 4 misdiagnoses caught (pinned in PR #30 commits + tests)

| # | Plan/study claim | Manual reality | How it's pinned |
|---|---|---|---|
| 1 | `posicao_upload` returns `<UltimoByteRecebido>` | §5.3.1: returns `<RangesRecebidos>0-3;5-8</RangesRecebidos>` (semicolon-separated, possibly discontiguous) | Parser + 6 Bypass tests in `client_test.exs` `posicao_upload/2 wire format` describe |
| 2 | "HTTP 410 = protocol expired" | §5.3.1 + §5.6 + §6.1 + §6.4: HTTP 410 is "cancelado pelo Banco Central" (upload) or "arquivo não está disponível" (download) — never "expired" | Error atom renamed to `:file_unavailable` in `Client.download_part/2` errors |
| 3 | "HTTP 429 with `Retry-After`" | Manual §2.6 establishes limits but does not document a 429 response code | `[STUDY-CONJECTURE]` for Onda 2.C; not pre-implemented |
| 4 | "Default chunk threshold 1 MB" | Manual specifies no chunk size limit | `[STUDY-CONJECTURE]`; default 1 MB env-tunable as `STA_CHUNK_THRESHOLD_BYTES` |

### The 5 new findings

1. `<RangesRecebidos>` shape (§5.3.1) — semicolon-delimited dash-pairs `"0-3;5-8"`. New parser written.
2. `<Situacao>` enum (§5.3.1) — `:nao_iniciada | :pendente | :finalizada`. Distinct from `<EstadoAtual><Codigo>` (Onda 2.B) — orthogonal concepts.
3. `X-Content-Hash: SHA-256 <hex>` (§6.1) — BCB-specific non-standard, the canonical integrity check. Now extracted by both `download_file` and `download_part`.
4. HTTP 501 on download (§6.4) — "O range multipart não é suportado". Maps to `{:error, :range_multipart_unsupported}`.
5. `Content-Type` MUST NOT be sent on `posicao_upload` (§5.3.1), `download_full` (§6.1), `download_part` (§6.4) requests. Pinned via test refute on each endpoint.

### Items still `[NEEDS-OPERATOR-CONFIRM]`

- Concurrency budget split between upload/download within the §2.6 limit of 10 simultaneous transfers.
- Default chunk size — picked 1 MB as a working value; revisit after first real BCB smoke.

---

## Pre-existing issues we discovered (NOT introduced by this session)

These were caught while running the test suite during the session. **None are caused by Onda 2.A work**; they're latent issues that the test runner happened to hit. Documenting them here so the next session doesn't burn time investigating.

### 1. `outbound_test.exs` has 9 `:utc_datetime`/usec mismatch failures

```
** (ArgumentError) :utc_datetime expects microseconds to be empty,
   got: ~U[2026-04-26 19:16:34.157186Z]

   Use `DateTime.truncate(utc_datetime, :second)` to remove microseconds.
```

**Root cause:** schema in `lib/sta_connector/files/outbound_file.ex` declares `field :last_attempt_at, :utc_datetime` (no `_usec`) but migration `20260131000002_create_outbound_files.exs` uses `:utc_datetime_usec`. Code in `Outbound.mark_uploading/1` and similar uses `DateTime.utc_now()` which returns usec precision. Ecto rejects the cast.

**Verified pre-existing:** `git stash` on Onda 2.A code state, run `mix test test/sta_connector/outbound_test.exs` → still 9 failures. So this exists on `main` independent of any Onda 2.A change.

**Fix (not in scope):** either bump schema fields to `:utc_datetime_usec` to match migration, OR change the Outbound module callers to `DateTime.utc_now() |> DateTime.truncate(:second)`. Schema fix is more correct (the column IS usec-precision in the DB).

**Workaround in this session:** ran `mix test` per-file, not suite-wide; my new `set_bytes_uploaded` tests are explicitly tagged via `--only describe:"set_bytes_uploaded/2 ..."` to confirm green.

### 2. 6 pre-existing `Soap.parse_response/2` failures in `client_test.exs`

These predate Onda 1 entirely. They reference a `StaConnector.Sta.Soap` module that exists but has parse_response logic that doesn't match the test expectations. Treated as baseline; not investigated.

---

## Remaining deferred work

### Onda 2.A follow-up #2 — Ranged-resume on transient mid-download failure (~2-3h, NOT STARTED)

`Operations.download_with_retry/2` currently does a single full GET. The mid-stream resume path was deferred from PR #30 Task 6.

**What's needed:**
- After a transient failure mid-download (e.g., connection reset after N bytes received), retry via `Client.download_part/2` with `Range: bytes=N-{end}` + `If-Match: <etag from earlier attempt>`.
- On 412 (file changed): restart from byte 0 without `If-Match`.
- On 416 (bad range): restart from byte 0.
- On 501 (multipart range unsupported): restart from byte 0 with single contiguous range.

**Open question / Manual gate:** Manual §6.4 specifies `Range: bytes={start}-{end}` (both bounds explicit). The open-ended form `Range: bytes=N-` is RFC 7233 standard but **not documented in the Manual**. Two paths forward:

1. **Read-Manual-first:** re-open `sta/Manual_STA_Web_Services.pdf` §6.4 carefully; check whether BCB tolerates the open-ended form. If yes, implement as described above. If no or ambiguous, mark as `[NEEDS-OPERATOR-CONFIRM]` per the Pattern: Manual Verification gate and use option 2.

2. **Explicit-end-byte form:** thread an `:expected_size` opt through `Operations.download_with_retry/2` (caller provides total file size from `FileInfo.file_size`, which `list_available_files` already returns). Resume PUT becomes `Range: bytes=N-{expected_size - 1}`.

**Recommendation:** option 2 is safer and the data is already available from `list_available_files`. The `:expected_size` opt is a small additive change to `download_with_retry/2`; the caller convention is "if you want resume, supply `expected_size`; if you don't, the function falls back to single-shot full GET like today".

**Files this would touch:**
- `lib/sta_connector/sta/operations.ex` — `download_with_retry/2` gains resume branch
- `test/sta_connector/sta/operations_test.exs` — add Bypass tests covering 412/416/501 restart + happy-path mid-stream resume

### Caller wiring for `Operations.resume_upload/3` (NOT STARTED)

`Operations.resume_upload/3` (PR #36) is a public function but **not yet wired into any caller**. Worker.ex still hard-resets on retry (each retry calls `request_protocol/2` afresh, getting a new protocol — the old protocol's partial bytes are abandoned).

**What's needed:**
- In `Outbound.Worker.init/1`, when the worker boots, check if the file is in `status: "uploading"` with a `protocol_number` already set AND `bytes_uploaded > 0`. If so, that's a recovery scenario — call `Operations.resume_upload/3` with the persisted protocol instead of starting fresh.

**Or** (alternative design): an admin/operator endpoint that takes a `file_id` and triggers `resume_upload` manually. Simpler; no Worker.init complexity; doesn't auto-recover but lets operator decide.

**Recommendation:** start with the admin endpoint approach. Worker.init auto-recovery has subtle race conditions (e.g., what if the worker was retrying a brand-new upload that just happened to set `protocol_number` and then crashed before any byte transfer?). An explicit "operator says resume this" is safer.

**Out of scope for any current branch.** Could be its own follow-up sub-PR.

### Fresh sub-PRs from the parent rollout plan

Onda 2.B / 2.C / 2.D from `sta/docs/plans/2026-04-26-sta-conformance-rollout.md`. None are blocked anymore (Onda 2.A core is in main):

| Sub-PR | Estimate | Depends on | Notes |
|---|---|---|---|
| 2.B status & queries | ~2 days, ~400 LOC | Onda 1 (in main) | Parallel with 2.D. 14 status codes, query params, semicolon-batched protocols |
| 2.C rate & lifecycle | ~? | Onda 2.A (now in main) | HTTP 410 / 429 / 48h expiry / bucket sizes — has multiple `[STUDY-CONJECTURE]` items from Task 0 |
| 2.D password mgmt | ~? | Onda 1 | Parallel with 2.A/B. Separate `/senhaws/senha` endpoint, separate hosts |

Each gets its own bite-sized plan + Task 0 Manual Verification per the Pattern.

---

## Risk register / footguns

### F1. Worktree state at next session start may differ

If someone (you or another session) merges PR #36 between now and the next session start, the worktree state changes:

| State | Where | Action on resumption |
|---|---|---|
| **A** | PR #36 OPEN, branch `sta/onda2a-resume-upload` at `9ff657fa` (or one ahead if this handoff was committed) | Keep branch, optionally do follow-up #2 in parallel off main, OR continue improving #36 |
| **B** | PR #36 MERGED, worktree NOT YET cleaned up | `git fetch && git checkout main && git pull && git branch -d sta/onda2a-resume-upload` (or use `-D` if the branch wasn't fast-forward) and `git push origin --delete sta/onda2a-resume-upload`. Then cut new branch from main. |
| **C** | PR #36 MERGED, worktree already on `main` post-cleanup | Cut new branch from main directly |

The "Decision tree at session start" below handles all three.

### F2. Suite-level `mix test` is broken on `outbound_test.exs`

Don't run `mix test` (full suite). It will hit the 9 pre-existing `:utc_datetime`/usec failures and create noise. Always run **per-file** OR target your describe blocks via `--only describe:"<name>"`.

### F3. `mix format` baseline drift

The `sta/backend/` codebase has 70+ files with format drift relative to the current `.formatter.exs`. **Do NOT run `mix format` without arguments** — it will reformat unrelated files and contaminate the diff. Always run `mix format <specific files>` for files you actually touched.

### F4. Parallel sessions

This worktree is one of four parallel sessions (`efinanceira-paridade`, `pix-paridade`, `sisbajud-paridade`, this). **STA scope only:** never modify `core/`, `pix/`, `spb/`, `npc/`, `clst/`, `backoffice/`, `mobile/`, `infra/`, `docs/` (root), `MEMORY.md` (root), `CLAUDE.md` (root). Only `sta/*` (including `sta/docs/*`) is permitted.

### F5. Postgres dev container

Required for Task 4 migration verification + any DB-touching tests via DataCase. The container is `sta-connector-db-dev` on port 15432. If it's down: `docker compose -f sta/docker-compose.dev.yml up -d db`. The migration `20260426150000_add_resilient_transfer_columns.exs` must be applied on dev DB (it was during this session).

### F6. Mix project working directory

`mix` commands must run in `sta/backend/`, not the worktree root. If you see `** (Mix) Could not find a Mix.Project`, you're in the wrong directory. Use absolute paths in shell commands or `cd sta/backend` first.

### F7. Manual `mix ecto.migrate` runs against dev (port 15432) by default

`MIX_ENV=test mix ecto.migrate` is what hits the test DB. The `mix test` alias does this automatically (`ecto.create --quiet && ecto.migrate --quiet && test`). For dev DB, `MIX_ENV=dev mix ecto.migrate` (or default since dev is default).

---

## Decision policy (re-stated from PR #30 handoff)

When something is ambiguous in the next session:

1. **Plan vs código diverge** → confiar no código, atualizar plano (precedente: Onda 1 Brainstorm 2; this session caught the same with the "todos client-level, arquivos diferentes" claim from the parent plan being inconsistent with the actual file layout).
2. **Plan vs Manual diverge** → confiar no Manual, fix-commit como misdiagnosis (precedente: 4 misdiagnoses caught in PR #30 Task 0).
3. **Manual silencia sobre algo** → marcar `[STUDY-CONJECTURE]`, escolher default sensato + env-tunable, documentar em código + commit message + PR body. Examples already in main: chunk threshold (1 MB default), HTTP 429 (no implementation).
4. **Manual ambíguo (duas leituras possíveis)** → marcar `[NEEDS-OPERATOR-CONFIRM]`, escolher leitura conservadora, **flag explícito no PR body** pedindo confirmação humana antes de merge. Example: open-ended `Range: bytes=N-` for follow-up #2.

---

## Hard rules (re-stated from CLAUDE.md + parent plan)

- **STA scope only.** Touches outside `sta/*` are forbidden.
- **`mix format` ONLY on files you touched.** Never run bare `mix format` (would contaminate diff with 70+ unrelated baseline files).
- **`mix test` is broken suite-wide.** Run per-file or per-describe. Cite the 6 baseline `Soap.parse_response` failures in `client_test.exs` and the 9 baseline `:utc_datetime`/usec failures in `outbound_test.exs` as known noise.
- **NÃO push pro origin nem abra PR sem confirmação explícita.**
- **Pattern: Manual Verification mandatory** for any sub-PR that introduces new wire-format / endpoint / response-code / field-name / numeric-threshold claims. Pure internal wiring sub-PRs (like #34 and #36) skip the Task 0 inventory but document the skip rationale.
- **Worktree branch policy:** stay on the current branch until PR is merged; then cut new branch off `origin/main`.

---

## Resumption checklist (commands to verify environment)

In the next session, run these in order — DO NOT skip any. If any fails, investigate before continuing.

```bash
# 1. Be in the right worktree
cd /Users/luizpenha/monetarie/.worktrees/sta-paridade
pwd                                                 # → /Users/luizpenha/monetarie/.worktrees/sta-paridade

# 2. State check
git fetch origin --prune
git status                                          # working tree should be clean
git log --oneline -5

# 3. Determine PR #36 state — drives the decision tree below
gh pr view 36 --json state,mergedAt 2>&1 | head -3

# 4. Determine the worktree branch
git branch --show-current
git log --oneline origin/main -3                    # see what landed on main

# 5. Compile baseline (5 warnings expected)
cd sta/backend
mix deps.get
mix compile 2>&1 | grep -c "^[[:space:]]*warning:"  # → 5

# 6. Touchstone tests (per-file, NOT suite-wide)
mix test test/sta_connector/sta/client_test.exs                          # 55 tests, 6 baseline failures
mix test test/sta_connector/sta/operations_test.exs                      # 51 tests, 0 failures (post-#36 merge: 51; pre-merge on main: 45)
mix test test/sta_connector/files/outbound_file_test.exs                 # 7/7 PASS
mix test test/sta_connector/application_test.exs                         # 3/3 PASS
mix test test/sta_connector/outbound_test.exs --only describe:"set_bytes_uploaded/2 (Onda 2.A worker chunked-wiring follow-up)"  # 4/4 PASS

# 7. Postgres dev (only needed if you'll do DB-touching work)
docker ps --filter name=sta-connector-db-dev --format '{{.Names}}: {{.Status}}'
# If down: docker compose -f sta/docker-compose.dev.yml up -d db

# 8. ICP-Brasil chain (sanity — installed in Onda 1)
ls -la sta/backend/priv/certs/icp_brasil_ca_chain.pem
```

---

## Decision tree at session start

After running the resumption checklist above, branch on these three states:

### State A — PR #36 still OPEN (worktree on `sta/onda2a-resume-upload` or similar)

Most likely state if PR #36 hasn't been merged.

**Options:**

1. **Continue improving PR #36 in place** (e.g., respond to review feedback, add more tests, refactor based on operator input). Stay on the branch.
2. **Start follow-up #2 (ranged-resume mid-download) in parallel** — cut a new branch from `origin/main` (NOT from `sta/onda2a-resume-upload`, which has un-merged work). The two PRs are orthogonal: #36 is upload-side, #2 is download-side. They can land independently.
3. **Pivot to Onda 2.B / 2.C / 2.D** — same parallel-branch approach as #2.

### State B — PR #36 MERGED but worktree NOT cleaned up

User merged the PR but didn't run the cleanup script. Worktree still on `sta/onda2a-resume-upload`.

```bash
cd /Users/luizpenha/monetarie/.worktrees/sta-paridade
git fetch origin --prune
git checkout main
git pull origin main
git branch -d sta/onda2a-resume-upload          # safe — branch is fully merged
git push origin --delete sta/onda2a-resume-upload  # may already be deleted by GitHub auto-delete
```

Then proceed to State C.

### State C — PR #36 MERGED and worktree on `main`

Clean state. Cut a new branch and start the next piece of work:

```bash
cd /Users/luizpenha/monetarie/.worktrees/sta-paridade
git fetch origin --prune
git checkout main && git pull origin main

# For follow-up #2 (ranged-resume mid-download):
git checkout -b sta/onda2a-followup-2-ranged-resume-mid-download

# For Onda 2.B (status & queries):
git checkout -b sta/onda2-status-and-queries

# For caller-wiring of resume_upload (Worker.init OR admin endpoint):
git checkout -b sta/onda2a-resume-upload-caller-wiring
```

---

## Suggested next move (recommendation, not mandatory)

**My recommendation: follow-up #2 (ranged-resume mid-download).**

Why:
- It's the **last documented Onda 2.A follow-up**. Closing it makes Onda 2.A truly complete in its design intent.
- Estimated 2-3h actual; pattern is established (Bypass + Operations layer test, mirror of `upload_content/3`'s reconciliation logic but on the download side).
- Forces the Manual §6.4 re-read for `bytes=N-` open-ended form decision — that's a real Manual Verification gate moment that should be done while context is fresh.

After follow-up #2 lands, Onda 2.A is done done. Onda 2.B/C/D are independent fresh work after that.

**Counter-recommendations if you have a different priority:**

- **Onda 2.B (status & queries)** — if you'd rather move forward on a fresh Onda than close out follow-up debt. Bigger scope (~2 days, ~400 LOC) but unlocks file-status visibility for downstream consumers.
- **Caller-wiring for `resume_upload`** — if you want to actually exercise the resume_upload code path in production (currently just a public function nobody calls). Smaller (~1h) but riskier (Worker.init recovery has race conditions to think through; admin endpoint is safer).

---

## References

- **Manual canônico (THE spec):** `sta/Manual_STA_Web_Services.pdf` v1.5, jul/2022 (1832 lines via `pdftotext -layout`)
- **Parent rollout plan:** `sta/docs/plans/2026-04-26-sta-conformance-rollout.md` (Onda 1-4 + Pattern: Manual Verification)
- **Onda 2.A bite-sized plan:** `sta/docs/plans/2026-04-26-sta-onda2a-resilient-transfer.md` (Task 0 verification report + Tasks 1-7)
- **PR #30 (Onda 2.A core, MERGED):** https://github.com/FluxiqBR/monetarie/pull/30
- **PR #34 (Follow-up #1, MERGED):** https://github.com/FluxiqBR/monetarie/pull/34
- **PR #36 (Follow-up #3, OPEN):** https://github.com/FluxiqBR/monetarie/pull/36
- **Original handoff (PR #30 era):** `sta/docs/handoff/2026-04-26-sta-onda2a-resume-handoff.md` (preserved as historical record)
- **This handoff:** `sta/docs/handoff/2026-04-26-sta-onda2a-followups-status-and-next-session.md`

---

**End of handoff.** Read this top-to-bottom before any code or commands in the next session. The "Decision tree at session start" handles all three plausible worktree states; the "Suggested next move" gives a recommendation you can override.
