# Handoff — STA Onda 2.B (C full+admin) complete, awaiting push/PR auth

**Data:** 2026-04-27
**Worktree:** `/Users/luizpenha/monetarie/.worktrees/sta-paridade`
**Branch:** `sta/onda2-status-and-queries` (cut from `origin/main` HEAD `e54399ab`)
**Status:** All 7 Onda 2.B (C) tasks complete. Touchstones green. Ready for `git push -u origin sta/onda2-status-and-queries` + `gh pr create` after explicit user authorization.

---

## TL;DR (one paragraph)

Implemented Onda 2.B per option **(C) full + admin endpoints** decided at session start: `StateCode` module (Manual Tabela 3 enum + classifications), batched `change_status/2` (Manual §7.1, replaces singular `confirm_receipt` build path while keeping the public function as a thin wrapper), worker `decide_next_action/1` future-readiness wiring, `Client.query_protocol/2` (Manual §8.2), `Client.advanced_query/2` (Manual §8.3 with date-pair validation + a_rec warning + max_results clamp), and a new admin controller `Api.Admin.StaQueryController` exposing both queries via `GET /api/admin/sta/{protocols,queries/advanced}`. 7 commits totaling +1928/-83 LOC across 14 files. **63 new tests** added across 4 new test files; combined 235/229 PASS (vs. 172/166 pre-Onda 2.B baseline; the 6 `Soap.parse_response` baseline failures are unchanged). Compile preserves the 5 baseline warnings exactly. Zero out-of-scope file changes (`git diff base..HEAD --name-only | grep -v "^sta/"` is empty).

---

## What's in this branch (chronologically)

| # | SHA | Type | Subject |
|---|---|---|---|
| 1 | `e62bb70f` | docs | Onda 2.B (C full+admin) plan + Task 0 Manual Verification |
| 2 | `a604b8dd` | feat | StateCode module per Manual Tabela 3 (Task 1) |
| 3 | `b41aedf3` | feat | Batched change_status + confirm_receipt thin wrapper (Task 2) |
| 4 | `d2ee0ea8` | feat | Wire StateCode into worker decide_next_action helpers (Task 3) |
| 5 | `73f5350f` | feat | query_protocol/2 per Manual §8.2 (Task 4) |
| 6 | `1c875046` | feat | advanced_query/2 per Manual §8.3 (Task 5) |
| 7 | `e16cf432` | feat | Admin endpoints /api/admin/sta/{protocols,queries/advanced} (Tasks 6+7) |

**Note on Tasks 6+7 combined commit:** the plan §Tasks listed them as separate commits, but the controller is shared between both endpoints — splitting would have created a "dead helper functions" window in commit 6 (route absent + tests absent for `:advanced` action while the helpers were already defined). One commit is the truthful representation of the change. PR body reference both tasks.

---

## Acceptance criteria — all satisfied

From rollout plan §Sub-PR 2.B (verbatim):

- ✅ "Workers no longer string-compare status descriptions." Pre-flight grep confirmed they never did (their retry logic is `RetryEntry`-based / GenServer state machine). Task 3 satisfies the spirit by adding `decide_next_action/1` future-readiness wiring + tests.
- ✅ "A_REC works against Bypass mock." Task 2 covers `change_status` with `:a_rec`; Task 5 covers `advanced_query` with `transmission_situation: :a_rec` AND emits the §8.3 Atenção warning.
- ✅ "query_protocol parses both single-protocol and batch responses." Task 4 covers both via dedicated tests.

Plus Onda 2.B (C) extension:
- ✅ Admin endpoints `GET /api/admin/sta/protocols` and `GET /api/admin/sta/queries/advanced` exposed under `:admin_api` pipeline (Tasks 6+7).
- ✅ Manual Verification gate satisfied — Task 0 inventory pre-collected in plan §Task 0 (20 [VERIFIED §X.Y], 5 [STUDY-CONJECTURE], 2 [NEEDS-OPERATOR-CONFIRM] both confirmed during execution).
- ✅ No out-of-scope file changes.

---

## Test surface delta

### Touchstone files

| File | Pre-2.B | Post-2.B | Δ | Notes |
|---|---|---|---|---|
| `client_test.exs` | 59 / 6 | **86 / 6** | +27 | 8 change_status + 9 query_protocol + 10 advanced_query. Baseline 6 `Soap.parse_response` failures preserved. |
| `operations_test.exs` | 58 / 0 | **58 / 0** | 0 | unchanged |
| `outbound_file_test.exs` | 7 / 0 | **7 / 0** | 0 | unchanged |
| `application_test.exs` | 3 / 0 | **3 / 0** | 0 | unchanged |
| `outbound_test.exs` | 38 / 0 | **38 / 0** | 0 | unchanged |
| `outbound_files_controller_test.exs` | 7 / 0 | **7 / 0** | 0 | unchanged |
| **Touchstone total** | **172 / 6** | **199 / 6** | **+27** | |

### New test files (NOT in original 6 touchstones)

| File | Tests | Failures | Source task |
|---|---|---|---|
| `state_code_test.exs` | 14 | 0 | Task 1 |
| `inbound/worker_test.exs` | 3 | 0 | Task 3 |
| `outbound/worker_test.exs` | 3 | 0 | Task 3 |
| `sta_query_controller_test.exs` | 16 | 0 | Tasks 6+7 |
| **New file total** | **36** | **0** | |

### Combined Onda 2.B test surface

- **63 new tests across 4 new files + extended client_test.exs** (verbatim breakdown: Task 1 = 14, Task 2 = 8, Task 3 = 6, Task 4 = 9, Task 5 = 10, Tasks 6+7 = 16).
- **235 / 229** when running all 10 test files together (one batch run: `2.5s async + 0.2s sync`).
- 6 baseline failures preserved (all from `Soap.parse_response/2` describe in `client_test.exs` — pre-Onda 1 noise, documented in handoff predecessors).

### Compile baseline

- **5 warnings preserved** before/after every commit. The two warnings I introduced in Task 2 (orphan `@doc` block + helper interrupting `build_rest_request` clause group) were caught and fixed before commit. Subsequent tasks were warning-clean from the start.

---

## Manual Verification gate — execution log

The plan §Task 0 inventory listed:
- **20 `[VERIFIED §X.Y]` claims** against Manual STA Web Services v1.5 §7, §8.1-8.3, Tabelas 1-4. None deviated during implementation.
- **5 `[STUDY-CONJECTURE]` items** with conservative reads:
  - #1: `<EstadoAtual>` ≠ `<SituacaoAtual>`. Documented divergence in `StateCode` moduledoc + `Types.FileQueryResult` moduledoc. Did **NOT** refactor `:list_available_files` parser per plan §Out of scope #11.
  - #2: `qtdMaxResultados` default = 100 (the cap). Implemented + Logger.warning on clamp.
  - #3: `dependencia` no default; caller-supplied opaque string. Implemented per plan.
  - #4: `dataHoraInicio` (atualização) vs `dataHoraCriacaoInicio` (criação) caller-supplied. Surfaced both in `advanced_query/2` shape.
  - #5: Unknown protocol → empty `<Resultado>`. Confirmed: parser returns `{:ok, []}` cleanly when `<Arquivo>` absent.
- **2 `[NEEDS-OPERATOR-CONFIRM]` items** — both confirmed mid-execution:
  - #1: Admin UI calls direct → YES, by user's (C) selection.
  - #2: Workers should switch to StateCode immediately → confirmed by pre-flight grep (workers never had string-compares to begin with), so Task 3 is future-readiness only.

**Misdiagnoses caught during execution:**
- One in Task 2: thought the existing `parse_rest_response(:confirm_receipt, _status, _, _)` clause was buggy (silently mapping 400 to `:confirmed`). Re-reading `execute_request/3` at `client.ex:854-870` showed it only routes `[200, 201, 204, 206]` to `parse_rest_response`; non-2xx is mapped via `map_operation_error/2` + `Error.from_http_status/2`. The "always `:confirmed`" line was permissive-on-success-codes, not bug-on-errors. Plan was updated mid-flight (compat decision in §Component 2).

---

## Public API additions (cheat sheet)

### `StaConnector.Sta.Client`

```elixir
@spec change_status(%{protocols: [String.t()], situation: :rec | :a_rec}, keyword()) ::
        {:ok, :ok} | {:error, Error.t()}
@spec confirm_receipt(String.t(), keyword()) ::
        {:ok, :confirmed} | {:error, Error.t()}    # compat wrapper
@spec query_protocol(%{...}, keyword()) ::
        {:ok, [Types.FileQueryResult.t()]} | {:error, Error.t()}
@spec advanced_query(map(), keyword()) ::
        {:ok, [Types.FileQueryResult.t()]} | {:error, Error.t()}
```

### `StaConnector.Sta.StateCode`

```elixir
@spec from_int(integer()) :: {:ok, atom()} | :error
@spec to_int(atom()) :: integer() | nil
@spec terminal?(integer()) :: boolean()
@spec success?(integer()) :: boolean()
@spec failure?(integer()) :: boolean()
```

### `StaConnector.Sta.Types.FileQueryResult`

New struct for §8.2/§8.3 `<Arquivo>` blocks. Distinct from `FileInfo` (§8.1) because it carries `<EstadoAtual><Codigo>` (Tabela 3 enum). Fields: `protocol_number, system_id, current_state_code, current_state_desc, file_name, file_size, hash, created_at, updated_at, metadata`.

### Inbound + Outbound `Worker.decide_next_action/1`

```elixir
@spec decide_next_action(integer()) :: :done | :fail | :retry
```

Future-readiness for Onda 2.C state polling. Routes via `StateCode.success?/1` + `StateCode.failure?/1`.

### HTTP routes added (under `:admin_api` pipeline)

```
GET /api/admin/sta/protocols?ids=P1[,P2,...]&detail=res|bas|compl&origin=origin|resp|prot_resp
GET /api/admin/sta/queries/advanced?date_creation_from=...&state_codes=25,35&systems=CCS,SPI&...
```

Both wrap their respective Client functions; Client module injection seam via `Application.get_env(:sta_connector, :sta_client_module, StaConnector.Sta.Client)` (mirrors PR #46 OutboundFilesController pattern).

---

## Files touched (14 total — all in `sta/`)

```
sta/backend/lib/sta_connector/inbound/worker.ex                                       (modified, +35/-1)
sta/backend/lib/sta_connector/outbound/worker.ex                                      (modified, +24/-1)
sta/backend/lib/sta_connector/sta/client.ex                                           (modified, +260/-29)
sta/backend/lib/sta_connector/sta/client_behaviour.ex                                 (modified, +85/-3)
sta/backend/lib/sta_connector/sta/state_code.ex                                       (NEW, 96 LOC)
sta/backend/lib/sta_connector/sta/types.ex                                            (modified, +69/-0)
sta/backend/lib/sta_connector_web/controllers/api/admin/sta_query_controller.ex       (NEW, 248 LOC)
sta/backend/lib/sta_connector_web/router.ex                                           (modified, +5/-0)
sta/backend/test/sta_connector/inbound/worker_test.exs                                (NEW, 28 LOC)
sta/backend/test/sta_connector/outbound/worker_test.exs                               (NEW, 28 LOC)
sta/backend/test/sta_connector/sta/client_test.exs                                    (modified, +397/-1)
sta/backend/test/sta_connector/sta/state_code_test.exs                                (NEW, 115 LOC)
sta/backend/test/sta_connector_web/controllers/api/admin/sta_query_controller_test.exs (NEW, 224 LOC)
sta/docs/plans/2026-04-27-sta-onda2b-status-and-queries-full-admin.md                 (NEW, 650 LOC plan)
```

Use `git diff $(git merge-base origin/main HEAD)..HEAD --stat` for exact line counts.

---

## Out of scope (will NOT be in this PR — deferred per plan §Out of scope)

1. Onda 2.C scope — HTTP 410 protocol-expired auto-renew, HTTP 429 with `Retry-After`, 48h protocol expiry, 3 separate rate limiter buckets.
2. Onda 2.D scope — `/senhaws/senha` password management endpoints.
3. Onda 3 scope — leiautes corpus.
4. Onda 4 scope — identifier mapping in `core/`.
5. Worker.init auto-recovery for upload-side resume.
6. Full `worker_test.exs` for Inbound.Worker — only the minimal `decide_next_action/1` tests are in this PR.
7. Cross-process / cross-restart download resume persistence.
8. Admin auth enforcement — `:admin_api` pipeline still has the `# Future: Add admin authentication here` TODO. New endpoints inherit the current state.
9. Real BCB smoke test — deferred to operator post-merge.
10. Telemetry events for the new endpoints — Wave 11 P2 metrics framework will be the home.
11. Refactor `:list_available_files` parser to align with `<EstadoAtual>` semantics (per [STUDY-CONJECTURE] #1).
12. New `Types.FileInfo` fields. The new `Types.FileQueryResult` is added separately.
13. `dependencia` content/format validation. Caller-supplied opaque string per [STUDY-CONJECTURE] #3.
14. `update`/`delete` actions on `StaQueryController`. Read-only endpoints only.

---

## Hard rules respected (carry-over from prior handoffs)

| # | Rule | Verified |
|---|---|---|
| 1 | STA scope only | ✅ `git diff base..HEAD --name-only` empty when filtered for `^sta/` |
| 2 | Never modify `core/`, `pix/`, `spb/`, `npc/`, `clst/`, `backoffice/`, `mobile/`, `infra/`, root `docs/`, root `MEMORY.md`, root `CLAUDE.md` | ✅ |
| 3 | `mix format` ONLY on touched files | ✅ ran `mix format` with explicit file list each commit |
| 4 | Run tests per-file, never full suite | ✅ |
| 5 | Pattern: Manual Verification mandatory | ✅ Task 0 inventory in plan + execution log above |
| 6 | Push + PR só com auth explícita do usuário | ⏳ pending — this handoff serves as the request |
| 7 | Worktree branch policy: cut new branch off `origin/main` | ✅ branch cut from `e54399ab` |
| 8 | Decision policy when ambiguous | ✅ Plan §Component 2 documents the misdiagnosis-caught compat decision |

---

## Resumption checklist (commands to verify environment)

For the next session (after PR merge OR before further work):

```bash
cd /Users/luizpenha/monetarie/.worktrees/sta-paridade
pwd                                                 # → /Users/luizpenha/monetarie/.worktrees/sta-paridade
git fetch origin --prune
git status                                          # working tree should be clean

# After this PR merges:
git checkout --detach origin/main
git branch -d sta/onda2-status-and-queries          # cleanup local
git log --oneline -1                                # → merge commit (whichever Onda 2.B merges as)

# OR before merge (resumption mid-PR):
git branch --show-current                           # → sta/onda2-status-and-queries

cd sta/backend
mix compile 2>&1 | grep -c "^[[:space:]]*warning:"  # → 5

# Touchstones — combined batch (fastest):
mix test \
  test/sta_connector/sta/client_test.exs \
  test/sta_connector/sta/operations_test.exs \
  test/sta_connector/files/outbound_file_test.exs \
  test/sta_connector/application_test.exs \
  test/sta_connector/outbound_test.exs \
  test/sta_connector_web/controllers/api/admin/outbound_files_controller_test.exs \
  test/sta_connector/sta/state_code_test.exs \
  test/sta_connector/inbound/worker_test.exs \
  test/sta_connector/outbound/worker_test.exs \
  test/sta_connector_web/controllers/api/admin/sta_query_controller_test.exs
# Expected: 235 tests, 6 failures (the 6 pre-existing Soap.parse_response baseline failures)

# Postgres dev (only if DB-touching work — Onda 2.B is fully stateless)
docker ps --filter name=sta-connector-db-dev --format '{{.Names}}: {{.Status}}'
```

---

## Decision tree for next session

### State A — This PR not yet merged

Branch on the worktree is `sta/onda2-status-and-queries`. Either wait for merge OR work on a non-overlapping next sub-PR (e.g., Onda 2.C — touches `Operations` + `RateLimiter`, not the Client routes added here).

### State B — This PR merged + worktree on detached HEAD

Cut new branch off `origin/main` for whichever sub-PR is next. Default suggested: **Onda 2.C `sta/onda2-rate-and-lifecycle`** per parent rollout plan §Sub-PR 2.C (lines 739+). 2.C handles HTTP 410 / HTTP 429 / Retry-After / 48h expiry / 3 rate limiter buckets — naturally consumes the StateCode classifications added in this PR.

### State C — Other sub-PR started in another session / partial

Unlikely but check `gh pr list --state open --search "sta/"` first.

---

## Suggested next sub-PR (post-merge)

**Onda 2.C `sta/onda2-rate-and-lifecycle`** per parent rollout plan §Sub-PR 2.C (lines 739+). Estimate 2 days, ~500 LOC. Depends on 2.A merged ✅, naturally consumes 2.B's `StateCode.terminal?/1`, `Worker.decide_next_action/1`, and `Client.query_protocol/2` (for state polling).

Alternative: **Onda 2.D `sta/onda2-password-management`** if operators have a deadline for `/senhaws/senha` rotation. Independent of 2.C.

---

## References

### This PR
- **This handoff:** `sta/docs/handoff/2026-04-27-sta-onda2b-full-admin-complete.md`
- **This plan:** `sta/docs/plans/2026-04-27-sta-onda2b-status-and-queries-full-admin.md`
- **Branch:** `sta/onda2-status-and-queries`
- **Base SHA:** `e54399ab` (origin/main HEAD at session start, post PR #59 merge)

### Predecessor handoff (resumption point)
- `sta/docs/handoff/2026-04-27-sta-onda2b-brainstorming-pause-and-onda2a-complete.md` — contains the Task 0 Manual Verification inventory + 3-option scope decision rationale + pre-flight infrastructure inventory.

### Plans
- **Parent rollout plan:** `sta/docs/plans/2026-04-26-sta-conformance-rollout.md` §Sub-PR 2.B (lines 670-737), §Pattern: Manual Verification.
- **Onda 2.A core plan + 3 follow-up plans** for the precedent pattern: `2026-04-26-sta-onda2a-resilient-transfer.md`, `2026-04-26-sta-onda2a-followup-2-ranged-resume.md`, `2026-04-26-sta-onda2a-followup-caller-wiring.md`.

### Manual STA references
- `sta/Manual_STA_Web_Services.pdf` — v1.5 jul/2022 (canonical PDF).
- §7 Alteração de situação (Task 2 build clause).
- §8 Consulta a transferências de arquivos (§8.1 already implemented; §8.2 → Task 4; §8.3 → Task 5).
- Tabela 1 (§8.2 params), Tabela 2 (§8.3 params), Tabela 3 (state codes).

### Onda 2.A merged PRs (cross-reference)
| PR | SHA | Title |
|---|---|---|
| #24 | `301503ec` | Onda 1 wire-format + ICP-Brasil chain |
| #30 | `3af17964` | Onda 2.A core |
| #34 | `ed03ce39` | Worker chunked-upload wiring |
| #36 | `100e5154` | Operations.resume_upload/3 |
| #43 | `99e6e57c` | Streaming download + ranged-resume mid-download |
| #46 | `1c10b7fa` | Caller-wiring bundle (StaQueryController mirrors this controller pattern) |
| #52 | `fbf4dac2` | upload_attempts retry-cap fix |
| #59 | `e54399ab` | Onda 2.B brainstorming pause handoff |

---

## Awaiting auth

Per Hard rule #6, no `git push` or `gh pr create` without explicit user authorization. When ready:

```bash
cd /Users/luizpenha/monetarie/.worktrees/sta-paridade
git push -u origin sta/onda2-status-and-queries
gh pr create --title "feat(sta): Onda 2.B status & queries (C full+admin)" --body "..."
```

PR body should reference:
- This handoff doc (full context)
- 7 commits with per-task breakdown
- Acceptance criteria from rollout plan §Sub-PR 2.B
- Touchstone delta (235/229 vs baseline 172/166; 6 pre-existing failures preserved)
- Manual Verification gate satisfied (Task 0 inventory in plan)
- Out of scope (deferred per plan)

---

**End of handoff.** All Onda 2.B (C) deliverables complete; awaiting push + PR authorization.
