Skip to content

fix: widen signed_at/signed_by columns to prevent PostgreSQL overflow#15

Merged
bradleygauthier merged 1 commit intomainfrom
fix/signed-at-column-overflow
Mar 17, 2026
Merged

fix: widen signed_at/signed_by columns to prevent PostgreSQL overflow#15
bradleygauthier merged 1 commit intomainfrom
fix/signed-at-column-overflow

Conversation

@bradleygauthier
Copy link
Contributor

Summary

signed_at column (String(30)) was 2 characters too narrow for datetime.isoformat() output from timezone-aware datetimes (32 chars for UTC +00:00), causing StorageError on every PostgreSQL write. SQLite was unaffected (it ignores VARCHAR length). Also widens signed_by from String(16) to String(32) — the legacy 16-char hex fingerprint had zero headroom.

  • Widen signed_at from String(30) to String(40) in both CapsuleModel and CapsuleModelPG
  • Widen signed_by from String(16) to String(32) in both models
  • Bump version to 1.5.1

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Documentation update
  • Test improvement

Checklist

Python reference (reference/python/)

  • Tests pass: cd reference/python && pytest tests/ — 761 passed, 7 skipped
  • Linter passes: cd reference/python && ruff check src/ tests/ — All checks passed
  • Type checker passes: cd reference/python && mypy src/qp_capsule/ — Success
  • Golden fixtures pass: cd reference/python && pytest tests/test_golden_fixtures.py

TypeScript reference (reference/typescript/)

  • Tests pass — N/A (no TypeScript changes)
  • Type check passes — N/A
  • Conformance passes — N/A

General

  • Documentation updated — Storage Schema section added to API docs with full column reference and migration guide
  • CHANGELOG.md updated — [1.5.1] - 2026-03-17 with Fixed + Migration sections

Protocol Impact

  • No protocol impact (implementation only)

Migration

For existing PostgreSQL deployments:

ALTER TABLE quantumpipes_capsules
  ALTER COLUMN signed_at TYPE VARCHAR(40),
  ALTER COLUMN signed_by TYPE VARCHAR(32);

New installations get the correct widths automatically via create_all(). SQLite databases require no action.

Test Coverage

24 new regression tests in test_column_width.py:

  • Schema introspection (4): verify both models declare the correct column widths
  • Isoformat length validation (7): prove UTC-aware strings exceed old limit, fit new limit
  • Fingerprint format lengths (2): legacy hex prefix + keyring qp_key_XXXX both fit
  • SQLite roundtrip (4): signed_at/signed_by survive get, list, get_latest
  • PostgreSQL roundtrip (7): same paths plus get_all_ordered, keyring format, and post-roundtrip verify()

…SQL overflow

`Seal.seal()` stamps `signed_at` with `datetime.now(UTC)`, whose
`.isoformat()` produces 32-character strings (e.g. `2026-03-17T05:24:42.485699+00:00`).
Both `CapsuleModel` and `CapsuleModelPG` declared this column as `String(30)`,
causing every PostgreSQL write to raise `StorageError: value too long for type
character varying(30)`. SQLite was unaffected (it ignores VARCHAR length).

Changes:
- Widen `signed_at` from String(30) to String(40) in both models
- Widen `signed_by` from String(16) to String(32) for headroom (legacy hex
  fingerprint is exactly 16 chars — zero margin for format changes)
- Bump version to 1.5.1
- Add 24 regression tests covering schema introspection, isoformat length
  validation, and store-retrieve roundtrips for both storage backends
- Document storage schema with full column reference in API docs
- Add migration SQL for existing PostgreSQL deployments
@bradleygauthier bradleygauthier merged commit a380afa into main Mar 17, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant