← All pages
Venipak · 4H · UAT cut 2026-08-25 · updated 2026-08-28

Test results & evidence

4H Phase 1 + Phase 2 is on uat — since 2026-08-25, updated 2026-08-28: QA round live, automated part green on gouat, 74 manual cases + P7 open, kl_view 4H AUTO row now in the all-regions price table (#634/#635 merged). This page carries the automated results from the merge result (green), the full manual test list handed to QA on 2026-08-26 (not yet run), and below them the earlier dev evidence kept as provenance.

uat
environment under test
305
automated tests green
121
manual cases — awaiting QA
9
tickets at Waiting for Q/A
0
new regressions

UAT — the release under test automated live round 2026-08-27 green manual round pending

4H Phase 1 + Phase 2 merged to uat on 2026-08-25 (cut day — the 2026-08-27/28 live gouat round below is newer). The automated matrix below was run on the merge result and is green; the 121 manual cases were handed to QA on 2026-08-26. On 2026-08-27 an automated first pass was run live against gouat (block below) and its results are entered in the Result column; every other row still awaits manual QA. Nothing on this page claims a full manual UAT pass.

repouat mergePRbase (master)payload
pakasa88b5ea9#618 · pipeline #733a130b76c42 files, +2032 / −47
siuntaff4e6aef#158d7214ae628 files, +1764 / −35
go-import842eaa41#64d0fe853c5 files, +735 / −1
venishipexcluded from this window — nothing on this page tests it

UAT database — cut-day snapshot, verified 2026-08-25

objectstate
LT postcodes posti_service1all 17 246 enabled
tbl_klientai.kl_4rp_autopresent · 4 AUTO (3464 JYSK BALTIC · 89398 ROMITEKA · 157673 ELECTRONIC TRADE · 158280 PRO TRADE) · 166 557 MANUAL
tbl_log_siunt_4rppresent, empty · s4rp_user_id int(8) unsigned · s4rp_source enum('auto','manual')
ALTER cost19 s on 166 561 rows / 60.3 MB (MyISAM full copy) — the prod estimate

Credentials are identical on godev.* and gouat.* — so veni-tests/.env.uat is .env.dev plus the go-import block from .env.local with godev. swapped for gouat.. No new logins to chase; .gitignore already covers .env.*.

Payer setup — QA uses their own client card

Every auto-apply case below depends on the payer being AUTO. QA ticks 4H AUTO on their own client card in PAKAS and tests as their own account — no DB change, no borrowed payer, nothing to restore for anyone else. Set GO_IMPORT_USER_ID in .env.uat to your own client id.

stepactionwhy this order
1Run the MANUAL-payer cases while the box is still unticked — 5.1 and go-import C10a real test result, not a setup step; running it first means the MANUAL state is never wasted
2Tick 4H AUTO on your client card, as a kl_edit_plius userthis action is VDT-3384 §B2 step 7 — do it through the UI, never by SQL, or the ACL path that steps 15.1–15.3 test is skipped and nothing proves the checkbox saves
3Run every auto-apply case — sections 1, 2, 3, 4, 6, 7, 9, 10, 13, 14the payer is now AUTO, so a 0 means a real defect rather than a MANUAL payer behaving correctly
4Untick when finished; confirm a new qualifying shipment stays unflaggedVDT-3384 §B2 step 5 — the reversibility proof Sales relies on

If a case returns siunt_4rp = 0 where you expected 1, check the payer’s switch before raising anything: a MANUAL payer returning 0 is the feature working, and it is indistinguishable from the feature being broken. SELECT kl_id, kl_pav, kl_4rp_auto FROM tbl_klientai WHERE kl_id = <your client id>;

Client ids are consistent between dev and uat — verified on demovenipak_new 2026-08-26 — so whatever id works locally is the same id on uat. On uat there are exactly 4 AUTO clients out of 166 561 (3464 JYSK BALTIC, 89398 ROMITEKA, 157673 ELECTRONIC TRADE, 158280 PRO TRADE), which is the seeded cutover set. Leave that count at 4 when the round ends.

Cron: pack_4rp sweeps yesterday+today nightly. Every case below that says “run the cron” means a manual trigger — ask the developer rather than waiting overnight.

Automated results — run on the merge result 305 green

Each suite was run against origin/uat + the branch, not the branch alone.

305
tests green
42/0
veni-guard, per repo
0
new regressions
5/5
four-hands-notice specs
reposuiteresult
pakasPHPUnit in ss1-web vs venipak_dev144 tests, 297 assertions, 0 failures
siuntaPHPUnit, helper 0.9.2 + veniship-client 3.0.0 freshly resolved91 tests, 370 assertions, 0 failures
siuntaPlaywright smoke + functional48 passed · 3 failed, all cleared below
go-importPHPUnit70 tests, 78 assertions, 0 failures
go-importveni-tests Jest API36 passed, 8 skipped
pakasPlaywright smoke + functional92 passed, 15 failed — identical 15 on plain origin/uat, 0 regressions
all fourveni-guard PR guards, permissive42 ran, 0 block-fails per repo

Every failure accounted for

failureverdictproof
siunta baltic-pickup-browse BALTIC-3pre-existingfails identically on plain origin/uat; the spec guards VDT-3430, which is on neither branch
siunta pudo-picker PUDO-UI-1pre-existingsame baseline run; the spec's own comment cites VDT-3430
siunta shipment TC10flakyre-ran 3× on the merge result: 3/3 pass. The first run raced the stress-project shipments
pakas Playwright, 15 testsenvironment gapthe same 15 fail on plain origin/uat — PAKAS_URL points at localhost:8001, absent from this stack

Direct 4H functional evidence: all five four-hands-notice.spec.ts cases (VDT-3407 — notice, badges, the 25.99/26.00 kg inclusive floor, PL-receiver removal) passed on the siunta merge result.

One deliberate deviation from the written gate. npx playwright test tests/siunta/ sweeps three projects including siunta-stress, which creates 3000 shipments across 30 parallel sessions in the shared dev DB. It was stopped part-way and the two required projects (smoke, functional) were run explicitly instead. A partial set of stress shipments was created in venipak_dev and adds to the outstanding cleanup.

Automated — live uat round 2026-08-27 · 191 suite + 33 targeted green

Layout note 2026-08-28: the kl_view “4H AUTO” row moved mid-round from the left client card into the all-regions price table (PRs #634 uat / #635 dev, merged; live on gouat) — do not chase it in the left card; it shows only for kl_edit_plius viewers on clients that have a price list. Case 15.8 reworded accordingly; four-hands siunta specs unaffected.

Same veni-tests suites, this time run against the deployed uat apps on gouat (TEST_ENV=uat, .env.uat created 2026-08-27), plus three targeted 4H XML imports. Payer for API imports = the login’s uat client (1 · VENIPAK KAUNAS & MORE, MANUAL), so only MANUAL-side 4H behaviour is provable this way; AUTO-payer cases wait on a client-card ruling, cron cases on the P7 trigger.

appsuiteresult
siuntaPlaywright smoke (gouat)20 passed
siuntaPlaywright functional (gouat)28 passed · 3 failed + 1 skipped, all cleared below
go-importJest API (gouat, real XML posts)36 passed, 8 deliberately skipped — equals the dev baseline
pakasPlaywright smoke (gouat)8 passed
pakasPlaywright functional (gouat)99 passed — the 15 local “env fails” do not occur against the real host

Every live-round failure accounted for

failureverdictproof
siunta four-hands-notice test 1spec artifactthe notice IS shown with the correct full English text (“…handed over to the recipient at the courier’s vehicle, without delivery to the door”); the spec asserts the Lithuanian substring and the uat session renders EN. Functionally 12.1 passes — and doubles as EN-translation evidence for 12.13
siunta baltic-pickup-browse BALTIC-3pre-existingguards VDT-3430, ancestry-proven absent from the uat tip — same disposition as the 08-22/08-27 local runs
siunta pudo-picker PUDO-UI-1 (+UI-2 serial-skipped)pre-existingsame VDT-3430 gap (Helsinki auto-expand)

Targeted 4H XML imports (payer MANUAL) + DB verification

probescenarioexpectedobserved
T-ALT→LT 40 kg, allowlisted postcode, no tag, MANUAL payer00 — siunt 24478867 (case 5.1, creation channel)
T-B<four_hands>1</four_hands>, 10 kg11 — siunt 24478868 (case 8.2)
T-C<four_hands>0</four_hands>, 40 kg00 — siunt 24478869 (case 8.1, MANUAL-payer variant)

Post-run DB check (read-only): 26 suite shipments + 3 probes created today for payer 1 — 0 spuriously flagged; tbl_log_siunt_4rp still 0 rows (creation-time initial values do not write provenance; the log records changes). Environment traps hit and fixed exactly as the list predicted: uat GO_IMPORT_USER_ID is the login’s user_id 17802 (dev 20579 / stress 17766 are both wrong — manifest TITLE prefix must equal it), and PAKAS_URL needs a trailing slash. Both fixes live only in .env.uat.

AUTO-payer tranche (owner-approved: client 1 ticked via the client-card UI, unticked after)

With the owner’s say-so, client 1 (the shared uat login’s payer) was set 4H AUTO through the pakas client-card UI (that is case 15.4 itself), the §1–§8 creation-channel matrix was driven through real XML imports and the siunta form, and the card was unticked again (case 15.5, proven by siunt 24478914 staying 0). Final state re-verified: exactly the canonical 4 AUTO clients remain. All flags checked in the DB, read-only. The pack_4rp cron did not run during the window and payer-1 shipments are MANUAL again, so the nightly sweep will not disturb the evidence.

scoperesult
LT band boundaries 25.9 / 26.0 / 40 / 75.0 / 75.1 (§1)5/5 flags exact (siunt 24478870–74)
LV+EE boundaries 30.9 / 31.0 / 90.0 / 90.1 / EE 26 (§2)6/6 flags exact (24478875–76, 24478887–90)
Volume irrelevance (§3), multi-pack never-summed (§4)5/5 (24478877–81)
Gates: PL sender / PL receiver / pickup receiver / disabled postcode (§5)4/4 stay 0 (24478882, 24478892, 24478895, 24478891)
Explicit decision (§8): fh=0 under AUTO · empty tag · omitted tag3/3 — incl. the full VDT-3403 proof (24478886 stays 0)
siunta form: create 40 kg → immediate 1 (6.1) · edit 20→40 flips (6.3)2/2 (24478897, 24478899)
Client-card switch (§15): render / tick / untick / kl_view row15.1, 15.4, 15.5, 15.8

Findings for the owner (not self-judged as defects)

#observedroot causedecision needed
F-1 (6.4)Editing an auto-flagged shipment’s weight 40→20 kg keeps siunt_4rp=1; unticking the box during the edit does clear it (24478897 → 0)the edit form pre-renders the box ticked from the existing flag; on save rp4=1 posts and isset($_POST['rp4']) reads it as a client orderaccept (weight-drop clearing is the §10 re-weigh hook’s job) or ticket a siunta-side auto-clear
F-2 (8.5)An AUTO payer cannot decline 4H through the siunta form — a qualifying 40 kg save with the box unticked still stores 1 (24478898)an unchecked checkbox posts nothing; !isset($_POST['rp4']) then triggers auto-apply — “deliberately unticked” and “untouched” are one POST state (same family as the fixed go-import defect A, where the tag carries the distinction)accept-and-document for Phase 1 (decline channels: API fh=0, or Sales flips the card) or ticket a tri-state UI

Also observed, consistent with design: siunta-side flag changes (client edits) write no tbl_log_siunt_4rp rows — the provenance log’s writers are pakas-side (cron / siunt_edit / re-weigh); creation-time initial values do not log either. Log row count after the whole round: 0. Language note: the 4H notice rendered correct in EN in one session and LT in another (12.13 partial evidence).

Manual UAT test list — 121 cases handed to QA 2026-08-26

Derived by diffing origin/uat against each merge result, not from ticket intent. The nine tickets’ own validation steps are subsets of this. The Result column is deliberately empty — it is filled by the QA round, not by the developer.

envurl
pakashttps://gouat.venipak.lt/pakas2
siuntahttps://gouat.venipak.lt/siunta2
go-importhttps://gouat.venipak.lt/import — XML POST endpoint …/import/send_auth_basic.php

0. Preconditions — verify before any test

#checkexpectedticketresult
P1SELECT posti_zone, COUNT(*), SUM(posti_service1='1') FROM tbl_post_info WHERE posti_salis='LT' GROUP BY posti_zone;enabled == total on every LT zoneVDT-3413PASS probe 08-27
P2SHOW COLUMNS FROM tbl_klientai LIKE 'kl_4rp_auto';exists, tinyint(1), default 0VDT-3384PASS probe 08-27
P3SELECT kl_id, kl_pav, kl_4rp_auto FROM tbl_klientai WHERE kl_4rp_auto=1;exactly 4 rows — 3464 JYSK BALTIC · 89398 ROMITEKA · 157673 ELECTRONIC TRADE · 158280 PRO TRADEVDT-3384PASS probe 08-27
P4SHOW CREATE TABLE tbl_log_siunt_4rp;exists, MyISAM, s4rp_user_id int(8) unsigned, s4rp_source enum('auto','manual')VDT-3395PASS probe 08-27, 0 rows
P5helper version resolved on uatpakas ≥ 0.8.3, siunta ≥ 0.9.1VDT-3203git PASS deployed resolution unverified
P6siunta asset VERSION50 — otherwise the new JS is cached and section 12 fails for the wrong reasonVDT-3407PASS version=50 on a logged-in page 08-27
P7pack_4rp cron scheduled, last run cleanno error in the cron logVDT-3203OPEN awaiting dev

1. Weight bands — LT (floor 26.0 inclusive, ceiling 75.0 inclusive)

#caseexpectedresult
1.1one pack 25.9 kgsiunt_4rp stays 0PASS auto 08-27 (creation channel)
1.2one pack 26.0 kgbecomes 1PASS auto 08-27 (creation channel)
1.3one pack 40.0 kg1PASS auto 08-27 (creation channel)
1.4one pack 50.0 kg1, single charge
1.5one pack 50.1 kg1, 2× charge
1.6one pack 75.0 kg1, 2× chargeflag PASS auto 08-27; charge = §16 manual
1.7one pack 75.1 kg0 — above the ceiling there is no 4H at allPASS auto 08-27 (creation channel)

2. Weight bands — LV and EE (floor 31.0, ceiling 90.0)

#caseexpectedresult
2.1LV receiver, 30.9 kg0PASS auto 08-27 (creation channel)
2.2LV receiver, 31.0 kg1PASS auto 08-27 (creation channel) — LV and EE both
2.3LV receiver, 60.0 kg1, single charge
2.4LV receiver, 60.1 kg1, 2×
2.5LV receiver, 90.0 kg1, 2×flag PASS auto 08-27; charge = §16 manual
2.6LV receiver, 90.1 kg0PASS auto 08-27 (creation channel)
2.7EE receiver, 26.0 kg0 — EE does not use the LT floorPASS auto 08-27 (creation channel)

3. Volume is gone

#caseexpectedresult
3.1LT pack 30 kg, volume below 0.179 m³1 — the old rule required volume > 0.179 and would have said 0PASS auto 08-27 (creation channel)
3.2LT pack 20 kg, volume above 0.179 m³0 — weight alone decidesPASS auto 08-27 (creation channel)

4. Multi-pack shipments

#caseexpectedresult
4.1two packs, 20 kg + 20 kg (sum 40)0 — weights are never summedPASS auto 08-27 (creation channel)
4.2two packs, 10 kg + 30 kg1 — one pack in band is enoughPASS auto 08-27 (creation channel)
4.3three packs, one 80 kg (over ceiling) + one 40 kg1 — the in-band pack qualifiesPASS auto 08-27 (creation channel)
4.4one 40 kg pallet-flagged pack + one 40 kg normal pack1 — pallet pack stripped, the other qualifies

5. Gates that must block auto-4H

#caseexpectedresult
5.1MANUAL payer — card shows 4H AUTO unticked0PASS creation via go-import (siunt 24478867); cron variant pending trigger
5.2sender PL0PASS auto 08-27 (creation channel)
5.3receiver PL0PASS auto 08-27 (creation channel)
5.4sender PL → receiver DE0
5.5pallet — pack_paletes_tipas != '0'0
5.6receiver name contains VENIPAK LOCKER0PASS by construction — import rejects >25 kg to a locker outright, an in-band locker 4H cannot exist on this channel; cron/siunta variants pending
5.7receiver name contains VENIPAK PICKUP0PASS auto 08-27 — real pickup point, 40 kg, stays 0 (siunt 24478895)
5.8receiver postcode with posti_service1 != '1'0PASS auto 08-27 (disabled LV postcode)
5.9non-Venipak locker (e.g. an LP Express point)1 is acceptable — name-match only, out of scope. Record, do not fail

6. Every channel applies the rule at creation, not overnight

#caseexpectedresult
6.1siunta shipment form, AUTO payer, LT 40 kgsiunt_4rp = 1 immediately, before any cronPASS auto 08-27 (siunt 24478897); the rp4 box does NOT auto-tick — the flag is server-side
6.2siunta form, MANUAL payer0 immediately, and still 0 after the cron
6.3siunta shipment edit — create 20 kg, edit to 40 kgflips to 1 on savePASS auto 08-27 (siunt 24478899)
6.4siunta edit downward — create 40 kg (auto-flagged), edit to 20 kgflag clearedFINDING F-1 stays 1 — the pre-ticked box re-posts as an order; unticking during the edit DOES clear it. See findings below
6.5siunta XLS import, one qualifying row, AUTO payer1 on the imported shipment
6.6same via the inc.import.xls.2 path1
6.7go-import API, qualifying shipment, AUTO payer1PASS auto 08-27 (siunt 24478872)
6.8insert a qualifying shipment directly, bypassing the channelsthe cron backstop flags it
6.9the same shipment data through 6.1, 6.5 and 6.7identical siunt_4rp in all three

7. Export / manifest reads the real consignee

#caseexpectedresult
7.1depot hand-off routing, true consignee in LT, 40 kgevaluated against the consignee → 1
7.2same but true consignee in PL0 — previously the depot's own LT address was read and this wrongly qualified

8. An explicit client decision wins

#caseexpectedresult
8.1go-import <four_hands>0</four_hands>, otherwise qualifying, AUTO payerstays 0 — the VDT-3403 defectPASS full — AUTO payer, fh=0, 40 kg stays 0 (siunt 24478886). The VDT-3403 fix holds on uat
8.2go-import <four_hands>1</four_hands>, pack 10 kg1 — client ordered itPASS siunt 24478868
8.3go-import empty <four_hands></four_hands>treated as absent → auto-apply runs → 1PASS auto 08-27 (creation channel)
8.4go-import tag omitted entirelyauto-apply runs → 1PASS auto 08-27 (creation channel)
8.5siunta form, 4H box deliberately unticked on a qualifying packstays 0, and still 0 after the cronFINDING F-2 AUTO payer: flagged 1 — an unticked box posts nothing, so a decline cannot be expressed; holds only for MANUAL payers. See findings below
8.6siunta form, 4H box ticked on a non-qualifying 10 kg pack1, and the cron does not clear it

9. Provenance log

#caseexpectedresult
9.1cron flags a shipmentone row: source=auto, old 0, new 1, user id, timestamp
9.2operator sets 4H in siunt_editone row: source=manual, correct user id
9.3operator clears 4H in siunt_edit_allrow with old 1 → new 0
9.4order of writesthe log INSERT precedes the flag UPDATE — never flagged without a log row
9.5log write fails (ask dev to simulate)the flag change is aborted, loudly; no silent flip
9.6a cron run that flags nothingwrites nothing

10. Terminal re-weigh

#caseexpectedresult
10.1auto-flagged 40 kg pack re-weighed to 20 kgflag cleared, log row records it
10.2unflagged 20 kg pack re-weighed to 40 kg, AUTO payerflag set
10.3client-ordered 4H, pack re-weighed to 10 kgflag kept — a client order is never cleared by re-weigh
10.4manually-set 4H, pack re-weighed out of bandflag kept
10.5re-weigh within band, 40 → 45 kgflag unchanged, no duplicate log spam
10.6re-weigh to 80 kg (over ceiling), previously auto-flaggedflag cleared

11. Pack reassignment

#caseexpectedresult
11.1SplitLatePackageCommand moves a pack off a 4H shipmentprovenance copied to the destination; source re-evaluated
11.2split leaves the origin with only sub-floor packsorigin's auto flag clears
11.3split moves a qualifying pack onto a non-4H shipmentdestination gains the flag with correct provenance

12. Client-facing UI — siunta (confirm VERSION=50 and hard-reload first)

#caseexpectedresult
12.1MANUAL client, qualifying pack, 4H not ordered, press Skaičiuotinotice appears — handed over at the vehicle, not to the doorPASS auto 08-27 (EN session; full EN text correct)
12.24H orderedno noticePASS auto 08-27
12.3non-qualifying packno noticePASS auto 08-27
12.4badge, 4H orderedred 4H badge on that packPASS auto 08-27
12.5badge, qualifies but not orderedblack no 4H badgePASS auto 08-27
12.6live repaint — weight 20 → 40 kgbadge appears without reloadPASS auto 08-27
12.7live repaint — flag as palletbadge disappears
12.8live repaint — switch to envelopebadge disappears
12.9boundary in the UI25.99 kg → no badge; 26.00 kg → badgePASS auto 08-27
12.10PL receiverbadges and notice removedPASS auto 08-27
12.11over-ceiling pack, LT 80 kgthe over-ceiling message, not a 4H badge
12.12tooltip contentLT 26–75 doubling above 50; LV/EE 31–90 doubling above 60; the 22-city serviced list
12.13languagesLT, EN, LV, ET, RU, PL — notice, badges and tooltip all translated, no raw keyspartial: notice correct in EN and LT (two sessions); other languages + tooltip pending

13. Pakas terminal reports — all three views (…cm.php, …cm_new.php, …_ee48.php)

#caseexpectedresult
13.14H kaina columnpresent, money per shipment, matches the payer's price list
13.2Kiek 4H footercount equals the number of 4H rows shown
13.3Neužsakytos 4 rankos filteronly shipments that qualify and were not orderedpartial: the filter link renders on …cm.php; value-level check manual (multi-minute query)
13.4filter offfull list returns, no rows lost
13.5row indicator, LT 60 kgshows the 2×4H cue (over LT's 50)
13.6row indicator, LV 55 kgsingle 4H — under LV's 60. A country-blind implementation passes 13.5 and fails only here
13.7sorting / paging with the new columnno layout break, no SQL error
13.8empty resultcolumn and footer render cleanly with no rows

14. Routing map and courier payload

#caseexpectedresult
14.1stop with 4H orderedgreen bubble
14.2stop that qualifies, not orderedred bubble
14.3weights on red stopsrendered red
14.4side listqualifying-unordered stops listed
14.5route aggregate countcounts only unordered qualifiers — ordered stops must not inflate it
14.6mixed stop, one ordered + one unordered shipmentper the documented rule; record actual behaviour
14.7jquery.routing.php payloadcontains shipment_4rp and shipment_4rp_weight per shipment
14.8payload valuesshipment_4rp matches siunt_4rp; shipment_4rp_weight matches the heaviest qualifying pack
14.9route with no 4Hbubbles normal, aggregate 0, payload keys present with 0 values
14.10scanner / driver viewconsumes the new keys without error — courier-team owned, report, do not fix

15. Client card AUTO/MANUAL switch

#caseexpectedresult
15.1kl_edit_plius user, client edit4H AUTO checkbox renders, with the hint textPASS auto 08-27
15.2non-plius user, client editcheckbox not rendered
15.3non-plius user hand-posts kl_4rp_auto=1ignored — client stays MANUAL
15.4plius user ticks AUTO, saveskl_4rp_auto = 1; a qualifying shipment then auto-flagsPASS auto 08-27 — ticked via UI; the whole §1–§5 matrix then flagged correctly
15.5plius user unticksback to 0; new qualifying shipments stay 0PASS auto 08-27 (siunt 24478914 stays 0 after untick)
15.6new client via kl_add, non-plius creatorcreated MANUAL (0)
15.7new client via kl_add, plius creator, box tickedcreated AUTO (1)
15.8kl_viewread-only “4H AUTO” row renders in the all-regions price table (between “COD keitimo mokestis” and “Siuntos duomenų įvedimas rankiniu būdu”), kl_edit_plius viewers only; non-plius viewers — and clients without a price list — see none. Moved 2026-08-28 (PR #634; supersedes the “visible to all” wording)PASS live on gouat 2026-08-28 post-merge (client 3464: row once, ruled position, two-line taip/ne hint)
15.9save an unrelated client fieldkl_4rp_auto unchanged

16. Pricing — the one live money change (CONFIG_2X4RP_LOW_LIMIT 80 → 50)

#caseexpectedresult
16.1pre-existing siunt_4rp=1, LT pack 60 kgnow prices at 2× — it priced single before the merge
16.2LT pack 45 kg, flaggedsingle
16.3LV pack 55 kg, flaggedsingle — LV doubles above 60, not 50
16.4LV pack 65 kg2×
16.5EE pack 65 kg2×
16.6print_courier_load_list2× shown at the country-correct threshold
16.7print_courier_load_out2same
16.8inc.siuntos.nurodymai indicator2× cue at the country-correct threshold
16.9parcel label direction“2x4 hands” at the country-correct threshold (helper DirectionProvider)
16.10tariff sanity on a default price listbills 50 € / 100 €. Expected — VDT-3415 has not run. Record the amount, do not raise a defect

17. Idempotency and regression

#caseexpectedresult
17.1run the cron twice over the same daysecond run flags 0 additional rows, no duplicate log rows
17.2pre-existing siunt_4rp=1 outside the new criteriapreserved — no retro-clearing of historical flags
17.3historical shipmentsno mass recalculation
17.4shipment registration with no 4H involvedunchanged end-to-endPASS smoke CRUD TC7–TC10
17.5XLS import of a non-4H fileimports exactly as before
17.6go-import of a non-4H shipmentunchanged responsePASS API suite 36/36
17.7terminal reports without the filtersame rows and totals as before the mergepages render (31 report checks green); totals not compared
17.8routing map for a non-4H routeunchanged
17.9error log across the whole roundno new PHP warnings/notices from 4H code paths
17.10client card save, unrelated clientno error

18. Deliberately out of scope — do not raise defects

#itemwhy
18.14H bills 50 €/100 € on default price listsVDT-3415 tariff seeding not run on any environment
18.2only 4 clients on AUTOby design — kl_4rp_auto defaults to 0
18.3non-Venipak lockers not excludedreceiver-name match only, Phase 1 scope
18.4veniship shows no 4H behaviourexcluded from this window
18.5venicourier / vpcourier-api / vpdriver-apicourier team, not in this release
18.6bands duplicated in three repos + vpdriver-apiVDT-3396 deferred
18.7go-import tests/ present in the web rootknown deploy-hygiene item; they cannot run on uat
18.8auto_weighed missing from s4rp_sourcethe re-weigh-origin change is not in this release

Coverage matrix — nine tickets, all at Waiting for Q/A testing

ticketscopesections
VDT-3203pakas cron + bands1, 2, 3, 4, 5, 6.8, 16, 17.1, 17.2
VDT-3384client AUTO/MANUALP2, P3, 5.1, 15
VDT-3395provenance + re-weighP4, 9, 10, 11
VDT-3204siunta order/import paths1, 2, 4, 5, 6.1–6.6, 6.9, 7, 8.5, 8.6
VDT-3202go-import validation2, 5, 6.7, 6.9
VDT-3403explicit decline8.1–8.4
VDT-3407client-facing UIP6, 12
VDT-3408reports & filters13, 14.5, 17.7
VDT-3410route & stop visibility14

Test data needed: one AUTO client (3464), one MANUAL client, LT/LV/EE/PL sender and receiver addresses on posti_service1='1' postcodes, a pallet-flagged pack, receivers named VENIPAK LOCKER and VENIPAK PICKUP, one pre-existing siunt_4rp=1 shipment with a 60 kg LT pack (for 16.1 and 17.2), and a Baltic-domestic price list with kain_4rp still at 50.00.

Historical — dev evidence (2026-08-05 · re-validated 2026-08-12)

Everything below predates the uat cut and was captured against godev.venipak.lt / venipak_dev. Kept as provenance for how the rules were proven; it is not UAT evidence.

0. 2026-08-12 re-validation — the full automated matrix, post-merge dev

Everything below ran against the merged dev branches (pakas 5572933 · siunta 0c0d90c9 · go-import 1ec026a) and the live venipak_dev database, after the dev-sync merges, the INT(8) DDL alignment and the pipeline auto-deploys.

SuiteScopeResult
pakas PHPUnitunit + integration incl. PPSchedule, FourHandsReweigh, routing payload contracts136 / 136
siunta PHPUnitunit + integration, 4H bands/notice logic91 / 91
go-import PHPUnitimport validation, declared-capture, auto-4H guard70 / 70
go-import API (veni-tests, Jest)Baltic-domestic contract vs godev36 / 36 (+8 FI/MH describe.skip — out of scope by ruling)
siunta Playwright (smoke + functional)47 UI tests incl. the 5-case 4H notice/badge spec45 ✓ + PUDO-UI-1 env-fail (MH picker :8004 down — VDT-3250, constant) + its dependent skip
pakas Playwright (smoke + functional)back-office page coverage107 / 107 — run against godev with the siunta admin login (owner-directed; the two ss1 apps share tbl_user — .env.local's PAKAS_ADMIN_* keys are present but empty). First attempts failed for two reasons worth recording: the empty keys silently fall back to dummy creds, and godev itself was unreachable for ~1 h mid-window.

UI evidence — captured by the authenticated Playwright run

30 kg without 4H — black no-4H badge and the Skaičiuoti notice
30 kg, 4H not ordered. Black no 4H badge on the pack row; after "Skaičiuoti" the notice tells the client 4H must be ordered.

Click the image to view full size

30 kg with 4H ticked — red 4H badge, price shown, notice suppressed
30 kg, 4H ticked. Red 4H badge, the notice is suppressed and the estimate renders — the exact path that regression-tests the 0.9.2 pricing chain.

Click the image to view full size

25.99 kg — no badge
25.99 kg. Below the inclusive LT floor — no badge.

Click the image to view full size

26.00 kg — badge appears
26.00 kg. Exactly on the floor — the badge appears (Q2 inclusive-floor ruling pinned in the UI).

Click the image to view full size

pakas report_all — 4H radio filter set to 4H-only
pakas report_all (godev). The VDT-3408 4H filter — visos / 4H / be 4H radio set, here filtered to 4H-ordered shipments.

Click the image to view full size

pakas routing map with stop bubbles
pakas routing map. The VDT-3410 stop-bubble view (green = 4H ordered · red = heavy-but-unordered) rendering live dev data.

Click the image to view full size

Not captured: the 12-month status report carrying the "Neužsakytos 4 rankos" sort — the page exceeds even a 5-minute render budget on both godev and the local instance — the demo DB holds 61k "in-terminal" packs that never advance status, and the report runs a correlated subquery per row (a pre-existing dataset/report characteristic, unrelated to 4H); its live render was verified in the 2026-08-06 pass.

Two false alarms run down during this pass (documented so nobody re-chases them): (1) go-import API "credential failures" — TEST_ENV=dev loads .env.dev, which carries no import creds; the suite's real environment is TEST_ENV=local. (2) a 4H price-estimate timeout — a local-lab-only vendor inconsistency (pre-rename helper Price.php vs a 0.9.2-synced FourHandsWeightBands); server vendors are composer-resolved and consistent, dev was never affected.

0b. The complete 4H gating matrix — every UI gate, captured (2026-08-12)

Every rule that decides whether a client can order 4H (or whether the system flags it), driven through the real siunta form on the merged dev code by an authenticated Playwright session. Badges: black no 4H = pack weight-qualifies but the service is not ordered; red 4H = ordered.

Gate / ruleCase drivenObserved
LT band floor (inclusive 26 kg)25.99 kg vs 26.00 kgno badge → badge
LT hard ceiling (75 kg)80 kg packno badge — 4H impossible above ceiling
2×4H tier (LT >50 kg)55 kg + 4H ticked + Skaičiuotired 4H badge · doubled price rendered (27.45 €)
LV band floor (inclusive 31 kg)30 kg vs 31 kg, LV receiver, enabled postcodeno badge → badge
Postcode allowlist (posti_service1)LV receiver on a 4H-disabled postcode (1053)4H checkbox disabled
Country gate (Baltic only)eligible 40 kg, receiver switched LT → PLcheckbox disabled + badge removed
OOH receiver (pickup/locker)receiver named "VENIPAK PICKUP …", 30 kgbadges suppressed
Late-window gatedelivery time 18–22 selected4H checkbox disabled
Pallet exclusionper-pack row, pallet type selectedbadge suppressed on that pack
Notice on Skaičiuoti30 kg, 4H not orderednotice shown; suppressed once 4H ticked
80 kg — above ceiling, no badge
Hard ceiling. 80 kg LT — no badge, no 4H offered.

Click the image to view full size

55 kg with 4H — doubled price
2×4H tier. 55 kg with 4H ticked — red badge and the doubled estimate (27.45 €).

Click the image to view full size

LV 30 kg — below floor
LV floor, below. 30 kg to Riga — no badge (LV floor is 31).

Click the image to view full size

LV 31 kg — badge appears
LV floor, on it. 31.00 kg — the badge appears.

Click the image to view full size

disabled postcode — checkbox disabled
Postcode allowlist. LV postcode 1053 has posti_service1=0 — the 4H checkbox greys out.

Click the image to view full size

PL receiver — 4H disabled
Country gate. Switching the receiver to PL kills the badge and disables 4H.

Click the image to view full size

pickup receiver — badges suppressed
OOH gate. Receiver "VENIPAK PICKUP Vilnius" — 4H badges suppressed (hand-over at the vehicle rule).

Click the image to view full size

late window — checkbox disabled
Late-window gate. Delivery 18–22 selected — the 4H checkbox greys out.

Click the image to view full size

pallet pack — badge suppressed
Pallet exclusion. The same 30 kg pack loses its badge the moment a pallet type is selected on its row.

Click the image to view full size

payer billing report
pakas payer billing report (read-only run over dev data, payer 14 / Apr 2025 — the freshest picked-up 4H data the demo DB holds).

Click the image to view full size

Not UI-capturable on this account/dataset: the AUTO-client badge (badge pre-set to red "4H" for kl_4rp_auto payers — the test login is deliberately MANUAL; the cron/client-card halves of that flow are evidenced in sections 1–2 below) and the creation-time strip in go-import (API-level, covered by the XML matrix in section 4 and the 36/36 Baltic contract suite).

1. The nightly cron — the authoritative auto-4H writer

The real pack_4rp.php from the dev branch, executed against the dev database. Test shipments were created, their flags cleared, and the payer switched to AUTO — the cutover scenario Sales will actually perform.

RunConditionResultVerdict
1Payer AUTO, 5 shipments, flags cleared30 kg → 1 · 55 kg → 1 · 20 kg → 0 · 80 kg → 0band + ceiling honoured
2Immediate re-run, no changesidentical — no rows alteredidempotent
3Payer switched back to MANUAL, flags clearednothing flaggedfails closed on the client switch

Also learned: the cron only considers shipments whose siunt_priemimo_data falls in the last two days. Freshly created shipments carry 0000-00-00 until pickup is registered, so they are invisible to it — creation-time application in siunta/go-import and the cron cover different moments, and both are needed.

2. PAKAS client card — the Sales switch

The switch is gated behind the kl_edit_plius right (a commercial field, per Product). Enabled and disabled through the real form, reloading each time to prove persistence — not written directly to the database.

Client card — 4H AUTO unchecked (MANUAL)
Default state — MANUAL. The client card renders the 4H AUTO switch unchecked. This is the default for every client; only the four seeded legacy payers are AUTO on dev.

Click the image to view full size

Client card — 4H AUTO checked and saved
Enabled by Sales — AUTO. Ticked and saved through the form, then reloaded: the switch persists and the database reads kl_4rp_auto = 1.

Click the image to view full size

The switch was returned to MANUAL through the same form afterwards; dev is back to exactly 4 AUTO clients.

3. siunta UI — creation-time application

CasePayerWeightExpectedStored
Default clientMANUAL30 kgno 4H0 ✓
In bandAUTO30 kg4H applied1 ✓
Below LT floor 26AUTO20 kgno 4H0 ✓
2×4H tier (>50)AUTO55 kg4H applied1 ✓
Above LT ceiling 75AUTO80 kgno 4H0 ✓

Same shipment, only the client switch differs

MANUAL payer 30 kg — unchecked
MANUAL payer, 30 kg. Eligible by weight and postcode, but the client is not opted in → not flagged.

Click the image to view full size

AUTO payer 30 kg — checked
AUTO payer, 30 kg. Identical shipment; only kl_4rp_auto=1 differs → 4H applied automatically.

Click the image to view full size

20 kg — unchecked
20 kg, AUTO. Below the 26 kg floor → not flagged.

Click the image to view full size

55 kg — checked
55 kg, AUTO. In band, above the 50 kg doubling threshold → flagged (2×4H tier).

Click the image to view full size

80 kg — unchecked
80 kg, AUTO. Above the 75 kg ceiling → not flagged.

Click the image to view full size

4. XML / API import route — full scenario matrix

Each scenario posts real XML to /import/send_auth_basic.php on dev and the stored flag is read back from the database. Expand any row for the exact request and response.

KeyScenarioExpectedActualVerdict
auto-30AUTO payer · 30 kg · four_hands not sentauto-applied → siunt_4rp = 1siunt_4rp = 1as specified
auto-20AUTO payer · 20 kg · four_hands not sentnot applied → 0siunt_4rp = 0as specified
auto-55AUTO payer · 55 kg · four_hands not sentauto-applied → 1siunt_4rp = 1as specified
auto-80AUTO payer · 80 kg · four_hands not sentnot applied → 0siunt_4rp = 0as specified
explicit-1Explicit four_hands=1 · 10 kghonoured → 1siunt_4rp = 1as specified
explicit-0Explicit four_hands=0 · 30 kgdeclined → 0siunt_4rp = 1deviates
bad-postcodeExplicit four_hands=1 → 4H-disabled postcodesilently stripped → 0, import still succeedssiunt_4rp = 0as specified
lv-35AUTO payer · LV destination · 35 kgauto-applied → 1import rejectedblocked
lv-25AUTO payer · LV destination · 25 kgnot applied → 0import rejectedblocked
ooh-nameAUTO payer · 30 kg · receiver named VENIPAK PICKUPexcluded by the cron → 0siunt_4rp = 1deviates

Request & response, scenario by scenario

auto-30 — AUTO payer · 30 kg · four_hands not sent as specified

Client is opted in and the weight is inside the LT band 26–75 kg, so the system decides.

Expected: auto-applied → siunt_4rp = 1 · Actual: siunt_4rp = 1 · pack V20579E2546731

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808300">
<shipment>

<consignee>
<name>4H XML auto-30</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546731</pack_no>
<weight>30</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546731</text></answer>
auto-20 — AUTO payer · 20 kg · four_hands not sent as specified

Below the LT floor of 26 kg.

Expected: not applied → 0 · Actual: siunt_4rp = 0 · pack V20579E2546732

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808301">
<shipment>

<consignee>
<name>4H XML auto-20</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546732</pack_no>
<weight>20</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546732</text></answer>
auto-55 — AUTO payer · 55 kg · four_hands not sent as specified

Inside the band and above the 50 kg doubling threshold (2×4H tier).

Expected: auto-applied → 1 · Actual: siunt_4rp = 1 · pack V20579E2546733

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808302">
<shipment>

<consignee>
<name>4H XML auto-55</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546733</pack_no>
<weight>55</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546733</text></answer>
auto-80 — AUTO payer · 80 kg · four_hands not sent as specified

Above the LT ceiling of 75 kg — too heavy for the service.

Expected: not applied → 0 · Actual: siunt_4rp = 0 · pack V20579E2546734

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808303">
<shipment>

<consignee>
<name>4H XML auto-80</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546734</pack_no>
<weight>80</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546734</text></answer>
explicit-1 — Explicit four_hands=1 · 10 kg as specified

Client declares 4H on a light parcel. A declared request is always honoured, regardless of weight.

Expected: honoured → 1 · Actual: siunt_4rp = 1 · pack V20579E2546735

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808304">
<shipment>

<consignee>
<name>4H XML explicit-1</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<attribute>
<four_hands>1</four_hands>
</attribute>
<pack>
<pack_no>V20579E2546735</pack_no>
<weight>10</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546735</text></answer>
explicit-0 — Explicit four_hands=0 · 30 kg deviates

Client explicitly declines on an otherwise eligible parcel — the client decision must win over the auto rule.

Expected: declined → 0 · Actual: siunt_4rp = 1 · pack V20579E2546736

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808305">
<shipment>

<consignee>
<name>4H XML explicit-0</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<attribute>
<four_hands>0</four_hands>
</attribute>
<pack>
<pack_no>V20579E2546736</pack_no>
<weight>30</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546736</text></answer>
bad-postcode — Explicit four_hands=1 → 4H-disabled postcode as specified

Destination postcode has posti_service1 = 0, so the service cannot be performed there.

Expected: silently stripped → 0, import still succeeds · Actual: siunt_4rp = 0 · pack V20579E2546737

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808306">
<shipment>

<consignee>
<name>4H XML bad-postcode</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>99999</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<attribute>
<four_hands>1</four_hands>
</attribute>
<pack>
<pack_no>V20579E2546737</pack_no>
<weight>30</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546737</text></answer>
lv-35 — AUTO payer · LV destination · 35 kg blocked

LV band is 31–90 kg, so 35 kg qualifies where the LT rule would also pass. Confirms the per-country floor is applied, not a single global one.

Expected: auto-applied → 1 · Actual: import rejected · pack V20579E2546738

Rejected: code 24 — Consignee POST_CODE has to be in digits and exact legth -> 01981.

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808307">
<shipment>

<consignee>
<name>4H XML lv-35</name>

<country>LV</country>
<city>Riga</city>
<address>Gedimino pr. 1</address>
<post_code>01981</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546738</pack_no>
<weight>35</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?><answer type="error"><error shipment="0" pack="" code="24"><text>Consignee POST_CODE has to be in digits and exact legth -> 01981.</text></error>
</answer>
lv-25 — AUTO payer · LV destination · 25 kg blocked

Below the LV floor of 31 kg — and also below LT 26, so it must not qualify under either.

Expected: not applied → 0 · Actual: import rejected · pack V20579E2546739

Rejected: code 24 — Consignee POST_CODE has to be in digits and exact legth -> 01981.

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808308">
<shipment>

<consignee>
<name>4H XML lv-25</name>

<country>LV</country>
<city>Riga</city>
<address>Gedimino pr. 1</address>
<post_code>01981</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546739</pack_no>
<weight>25</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?><answer type="error"><error shipment="0" pack="" code="24"><text>Consignee POST_CODE has to be in digits and exact legth -> 01981.</text></error>
</answer>
ooh-name — AUTO payer · 30 kg · receiver named VENIPAK PICKUP deviates

Out-of-home delivery: a parcel handed to a pickup point is never carried by two couriers, so it must be excluded.

Expected: excluded by the cron → 0 · Actual: siunt_4rp = 1 · pack V20579E2546740

Request XML → POST /send_auth_basic.php

<description type="1">
<manifest title="20579260808309">
<shipment>

<consignee>
<name>VENIPAK PICKUP Vilnius</name>

<country>LT</country>
<city>Vilnius</city>
<address>Gedimino pr. 1</address>
<post_code>01103</post_code>

<contact_tel>+37061234567</contact_tel>

</consignee>

<pack>
<pack_no>V20579E2546740</pack_no>
<weight>30</weight>




</pack>
</shipment>
</manifest>
</description>

Response HTTP 200

<?xml version="1.0" encoding="UTF-8"?>
  <answer type="ok">
    <text>V20579E2546740</text></answer>

5. Defects found

A. An explicit four_hands=0 cannot be expressed through the API

A client on AUTO who explicitly sends <four_hands>0</four_hands> on an eligible parcel still gets the service applied and billed. Verified on dev: scenario explicit-0, 30 kg, returned siunt_4rp = 1.

Cause: the auto-apply guard is !empty($shipmentData['attribute']['four_hands']), and in PHP empty("0") is true. The validator also defaults an absent field to '0', so “not sent” and “explicitly declined” are indistinguishable by the time the guard runs. siunta handles the same situation correctly because it tests isset() on the posted field instead, which separates blank from an explicit zero.

Impact: billing-relevant, but limited to opt-in AUTO clients who actively send a zero.

FIXED — 2026-08-05, go-import PR #57 (VDT-3403, open to dev, 4 reviewers assigned). Presence is now captured at parse time (four_hands_declared, before the coercion) and the auto-apply is guarded on declaration, not value — siunta's isset() approach. Empty tags (<four_hands/>) and non-scalars count as absent, so integrations that always emit the tag keep auto-apply. Proven end-to-end through the real /import/send_auth_basic.php route: pre-fix, scenario explicit-0 stored siunt_4rp = 1 (shipment 32820245); on the fixed code the identical request stores 0 (shipment 32820247), while absent-tag and explicit-1 controls are unchanged. 70 phpunit tests green (regression pinned — reverting the guard fails the new tests, and one pin runs without DB credentials); veni-guard 42 guards / 0 blocking. Pickup/locker (error 136), pallets and the Baltic-domestic-only gates are untouched.

B. Out-of-home exclusion is not applied at import time

A 30 kg parcel addressed to a receiver named VENIPAK PICKUP Vilnius was flagged for 4H at import (siunt_4rp = 1). The cron excludes exactly this pattern by receiver name; the import path does not replicate that check.

Corrected analysis (2026-08-05, ticketed as VDT-3404): both paths turn out to be name heuristics — there is no structured pickup-point field in the XML import contract at all. The import detects OOH with a comma-anchored match (isPickup() = "venipak pickup,", the canonical generated form; likewise isLocker()), while the cron matches the substring anywhere (%VENIPAK PICKUP%). A canonical pickup order is excluded at import (and an explicit 4H on it errors with 136); only non-canonical free-text names like VENIPAK PICKUP Vilnius (no comma) slip through. Blocked on P11: Evelina confirmed the business rule (no OOH shipment may ever get 4H/2×4H/HF) but explicitly delegated the detection mechanism decision to PO / sys arch — no ruling exists yet, so no code is written. Options on the ticket: align import to the cron's looser match, tighten the cron to canonical forms, or introduce a structured field.

C. LV test scenarios rejected — downgraded on investigation

Both LV scenarios were rejected before any 4H logic ran, with error 24 — Consignee POST_CODE has to be in digits and exact legth. The validator requires LV postcodes to be 4 digits, and the table appeared to hold only 5-digit codes.

Downgraded (2026-08-05, ticketed as VDT-3405): tbl_post_info.posti_kodas is MEDIUMINT(5) UNSIGNED ZEROFILL — the "786 five-digit LV rows" are 4-digit values zero-padded for display only. Real LV consignee postcodes in tbl_siuntos are 4-digit at massive scale (e.g. 1067 ×344 832) and pass the validator, which matches both the published import contract ("LV – 4 digits") and the official LV-NNNN format. The test scenarios failed because they sent the padded form 01981; the harness will be corrected to 4-digit codes. LV 4H is therefore NOT blocked on the API route for canonical input. Residual question on the ticket: whether prod error-24 logs show real clients sending LV--prefixed or zero-padded forms — if so, the fix is input normalisation at the validator boundary, never a change to the 4-digit rule (six call sites depend on it).

Evidence captured against https://godev.venipak.lt · dev database venipak_dev · 2026-08-05. All test data and the client switch were restored afterwards; dev holds exactly the 4 seeded AUTO clients.