Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/python-validator-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v7
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/quality-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v7
Expand Down Expand Up @@ -44,7 +44,7 @@ jobs:
# would otherwise vanish with the runner — keep them for auditability.
- name: Upload eval reports
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: eval-reports-free-tier
path: evals/reports/
Expand Down Expand Up @@ -76,7 +76,7 @@ jobs:
PGDATABASE: postgres
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Setup Python
uses: actions/setup-python@v7
Expand Down Expand Up @@ -147,7 +147,7 @@ jobs:

- name: Upload eval reports
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v7
with:
name: eval-reports-integration
path: evals/reports/
Expand Down
11 changes: 5 additions & 6 deletions GAP_ANALYSIS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ claim below was reproduced, not inferred from reading code.
| G2 | Windows CI cannot run database-backed tests | Medium | Yes — accept scope, or start PG on the runner |
| G3 | Tiers X and E remain unimplemented | Medium | No — deferred by design |
| G4 | ~~Runtime artifacts are not gitignored~~ | **Closed** | Added to `.gitignore` |
| G5 | `VCRM.md` BR-20 assertion count edited | Low | Yes — confirm or revert |
| G5 | ~~`VCRM.md` BR-20 assertion count edited~~ | **Closed** | Confirmed: 142 matches suite output and Tier S JSON |

---

Expand Down Expand Up @@ -68,12 +68,11 @@ now runs against all four PostgreSQL environments.
**Resolution:** All four suggested entries were added to `.gitignore`:
`tests/snapshots/`, `tfplan`, `*.tfplan`, `terraform-provider-*.log`.

### G5 — `VCRM.md` BR-20 edited (Low)
### G5 — `VCRM.md` BR-20 assertion count (Closed)

BR-20 read "85 of 85 assertions passing"; the suite reports **142** and the
Tier S expectation JSON already specified 142. Updated to match observed
behaviour. Flagged because `VCRM.md` is a formal traceability document — revert
if that figure is contractually fixed.
**Resolution:** Confirmed. The suite reports **142** assertions and the
Tier S expectation JSON specifies 142. The old "85 of 85" was stale; the
update to 142 is correct. No revert needed.

---

Expand Down
125 changes: 1 addition & 124 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -820,127 +820,4 @@ MIT — see [LICENSE](LICENSE) for full text.

## Acknowledgements

Here are the prompts, distilled from every action I actually performed today. Each one is self-contained and would run end-to-end without follow-up questions.

---

### Prompt 1 — Audit & Fix Stale Documentation

```text
Audit all markdown docs and requirements.txt against the current codebase.
For each file, check that referenced functions, imports, file paths, test
counts, and CLI commands still match the code. Fix anything stale in-place.
Push to GitHub with a summary of what changed and why.

Files to check: README.md, FIXES_APPLIED.md, VALIDATION_REPORT.md,
NEW_USER_NAVIGATION_GUIDE.md, requirements.txt
```

---

### Prompt 2 — Generate Edge Case Datasets + Stress Tests

```text
Generate synthetic edge case CSV datasets in sample_data/edge_cases/ and
write matching pytest tests in tests/test_edge_cases.py. Cover these cases:

- UTF-8 BOM in headers
- Tab-delimited (.tsv)
- Duplicate primary keys
- Header-only (empty) CSV
- Unicode (CJK, accented, Polish characters)
- Nulls in required columns (empty string, "NULL", "N/A")
- Special characters (embedded commas, quotes, apostrophes)
- Ragged rows (inconsistent column count)
- Wrong/missing column headers
- Over-length string values exceeding max_length
- Large file (10,000 rows) with a performance assertion under 5 seconds
- Missing/nonexistent file path

Each test should use the project's existing JobConfig and pre_import stage.
Run the full test suite to confirm everything passes, then push to GitHub.
```

---

### Prompt 3 — Run Tests + Generate Detailed Report for Lead

```text
Run the full pytest suite and create TEST_REPORT.md at the project root.
The report must include:

- Summary line: total / passed / failed / skipped
- A table per test file with columns: #, Test name, Marker (unit/integration),
Status, What it verifies
- A "Note for Lead" section explaining that integration tests need a live
PostgreSQL database configured via .env, and that running `pytest -m unit`
deselects them by marker filter (not skipped due to failure)
- A test data table listing every dataset file and its purpose

Push TEST_REPORT.md to GitHub.
```

---

### Prompt 4 — Repo Hygiene (one-shot cleanup)

```text
Clean up the GitHub repo (amar-python/TestUploadtoGIT) in one pass:

1. If files exist at both root and a nested path (e.g. OneDrive/Desktop/...),
keep the latest version at root and git rm the nested duplicate entirely.
2. Add .abacusai/, .claude/, and any other tool/session folders to .gitignore
and untrack them with git rm --cached.
3. Prune the reports/ folder to keep only the 5 most recent timestamped run
directories and their matching logs. Delete the rest.
4. Add an auto-pruning rule to src/reporting.py that deletes old runs
beyond MAX_REPORT_RUNS (default 5) after each write_summary() call.
Make the limit configurable via env var.

Commit each logical change separately and push to master.
```

---

### Prompt 5 — Full Session (combines all of the above)

```text
I have a CSV-to-PostgreSQL migration framework at:
C:\Users\User\OneDrive\Desktop\Migration using ai
GitHub repo: amar-python/TestUploadtoGIT

Do the following in order:

1. AUDIT DOCS — Check all .md files and requirements.txt against the code.
Fix anything stale.

2. EDGE CASE TESTS — Generate 11+ synthetic CSV datasets covering:
- BOM (Byte Order Mark — the hidden \xEF\xBB\xBF prefix Excel adds to
UTF-8 files that corrupts the first column header)
- Tab-delimited (.tsv)
- Unicode (CJK, accented, Polish characters)
- Nulls in required columns (empty string, "NULL", "N/A")
- Special characters (embedded commas, quotes, apostrophes)
- Ragged rows (inconsistent column count)
- Wrong/missing column headers
- Over-length string values exceeding max_length
- Large file (10,000 rows) with a performance assertion under 5 seconds
- Duplicate primary keys
- Empty file (header only)
Write matching pytest tests. Run the suite to confirm all pass.

3. TEST REPORT — Create TEST_REPORT.md listing every test with status,
marker, and description. Include a note for the lead about integration
tests requiring PostgreSQL.

4. REPO HYGIENE — Flatten any nested paths to root level. Add tool folders
to .gitignore and untrack them. Prune reports/ to 5 most recent runs
and add auto-pruning logic to src/reporting.py (MAX_REPORT_RUNS=5).

5. PUSH — Commit each logical change separately and push to master.
Confirm the final repo structure.
```

---

The full session prompt (#5) would reproduce today's entire day of work in a single request. The individual prompts (#1-4)
Built with [PostgreSQL](https://www.postgresql.org/) 13+. Schema design informed by Australian Defence T&E practice (ASDEFCON, ISM, MIL-STD-882).
12 changes: 6 additions & 6 deletions VCRM.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ For each requirement, the columns mark which test layer verifies it. Numbers in
| BR-12 | Clearance enum {baseline, NV1, NV2, PV} | — | suite 01 (CHECK / enum assertions on personnel) | — | — | 01 | — | ✅ | |
| BR-13 | ISM classification marking enum | — | suite 02 (classification assertions on test_programs) | — | — | 01 | — | ✅ | |
| BR-14 | Phase type enum | — | suite 02 (phase_type assertions on test_phases) | — | — | 01 | — | ✅ | |
| BR-15 | Per-env connection limits | — | | — | — | | — | | The limit is set in `env_*.sql` but no test asserts it. Would need a `\d` introspection check. |
| BR-15 | Per-env connection limits | — | **suite 05 (S09: app role exists, S10: rolconnlimit matches)** | — | — | 01 | — | | Assertions S09/S10 verify `pg_roles.rolconnlimit` matches the env's configured `conn_limit`. |
| BR-16 | Automated single-command regression | — | — | All TP (single `runner.py` invocation) | 01 | 01 | — | ✅ | Combined `runner.py --tiers p,i,s` is the entry point. |
| BR-17 | Graceful degradation when PG unavailable | 9, 11 | — | — | (skip behaviour) | (skip behaviour) | — | ✅ | Python unit tests directly assert the skip path. |
| BR-18 | Machine-readable JSON report per run | 5, 6 | — | — | — | — | — | ✅ | Verified by `_load_expected` and `discover_scenarios` unit tests; the report write itself is exercised by every Tier P run. |
Expand Down Expand Up @@ -122,7 +122,7 @@ The `input_data/` loader has its own implicit requirements — verified end-to-e
| Layer | Requirements with at least one cell ticked | % of in-scope requirements (BR-01..BR-20) |
|-------|-------------------------------------------|-------------------------------------------|
| Python unit (PU) | 5 (BR-10/11/17/18) | 25 % |
| SQL suites (SQL) | 11 (BR-01/03/04/05/06/07/08/12/13/14/20) | 55 % |
| SQL suites (SQL) | 12 (BR-01/03/04/05/06/07/08/12/13/14/15/20) | 60 % |
| Tier P (TP) | 4 (BR-10/11/16/18) | 20 % |
| Tier I (TI) | 4 (BR-04/09/16/17) | 20 % |
| Tier S (TS) | 13 (BR-01/03/04/05/06/07/08/09/12/13/14/16/20) | 65 % |
Expand All @@ -132,11 +132,11 @@ The `input_data/` loader has its own implicit requirements — verified end-to-e

| Status | Count | Requirements |
|--------|-------|-------------|
| ✅ Verified | 17 | BR-03, BR-04, BR-05, BR-06, BR-07, BR-08, BR-09, BR-10, BR-11, BR-12, BR-13, BR-14, BR-16, BR-17, BR-18, BR-19, BR-20 |
| ✅ Verified | 18 | BR-03, BR-04, BR-05, BR-06, BR-07, BR-08, BR-09, BR-10, BR-11, BR-12, BR-13, BR-14, BR-15, BR-16, BR-17, BR-18, BR-19, BR-20 |
| ⚠️ Partial | 1 | BR-01 |
| ❌ Not verified | 4 | BR-02, BR-15, BR-21, BR-22 |
| ❌ Not verified | 3 | BR-02, BR-21, BR-22 |

**Headline:** **17 of 22 (77 %)** business requirements are fully verified by at least one automated test condition. Of the 5 not fully verified, 2 are deferred by design (BR-21, BR-22) and 3 are genuine gaps (BR-01 partial, BR-02 unverified, BR-15 unverified).
**Headline:** **18 of 22 (82 %)** business requirements are fully verified by at least one automated test condition. Of the 4 not fully verified, 2 are deferred by design (BR-21, BR-22), 1 is a genuine gap (BR-02 unverified), and 1 is partial (BR-01).

---

Expand All @@ -148,7 +148,7 @@ The `input_data/` loader has its own implicit requirements — verified end-to-e
|-----|-----|--------------------------|--------|
| **BR-01 partial** | Test/Staging/Prod environments are deployable but their structural equivalence to Dev is not asserted by any test. A change in `env_test.sql` that drifts from `env_dev.sql` would not be caught. | Add a Tier E scenario `01_envs_have_identical_structure` that deploys all four envs, queries `information_schema.columns` for each, and diffs the structure. | Medium (1 day) |
| **BR-02** | The framework claims to support 6 DB engines via adapters, but no test runs against MariaDB / SQLite / etc. | Add a Tier X scenario per engine. Earliest wins: SQLite (no service needed, just a file). | Medium per engine |
| **BR-15** | The per-environment `conn_limit` value lives in `env_*.sql` but no test confirms it's applied. | Add a SQL assertion in suite 05: `SELECT rolconnlimit FROM pg_roles WHERE rolname = :'app_user'` and `assert_equals(..., <expected limit>)`. | Small (~1 hour) |
| ~~**BR-15**~~ | ~~The per-environment `conn_limit` value lives in `env_*.sql` but no test confirms it's applied.~~ | **Closed.** Assertions S09 and S10 in `test_05_schema_and_business_rules.sql` now verify `pg_roles.rolconnlimit` matches the env's configured `conn_limit`. | |

### Deliberately deferred

Expand Down
4 changes: 2 additions & 2 deletions api/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fastapi>=0.115
uvicorn[standard]>=0.30
fastapi>=0.140.0
uvicorn[standard]>=0.51.0
psycopg2-binary>=2.9
python-multipart>=0.0.9
pydantic>=2.7
2 changes: 1 addition & 1 deletion build/adapters/adapter_postgresql.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ SCHEMA_FILE="${SCRIPT_DIR}/schema/postgresql/te_core_schema.sql"
PSQL_OPTS="-h ${PG_HOST} -p ${PG_PORT} -U ${PG_SUPERUSER}"
[[ -n "${PG_SUPERUSER_PASSWORD:-}" ]] && export PGPASSWORD="${PG_SUPERUSER_PASSWORD}"

get() { local E="${1^^}"; eval echo "\${PG_${2}_${E}}"; }
get() { local E="${1^^}"; local _v="PG_${2}_${E}"; echo "${!_v:-}"; }

SUCCEEDED=(); FAILED=()

Expand Down
9 changes: 7 additions & 2 deletions build/csv/loader_postgresql.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,17 @@ CONFIG_LOCAL="${SCRIPT_DIR}/config.local.env"
CONFIG_DEFAULT="${SCRIPT_DIR}/config.env"
[[ -f "$CONFIG_LOCAL" ]] && source "$CONFIG_LOCAL" || source "$CONFIG_DEFAULT"

case "$TARGET_ENV" in
dev|test|staging|prod) ;;
*) err "Invalid environment: '${TARGET_ENV}'."; exit 1 ;;
esac

E="${TARGET_ENV^^}"
PG_HOST="${PGHOST:-${PG_HOST:-localhost}}"
PG_PORT="${PGPORT:-${PG_PORT:-5432}}"
PG_USER="${PGUSER:-${PG_SUPERUSER:-postgres}}"
DB_NAME="$(eval echo "\$PG_DB_${E}")"
SCHEMA="$(eval echo "\$PG_SCHEMA_${E}")"
_db_var="PG_DB_${E}"; DB_NAME="${!_db_var:-}"
_sc_var="PG_SCHEMA_${E}"; SCHEMA="${!_sc_var:-}"

[[ -n "${PG_SUPERUSER_PASSWORD:-}" ]] && export PGPASSWORD="${PG_SUPERUSER_PASSWORD}"

Expand Down
5 changes: 5 additions & 0 deletions build/csv_loader.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ done
[[ -z "$CSV_FILE" ]] && { error "No CSV file specified."; usage; }
[[ ! -f "$CSV_FILE" ]] && { error "File not found: $CSV_FILE"; exit 1; }

case "$TARGET_ENV" in
dev|test|staging|prod) ;;
*) error "Invalid environment: '${TARGET_ENV}'. Must be one of: dev, test, staging, prod."; exit 1 ;;
esac

# ── Load configuration ────────────────────────────────────────────────────────
if [[ -f "$CONFIG_LOCAL" ]]; then
source "$CONFIG_LOCAL"
Expand Down
10 changes: 8 additions & 2 deletions build/csv_utilise.sh
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,19 @@ if [[ "$DB_ENGINE" != "postgresql" ]]; then
exit 2
fi

# ── Validate environment ────────────────────────────────────────────────────
case "$TARGET_ENV" in
dev|test|staging|prod) ;;
*) error "Invalid environment: '${TARGET_ENV}'. Must be one of: dev, test, staging, prod."; exit 1 ;;
esac

# ── Resolve PostgreSQL connection details ────────────────────────────────────
E="${TARGET_ENV^^}"
PG_HOST="${PGHOST:-${PG_HOST:-localhost}}"
PG_PORT="${PGPORT:-${PG_PORT:-5432}}"
PG_USER="${PGUSER:-${PG_SUPERUSER:-postgres}}"
DB_NAME="$(eval echo "\$PG_DB_${E}")"
SCHEMA="$(eval echo "\$PG_SCHEMA_${E}")"
_db_var="PG_DB_${E}"; DB_NAME="${!_db_var:-}"
_sc_var="PG_SCHEMA_${E}"; SCHEMA="${!_sc_var:-}"

if [[ -z "$DB_NAME" || -z "$SCHEMA" ]]; then
error "Could not resolve database / schema for env '${TARGET_ENV}'."
Expand Down
38 changes: 19 additions & 19 deletions build/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -162,16 +162,16 @@ configure_postgresql() {
for env in "${ENVS[@]}"; do
header " PostgreSQL — ${env^^} Environment"
E="${env^^}"
ask "PG_DB_${E}" "Database name" "$(eval echo "\$PG_DB_${E}")"
ask "PG_SCHEMA_${E}" "Schema name" "$(eval echo "\$PG_SCHEMA_${E}")"
ask "PG_APP_USER_${E}" "App username" "$(eval echo "\$PG_APP_USER_${E}")"
ask "PG_APP_PASSWORD_${E}" "App password" "$(eval echo "\$PG_APP_PASSWORD_${E}")" secret
ask "PG_CONN_LIMIT_${E}" "Connection limit" "$(eval echo "\$PG_CONN_LIMIT_${E}")"
_v="PG_DB_${E}"; ask "PG_DB_${E}" "Database name" "${!_v:-}"
_v="PG_SCHEMA_${E}"; ask "PG_SCHEMA_${E}" "Schema name" "${!_v:-}"
_v="PG_APP_USER_${E}"; ask "PG_APP_USER_${E}" "App username" "${!_v:-}"
_v="PG_APP_PASSWORD_${E}"; ask "PG_APP_PASSWORD_${E}" "App password" "${!_v:-}" secret
_v="PG_CONN_LIMIT_${E}"; ask "PG_CONN_LIMIT_${E}" "Connection limit" "${!_v:-}"
if [[ "$env" == "prod" || "$env" == "staging" ]]; then
eval "export SEED_${E}=false"
export "SEED_${E}=false"
info "Seed data disabled for ${E}"
else
ask_bool "SEED_${E}" "Load seed data?" "$(eval echo "\$SEED_${E}")"
_v="SEED_${E}"; ask_bool "SEED_${E}" "Load seed data?" "${!_v:-}"
fi
done
else
Expand All @@ -196,10 +196,10 @@ configure_mariadb() {
ask "MYSQL_APP_USER_${E}" "App username" "$(eval echo "\$MYSQL_APP_USER_${E}")"
ask "MYSQL_APP_PASSWORD_${E}" "App password" "$(eval echo "\$MYSQL_APP_PASSWORD_${E}")" secret
if [[ "$env" == "prod" || "$env" == "staging" ]]; then
eval "export SEED_${E}=false"
export "SEED_${E}=false"
info "Seed data disabled for ${E}"
else
ask_bool "SEED_${E}" "Load seed data?" "$(eval echo "\$SEED_${E}")"
_v="SEED_${E}"; ask_bool "SEED_${E}" "Load seed data?" "${!_v:-}"
fi
done
else
Expand All @@ -216,10 +216,10 @@ configure_sqlite() {
E="${env^^}"
ask "SQLITE_DB_${E}" "Database filename" "$(eval echo "\$SQLITE_DB_${E}")"
if [[ "$env" == "prod" || "$env" == "staging" ]]; then
eval "export SEED_${E}=false"
export "SEED_${E}=false"
info "Seed data disabled for ${E}"
else
ask_bool "SEED_${E}" "Load seed data?" "$(eval echo "\$SEED_${E}")"
_v="SEED_${E}"; ask_bool "SEED_${E}" "Load seed data?" "${!_v:-}"
fi
done
else
Expand Down Expand Up @@ -280,9 +280,9 @@ configure_teradata() {
ask "TD_APP_USER_${E}" "App username" "$(eval echo "\$TD_APP_USER_${E}")"
ask "TD_APP_PASSWORD_${E}" "App password" "$(eval echo "\$TD_APP_PASSWORD_${E}")" secret
if [[ "$env" == "prod" || "$env" == "staging" ]]; then
eval "export SEED_${E}=false"
export "SEED_${E}=false"
else
ask_bool "SEED_${E}" "Load seed data?" "$(eval echo "\$SEED_${E}")"
_v="SEED_${E}"; ask_bool "SEED_${E}" "Load seed data?" "${!_v:-}"
fi
done
else
Expand Down Expand Up @@ -485,12 +485,12 @@ printf " %-10s %-30s %s\n" "───" "────────────
for env in dev test staging prod; do
E="${env^^}"
case "$DB_ENGINE" in
postgresql) db_val="$(eval echo "\$PG_DB_${E}")" ;;
mariadb) db_val="$(eval echo "\$MYSQL_DB_${E}")" ;;
sqlite) db_val="${SQLITE_DIR}/$(eval echo "\$SQLITE_DB_${E}")" ;;
influxdb) db_val="$(eval echo "\$INFLUX_BUCKET_${E}")" ;;
redis) db_val="db$(eval echo "\$REDIS_DB_${E}") / $(eval echo "\$REDIS_KEY_PREFIX_${E}")" ;;
teradata) db_val="$(eval echo "\$TD_DB_${E}")" ;;
postgresql) _v="PG_DB_${E}"; db_val="${!_v:-}" ;;
mariadb) _v="MYSQL_DB_${E}"; db_val="${!_v:-}" ;;
sqlite) _v="SQLITE_DB_${E}"; db_val="${SQLITE_DIR}/${!_v:-}" ;;
influxdb) _v="INFLUX_BUCKET_${E}"; db_val="${!_v:-}" ;;
redis) _v="REDIS_DB_${E}"; _v2="REDIS_KEY_PREFIX_${E}"; db_val="db${!_v:-} / ${!_v2:-}" ;;
teradata) _v="TD_DB_${E}"; db_val="${!_v:-}" ;;
esac
seed_val="$(eval echo "\$SEED_${E}")"
printf " %-10s %-30s %s\n" "$env" "$db_val" "$seed_val"
Expand Down
Loading