diff --git a/docs/HANDOFF-20261104.md b/docs/HANDOFF-20261104.md new file mode 100644 index 0000000..6106021 --- /dev/null +++ b/docs/HANDOFF-20261104.md @@ -0,0 +1,263 @@ +# Handoff: PostgreSQL test cases and coverage (4 Nov 2026) + +Repo: `amar-python/PostgreDataMigrationAppWithCSVLoader`, `main` at `c7bebd1` (merge of PR #79, 3 Nov 2026). +Session clone: `/home/claude/amar-python/postgredatamigrationappwithcsvloader` (sandbox only). +Nothing has been committed or pushed. No code has been changed in the repo. + +## 1. Goal + +- Automate the PostgreSQL product test cases so they can be configured and run from Azure DevOps CI/CD. +- Confirm that every test artifact in the repo is exercised by a test, and close the coverage gaps found. +- Turn the feedback on defects and gate scope into tracked issues with evidence rules. +- Panel-proposed goal (attached debate, 4 Nov 2026; not a product-owner decision yet): make the server-side upload audit record authoritative, with recovery verified by a test that fails rather than skips, and make the merge gate cover the loader path that writes it. Owner acceptance is pending. + +Decisions already taken by the product owner (Amar): +- CI platform: **Azure DevOps** is the source of truth. The repo stays on GitHub; Azure DevOps connects to it through a service connection (created by Amar in Azure DevOps; not yet done). +- Scope: all applicable cases. Blocked, deferred and unbuilt cases are reported as blocked, never as passes. +- Runners: hosted agents for API, SQL and UI tests; a self-hosted agent for the offline (OFF) suite. +- Coverage gate: move `api/services` coverage into the DB-backed gate job, with floors for the three loaders. +- Formula injection: apply the same guard to XLSX as to CSV. +- Dynamic mode: confirm inferred types before table creation, and add a provenance flag. + +## 2. Current State + +**Test suite at `c7bebd1`** +- Database-free run (`-m "unit or regression or security or snapshot"`): 144 passed, 0 failed, 221 deselected. +- Full run against local PostgreSQL 16 with the four environments deployed (same steps as CI): **365 passed, 0 failed, 116 subtests passed**. +- Coverage, full run: `api/services/csv_parse.py` 79.5%, `dynamic_loader.py` 84.2%, `te_loader.py` 96.2%, `evals/runner.py` 43.3%, `evals/gap_report.py` 0%. +- The gate (`make test-gate`) measures only `--cov=build/csv --cov=evals`, so the loaders are not measured by the gate. + +**Test documents** +- Original: 230 cases, 17 suites (P1 181, P2 49). All "Not run". +- Consolidated: 241 cases (P1 187, P2 54). Addendum A adds 11 cases: UIX015–018, OPS015–016, SET013, CSV017, AUD015, ENV014–015. +- Structured version: 241 cases, 578 step rows, six columns per step (Test Step No, Test Step Name, Preconditions, Step Description, Sequence of Steps, Expected Outcome). Preconditions appear on step 1 only. Test Step Names are generated from the step text. The source gives no per-step expected outcomes, so Expected Outcome sits on the final step. +- Sections 1–6 and 24–28 of the source are not reproduced in the structured file. + +**Issues** +- 121 repo issues (#9 to #195): 47 open, 74 closed. Consolidated in `All_issues_by_subject.xlsx` (12 subjects). +- Created today: #191 (registry race, F1), #192 (ragged rows, F2), #193 (formula injection, F3), #194 (gate floors), #195 (dynamic-mode type confirmation). +- Label clash: the repo already uses "F1" (#178) and "RV-F3" (#170) for different defects. + +**Azure** +- No Azure DevOps pipeline YAML has been written yet. +- Existing GitHub Actions workflows: `python-validator-tests.yml` and `quality-gate.yml`. The quality-gate workflow already runs PostgreSQL tests with a deployed environment. + +**Sandbox state (not in the repo)** +- Local PostgreSQL 16 server running on `127.0.0.1:5432`, user `postgres`, trust auth, data dir `/tmp/pgdata-1793762035`. +- Four databases created (`te_mgmt_dev`, `te_mgmt_test`, `te_mgmt_staging`, `te_mgmt_prod`) and deployed. +- `build/config.local.env` and `build/environments/env_*.sql` exist in the sandbox clone. These contain a throwaway local password (not recorded here). Delete them before any commit or push, and never paste the password into a repo file, issue or tracker. + +**Attached debate, checked against `c7bebd1`** + +Source: `49a22e69-conversation.docx`, a simulated four-person panel review of the project. Its claims came from the uploaded working copy and a `.coverage` file from a laptop. The clone is `main` at `c7bebd1`, so where the two differ, the clone is the reference below. + +Verified at `c7bebd1`: +- `Makefile` `test-gate` measures `--cov=build/csv --cov=evals` only. No `--cov-branch`, no `coverage.xml`. +- `Makefile` line 19 says Tier I/S "skip cleanly if no PostgreSQL". This conflicts with the CI policy the panel quotes (unmet prerequisites fail). +- `pytest.ini` has `addopts = -ra -q` with no `--strict-markers`. +- `env.dev.example` sets `PGPORT=5433`. `README.md` line 177 provisions with `PGPORT=5432`, and line 290 gives 5432 as the default. +- `api/db.py` (lines 139–154) runs `alembic upgrade head` on API start. Concurrency is not analysed anywhere in the repo. +- `README.md` line 3 says "A production-grade CSV-to-PostgreSQL data migration platform". No register row supports it. +- `api/config.py` line 51 defaults `API_MAX_ROWS` to 100000. The panel cited 10000, which may be an environment setting on its side. +- `preflight.sh` line 108 probes TCP with `timeout`, which macOS does not ship. Line 110 gates the credential check on `psql` and `PGPASSWORD`. +- `.dockerignore` has no `*.tfvars` entry. `.gitignore` excludes `.coverage`, `.coverage.*`, `config.local.env`, `.env*` and `*.tfvars`. + +Four claims from the panel, checked against full history (clone deepened to 2,000 commits; `main` has 189 commits in the clone): +- `preflight.ps1` had six `??` operators before commit `a83a1a4` (31 Oct 2026, "fix(preflight): PowerShell 5.1 compatible defaults"). That commit is inside PR #145 (merge `1e41eda`), which is on `main`. HEAD has zero. The panel read a copy from before the fix. +- `.dockerignore` excluded `.env` and `.env.*` from commit `7726de4` (31 Oct 2026, "harden dockerignore"), which is on `main`. The panel's copy predates it. HEAD excludes `.env` but still has no `*.tfvars` entry. +- The marker `integraton` appears in no commit on `main`. The panel's typo is not in the repo. +- `preflight.ps1` printed a hardcoded `'port 5432 reachable'` label until `a83a1a4`. HEAD prints `"port $pgPort reachable"` from `$env:PGPORT`, so the fix is on `main`. +- The regression test `tests/test_preflight_ps1.py` passes at HEAD (11 tests). Its static `??` check would fail on the pre-fix file (2 lines, 6 operators). The true PowerShell 5.1 parse test runs only on Windows, in `python-validator-tests.yml` (`windows-latest`). + +Audit-row ordering, traced in code at HEAD (4 Nov 2026). The panel's main finding is **confirmed**: +- `api/routers/csv_routes.py` `upload()` calls `upload_dynamic` or `upload_te`, which commit the load (`dynamic_loader.py` line 394; `te_loader.py` line 323). Only after that returns does `record_audit(action="upload", ...)` run (lines 89–101). +- Three separate commits: the load, then `record_upload` for the original (`originals.py` line 64), then `record_audit` (`audit.py` line 111). Each is a separate transaction. +- `record_audit` swallows exceptions and logs at ERROR (`audit.py` lines 99–116). A failed audit write does not fail the request. +- The code says so itself: the `audit.py` docstring lists this as a "known limitation (deliberate, documented)", and `originals.py` line 8 says the same. +- No test covers the crash window between commit and audit. `tests/test_api_integration.py` lines 466–477 only check that a failed upload writes no row. + +Not verifiable from the clone: +- The "23 of 38 verified" count, and the "13 features" list in the README. `docs/VCRM.md`, `docs/VCRM_GAPS.md`, `docs/RECONCILED_GAPS.md` and the README feature list were not checked. +- The `.coverage` figures (168 executed lines in `evals/runner.py`, highest flagged line 655, `coverage` version 7.15.4, no `when` or `sys_argv`). The file is on the user's laptop and is excluded from the repo by `.gitignore`. This sandbox has coverage 7.17.1, so the file can't be re-read here. Our own full run measured `evals/runner.py` at 43.3% of 526 statements, which is a different run and not comparable. + +## 3. Active files + +Repo (sandbox clone): +- `Makefile` (`test-gate` at line 15 sets the coverage scope) +- `.github/workflows/quality-gate.yml`, `.github/workflows/python-validator-tests.yml` +- `pytest.ini`, `requirements-dev.txt`, `api/requirements.txt` +- `api/services/csv_parse.py`, `api/services/dynamic_loader.py`, `api/services/te_loader.py` +- `api/services/csv_parse.py:170` (`ragged_row_reason`) +- `alembic/versions/0002_registry_unique.py` (UNIQUE constraints for F1) +- `build/deploy_all.sh` (deploys environments with `psql`) +- `build/csv/validator.py` (run as a subprocess by tests; not measured in-process) +- `evals/gap_report.py` (0% coverage; only syntax-checked) +- `csv-table-hub-main/src/lib/export.ts` (CSV guard `escapeCsv`; XLSX path unguarded) +- `csv-table-hub-main/src/__tests__/export.test.ts` +- `tests/test_ragged_rows.py`, `tests/test_csv_validator.py`, `tests/test_e2e_pipeline.py` +- `api/db.py` (startup `alembic upgrade head`, lines 139–154), `api/config.py` (`API_MAX_ROWS`, `MAX_UPLOAD_BYTES`) +- `preflight.sh` (lines 102–111), `preflight.ps1` (port and PG checks near lines 145–148) +- `env.dev.example` (`PGPORT=5433`), `README.md` (line 3 claim; lines 177 and 290 port values) +- `.dockerignore` (no `*.tfvars` entry), `.gitignore` +- `Makefile` line 19 (`test-evals` comment) +- Not checked: `docs/VCRM.md`, `docs/VCRM_GAPS.md`, `docs/RECONCILED_GAPS.md` (the panel cites proposed BR-39 to BR-44 and a "23 of 38" count from them) +- Attached debate: `/mnt/user-data/attachments/06c8a18b-fd05-5432-b07c-88b8a407fde9/49a22e69-conversation.docx` + +Scratchpad (`/tmp/claude-0/-home-claude/06c8a18b-fd05-5432-b07c-88b8a407fde9/scratchpad/`): +- `PostgreSQL_Product_Test_Cases_consolidated.docx` (241 cases, original layout plus addendum) +- `PostgreSQL_Product_Test_Cases_structured.docx` (241 cases, six-column layout) +- `build_consolidated.py`, `build_structured.py` (generators; `build_structured` imports `build_consolidated.NEW`) +- `artifact_coverage_inventory.csv` (134 artifacts with coverage status) +- `Issues_created_4Nov2026.xlsx`, `All_issues_by_subject.xlsx` +- `issues/*.md` (bodies used for #191–#195) +- `handoff.md` (this file) + +Source document: `/mnt/user-data/attachments/06c8a18b-fd05-5432-b07c-88b8a407fde9/a455a978-PostgreSQL_Product_Test_Cases.docx` + +## 4. Changes + +Made in this session: +- Created the consolidated test document (241 cases) and the structured document (241 cases, 578 step rows). +- Fixed table overflow in the structured document (column widths reduced to fit Letter landscape). Confirmed by rendering page 3. +- Preconditions blanked from step 2 onward, as requested. +- Created GitHub issues #191–#195 (REST API; `gh issue` commands are blocked because they use GraphQL). +- Built two spreadsheets: the five new issues, and all 121 issues grouped by subject. Subject placements were reviewed row by row and corrected with explicit overrides. +- Built `artifact_coverage_inventory.csv`. +- Read the attached debate document, then ran nine checks against `c7bebd1` (`??` count, `.dockerignore`, `.gitignore`, `pytest.ini`, port values, `Makefile` gate and comment, `api/db.py` bootstrap, marker names, `preflight.ps1` port label). The results are in section 2 under "Attached debate". +- Updated this file with the verified and contradicted findings. No repo changes. + +Not changed: +- No commits, pushes or PRs in the repo. +- No tests added to the repo. +- The Outstanding Items Tracker and `claude/project-status.md` have not been updated with #191–#195 (working rule 6). + +## 5. Failed Attempts + +- **Local folder access.** Requesting access to `C:\Users\User\OneDrive\Desktop\Migration using ai\PostgreDataMigrationAppWithCSVLoader` timed out. The repo is public, so I cloned it from GitHub instead. +- **Dev requirements alone.** `requirements-dev.txt` does not include the API dependencies. `api/requirements.txt` is also needed. +- **First full run.** 184 errors and 7 failures, all from the missing `te_dev` template schema. Fixed by replicating the CI setup: database config, environment launchers, `CREATE DATABASE`, then `deploy_all.sh` for each environment. +- **Missing summary.** `pytest.ini` addopts (`-ra -q`) combined with `-q` hid the totals. Reran with `-o addopts=""`. +- **`python3 -I` for local modules.** Isolated mode ignores the working directory, so my own generators failed to import. Ran them without `-I`. +- **Recursive `rm -rf` on a variable path.** Blocked by the safety check. Did not retry. Used a fresh data directory. +- **`gh issue list`.** Fails: the GitHub token in `GH_TOKEN` is invalid, and GraphQL is blocked in this session. `gh api` on REST works; numeric repo paths are blocked, so use `repos/{owner}/{repo}/...`. +- **First issue listing** returned 58 issues. Paging returned 121 (#9 to #195). +- **Addendum count.** The first build had 10 cases, not 11: the evals-runner case (OPS016) had been dropped. Caught by recounting from the output file and fixed. +- **Earlier claim about the loaders.** I first described them as unmeasured in a way that suggested they were untested. They are tested by the full run; the gate just doesn't measure them. +- **Subject grouping.** The first keyword pass misfiled about 40 issues. Corrected with explicit overrides. +- **Panel claims not reproduced at HEAD.** Six `??` operators in `preflight.ps1`, `.dockerignore` missing `.env`, the `integraton` typo, and a hardcoded "port 5432 reachable" label. The first three are fixed on `main` (`a83a1a4`, `7726de4`); the typo never existed in the repo. Checked against full history on 4 Nov 2026. +- **Git ancestry check.** First attempt failed because the clone was shallow. Deepening it with `git fetch --depth=2000 origin main` resolved it. +- **Tooling mismatch.** The panel's `.coverage` reports coverage 7.15.4. This sandbox has 7.17.1, so the file cannot be re-read here with the same version. + +## 6. Next Steps + +Ordered by dependency: + +1. **Product owner: confirm the gate floors** (79, 84, 96) against a CI run, not only the local run (#194). +2. **Add `--cov=api/services` to the DB-backed job** in `quality-gate.yml`. Keep the database-free `test-gate` as it is. Show a CI run log with the coverage table (#194). +3. **Regression tests for F1, F2, F3** (#191, #192, #193). Include the XLSX formula guard and a spreadsheet-application check. Each needs a mutation check showing the test fails without the fix. +4. **Dynamic mode** (#195): confirm with the product owner that this does not reopen BR-22. Then add type confirmation and a provenance flag. Ask first if the design needs choices beyond those in the issue. +5. **Resolve the label clash** for "F1" and "F3": rename the feedback labels or keep both, as the product owner decides. +6. **Map the 241 cases to existing tests and entry points.** Mark each case as automated, blocked (with the reason), or gap. Do not invent passes. +7. **Verify the two unverified addendum cases** against the code: AUD015 (hash chain) and ENV014 (`API_ALLOW_PROD_LOAD`). If a feature is missing, record a defect, not a pass. +8. **Recount OPS001's 142 assertions.** The 142 figure comes from counting lines that contain "assert" in `tests/suites/*.sql`. Count assertion records, not lines. +9. **Write the Azure DevOps pipeline** (YAML in the repo): PostgreSQL service container, the same deploy steps as CI, a self-hosted agent for the OFF suite, and a clear blocked-case report. Amar creates the GitHub service connection in Azure DevOps. +10. **Measure frontend coverage** (Vitest with coverage) and add a test for `csv-table-hub-main/scripts/e2e-csv.sh`. +11. **Decide the fate of** `scripts/fix_api_imports.py` and `scripts/fix_inserted_rows_count.py` (look like one-time fixes). Deletion is the product owner's call. +12. **Update the Outstanding Items Tracker and `claude/project-status.md`** with #191–#195, and with the 121-issue subject grouping, as working rule 6 requires. +13. **Clean up the sandbox:** stop the local PostgreSQL server, delete `build/config.local.env` and `build/environments/env_*.sql` from the clone, and check `.gitignore` covers them before any commit. +14. **Verification for every closure:** each issue closes only with clean evidence (run output with counts, or a CI log) attached, per working rule 7. +15. **Done (4 Nov 2026).** PR #145 (`1e41eda`) is on `main`, and it contains the PowerShell 5.1 fix (`a83a1a4`) and the `.dockerignore` hardening (`7726de4`). PR #146 (`ed729b8`) is also on `main`. No issue needed. Remaining question: does the user's own working copy match `main`? The panel's copy did not. +16. **Get CI coverage evidence, not a laptop file.** Ask for the CI `coverage.xml` or a coverage report from the quality-gate job. The `.coverage` file is gitignored, so no reviewer can see it. +17. **Gate change (proposed by the panel, needs owner sign-off):** add `--cov=api`, `--cov-branch` and `--cov-report=xml:coverage.xml` to `test-gate`. Do not add `--cov-fail-under` in the same change. Land the scope change, read the number, then add the floor in a second commit (links to #194). +18. **Add a `.coveragerc`** (coverage.py reads `.coveragerc`, `setup.cfg`, `tox.ini` or `pyproject.toml`, not `pytest.ini`) with `source`, `branch = True` and `skip_empty = False`. Confirm that `evals/gap_report.py` and `validator.py` then report as zero rather than vanishing. +19. **Add `--strict-markers` to `pytest.ini` `addopts`** (proposed). Run the suite to confirm no marker is undeclared. +20. **Resolve the `test-evals` policy contradiction.** The Makefile comment says Tier I/S "skip cleanly". The project's CI policy says unmet prerequisites fail. The panel proposed a `--require-prereqs` runner flag, but `evals/runner.py` is not in the attached file set, so check the runner before adding the flag. +21. **Fix the PostgreSQL port mismatch.** `env.dev.example` says 5433, while the README provisioning command and default say 5432. The product owner picks the authority, then the README and template are aligned. +22. **Review `api/db.py` startup migrations.** Two containers starting against the same database would both run `alembic upgrade head`. Trace this to a requirement row, or move migrations out of app start. Owner decision. +23. **Add `*.tfvars` to `.dockerignore`.** Verified missing. Low risk, one line. +24. **Audit row ordering (traced 4 Nov 2026: confirmed).** The audit row commits after the load, in its own transaction, and a failure there is swallowed. The code documents this as a known limitation. Next: decide, with the owner, whether it is a requirement (the panel proposed BR-45). If it is, the fix is to thread the caller's connection through the loaders, and a test must kill the process between the load commit and the audit write and assert recovery, failing rather than skipping. +25. **Export guard and README wording.** The formula guard for XLSX is already tracked in #193. Check the README's "Invalid row export" feature line against the guard once it lands. +26. **README "production-grade" line.** Either add a register row that says what it is graded against, by whom, on what evidence, and when it expires, or remove the word. Owner decision. +27. **Deferrals need an owner and a date.** BR-21 and BR-22 are deferred by decision. The panel asks for owner, date and detector on each deferral. Confirm with the owner before changing any wording. +28. **Proposed BR-39 to BR-44** (accessibility, disposal, backup) are awaiting disposition. Owner decision. Not numbered here; the register itself must confirm the next free number. + +## 7. Issues Identified + +Each item states what was observed and where it was checked. "No issue" means no repo issue exists yet. + +### A. Coverage and measurement + +| ID | Issue | Evidence | Tracking | +|---|---|---|---| +| A1 | The gate measures only `build/csv` and `evals`. The three loaders in `api/services` are not measured by the gate. | `Makefile` `test-gate`; full run gives csv_parse 79.5%, dynamic_loader 84.2%, te_loader 96.2% | #194 | +| A2 | `evals/gap_report.py` has 159 statements and 0% coverage. It is only syntax-checked by `health_check.py` and lint. | Full run coverage JSON | No issue | +| A3 | `build/csv/validator.py` is run only as a subprocess. Its in-process coverage cannot be measured, so its real coverage is unknown. | `tests/test_csv_validator.py`, `tests/test_e2e_pipeline.py` run it as a process | No issue | +| A4 | 16 `scripts/*.py` files show zero measured lines. Some run as subprocesses or in CI (`test_report.py`, `health_check.py`). | Coverage inventory | No issue | +| A5 | About 20 shell and PowerShell scripts have no coverage tool. The inventory's "untested" label is a name match only. | `artifact_coverage_inventory.csv` | No issue | +| A6 | Frontend: 39 source files with no coverage measured. `csv-table-hub-main/scripts/e2e-csv.sh` is not referenced by any test. | Inventory | No issue | +| A7 | Earlier statement that the loaders were "outside coverage by construction" is wrong as stated. They are tested (79–96%); the gate does not report it. | Full run, and `Makefile` | Corrected here | + +### B. Defects from the feedback + +| ID | Issue | Evidence | Tracking | +|---|---|---|---| +| B1 | F1, registry race. UNIQUE constraints exist, but no test runs concurrent uploads. | `alembic/versions/0002_registry_unique.py` | #191 | +| B2 | F2, ragged rows. `ragged_row_reason` exists; the existing test's assertions are not confirmed. | `api/services/csv_parse.py:170`, `tests/test_ragged_rows.py` | #192 | +| B3 | F3, formula injection. CSV is guarded in `export.ts`. XLSX has no guard. The backend has no guard. | `csv-table-hub-main/src/lib/export.ts` | #193 | +| B4 | Dynamic mode creates a table from inferred types with no confirmation and no provenance flag. | `api/services/dynamic_loader.py` | #195 | + +### C. Test document + +| ID | Issue | Evidence | Tracking | +|---|---|---|---| +| C1 | The source has one expected outcome per case, not per step. The structured file places it on the final step, which is a design choice the owner has not confirmed. | Source document | Open question | +| C2 | Test Step Names in the structured file are generated from step text, not taken from the source. | `build_structured.py` | Open question | +| C3 | OPS001 expects 142 assertions. The count of 142 is lines containing "assert", not assertion records. | `tests/suites/*.sql` | Next step 8 | +| C4 | AUD015 (hash chain) and ENV014 (`API_ALLOW_PROD_LOAD`) describe features not yet confirmed in the code. | Addendum cases | Next step 7 | +| C5 | SET007 and ENV004 are blocked on owner decisions: the canonical database name, and the BR-15 Staging value. | Source document | Owner decision | +| C6 | The source says the entry points were "not executed as a product test run". They have now been run locally (365 passed), so the source needs updating. | Source section 25 | Update source | +| C7 | The source names no pinned commit. This handoff uses `main` at `c7bebd1`. | Source section 1 | Owner to confirm | +| C8 | Sections 1–6 and 24–28 of the source are not reproduced in the structured file. | `build_structured.py` | Known, deliberate | + +### D. Tracking and process + +| ID | Issue | Evidence | Tracking | +|---|---|---|---| +| D1 | Label clash: "F1" and "F3" are already used by repo issues #178 and #170 for different defects. | Repo issue list | Owner decision | +| D2 | The Outstanding Items Tracker and `claude/project-status.md` do not yet list #191–#195. | Working rule 6 | Next step 12 | +| D3 | Subject grouping of the 121 issues uses keyword rules plus manual overrides. The owner has not validated it. | `build_all_issues.py` | Owner review | +| D4 | `gh issue` commands fail (invalid `GH_TOKEN`; GraphQL blocked). REST works. | Session tooling | No issue (tooling) | +| D5 | The sandbox clone holds `build/config.local.env` with a throwaway password. Whether `.gitignore` covers it is not verified. | Sandbox clone | Next step 13 | + +### E. Environment and CI + +| ID | Issue | Evidence | Tracking | +|---|---|---|---| +| E1 | The CI integration job's status is unknown since #45 was closed. The local full run passes; CI evidence is still needed. | Issue #45 (closed) | Next step 2 | +| E2 | Azure paths are paused (#31, #32, #34). ENV015 and any Azure pipeline work are blocked. | Source section 1, issue list | Owner decision | +| E3 | Recent CI-blocking items already tracked: #181 (SQL wrapper exits 0 on failed assertions), #180 (Tier I eval passes after SQL errors), #182 (offline bundle suppresses failures). These affect whether the pipeline can report failures honestly. | Issue list | Existing issues | + +### F. Findings from the attached debate + +Status key: **Verified** = checked at `c7bebd1`. **Contradicted** = the clone disagrees with the panel. **Claimed** = the panel asserted it, and it is not yet checked. + +| ID | Finding | Status | Evidence | Tracking | +|---|---|---|---|---| +| F1 | The gate measures `build/csv` and `evals` only, and no branch coverage. | Verified | `Makefile` `test-gate` | #194 | +| F2 | The "skip cleanly" comment for Tier I/S conflicts with the fail-not-skip policy. | Verified | `Makefile` line 19 | No issue | +| F3 | `pytest.ini` has no `--strict-markers`. | Verified | `pytest.ini` line 11 | No issue | +| F4 | `env.dev.example` (5433) and the README provisioning command (5432) disagree on the PostgreSQL port. | Verified | `env.dev.example` line 11; `README.md` lines 177, 290 | No issue | +| F5 | `api/db.py` runs migrations on every API start. Concurrent starts are not analysed. | Verified (the code); concurrency risk Claimed | `api/db.py` lines 139–154 | No issue | +| F6 | The README calls the platform "production-grade" with no register row to support it. | Verified (the text); no register checked | `README.md` line 3 | No issue | +| F7 | `.dockerignore` does not exclude `*.tfvars`. | Verified | `.dockerignore` | No issue | +| F8 | `preflight.sh` uses `timeout`, which macOS lacks. The credential check runs only if `psql` is present. | Verified | `preflight.sh` lines 108, 110 | No issue | +| F9 | `.coverage` is gitignored, so no reviewer can see the measurement. | Verified | `.gitignore` lines 62–63 | No issue | +| F10 | `API_MAX_ROWS` defaults to 100000. The panel cited 10000. | Verified (default); the panel's figure may be an environment setting | `api/config.py` line 51 | No issue | +| F11 | The upload audit row is written after the load commits, so a crash in between leaves a loaded table with no audit row. | Verified in code. No test covers the window. | `csv_routes.py` 89–101; `dynamic_loader.py` 394; `te_loader.py` 323; `audit.py` 99–116 | No issue (proposed BR-45) | +| F12 | The "production-grade" claim, and the deferrals of BR-21 and BR-22, have no owner and date. | Claimed (register not checked) | Panel | No issue | +| F13 | `preflight.ps1` contains six `??` operators, so it fails to parse on Windows PowerShell 5.1. | Fixed on `main` in `a83a1a4` (31 Oct 2026, inside PR #145). The panel's copy predates the fix. | `git show a83a1a4^:preflight.ps1` has 6 occurrences; HEAD has 0 | No issue | +| F14 | `.dockerignore` does not exclude `.env`. | Fixed on `main` in `7726de4` (31 Oct 2026). The panel's copy predates the fix. | `.dockerignore` lines 14–15 at HEAD | No issue | +| F15 | The pytest marker `integraton` is misspelt. | Not in the repo: zero occurrences in full history | `git log -S integraton` returns nothing | No issue | +| F16 | `preflight.ps1` prints a hardcoded "port 5432 reachable" label. | Fixed on `main` in `a83a1a4`. HEAD prints `port $pgPort reachable`. | `preflight.ps1` line 152 at HEAD; line 147 before the fix | No issue | +| F17 | Whether PR #145 (`1e41eda`) is merged on `main`. | Verified: merged on `main` on 31 Oct 2026, containing `a83a1a4` and `7726de4`. | `git merge-base --is-ancestor` | No issue | +| F18 | The `tfvars` entry is missing from `.dockerignore`. | Verified at HEAD (zero entries in full history) | `grep -c tfvars .dockerignore` = 0 | No issue; see next step 23 |