fix(jobs): store the print job creation instant as a real date-time (created_time) #38

Merged
james.maes merged 1 commits from fix/print-job-created-date-time into main 2026-11-11 14:09:22 +00:00
Owner

Problem

printing_job.created_at is ISO-8601 text (VARCHAR(40), written with Instant.now().toString()) and its QQQ field is a STRING. QQQ therefore cannot apply a relative date filter ("created in the last day"), a date sort or a date bucket to print jobs. The assistant and the data-analysis screens need exactly that ("printed documents from the last day, grouped by format").

Change (additive)

Area Change
Schema printing_job.created_time, a TIMESTAMP without time zone holding UTC (the QQQ DATE_TIME convention).
Write The job INSERT writes created_at and created_time from one Instant.
Metadata Read-only field Created (created_time, DATE_TIME); it replaces the text field in the Print jobs default columns and Summary section.
Kept created_at is untouched: queue order, history cursors, admission seeding, the Printing home and the job API still read it. Its field stays in Details, relabelled Created at (ISO text).
initialize() ADD COLUMN IF NOT EXISTS, backfill of existing rows from created_at (repeated on each start), printing_job_created_time_idx (tenant_id, created_time, id).
Docs CHANGELOG (Unreleased 1.2.0) and README, including the host schema step.

No wire or contract change (extension 2.4.0, wire v1). Other *_at text columns (device commands, devices, printers) are not changed.

Host-owned schemas: required step before deploying

A host that never calls initialize() must add the column in its own migrations. The PostgreSQL statements are in CHANGELOG.md. Without the column this version fails loudly and stores nothing: every submission is rolled back with the database's missing-column error for created_time, and QQQ cannot read the Print jobs table. The previous library keeps working on the new schema.

Validation (as run)

Check Result
./mvnw -B verify -Pui-demo on this commit (Windows, JVM zone America/Chicago) BUILD SUCCESS: 209 tests, 0 failures, 0 errors, 1 skipped (the opt-in PrintingWorkloadTest), 0 Checkstyle violations
PrintingJobCreatedTimeTest with the main sources reverted 5 of 5 fail
PostgreSQL 16 (throwaway local container, server zone America/Chicago), host-owned schema built from Forge's printing changesets plus the CHANGELOG statements; not part of the repository tests statements idempotent; 8 legacy rows (0 to 9 fractional digits) backfilled to the same instant; service submission stores the same instant in both columns; QQQ (Postgres module 4.1.0-RC.25) created_time >= now - 1 day returns the recent job and not a 30-hour-old one; count by format and day buckets work; submission on a schema without the column fails with column "created_time" of relation "printing_job" does not exist and stores nothing

New tests: a submitted job carries the instant in both columns (UTC, independent of the JVM zone); the produced field is DATE_TIME and in the default columns; a relative criterion (NowWithOffset.minus(1, DAYS), GREATER_THAN_OR_EQUALS) returns the recent job and not an old one, with sort, count by format and day buckets; initialize() backfills existing rows; a schema without the column refuses submissions and reads.

Notes for the merge

  • CHANGELOG.md adds an Unreleased (1.2.0) section at the top; the in-flight multi-node and station-identity branches add one too, so whichever merges second has a trivial textual conflict there.
  • Not merged, not tagged. A release needs a v1.2.0-RC.N (or v1.2.0) tag on main after the merge.

🤖 Generated with Claude Code

## Problem `printing_job.created_at` is ISO-8601 text (`VARCHAR(40)`, written with `Instant.now().toString()`) and its QQQ field is a `STRING`. QQQ therefore cannot apply a relative date filter ("created in the last day"), a date sort or a date bucket to print jobs. The assistant and the data-analysis screens need exactly that ("printed documents from the last day, grouped by format"). ## Change (additive) | Area | Change | |---|---| | Schema | `printing_job.created_time`, a `TIMESTAMP` without time zone holding UTC (the QQQ `DATE_TIME` convention). | | Write | The job `INSERT` writes `created_at` and `created_time` from one `Instant`. | | Metadata | Read-only field **Created** (`created_time`, `DATE_TIME`); it replaces the text field in the Print jobs default columns and Summary section. | | Kept | `created_at` is untouched: queue order, history cursors, admission seeding, the Printing home and the job API still read it. Its field stays in Details, relabelled **Created at (ISO text)**. | | `initialize()` | `ADD COLUMN IF NOT EXISTS`, backfill of existing rows from `created_at` (repeated on each start), `printing_job_created_time_idx (tenant_id, created_time, id)`. | | Docs | CHANGELOG (Unreleased 1.2.0) and README, including the host schema step. | No wire or contract change (extension 2.4.0, wire v1). Other `*_at` text columns (device commands, devices, printers) are not changed. ## Host-owned schemas: required step before deploying A host that never calls `initialize()` must add the column in its own migrations. The PostgreSQL statements are in `CHANGELOG.md`. Without the column this version fails loudly and stores nothing: every submission is rolled back with the database's missing-column error for `created_time`, and QQQ cannot read the Print jobs table. The previous library keeps working on the new schema. ## Validation (as run) | Check | Result | |---|---| | `./mvnw -B verify -Pui-demo` on this commit (Windows, JVM zone America/Chicago) | BUILD SUCCESS: 209 tests, 0 failures, 0 errors, 1 skipped (the opt-in `PrintingWorkloadTest`), 0 Checkstyle violations | | `PrintingJobCreatedTimeTest` with the main sources reverted | 5 of 5 fail | | PostgreSQL 16 (throwaway local container, server zone America/Chicago), host-owned schema built from Forge's printing changesets plus the CHANGELOG statements; not part of the repository tests | statements idempotent; 8 legacy rows (0 to 9 fractional digits) backfilled to the same instant; service submission stores the same instant in both columns; QQQ (Postgres module 4.1.0-RC.25) `created_time >= now - 1 day` returns the recent job and not a 30-hour-old one; count by format and day buckets work; submission on a schema without the column fails with `column "created_time" of relation "printing_job" does not exist` and stores nothing | New tests: a submitted job carries the instant in both columns (UTC, independent of the JVM zone); the produced field is `DATE_TIME` and in the default columns; a relative criterion (`NowWithOffset.minus(1, DAYS)`, `GREATER_THAN_OR_EQUALS`) returns the recent job and not an old one, with sort, count by format and day buckets; `initialize()` backfills existing rows; a schema without the column refuses submissions and reads. ## Notes for the merge - `CHANGELOG.md` adds an `Unreleased (1.2.0)` section at the top; the in-flight multi-node and station-identity branches add one too, so whichever merges second has a trivial textual conflict there. - Not merged, not tagged. A release needs a `v1.2.0-RC.N` (or `v1.2.0`) tag on `main` after the merge. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
james.maes added 1 commit 2026-11-11 13:22:05 +00:00
fix(jobs): store the print job creation instant as a real date-time (created_time)
maven / build (push) Successful in 2m14s
build / maven (push) Successful in 2m14s
d9f0c357a7
printing_job.created_at is ISO-8601 text and its QQQ field is a string, so QQQ
could not apply a relative date filter ("created in the last day"), a date sort
or a date bucket to print jobs.

- printing_job gains created_time, a TIMESTAMP without time zone holding UTC
  (the QQQ date-time convention), written by the same INSERT from the same
  instant as created_at.
- The job table exposes it as the read-only DATE_TIME field "Created"; it
  replaces the text field in the default columns and Summary section. The text
  field stays (relabelled "Created at (ISO text)") because the queue order,
  history cursors, admission seeding, the Printing home and the job API read it.
- initialize() adds the column, backfills existing rows from created_at and
  creates printing_job_created_time_idx (tenant_id, created_time, id).
- A host that owns the schema must add the column first (PostgreSQL statements
  in CHANGELOG.md). Without it every submission is rolled back with the
  missing-column error and QQQ cannot read the table; nothing is stored silently.

No wire or contract change (extension 2.4.0, wire v1).

Tests: PrintingJobCreatedTimeTest (5 tests; all fail without the change).
./mvnw -B verify -Pui-demo: 209 tests, 0 failures, 0 errors, 1 skipped
(opt-in workload test), 0 Checkstyle violations.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
james.maes merged commit 40089937bf into main 2026-11-11 14:09:22 +00:00
Sign in to join this conversation.