Report ID: TEST-20260409-PDF Date: 2026-04-09 Service: pdf-engine (ods-platform) Operator: ADLC Pipeline (automated) + manual validation Session: First E2E after 9-day outage (BUG-003 recovery)
| Metric | Value |
|---|---|
| Total tests executed | 12 |
| Passed | 10 |
| Failed | 1 |
| Blocked | 1 |
| Pass rate | 83% |
| Bugs found | 1 (BUG-004, severity HIGH) |
| Service status | RECOVERED – operational after 9-day outage |
| Verdict | PASS_WITH_NOTES |
pdf-engine is back online after the BUG-003 outage (2026-03-31 to 2026-04-09). Core functionality is healthy: template CRUD, job creation, authentication, and multi-tenant isolation all pass. One new bug discovered: BUG-004 – duplicate template names are accepted (HTTP 201) when the spec requires HTTP 409 Conflict. One test was blocked due to a test script crash unrelated to the service.
BUG-004: Duplicate template name returns 201 instead of
409. The database unique index
uq_templates_tenant_name_active exists but the Rust handler
does not catch the PostgreSQL error code 23505 (unique_violation). This
is a data integrity issue that allows ambiguous template names per
tenant.
| Parameter | Value |
|---|---|
| Staging URL | https://pdf-engine.staging.orbusdigital.com |
| Stack | Rust / Actix-web / PostgreSQL 17 (schema: pdf) |
| Auth method | OID RS256 JWT (Bearer token) |
| Auth provider | https://oid.staging.orbusdigital.com |
| Database | PostgreSQL 17, schema pdf, migrations up to 007 |
| Previous session | 2026-04-01 (TC-PDF-002 BLOCKED due to HS256/RS256 mismatch) |
| Comparison | First full CRUD test session since 2026-03-26 automated run |
| ID | Test Name | HTTP | Verdict | Notes |
|---|---|---|---|---|
| TC-PDF-001 | Health Check | 200 | PASS | /health returns 200 with service metadata |
| TC-PDF-002 | Unauthenticated -> 401 | 401 | PASS | Request without Bearer token correctly rejected |
| TC-PDF-003 | List Templates | 200 | PASS | Returns array for authenticated tenant |
| TC-PDF-004 | Create Template | 201 | PASS | Happy path, all fields returned |
| TC-PDF-005 | Get Template | 200 | PASS | Retrieved by UUID, correct tenant scoping |
| TC-PDF-006 | Update Template | 200 | PASS | PATCH updates body_html |
| TC-PDF-007 | Duplicate Name -> 409 | 201 | FAIL | BUG-004: Expected 409, got 201. See section 4. |
| TC-PDF-008 | List Jobs | 200 | PASS | Returns array for authenticated tenant |
| TC-PDF-009 | Create Job | 201 | PASS | Job created with status pending |
| TC-PDF-010 | Get Job | – | BLOCKED | job_id not captured due to test script crash |
| TC-PDF-011 | Delete Template | 204 | PASS | Soft delete confirmed (GET after returns 404) |
| TC-PDF-012 | Cross-Tenant Isolation | 200 | PASS | Tenant B cannot access Tenant A resources |
| Field | Value |
|---|---|
| Bug ID | BUG-004 |
| Severity | HIGH |
| Status | OPEN |
| Test case | TC-PDF-007 |
| Discovered | 2026-04-09 |
| Category | Data integrity / Error handling |
When creating a template with a name that already exists for the same tenant, the API returns HTTP 201 (Created) and inserts a duplicate row. The spec requires HTTP 409 (Conflict).
POST /v1/templates with
{"name": "E2E-Final-113903", "content_type": "html", "body_html": "<p>original</p>"}
– returns 201.POST /v1/templates with
{"name": "E2E-Final-113903", "content_type": "html", "body_html": "<p>dup</p>"}
– returns 201 (expected: 409).| Aspect | Expected | Actual |
|---|---|---|
| HTTP status | 409 Conflict | 201 Created |
| Response body | {"error": "conflict", "message": "Template with this name already exists"} |
New template object with different ID |
| Database | Insert rejected by unique index | Second row inserted |
The database unique index
uq_templates_tenant_name_active ON pdf.templates (tenant_id, name) WHERE deleted_at IS NULL
exists in the schema. However, the create_template handler
in src/api/templates.rs does not match on
sqlx::Error::Database with error code 23505
(unique_violation). The constraint error is either swallowed by a
generic error handler or mapped to HTTP 500, which then gets caught as a
different path.
In the create_template handler, catch the PostgreSQL
unique violation:
Err(sqlx::Error::Database(e)) if e.code() == Some(Cow::Borrowed("23505")) => {
HttpResponse::Conflict().json(json!({
"error": "conflict",
"message": "Template with this name already exists"
}))
}Estimated effort: ~10 lines across src/api/templates.rs
and src/repository/template_repo.rs.
This bug was previously identified as BUG-002 in the automated E2E suite run on 2026-03-26 (scenarios TPL-VAL-09 and TPL-VAL-10 failed with the same symptom: status 201 instead of 409). It was not prioritized during the BUG-003 outage recovery. The 2026-04-09 manual E2E session confirms the bug persists and has been reclassified as BUG-004 at HIGH severity.
| Date | Event |
|---|---|
| 2026-03-31 | pdf-engine stops responding on staging. Container exits with migration 007 panic. |
| 2026-04-01 | E2E session: TC-PDF-001 PASS (health), TC-PDF-002 BLOCKED (JWT auth fails, container running HS256 old build). |
| 2026-04-07 | BUG-003 diagnosed: sqlx ignores ?search_path=pdf in
DATABASE_URL. Migrator reads wrong schema, panics on migration 007
(table already exists in public). |
| 2026-04-07 | Fix applied: explicit SET search_path = pdf via sqlx
after_connect callback. PR#6 merged to staging. |
| 2026-04-07 | All 4 reviews completed: BA PASS, Architect PASS_WITH_NOTES, Security PASS, DevOps PASS_WITH_NOTES. |
| 2026-04-09 | Service redeployed and healthy. E2E session: 10/12 PASS (83%). BUG-004 discovered. |
?search_path=pdf is silently ignored. The migrator
defaulted to the public schema and panicked when migration
007 attempted to create a table that already existed.after_connect callback in
the connection pool configuration to run
SET search_path = pdf on every new connection.pdf schema.
Database has 0 duplicate entries.search_path must be set explicitly via
after_connect, not via URL parameter, when using sqlx with
schema isolation.curl in the Docker image
– missing curl caused Coolify healthcheck failures and masked the actual
migration error.is_preview env var must be set correctly for
Coolify deployments to avoid incorrect build behavior.| Metric | 2026-03-26 (automated) | 2026-04-01 (manual) | 2026-04-09 (manual) |
|---|---|---|---|
| Total tests | 69 | 2 | 12 |
| Pass rate | 68.1% (47/69) | 50% (1/2) | 83% (10/12) |
| Auth working | Yes (HS256) | No (HS256/RS256 mismatch) | Yes (RS256) |
| Template CRUD | Yes | Not tested | Yes |
| Job CRUD | Partial | Not tested | Partial (1 blocked) |
| Multi-tenancy | Yes (8/8) | Not tested | Yes (1/1) |
| Duplicate name bug | Present (TPL-VAL-09) | N/A | Present (TC-PDF-007) |
| Service status | Running | Unhealthy | Recovered |
Key improvements since 2026-03-26: - Auth upgraded from HS256 to RS256 (aligned with OID) - BUG-003 (migration panic) resolved - CORS configuration fixed (was returning 400 on OPTIONS) - Container healthcheck operational
Remaining from 2026-03-26: - BUG-004 (duplicate name) still open - PDF manipulation endpoints (split, merge, rotate) still not implemented (P1+ scope) - FK violation error message not sanitized to spec wording
| Field | Value |
|---|---|
| Test | TC-PDF-010: Get Job |
| Verdict | BLOCKED |
| Reason | Test script crashed before capturing the job_id from
TC-PDF-009 response |
| Service impact | None – this is a test infrastructure issue |
| Recommendation | Fix the test script to properly capture and propagate the job_id variable between test cases |
Fix BUG-004 – Add 23505 error code handling in
create_template handler. Estimated 10 lines. This is a data
integrity issue and should be resolved before any production
promotion.
Fix test script – TC-PDF-010 blocked due to variable propagation failure. Not a service bug but must be fixed for complete test coverage.
Rerun full 69-scenario automated suite – The last automated run was 2026-03-26 with 68.1% pass rate. Many failures were related to BUG-003 (now fixed) and test harness issues. A rerun will establish the true current baseline.
Audit for duplicate templates – Query
pdf.templates for any rows with duplicate
(tenant_id, name) pairs created during the period when
BUG-004 was active. Clean up if found.
Enable Coolify healthcheck – DevOps review noted
health_check_enabled=False. Must be corrected before
production deployment.
Implement PDF manipulation endpoints – Split, merge, rotate APIs are specified but not yet implemented (P1 scope). These accounted for most failures in the 2026-03-26 automated suite.
Set container memory limits – DevOps review noted no memory limits configured in Coolify.
| Path | Contents |
|---|---|
~/dev/ops/reviews/pdf-engine/e2e-report-20260409.json |
This session’s raw results (12 tests) |
~/dev/ops/reviews/pdf-engine/bug-004-duplicate-template-name.json |
BUG-004 detailed finding |
~/dev/ops/reviews/pdf-engine/e2e-report.json |
Previous automated run (69 tests, 2026-03-26) |
~/dev/ops/test-evidence/2026-04-01-v2/TC-PDF-001/verdict.json |
Previous session health check evidence |
~/dev/ops/test-evidence/2026-04-01-v2/TC-PDF-002/verdict.json |
Previous session auth block evidence |
Report generated 2026-04-09 by documentarian agent. Next action: fix BUG-004, then rerun full automated E2E suite.