# Decision Log Running rationale for protocol, auth, type, and architecture decisions made during the project. New decisions append; old ones are *amended* (with date) rather than overwritten. Format: every decision has a date, a status (`active` / `superseded` / `revisited`), the chosen path, the discarded alternatives, and the *why*. --- ## 2026-05-02 — Project goal & off-ramp **Status**: active **Decision**: Build a pure-Python implementation of the SQLI wire protocol. No IBM Client SDK. No JVM. No native libraries. **Off-ramp** (chosen by user during planning): if Phase 0 reveals the protocol is intractable in pure Python — e.g., mandatory undocumented crypto in the handshake — narrow scope (lock to one server version, drop async, drop prepared statements if needed) and stay pure-Python. Do **not** fall back to JPype/JDBC; that defeats the project's purpose. **Why**: The "no SDK / no JVM" goal is what makes this driver valuable. A JPype fallback would ship something that works but solves nothing the existing JDBC-via-JPype solution doesn't already solve. --- ## 2026-05-02 — Package name **Status**: active **Decision**: `informix-db` **Discarded**: `informixdb-pure` (longer), `ifxsqli` (less discoverable), `pyifx` (obscure) **PyPI availability**: confirmed available 2026-05-02 (HTTP 404 on `/pypi/informix-db/json`). The legacy `informixdb` is taken (HTTP 200), `informix` is also free (404) but too generic. **Why**: Discoverability balanced with brevity. Anyone searching PyPI for "informix" finds it; the hyphen distinguishes it from the legacy C-extension wrapper. --- ## 2026-05-02 — License **Status**: active **Decision**: MIT **Discarded**: Apache-2.0 (more defensive but less common in Python ecosystem), BSD-3-Clause **Why**: Simplest, most permissive, ecosystem-standard for Python libraries. --- ## 2026-05-02 — Sync first; async deferred **Status**: active **Decision**: Build a sync, blocking-socket implementation. Async lands in Phase 6+ as a separate `informix_db.aio` subpackage following asyncpg's I/O-agnostic-protocol pattern. **Why**: Wire protocols are hard enough; debugging protocol bugs through asyncio plumbing is two layers of indirection too many. Sync-first means we can test against blocking sockets, prove correctness, then mechanically swap the I/O layer. --- ## 2026-05-02 — Test target **Status**: active **Decision**: `icr.io/informix/informix-developer-database` (the IBM Informix Developer Edition image), port 9088 (native SQLI). **Why**: Free, official, no license click-through, supports plain-password auth out of the box. Pinning the digest (not `:latest`) is a Phase 1 requirement. --- ## 2026-05-02 — Phase 0 is a gate, not a step **Status**: active **Decision**: No library code is written until `PROTOCOL_NOTES.md` meets all four exit criteria: 1. Login byte layout documented end-to-end 2. Message-type tags identified for login/execute/row/end-of-result/error/disconnect 3. `SELECT 1` round-trip fully labeled 4. JDBC source and packet capture corroborate on login + execute paths If exit criteria can't be met within bounded effort, invoke the off-ramp. **Why**: Most greenfield projects fail by writing code before they understand the problem. This project has an undocumented wire protocol as its central unknown. Gating on Phase 0 means a failed spike still produces a publicly valuable artifact (`PROTOCOL_NOTES.md`) instead of a half-built driver. --- ## 2026-05-02 — Phase 1 architecture decisions (locked at start of Phase 1) > These are pre-decided so paramstyle/Python-floor/autocommit don't churn later. Recorded here so Phase 1 doesn't relitigate them. - **`paramstyle = "numeric"`** (`:1`, `:2`, …). Matches Informix ESQL/C convention. - **Python ≥ 3.10**. Gives us `match`, modern type hints, `tomllib`. - **`autocommit` defaults to off**. PEP 249 implicit semantics; opt-in via `connect(autocommit=True)`. - **Author**: Ryan Malloy `` (per global pyproject.toml convention). - **Versioning**: CalVer `YYYY.MM.DD` (`2026.05.02` initial); same-day fixes use PEP 440 post-release `2026.05.02.1`, `.2`, etc. --- ## 2026-05-02 — DATE pulled forward to MVP **Status**: active **Decision**: DATE is included in the Phase 2 MVP type set, alongside SMALLINT/INTEGER/BIGINT/FLOAT/CHAR/VARCHAR/BOOLEAN. **Discarded**: leaving DATE in the "medium" / Phase 6 bucket. **Why**: Almost no real Informix database is DATE-free. The encoding is trivial once the type code is known (4-byte day count from the Informix epoch 1899-12-31). Cheap to include; expensive to leave out. DATETIME / INTERVAL / DECIMAL / NUMERIC / MONEY remain in Phase 6+ — their encodings (qualifier-byte precision, BCD-style packed decimal) are non-trivial. --- ## 2026-05-02 — `CLAUDE.md` excluded from git and sdist **Status**: active **Decision**: `.gitignore` excludes `CLAUDE.md`. Once `pyproject.toml` exists, `[tool.hatch.build.targets.sdist].exclude` will also list `CLAUDE.md`. **Why**: `CLAUDE.md` contains the user's email and operator-private context. Per global convention, only commit `CLAUDE.md` to private repos. This project is destined for PyPI / public Git. --- ## (template — copy below this line for new entries) ``` ## YYYY-MM-DD — **Status**: active | superseded | revisited **Decision**: **Discarded**: **Why**: ```