2026-09-08

  • SLARAFIPI-84 ROUND 2 — the biggest finding is about our own record: the “final reply” this vault said was SENT was never posted. Re-fetched the thread: 4 comments, the last is Bihari Péter’s 2026-09-04 refutation, ticket State = Blocked — the customer had been waiting 4 days while SLARAFIPI-84 carried a callout reading “This is the text that was sent” above 90 verbatim Hungarian lines. Corrected in place; the block is now labelled an undelivered draft. Round 2 then re-derived all 19 claims at ref raiffeisen-1.9.11.100 = 2352f5117f from a blob-hash-verified git archive (worktree vuer_oss-rel100 is an ancestor of the tag by 6 commits → pin check exit 2), across four lenses (STATIC / ADVERSARIAL / CUSTOMER_DATA / DEPLOYMENT) and all 8 attachments (the .tgz and .xlsx fetched by hand after extract skipped them skipped-type, exit 0 — second occurrence). Regression check: 5 of our 9 posted 2026-08-31 claims regressed (P2 and P5 outright REFUTED, P4/P6/P7 PARTIAL) ⇒ the reply must open with one concession block. New facts: the debug flags raiffeisen.debug.cv and .liveness are true at the tag (config/docker.json:13-15) — nothing we need is gated off; the three recovery sources (selfService:attachment, selfService:cvTask:log, selfService:v2:config:state) are NOT in ENCRYPTED_ACTIVITIES (activity.js:152-163) ⇒ key deletion cannot make them unreadable, retiring the crypto-shred worry; “Auto delete customers” selects only room-less customers (CustomCustomerDeleteService.js:25-31) and deletes no rows; archive / flow-clear / delete-rooms / room-bulk-delete are not registered in their UAT vuer_cron.log (a runtime observation, not a repo not-finding); DebugLivenessTask is v1-only (instantiated only in the v1 init hook, self-service-v2.js:1208,:1269) so v2 sessions log nothing; springCloudConfigServer is configured in NEITHER docker.json NOR dev.json at the tag ⇒ the “second override path” caveat is retracted for this partner and config/local.json is the only in-repo mechanism; their effective config is docker.json + a host local.json (proved by a Sales Funnel cron that no repo config enables); NODE_ENV was set (the csv failure itself proves it — unset would have loaded dev.json and csv would have worked); and the delivery path is UNVERIFIABLE from the repo (no Dockerfile in vuer_oss; image built in vuer_docker/vuer_build) ⇒ “Ehhez nem kell release” must not be repeated. The decisive customer-checkable proof: the delivered xlsx’s Face comparison ID column runs 9559 → 10365 with ZERO gaps (807 ids, 807 rows), and 11651’s two comparisons (13:01:47 / 13:02:36) would fall between id 9559 (room 11646, 09:41:29) and 9560 (room 11652, 13:04:19) ⇒ not filtered — never created. Room 11651 precision fixes: window 13:00:34.680–13:02:36.286 (createdAtPrecise), sharpness 37/33 live in cvTask:log … messages.details.sharpness, 148702 failed face detection too, and the comparison ran on only 2 of 5 attempts. Fix branch fix/SLARAFIPI-84-facecomparison-export-rejected (worktree vuer_oss-SLARAFIPI-84, off the tag): 34/34 tests, eslint clean, UNCOMMITTED, three review findings being applied. Round-2 draft reply written but UNPOSTED — awaiting the user’s decision. Quarantined from the thread: Q1 the _isSameFace missing-TARGET fail-open (:338-367, score stays 0 ⇒ 0 <= perfect ⇒ portrait accepted uncompared — STATIC’s “fails closed” refutation quoted the missing-SOURCE branch :322-324 and does not overturn it), Q2 the unguarded liveness-v2 writer, Q3 test.selfService.recognition.submitEnabled, Q5 the release-state risk. → Round 2 — 2026-09-08
  • verification-failure-modes — four new traps, all of which exit 0. (1) A note that says “sent” is not evidence of posting — fetch the thread and count the comments; label vault drafts UNPOSTED in the heading, not just the prose. (2) A lens can refute the wrong branch: STATIC declared _isSameFace “fails CLOSED” quoting handler :322-324 (the missing-source branch, which does) while the quarantined fail-open is the missing-target branch :338-367; ADVERSARIAL declared the config threshold “never reaches the comparison” by reading migrateConfigState as “only a change detector” and overlooking the Setting-row write at SelfServiceCheckerService.js:1360-1364re-read the cited lines before accepting a refutation of a refutation. (3) Agent notifications truncate silently: 4 of 6 reports arrived cut mid-sentence with no marker ⇒ every agent must write its full report to a file and report only the path. (4) extract skips attachments with exit 0 (skipped-type on .tgz and .xlsx — the server log and the 807-row export, i.e. the two decisive files).
  • face-comparison-distance-thresholds SCOPED — classifier vs flow. The perfect/probable/different_face ladder is the export classifier’s semantics. The myra self-service flow does not use it: const success = faceComparisonResult === CHECK_SUCCESS (handler :366-367 @ raiffeisen-1.9.11.100) ⇒ for the flow, perfect (0.55) IS the accept/reject boundary and the 0.55–0.6 probable band can never be populated by it (max distance 0.5394541 over 807 rows, zero rows in [0.55,0.6)). The note’s §4 “0.55 trap” section is true of the classifier and was the Mode 3 failure that increased our confidence in the wrong answer to Raiffeisen — both it and the TL;DR row are now scoped rather than removed.
  • raiffeisen-1.9.11.100 CORRECTED — the release IS tagged. raiffeisen-1.9.11.100 is an annotated tag, object eaeacd0799 → commit 2352f5117f, tagged 2026-08-18 12:36 +0200; the release branch chore/FKITDEV-9156-raiffeisen-release-1.9.11.100 sits at the same commit. The 2026-08-11 “NOT tagged” warning is superseded, and the recorded branch head 350d3e626b is now 6 commits behind (see facekom-worktree-vs-tag-trap). Release-state risk re-confirmed and still open: customization/bin/raiffeisen-facecomparison-export.js exists only on that lineage — absent from origin/customization/raiffeisen (fa983a0eba) and from devel (ls-remote + ls-tree, 2026-09-08) ⇒ the next cut from customization/raiffeisen silently loses the delivered export script.

2026-09-07

  • FKITDEV-9252 LIVE FAULT INJECTION RUN — the fix’s core promise is VERIFIED, and one of my own review findings is REFUTED. 11 scenarios, real activedirectory2/ldapjs stack, live glauth behind a purpose-built BER-parsing TCP proxy. THE HEADLINE PASSES: with servers: [always-resetting proxy, real glauth], server 1 took 5 resets + 4 retry warnings then fail('ldap_unavailable'), the chain moved to server 2, which completed search + user bind and authenticated the user (id 4242) — previously the chain aborted and server 2 was never tried. The new success log line also fires with the right URL: "Active directory (%s) authenticated user (%s)", "ldap://127.0.0.1:60692", 4242. Also passing: baseline login succeeds; wrong password yields fail("Authentication failed for operator") and never ldap_unavailable (InvalidCredentialsError goes straight to this.fail, the classifier is not involved); closed port ⇒ ECONNREFUSED, no retry. REFUTED — my earlier “the retry depends on WHICH PHASE the reset lands in” (search → ECONNRESET → retries, bind → ConnectionError 80 → no retry) is WRONG and must not be repeated. The determinant is HOW the connection dies, and it behaves identically in both phases: RST (abortive) ⇒ Error, code: 'ECONNRESET' (string), 'read ECONNRESET'retries 4× then failover; FIN (graceful) ⇒ ConnectionError, code: 80 (number), '<id>__ldap://… closed'NO retry, immediate failover; black hole/hangTimeoutError, code: 80 (number), 'request timeout (client interrupt)' ⇒ no retry; closed portError, ECONNREFUSED ⇒ no retry. MECHANISM, OBSERVED not inferred (by attaching a listener to the ActiveDirectory instance): ldapjs emits BOTH the raw socket error and the ConnectionError from client.js:1083; activedirectory2’s client.on('error') handler fires FIRST with the raw socket error and its callbackInvoked once-guard swallows the ConnectionError arriving afterwards ⇒ on an RST the raw error wins the race, and on a clean FIN there is no socket error at all so only ConnectionError appears. THE FINDING THAT REPLACES IT — this is the one worth telling Varga: the 4× retry only ever fires for RST. A graceful FIN — idle-timeout close, F5/HAProxy drain, a domain controller restarting cleanly, arguably the more common real-world event — takes the no-retry path and burns the whole server. If retry is meant to absorb single-connection blips, ConnectionError (code 80) is the case that most deserves it and precisely the one excluded. NOT a defect against what the PR claims — a policy question worth a deliberate decision. SECONDARY: AD_CONNECTION_ERROR_NAMES is load-bearingConnectionError and TimeoutError both carry a NUMERIC code: 80, so AD_CONNECTION_ERROR_CODES can never match them; the classification is correct as written and every branch is reachable with a real stack; the retry budget is per strategy invocation and each attempt reopens both connections, so a deterministic RST costs 5 full round trips (~1 s of 250 ms sleeps) per server before failover. HONEST LIMITS: ECONNABORTED and EPIPE were never reached by any injection — no claim is made about them; glauth returns [] for getGroupMembershipForUser, so useMemberOfProperty: false cannot produce a successful login on this fixture and ALL runs used useMemberOfProperty: true; the chain driver was a re-implementation of passport’s chain semantics (fail→next, error→abort, success→done), not passport’s actual middleware. REUSABLE GOTCHAS: (a) passport-activedirectory’s main is the rollup build index.js, NOT src/strategy.js — the two differ (index.js normalises array attributes into {user: [...]}), always read index.js; (b) an LDAP fault-injection fixture now EXISTS where the vault previously said none did anywhere — proxy /Users/levander/coding/facekom/vuer_oss-FKITDEV-9252/scratch-9252/ldap-fault-proxy.js (BER-parsing TCP proxy; triggers accept, acceptHang, bind, search, bindResponse, finBind, finSearch, hangBind, hangSearch, selectable by connection and op ordinal; RST via socket.resetAndDestroy()), driver test/tests/unit/zz-ad-live-failover.test.js, output scratch-9252/full-run-output.txtALL UNTRACKED in a scratch worktree, so it is LOST if that worktree is removed; worth preserving somewhere tracked (first real tier-2 asset for facekom-test-tiers); (c) phase mapping observed on the wire — one login opens TWO TCP connections: conn#1 = technical bind + searchRequest, conn#2 = technical bind AGAIN (because createClient(null, null, this) inherits bindDN/bindCredentials) then the real user bind. — FKITDEV-9252, authentication, facekom-test-tiers
  • FKITDEV-9252 test round done — no regressions, three review findings, and the decisive test still unrun. (Earlier entry, kept for the trail. Superseded the same day by the live fault-injection entry above: the decisive test HAS since been run, and it REFUTED finding 1.) The ticket is a review request, not a bug: Varga Vencel had already written the fix and asked for a test round before merge — vuer_oss PR #8143, fix/FKITDEV-9252-generali-ldap-hotfixdevel, functional commit 5e24c3667d, approved by chrismakaay + marcuscosinus, verified NOT merged as of 2026-09-07; a first attempt origin/fix/FKITDEV-9252-ldap-auth-server-fix (b9dc560d2b) was abandoned with no PR — do not review the wrong branch. Defect: “Something broke into 400 pieces!” on OSS admin login, 47 failed vs 28 successful over 9 days; the network resets a share of LDAPS connections, one login opens several (user search, bind, and with useMemberOfProperty: false the group-membership query), and passport-activedirectory reports transport errors via this.error(), which passport sends straight to the error handler and which aborts the strategy chain ⇒ the configured second AD server was never tried. TEST ROUND (Node v24.18.0 = CI’s pinned NODE_VERSION: 24; two worktrees, each with its OWN yarn install --frozen-lockfile): web-server-auth.test.js 37/37 on the PR vs 21/21 on the devel baseline ⇒ +16 tests all green; full yarn test:unit 3 suites / 4 tests failing on the PR and an IDENTICAL 3 suites / 4 tests failing on devel ⇒ NO REGRESSIONS; yarn lint exit 0 on both. The 4 survivors are the usual ones — converter.test.js (ffmpeg mergeFiles), vuer-cv-service.test.js padDetection ×2 (hardcoded /workspace/ container path), self-service-v2.test.js photoCandidate. RUNNER GOTCHA worth carrying: npx jest -c jest.config-unit.js is NOT this repo’s runner — it omits --experimental-vm-modules and invents three bogus SyntaxError: Unexpected token 'export' failures from the ESM-only stack-trace package (logger/helpers, logger/syslog-client, logger/papertrail); always validate with yarn test:unit, and distrust any review figure that did not come from it. THREE REVIEW FINDINGS (mine, not in the PR, none blocking): (1) ⚠️ REFUTED LATER THE SAME DAY BY LIVE FAULT INJECTION — see the entry above; the phase-based version below is WRONG and must not be repeated. “retries 4× on the same server” is only half true — a reset during user search arrives as a raw ECONNRESET (activedirectory2/lib/components/search.js:65-68 hands the ldapjs error straight to the callback) so the retry fires, but a reset during bind comes back as a ConnectionError with the NUMERIC code 80 (ldapjs/lib/client/client.js:1083) which matches AD_CONNECTION_ERROR_NAMES but not AD_RETRYABLE_ERROR_CODES ⇒ immediate failover, no retry. The real determinant is how the connection dies (RST vs graceful FIN), not which phase. What does survive from this finding: the unit tests structurally cannot catch any of it — they set authenticate = jest.fn(), so the real strategy never runs and no test ever sees a real ldapjs error object. (2) _setupLocalRouting’s rewritten message-selection block has ZERO coverage although it decides the user-visible message AND whether the user.auth.wrong_password audit event fires, and it sits on the shared login path for every partner including non-AD ones. (3) Config-schema gapservers[*].ldap.connectTimeout/.timeout are documented in developer-hu.md but absent from docs/config/schemas/activeDirectory.schema.json; not a validation blocker (additionalProperties unset ⇒ permitted) but it breaks the project rule that new config fields get a schema entry. Minor: x || DEFAULT silently overrides an explicit 0 (ldapjs’s “no deadline”) and the config object is mutated in place. FOUR THINGS VERIFIED SOUND (the ways this shape of fix usually breaks): overriding this.error/fail/success inside authenticate is per-request, not shared state, because passport 0.7.0 does Object.create(prototype) per attempt (lib/middleware/authenticate.js:195); info.slice(0, adStrategyCount) indexing holds — AD strategies are pushed first (WebServerAuth.js:93) and AD/SAML/local are mutually exclusive (else if); info is always an array (passport returns a bare challenge only when !multi, and multi is true because strategyNames is an array); and as a bonus the rewrite fixes a latent TypeErrorpassport-activedirectory/index.js:107 calls this.fail() with no challenge and the old loop did item.message on undefined. DELIVERY: PR targets devel, Generali runs customization/generali-atvilagitas ⇒ it reaches them only via a devel update (FKITDEV-9194); no partner-side change needed because Generali’s customization/ui/pages/login/login.trans.js override is an intentional no-op, so the new ldap_unavailable string surfaces as-is. STILL OPEN — the live fault-injection round has NOT been run — SUPERSEDED: it was run the same day, see the entry above. The plan recorded here (the glauth image under OrbStack behind a TCP proxy that severs connections mid-login) is what got built; “no LDAP test fixture exists anywhere in the vault” is no longer true — the fixture now exists, though untracked. SIDE FINDING, corrects a standing claim: the long-unsourced “79 never-run customization tests” figure is now sourcedfind customization -path "*/test/tests/unit/*" -name "*.test.js"79 — and devel commit b704916a01 (fkqa-356) adds an explicit testMatch for customization/test/tests/unit/**, which is why devel runs 426 suites vs the PR branch’s 347. ⇒ jest.config-unit.js matches only test/tests/unit/** so customization tests never run” is now true only for branches predating b704916a01; customization-branch-ci-pipeline-inheritance §2 corrected accordingly. — FKITDEV-9252, authentication, customization-branch-ci-pipeline-inheritance, FKITDEV-9194
  • SLARAFIPI-84 re-corrected: our own post-mortem was wrong about WHY we were wrong. The note had blamed the stale worktree (HEAD 350d3e626b, an ancestor of tag raiffeisen-1.9.11.100 by 6 commits) for the two answers Bihari Péter refuted. It was not the cause. Read at both refs with subprocess.run(["/usr/bin/git","-C",repo,"show",…]): raiffeisen.customerPortrait.threshold = 0.55 at BOTH, the perfect: threshold override in customization/listeners/self-service-v2.js is identical at both, server/service/SelfServiceCheckerService.js (the 0.5/0.6 defaults + the <= perfect ladder) is byte-identical and not in the diff at all, and the face_compare writer only moved by 19 lines; the entire config/docker.json diff is maxRetryCount: 4, documentRecognitionVersion 2→3 and two liveness labels. ⇒ staleness produced wrong LINE NUMBERS, not wrong FACTS (it did mislead three agents, so the trap callout stays — rescoped to citation accuracy). The actual causes: (1) CUSTOMIZATION LAYERING — we read SelfServiceCheckerService.js:36-38 (perfect: 0.5, match: null, probable: 0.6) where the claim is TRUE in isolation, and never found the overlay at customization/listeners/self-service-v2.js:114-126 because the claim was framed around probable and nothing writes probable — the hook changes a different rung, silently changing the ladder’s answer; (2) TABLE vs VALUE — we searched for writers of the faceComparisons table, correctly found only the gated one, then generalised “no row is written” into “the value is not stored”, when it is in tasks.data.candidates[].recognitionDetails and in activities. Shared shape, and the transferable lesson: both times we verified the claim where we expected the answer to be, and both times the refuting evidence was ALREADY IN OUR POSSESSION (the overlay was in the same repo we were reading; the 0.7396 was in an attachment sent with the original ticket). Added a claim-validation table classifying every reply claim as CODE FACT @ tag / DATA FACT / DEPLOYMENT ASSUMPTION / INFERENCE — all VERIFIED, except that the retention claim is a NOT-FINDING (Activity.destroy, cascade deletes, crypto-shredding all searched, all empty) which is the same fallacy as Error 2, compounded by config.js:103 springCloudConfigServer being able to override any key at boot ⇒ features.archive=false at the tag proves nothing about their runtime, so the reply now promises June coverage only after confirming archival against their environment. Also corrected: an earlier draft called config/local.json the only override mechanism — springCloudConfigServer is a second path, so the reply says “the practical override point”. The final Hungarian reply is now stored verbatim in the note (previous draft removed): the 0.55 concession explains the base-vs-overlay mechanism instead of apologising, every figure is attributed to his own attachment (807 rows’ Threshold perfect, room 11651’s selfService:v2:config:state, the 0.5394541 max, the 11 rows in [0.50,0.55)) so he can check rather than trust, the four storage locations are listed for self-verification, room 11651’s five attempts are a table with attachment ids, and the retention promise is scoped to “no deletion path found + archival off in the release config + will confirm in your environment”. — SLARAFIPI-84
  • THE JANUS MEMORY LEAK IS NOW MEASURED ON REAL CALLS — and the measurement CORRECTS the RCA: BOTH clean and abandoned calls leak. Isolated full stack on fk-dev (postgres + rabbitmq + janus + vuer_oss + vuer_css, own bridge network, own DB, own TLS proxy; compose project vuerleak2 at /workspace/_leak2/, oss 20443 / css 20444 / janus wss 18990 + admin 17990), driving real browser calls with real media (verified: two <video> per side, 640×480, advancing currentTime = decoded remote frames), janus RSS + Admin API census after every cycle, 10 cycles per arm. ABANDONED arm (customer tab killed mid-call): sessions_delta 10, rooms_delta 10, rss_delta_kb 10064~794–999 kB per call, monotonic, reproduced independently (rss_delta_kb 9992 ⇒ 999.2 kB/cycle); each abandoned call permanently costs 1 session + 1 handle + 1 populated videoroom. CLEAN arm (operator ends via [data-action="leave"][data-dialog-name="leave-dialog"] [data-action="confirm"]): sessions_delta 0 — sessions and handles are reclaimed — but rooms_delta 10, rss_delta_kb 6872~453 kB per properly ended call, because the videoroom is never destroyed. ⇒ the old hypothesis (“abandoned calls leak, clean calls are fine”) was only HALF RIGHT, and the inferred ~0.5–1.5 MB per stranded session is SUPERSEDED by a measured ~0.8–1.0 MB/call. In the clean arm part of the RSS may be allocator retention — quote the room count, not the kilobytes. Permanence verified well after the runs: 9 sessions still alive, 10 videorooms (9 still with participants), 10 DB rooms stuck at status='incall'. TWO NEW SIDE-DEFECTS: (1) an abandoned call’s Room row stays incall forever (handleVideoChatLeave only writes an activity row; only videochat:close closes a room; CloseExpiredSelfServiceRoomsCronJob is self-service only) ⇒ videochat:createRoom then refuses with operator_in_open_roomafter ONE abandoned call the operator cannot take further calls until someone closes it manually — an availability bug, not just a memory bug; (2) role gatevideoChat.receiveCall is granted only to operator in config/roles.json, but WebServerAuth.js:934 sets req.session.role = req.user.getMainRole() and getMainRole() (server/db/model/user.js:187) returns the FIRST acl.roleList entry the user has ⇒ admin for multi-role users ⇒ waitinglist.script.js:113 never calls receiveAvailable(true).can-receive-call never added ⇒ WaitingList.styl:16 keeps .customer-item-actions at display:none (fix: POST /api/role-switch with document.body.dataset.csrftoken, as default.layout.js:48 does). CRON QUESTION ANSWERED (was an open gap): customization/cron/AutoCloseRoomsCronJob.js */5 * * * *queueClient.roomCron.autoClose (cron.js:139) → queue-room-cronqueue_server/RoomCron (server.js:509) → RoomService.autoClose (RoomService.js:447) → videochat.close()roomTransport.destroy()closeJanus()janus.destroy(); the chain WORKS and IS a real mitigation for the abandoned path because transports leave TransportPool.sessions only via destroySession()/rpcDestroy() (nothing removes them on socket death) so the cron can still find them — BUT (a) double-gated on roomAutoCloseHours which has NO DEFAULT (“Nincs alapértelmezett érték”) ⇒ unset = no-op, (b) it structurally cannot clean the VuerCVListenerSession path (SelfServiceTransportSession.terminate() has ZERO refs to vuerCVListenerSession), (c) it is createdAt-based not last-activity ⇒ cannot be tuned aggressively without killing live calls. Artifacts in /Users/levander/coding/facekom/out/janus-memory/ (leak-harness.js, janus-probe.js, cron-verify.sh, leakproof.js, heapdig.js, verify-claims.js, rss.sh, janus-leak.heapsnapshot, arm-clean.json, arm-abandoned.json, arm-abandoned2.json, FKITDEV-janus-leak-ticket.md); test code pushed on chore/FKITDEV-9239-e2e-janus-memleak (vuer_oss + vuer_docker). The vuerleak2 stack is still up holding the leak state as evidence — census it before anyone tears it down.janus-memory-leak-rca, FKITDEV-9239
  • Seven environment traps that make browser automation of vuer look “almost working” — all silent. Biggest: Content-Security-Policy: upgrade-insecure-requests + Secure cookies mean these apps CANNOT be driven over plain HTTP — the browser rewrites every subresource to https, hits the non-TLS nginx, every stylesheet/script fails ERR_SSL_PROTOCOL_ERROR, and you get a bare skeleton whose form is never wired; curl ignores CSP so curl-over-http always looks fine ⇒ curl is not a valid smoke test for anything browser-driven. Also: WebServerAuth.js:821 builds the post-login redirect from config, not the request (https://${config.get('hosts.oss')}${redirectTo}) ⇒ a non-standard port must be in hosts, not just the Host header; server-side gate GET /api/pre-check answers unknown for HeadlessChrome, not_compatible for Chrome/120, compatible for Chrome/141 ⇒ Playwright needs full chromium (channel: 'chromium', not the headless shell) plus a realistic UA; operator and customer need separate browser contexts (cookies are not port-scoped ⇒ one context leaks the operator session onto the customer origin); the submit handler attaches only after /api/pre-check resolves, so clicking early falls through to a native GET form submit (URL becomes ?_csrf=…&lastName=…, page just reloads); [data-action="take-call"] lives inside a <template> so a 0-length querySelectorAll means no customer row rendered, not “button hidden”; and firstName is letters-only (^[a-zA-Z…]{2,25}$). — vuer-browser-e2e-real-call-gotchas
  • SLARAFIPI-84 closed out — and BOTH of our first-reply claims were wrong; the export’s “missing rows” are a STRUCTURAL DEFECT, not a script bug. Raiffeisen (Bihari Péter) tested the FKITDEV-8827 face-comparison export and reported (1a) no above-threshold differences, (1b) no liveness comparisons, (2) -c/csv throws, (3) wants 644 instead of 600. Root cause: the myra customer-portrait comparison is computed in TWO places and only the second persists — the handler’s _isSameFace computes the cosine score itself and never writes faceComparisons, while the only writer (FlowService.submitTaskPhotohandleTaskRecognitionOptions) sits behind a server-side gate: a mismatch sets recognitionValid=falseactions.submitEnabled=actions.recognitionValidSelfServiceV2Service.photoFinalize throws 'Submit was not enabled for this photo candidate!'. ⇒ the export can only ever contain ACCEPTED comparisons; every different_face case — exactly what ASSRAFIPI-119 asked for — is structurally absent, and the observed ceiling (807 rows, max 0.5395, zero ≥ 0.55, 11 in [0.50,0.55), 395 of 1202 room-ids absent) follows from it. No bypass exists (the ungated screenshot-save RPC needs task.data.attachmentIds, never set on the portrait candidate path; test.selfService.recognition.submitEnabled is inert — no test key at the tag). REFUTED #1: 0.55 IS the boundaryraiffeisen.customerPortrait.threshold=0.55 applies to perfect and the flow accepts only <= perfect, so the 0.55–0.6 probable band can never appear; our “the boundary is 0.6” was wrong. REFUTED #2: room 11651 was NOT a recognition failure — his own room export shows 5 candidates in 2 minutes, 4 dead on sharpness (37 and 33 vs 40), #2 on geometry, and 5 RAN, scoring 0.7396 and 0.6507 with FACE_MISSMATCH:true (both selfie↔eMRTD chip, attachment 148700 md5-identical to api/emrtd-photo/11651/8631/face), ending no-more-photo-candidate-allowed; numeric scores prove descriptors on both sides. The rejected score IS recoverable: it lives in Activity selfService:attachment, in Flow.tasks[].data.candidates[].recognitionDetails.face_compare (most reliable — the activity path has a createActivityLog final-state drop + unawaited-vs-fail() race), and in FlowActivity; only the CVTask:failed copy is raiffeisen.debug.cv-gated. Field is score, not distance (zero occurrences of "distance"), and nothing prunes Activity/FlowActivity (features.archive false; AttachmentArchiveService only nulls attachment bytes) ⇒ June data is still there. Liveness reframed: the myra proto at the tag carries BOTH liveness steps (v2 added only 2026-08-17 by 1c05206ccb, absent from proto v12/v14/v15) and picks one via livenessCheckCompatibility only when envData.supportedSteps.length===0 — but neither task has recognitionOptions, so neither v1 nor v2 writes a row; the cheap fix is a proto change, and liveness distance is dropped by mergeRecognitions so full retroactive coverage is impossible. CSV = missing config key: under NODE_ENV=docker dev.json is never read, docker.json’s reporting block has no enabledExportFormats ⇒ fallback ['xlsx']; only config/local.json can override (env vars can’t — getconfig needs an existing $VAR placeholder), and ⚠️ an empty/malformed local.json kills startup (process.exit(2)). NEW, UNDISCLOSED SECURITY FINDING: _isSameFace fails OPENcompareTo.score starts at 0, only raised inside if (recognitionTo?.getFaceCount()), so zero resolved targets → 0 <= perfectCHECK_SUCCESS, silently (no row, and _logCVError only fires on failure); three reachable paths (webSDK session where emrtd is filtered out as [mobileSDK]-only while supportedSteps is client-supplied, null eMRTD data.attachmentId per CRRAFIPI-106, non-success eMRTD recognition). The core path fails SAFE — only the Raiffeisen customization fails open, likely a second population among the 395 absent rooms that recovery will NOT restore. Awaiting András’s call on disclosure. ⚠️ Three verification traps, all silent: the vuer_oss-rel100 worktree HEAD 350d3e626b is an ancestor of tag raiffeisen-1.9.11.100 by 6 commits touching exactly the files the conclusions rest on (always git show <tag>:<path>); git log -1 --format=%ad returned the rebase-preserved author date 2026-05-12 instead of committer date 2026-08-10 (use %cd); and rtk dropped three comment lines out of the extracted handler, shifting all line numbers by 3. — SLARAFIPI-84
  • Corrected the stale face-comparison-persistence-paths reference note — its §3 was the framing that produced the wrong first SLARAFIPI-84 diagnosis, and its customization/ line numbers were all wrong. Provenance failure: the note’s own stated verification basis, git describe = raiffeisen-1.9.11.99-7-g350d3e626b, was the worktree HEAD — an ancestor of tag raiffeisen-1.9.11.100 by 6 commits that touch the myra proto, the myra handler, customization/listeners/self-service-v2.js and config/docker.json, i.e. exactly the files it cites. Re-derived every customization/ citation from the tag with /usr/bin/git: the handler numbers were off by 19 (_isSameFace is :309-380, not :290-361; compareTo init :338-341; getFaceCount() guard :356; getFaceComparisonResult :366; the no-faceEncoding fail-closed branch :322-324; _logCVError called :376, defined :416, gate :418) and the proto numbers by 1-2 (emrtd :81-98, customer-portrait :99-122); server/ numbers were unaffected and re-confirmed. A different offset from a different cause than the rtk 3-line drop — do not assume one constant correction. §3 rewritten: the myra phase-1 proto at the tag (version 16, taskCount 9) carries BOTH liveness steps — v1 at order 6 (:123-133), v2 at order 7 (:134-145, screenshotCategory:'liveness-reference-face') — exactly one surviving per session via onBeforeCreateTaskslivenessCheckCompatibility(envData), which only runs in the envData.supportedSteps.length === 0 branch (otherwise the client’s declared supportedSteps decides); and the operative reason neither branch persists is that NEITHER task declares recognitionOptions at all, so the v2 gate task.options?.recognitionOptions?.compareFaceWith can never open, meaning the fix is a customization PROTO change, not a flow migration and not core-handler work (the note previously claimed feature work). Two former UNVERIFIED rows settled: the NFC question is YES, three reachable paths (webSDK step-filtering where emrtd is [mobileSDK]-only while supportedSteps is client-supplied, null eMRTD data.attachmentId per CRRAFIPI-106, non-success recognition) — and required: true on the emrtd step is a weak mitigation because filtering happens before the flow is built; and perfect = 0.55 IS a repo fact after all (config/docker.json:59-61 at the tag, applied at listeners/self-service-v2.js:124), so the note’s “not in the repo” reading was itself an artefact of the pre-tag working tree. Also corrected: the vuer_cv LivenessTask row now reads as a real mechanism but NOT the reason there is no row (and records that both v1 :1208 and v2 :1281 have an init hook, so it does not distinguish the branches), DebugLivenessTask citations added (:105 createLog, :117 type, :13-14 gate), and all three TOPICS entries reworded so none still reads as a live warning that this note’s advice caused a wrong diagnosis. ⚠️ rtk mangled git show <rev>:<path> again during this pass — it ate the :c and produced raiffeisen-1.9.11.100onfig/docker.json; the python3 subprocess.run([...]) argv bypass worked. — face-comparison-persistence-paths · SLARAFIPI-84

2026-09-04

  • CIB’s FIRST-EVER vuer-release cut cib@1 was made — and it FAILED at the Harbor publish step. Delivery is BLOCKED. Commit ac8aa5cc55 on TechTeamer/vuer-release master (chore: [asscib-166] cib 1.9.11.102 release/1, solo-author, adds projects/cib/release/1/release.json only), tag cib@1, autobuild run 33855979398. COMPONENT_LIST = vuer_oss + vuer_css, both VERSION 1.9.11.102 / TAG cib-1.9.11.102 / BUILD_NUMBER 1; NODE_VERSION 24.15.0, SECURITY_NUMBER 20221206, UID/GID 1000, BUNDLE_IMAGE false, PROJECT_NAME cib-facekom. parse_tag green; build built the images successfully and Harbor login SUCCEEDED, then died at “Project images publish to Registry”: CalledProcessError: Command '['docker','push','harbor.techteamer.com/cib-facekom/vuer_css:1.9.11.102.1-20221206']' returned non-zero exit status 1. Root cause NOT confirmed (no Harbor credentials locally) — hypothesis (record as such): the cib-facekom Harbor project does not exist, or the robot account lacks push rights on it, because login worked, the same runner pushed nusz@18 fine on 2026-09-03, and this is CIB’s first-ever push to that project (.101 was built on legacy vuer_build). NEEDS A HARBOR ADMIN. CORRECTION — image tag anatomy is <VERSION>.<BUILD_NUMBER>-<SECURITY_NUMBER> (1.9.11.102.1-20221206), a dot before the build number and a hyphen only before the security number — NOT the all-hyphen form. TOOLCHAIN TRAPS (.cliversion), all source-verified: the pin is exact equality (release_tool/pkg/util.py:validate_cli_version does Version(current) != Version(required)), currently 1.0.3; the runner’s .github/scripts/download-release-cli.sh selects the asset named release_tool but current-latest 1.1.1 renamed its asset to release-toolbumping .cliversion to 1.1.1 breaks CI with ERROR: Asset 'release_tool' not found; 1.0.3’s own pyproject.toml is invalid TOML (pyyaml/typing_extensions unquoted ⇒ pip install -e . dies with tomllib.TOMLDecodeError at line 16) and it has no [project.scripts] ⇒ invoke as python run.py, not release-tool; 1.1.1’s requirements.txt omits packaging; the two versions emit different release.json key sets (1.0.3 REQUIRED_ENV_VALUES = {"VERSION":"", "BUILD_NUMBER":""} vs 1.1.1 {"VERSION":…, "TAG":…} with a required-flag dict) and read incompatible schemas from the same ~/.release-tool/config.json (1.0.3 flat keys vs 1.1.1 current_context/contexts); commit message changed Release: <t>, version: <N>chore(release): <t>, release version: <N>; repository.create() gained a cfg arg. CORRECTION — COMPONENT_LIST is NOT “a complete manifest of what the customer runs” (measured across all 18 partners’ latest releases): janus has a component dir in 12 partners but ships in only 3 (barion, cofidis, kh); mkb-instant has rabbitmq + turn dirs and ships neither; demo-facekom@6 ships ONLY report-engine; 12 of 18 latest cuts are exactly vuer_oss + vuer_css. BUT release-tool gen builds the delivered docker-compose FROM COMPONENT_LIST, so an omission is a silent delivery gap — the same shape as SLARAFIPI-83’s janus-never-shipped. Decision: cib@2 adds portal_css at 1.4.0.74 (CIB runs a portal); descriptor prepared at projects/cib/release/2/release.json UNCOMMITTED, held for the Harbor fix. vuer-release has essentially NO branch protection — ruleset 12260273 “main-protect”, target ~ALL, one rule: non_fast_forward; direct push to master is the norm and the TechTeamer bracketed-ticket regex does not apply here. The 1.9.11.102 changelog was NEVER writtencustomization/RELEASE.MD still tops out at ## [1.9.11.101] - 2026-05-29 in BOTH repos (GitHub API, today); since the source tags already point at the branch tips, any changelog commit now lands after the tag ⇒ decision: FLAG ONLY, do not touch. Unresolved: how the base release version is selected (Dockerfiles take ARG BASE_COMPONENT_IMAGE_TAG, injected by release-tool, not named in release.json). client-registry’s “CIB = legacy vuer_build” row is now stale/corrected — CIB is modern as of .102. — cib-1.9.11.102 · vuer-release-cli-pinning · component-list-is-not-a-full-manifest · vuer-release-cut-recipe

  • Follow-up the same day — the COMPONENT_LIST counts were re-verified, and CIB’s own PROD compose now grounds the cib@2 decision. Corrected counts (Python over parsed JSON, not a shell pipe — rtk zeroes | wc -l and produced a wrong intermediate figure of 93): 91 projects/*/release/*/release.json files, 90 with a COMPONENT_LIST, 88 excluding the two new cib cuts; component ENTRY counts over those 88 = vuer_oss 84, vuer_css 84, portal_css 8, janus 5, resource-manager 3, report-engine 1 (including the cib cuts: 86/86/9, a clean +1/+1/+1 ⇒ self-consistent). The earlier “85” was an entry count mislabelled as a file count. No contradiction after all, and the finding is STRONGER: the four manifests with no vuer_oss/vuer_css are all single-component bundlesdemo-facekom/release/6['report-engine'] and demo-project/release/{1,2,3}['resource-manager'] — so demo-facekom@6 is not an isolated oddity. NEW: not every release.json even HAS a COMPONENT_LISTprojects/equilor/release/1/release.json uses an older, entirely lowercase legacy schema (default_args, docker_registry, git_remote, project, project_args, services, timestamp); equilor has exactly one release, so it is easy to miss, and any script iterating all manifests must guard for it or KeyError (hit for real). DECISIVE new evidence for cib@2, read from the local vuer_build clone: partner/cib/docker-compose.yml — what CIB PROD actually pulls — has exactly three image: lines, vuer_css, vuer_oss, portal_css, all harbor.techteamer.com/${PROJECT_NAME}/…, with portal_css on its own ${PORTAL_VERSION}.${PORTAL_BUILD_NUMBER} vars ⇒ portal_css is REQUIRED in the bundle (cib@1 without it cannot deploy a complete stack) and janus is CORRECTLY excluded (no janus image line; it rides as JANUS_VERSION_COMMIT on the vuer_oss entry) — this grounds the decision on CIB’s own production compose rather than unicredit-srb precedent. Generalisable check: count the image: lines in vuer_build/partner/<client>/docker-compose.yml. Also confirmed by direct grep: vuer_build contains NO docker push and NO docker login anywhere ⇒ the legacy toolchain cannot publish to Harbor at all, so nothing in the repo establishes the CI robot has ever had write access to cib-facekom — recorded alongside the hypothesis. And the hypothesis stays a hypothesis: Harbor’s API returns [] unauthenticated for EVERY project, including ones that certainly exist, so an empty response is not evidence of non-existence. — component-list-is-not-a-full-manifest · cib-1.9.11.102

2026-09-03

  • CIB release cib-1.9.11.102 TAGGED — and the cut carried a finding bigger than the release: both PRs were SQUASH-merged, so devel is no longer an ancestor of customization/cib. All live-verified via the GitHub API on 2026-09-03. Merged: vuer_oss #8126 at 13:10:49Z, vuer_css #3152 at 12:55:36Z; portal_css #712 left OPEN on purpose — components are vuer_oss + vuer_css only per ASSCIB-166, which finally answers the standing “does portal_css ship in .102?” question with no. Tags: annotated, tagger Andras Lederer, message the bare 1.9.11.102\nvuer_oss 12a8a9e328221829ae6d383fd5e23eda9cf81a38, vuer_css ca60fac34ac95b661336587b455924ab55e52def; created through the GitHub API rather than a local push to sidestep the vuer_css narrowed-fetch-refspec stale-ref trap (narrowed-fetch-refspec-stale-devel-merge). Convention matches cib-1.9.11.101 exactly (annotated, 1.9.11.101\n, Szabó Márton, 2026-05-29) — but cib-1.9.11.100 was LIGHTWEIGHT, so the convention changed at .101 and .100 is not the pattern. The squash: each result has exactly ONE parent (12a8a9e38abcc4c733; ca60fac3b043527c72, itself the .101 css target), so the 334 commits / ~11 months of devel drift collapsed into one commit per repo and git has no record they were merged — the next devel→CIB update will re-present all of it as new changes with heavy conflicts. Content is safe: squash trees are byte-identical to the reviewed PR heads (df853239b1… oss, 12a8a9e3 == head 86f7dab01d; 38079f89c7… css, ca60fac3 == head 83e4adbd2c) — tagged bits are exactly what was reviewed and tested, only history shape differs. NOT verified: whether earlier CIB releases used real merge commits — flagged as an open question, not asserted. Generalised with detection commands (git cat-file -p <sha> | grep -c '^parent ', git merge-base --is-ancestor) and three mitigations into squash-merge-erases-partner-devel-ancestry. Second finding: CIB’s /reports-advanced has no chart and no on-screen table — source-verified in vuer_oss/customization/ui/pages/reports-advanced/ (template renders only the filter form; handleDownload() always sends download:'true' and its only success path is window.location = /download/${res}), so the xlsx export is the page’s ONLY output. ASSCIB-166’s “a riport számai, a diagram adatai, valamint a XLSX export” names three places the FKITDEV-9230 async-filter bug surfaced in the computed data, all landing in the workbook — NOT three UI surfaces → FKITDEV-9230 test evidence can only ever be the spreadsheet, never an app screenshot (cib-reports-advanced-is-export-only). Still open after tagging: Docker image builds (./build.sh -b cib-1.9.11.102 -i vuer_oss from vuer_build main) and a TjK with blank tester/verifier name fields plus a date mismatch (document 2026.08.13 vs evidence 2026.08.17). — cib-1.9.11.102 · FKITDEV-9197 · squash-merge-erases-partner-devel-ancestry · cib-reports-advanced-is-export-only

2026-09-02

  • FKITDEV-9305 / ASSMKB-113 root-caused — the customer bundled TWO UNRELATED problems into one “rabbitmq hiba” question, and the answer to “does the queue error cause the compat-test failure?” is NO. Verified from source at the exact deployed tag mkb-instant-1.9.11.67 (commit 92e235bfd9, 2026-07-14, tagged bencelaszlo, ASSMKB-104) — MKB UAT was two tags behind on 2026-08-28 (.68 = 07-29, .69 = 08-14). Problem 1 (root-caused): no queue 'integration-log' in vhost '/' every 5 s = runDiagnosticTick() in vuer_oss/server/diagnostic.js calling ch.checkQueue(key) — amqplib’s passive queue.declare, which on a missing queue raises a channel-level not_found and kills the channel (hence a new Erlang channel pid per tick on one connection); cadence diagnostic.rpcRoundTripIntervalMs = 5000 (config/docker.json:736, config/dev.json:985) started unconditionally at server.js:606; the failure is swallowed (catch → push {0,0}continue) so vuer_oss logs nothing and only the broker sees it. The queue is missing because integration-log is an RPC client (server.js:442-444, gated on integrationLog.enabledverified true and committed in the partner branch at config/docker.json:808-809, not a runtime override) and @techteamer/mq v7.2.0 RPCClient.initialize() asserts only its reply queue (mq/src/RPCClient.ts:174), never its target — unlike QueueClient (mq/src/QueueClient.ts:34) — so the queue exists only while integrationLog.js runs. ROOT CAUSE: MKB’s partner supervisor overlay ships 7 [program:] blocks; vuer_integration_log and vuer_oss_storage are absent (canonical has 9 — lines 50 and 155). The mechanism is TWO SEQUENCED IMAGE BUILDS, not last-write-wins layering: the base image links the canonical conf into conf.d/ and is tagged+pushed to harbor first (vuer-release: install/configure-app.sh:16-19 from base/components/vuer_oss/Dockerfile:106; legacy vuer_build: base/vuer_oss/Dockerfile:241), then the partner image builds FROM that sealed base and COPYs its own file to the same path (projects/mkb-instant/components/vuer_oss/Dockerfile:1-2COPY :18; legacy partner/mkb-instant/vuer_oss/Dockerfile:6COPY :31, plus sed -i "/user=/d" at :25) — the COPY structurally cannot lose; legacy partner selection comes from the git tag (build.sh:365 strips mkb-instant-1.9.11.67mkb-instant, sources settings.cfg). CORRECTION recorded in the note — an earlier pass claimed MKB still builds from legacy vuer_build; that is WRONG, caused by a local vuer-release checkout stale at 2026-05-14. MKB has migrated: projects/mkb-instant/ is on origin/master (verified at fb78901, 2026-09-01) carrying the same stale 116-line / 7-program file, added by 4bf534e (2026-07-08, “migrate mkb-instant project (#36)”) and released as 939a189 (2026-07-09) — five days before the mkb-instant-1.9.11.67 tag, so the running image was built through vuer-release; the legacy file has been frozen since c78e02a (2023-01-13). The spam needs all three legs and therefore starts at the LATEST of them — the mkb-instant-1.9.11.54 tag of 2025-07-01, the first shipped tag carrying "integrationLog": { "enabled": true } (.53 of 2025-06-11 has no integrationLog key at all; still true at .55, .60 and the deployed .67); the checkQueue loop itself landed 2023-01-19 (76a06e1970) and the overlay froze 2023-01-13 (c78e02a) ⇒ ~14 months of continuous spam — chronic, not new, independent evidence it cannot explain a recently-appearing compat-test failure; the ordering also rules out “queue existed and was lost” (the program was already absent before the feature was switched on, so the durable queue was never created). (Two earlier drafts got this wrong — “~3.5 years”, then “~2 y 10 m”. git log -S is unreliable on customization/mkb-instant: its history is non-linear with periodic devel merges, so the key’s presence oscillates across parent paths — a73e993630 (2024-01-26) has no integrationLog at all. Read the value at release tags instead.) Positive confirmation from the customer’s own log: the overlay’s stdout_events_enabled=true wiring feeds a supervisor_stdout eventlistener, which is what emits the INFO nginx | … prefixes — the 887-line export contains zero INFO vuer_integration_log | lines. Fleet scope: 32 of 35 partner overlays omit it; only granit, mvm, vkta keep it — and since the vuer_oss_storage omission IS a documented convention while MVM keeps integration-log and drops storage, this reads as drift, not design. DO NOT DELETE THE OVERLAY — the mbh fix does not transfer. projects/mbh/components/vuer_oss/ has no supervisor conf (deleted in #35 / d7ebb37) so mbh inherits canonical, but MKB’s overlay is not “canonical minus 2 blocks”: every functional directive across the 7 shared blocks is identical (command, directory, environment, process_name, numprocs, umask, priority, autostart, autorestart, startsecs, exitcodes, stopsignal, stopwaitsecs), and the only deltas are dropped user=techteamer and file-logging (redirect_stderr + stdout_logfile=/var/log/<prog>.log + rotation) replaced by stdout_events_enabled=true / stderr_events_enabled=true / stdout_logfile=NONE / stderr_logfile=NONEthe container-stdout wiring MKB’s OpenShift log collection depends on. Correct minimal fix: add one [program:vuer_integration_log] block to vuer-releaseprojects/mkb-instant/components/vuer_oss/supervisor_vuer_oss_docker.conf in the overlay’s own logging style (canonical block, minus user=, minus rotation/logfile keys, plus the four events/NONE keys); only integration-log — vuer_oss_storage’s omission is the deliberate convention. Deployment note: integrationLog.js calls createEncryption() on startup, so the worker’s first successful start creates an integration-log encryption key — a one-time state change the release/test plan must expect. Consequence A — a latent defect, but GATED OFF in MKB’s committed config (do not cite as confirmed impact): DeviceIntegrityCheckService.checkDeviceIntegrity() returns {isValid:true} early unless integrityCheck.apple.enable/play.enable is truthy, and an integrityCheck block exists only in config/dev.json:367 — absent from docker.json and default.json, and config.get() returns its defaultValue for missing keys rather than throwing (config.js:139-151), so checkIntegrityToken() is never reached in the docker deployment unless MKB’s runtime local.json enables it. The defect itself: GooglePlayIntegrityCheckService.js (+ Apple twin) call rpcClient.integrationLog.createLog() inside try AND finally, with DeviceIntegrityCheckService.js:38,40 passing save=true hardcoded; each call waits rpcTimeoutMs = 10000 (config/docker.json:688) → ~10 s stall → catch return false (Google/Apple never contacted) → finally stalls another ~10 s → the throw from finally overrides the return false, so the caller gets a rejection after ~20 s. Mobile SDK app-integrity verification is effectively broken while the worker is missing. Latent smell alongside it: checkIntegrityToken’s setTimeout(() => { throw … }) throws from a timer callback the surrounding try cannot catch (→ uncaughtException), and its 10000 ms default races the identical 10000 ms RPC timeout. Consequence B — monitoring blind spot (core bug, every affected partner): the loop keeps using the dead channel, so every queue iterated after the missing one reports {messageCount: 0, consumerCount: 0}; channelNames iterates rpcClients last and integration-log is registered at server.js:442, silently zeroing background-recognition, rpc-esign:external, cronManager, rpc-xml-report, rpc-xlsx-report, rpc-transport-css ⇒ the QUEUE COUNT WARNING overload alert can never fire for them, the admin System Settings queue table is wrong, and any further missing queue stays invisible (only the first ever reaches the broker). Minimal fix ≈ 2 lines: re-fetch the channel inside the inner loop + this.diagnosticChannels.delete(name) in the catch. This also corrects cli-system-check-enhancement, whose 2026-04 freshness caveat said the tick may not have started without an admin on System Settings. Problem 2 (unrelated — TURN, and it is vuer_oss NOT vuer_css): the customer’s stack frame ConnectionCheck.startChecking matches vuer_oss/client/features/system-check/check-steps/connection-check/connection-check.js (throw in startChecking()); the vuer_css twin throws from checkConnection() and is the wrong repo — route is vuer_oss/server/web/routes/compat-test.endpoint.js, registered server/web/routes.js:109. Log evidence for 12:40–12:43 UTC: 384 nginx requests, every one 2xx/3xx/101 — zero errors, zero 5xx (/compat-test 200, 8× /socket.io/ 101 ⇒ socket path healthy, 366× /diagnostics/monitoring 200) and zero mentions of turn/stun/janus/media anywhere; the 111 Connection refused → 127.0.0.1:10081 lines the customer quoted are from 11:58, during their own restart, and that endpoint returns 200 by 12:40. Why it cannot be the queue: the check needs a real relay candidate (srflx is not enough); the ICE list is server-rendered into the page (TurnPasswordService.getPeerConnectionConfig(...) behind that route) with no queue and no RPC; a specifically-TURN error rather than a JSON parse error proves the config arrived and parsed; Janus is architecturally ruled out (browser never talks to Janus); and the RabbitMQ noise predates the failure by ~14 months. THE TRAP that reversed my first draft — vuer_oss has NO working differential diagnosis: in vuer_oss/client/features/webrtc/iceTest.js, AUTH_FAILED = 2 (:44) and NOT_REACHABLE = 3 (:45) are DEAD CONSTANTS — defined and read (isAuthFailed() :74, isUnreachable() :78) but setResultCode() is only ever called with DONE (:136, :153) and CONNECTION_TIMED_OUT (:172), and there is no onicecandidateerror handlercredentials rejected, TURN unreachable and no iceServers configured all collapse into the same message; the working classifier exists only in the vuer_css twin, so the earlier “ask MKB to read the AUTH_FAILED/NOT_REACHABLE classification” advice was wrong and is retracted. Compounding it, this.result.ice is assigned (connection-check.js:66) but never emitted or reported anywhere in vuer_oss (vuer_css emits a 'report' event), and the pass/fail logic if (isTimedOut() || isAuthFailed() || isUnreachable() || !(hasRelay || hasReflex)) passed = false; else if (hasRelay) passed = true leaves srflx-only (STUN works, relay doesn’t) in NEITHER branchpassed stays undefined → falsy → fails silently; TIMEOUT_PERIOD = 60000 (iceTest.js:41). ⇒ diagnosis must happen outside the product: chrome://webrtc-internals on the failing client, a Trickle-ICE test against the same TURN URL+credentials, or coturn’s own server-side logs. Three indistinguishable candidates, all config/network-side: TURN secret mismatch (coturn static-auth-secret must equal webrtc.turn.secret; TurnPasswordService.generateCredentials() = username <unixExpiry>:<name>, password base64(HMAC-SHA1(secret, username)); also clock skew past webrtc.turn.validityInSec), UDP/3478 or TLS/5349 blocked in the bank network / coturn down, and filterByJanusServer() leaving iceServers empty — identical error, no server-side log. Open: which tag UAT actually ran (.67 taken from a UI screenshot), which of the three TURN causes applies, MKB’s undocumented “szokásos” media-failure history, and the broker showing user: 'guest' on 5671 against the vault’s documented client-certificate RabbitMQ auth. No prior art anywhere — no ticket, note or session at ANY partner describes this queue missing; first recorded occurrence. Tooling: rtk again mangled git show | grep into a false “no match” and rewrote git show <tag>:<file> into a tag summary (all git reads went through rtk proxy), and a local vuer-release checkout stale by 3.5 months produced the wrong-pipeline claim corrected above ⇒ verify partner-pipeline facts against origin/master, never a local tree (rtk-mangles-curl-and-pipes, narrowed-fetch-refspec-stale-devel-merge). — FKITDEV-9305-rca
  • THE JANUS MEMORY LEAK IS ROOT-CAUSED, AND IT IS A vuer_oss BUG — NOT AN UPSTREAM JANUS BUG. Four years of tickets (ASSRAFIPI-38 2024 → SLARAFIPI-83 2026, FKITSYS-2994FKITSYS-9871 at Cofidis, DAP-1141/FKITDEV-8570/FKITDEV-8573 at DÁP) were closed on the premise “Janus leaks, it’s third-party, upgrade it.” That premise is wrong. MECHANISM (all verified from code): janus-api/src/Janus.js:407-425 keepAlive() reschedules itself with a setTimeout closure capturing this ⇒ a “leaked” Janus object is immortal AND actively pinging — V8 cannot collect it, its websocket stays open, so janus never times the session out (keepAliveIntervalMs: 30000 vs janus’s default session_timeout 60 s = 2× margin; session_timeout is set in NO FaceKom janus config — checked vuer_docker, vuer_build, vuer-release). MEASURED on fk-dev: janus destroys sessions in UNDER 5 SECONDS when the websocket dies — 40 sessions opened, sockets terminated with no destroy and no keepalive, count went 44 → 4 within 5 sa crash/disconnect leaks NOTHING; the only way to strand a session is a live, pinging JS object. Janus.destroy() itself is CORRECT — idempotent, clears the keepalive on the success, rejection and 5 s-timeout paths; the clean end-of-call flow is correct on both operator and customer side ⇒ the bug is always “destroy was never called”, never “destroy is broken”. LEAK PATHS, RANKED: (1) server/cv/VuerCVListenerSession.js:62 leaks on EVERY invocation, success path included — the class has no destroy()/close() and _janus.destroy() exists nowhere in either repo; owner SelfServiceTransportSession.terminate() (server/transport/session/SelfServiceTransportSession.js:392-404) closes only this.janus, but the listener’s Janus is a second independent session; cost = 1 session + 2 handles + recorder (record: true at :150) + up to 2 PeerConnections. (2) RoomTransportSession leaks on any call not ended via VideoChatService.close() (server/service/VideoChatService.js:201-233) — operator closing the tab emits videochat:leavehandleVideoChatLeave() writes an activity row and notifies CSS but never closes the room or touches the transport; vuer_css terminate() is return Promise.resolve() (a no-op), TransportPool.sessions is a Map with no TTL/sweep, and no base-install cron reclaims videochat rooms (only the AutoCloseRoomsCronJob customization, gated on roomAutoCloseHours). (3) RoomInspector.connect() failure strands a session with ZERO referencesclient.roomInspector = inspector is assigned after the await (server/socket/events/videochat.js:348-357), so the disconnect handler cannot see it; triggered normally by findRoom() throwing “Video room not found” for rooms nobody published into yet. (4) VuerCVSession registers teardown (task.result…finally) at line 87, AFTER _connectJanus() at line 58 — a throw in between strands it; adjacent defect: CVTask (server/cv/CVTask.js:6-28) never arms its timeout because this.timeout is undefined when super() runs, for LivenessTask/LivenessV2Task/ActionTask/DocumentTask/HoloV2Task/SpeechTask/PadTask/MRZTask. (5) concurrent videochat:senderPeer:init orphans HANDLES (not sessions) — VideoRoomPublisherJanusPlugin does not override hangup(), unlike the listener. SECONDARY FaceKom DEFECT — videoroom rooms are NEVER destroyed: janus-api’s videoroom plugins send only join/start/rtp_forward/stop_rtp_forward/edit/list/create/configure/listparticipants — no destroy; vuer_oss sends none either, and RoomTransportSession.closeJanus() ends at janus.destroy() = a SESSION destroy. One janus room per vuer Room DB id (id: this.getRoomId()), record: true. Present since janus-api’s first commit, 2018-01-12 — an 8-year-old design gap, not a regression (which is exactly why no upgrade or bisect ever found it). MEASURED ~6.0 kB retained per abandoned room — too small to dominate (100 MB/day would need ~17–21k rooms/day) — but the compounding bug is not small: findRoom() pulls the ENTIRE room list and linear-scans by description on every publisher connect AND every inspector connect, MEASURED 483 bytes/room, linear across 6 points: 3.0 KB @ 6 rooms → 969 KB / 69 ms @ 2006 rooms, extrapolating to ~9.7 MB per call setup at 20k rooms. Destroying rooms works (2000 destroyed, list back to baseline) but RSS does not return to the OS (glibc arena) ⇒ destroy CAPS growth, does not reclaim. Also MEASURED: 400 signalling-only sessions+handles ≈ 31.7 kB each. UPSTREAM/FORK FACTS: the TechTeamer/janus-gateway fork changes ZERO lines of janus C source*.c, *.h, src/, configure.ac, Makefile.am byte-identical to upstream; it is a pure CI/packaging wrapper (.travis.yml, test/check_janus.sh, npm demo tooling). Commit→version from configure.ac AC_INIT: b8bebd94=0.13.4, 08f25c9b=1.2.4 (actually a pre-release 1.2.4-dev snapshot, upstream master @ bad60d70 2024-08-02, git describe = v1.2.3-11-gbad60d70), cc0fdca8=1.4.1 (exactly upstream v1.4.1), af80f7ef=0.16.1. GOTCHA: the fork ships its OWN tags named v1.2.4/v1.3.0/v1.4.0/v1.4.1 pointing at FORK commits, and git fetch upstream --tags silently refuses to overwrite them (exit 0)any git diff v1.2.4..v1.4.1 in a fresh clone is WRONG; refetch via +refs/tags/*:refs/tags/up/* (same family as narrowed-fetch-refspec-stale-devel-merge). DEBUNK: upstream issue #3408 — cited in ASSRAFIPI-38 since 2024 as the relevant leak — DOES NOT APPLY: closed 2024-10-23, root cause was the Lua plugin, fixed by PR #3409 whose entire diff is g_thread_unref(g_thread_self()) in janus_lua.c and janus_duktape.c, and both plugins are excluded by --disable-all-plugins ⇒ the most-quoted evidence in the whole four-year chain is about code we do not compile. Upgrading 1.2.4-dev → v1.4.1 gains exactly ONE unconditionally-applicable leak fix: 4419baf0 (2024-12-10), janus_recorder_free() never freed recorder->description; four others are conditional and do not apply (SVC, dummy publishers, RTP forwarders, remote publishers). 4fc066ff (videoroom subscriber refcount leak in slow_link) is gated on slowlink_threshold > 0 and slowlink_threshold appears in NO FaceKom config ⇒ default 0 ⇒ disabled (caveat: Raiffeisen ships its own .jcfg via its own Dockerfile layer — confirm on their box). No OPEN upstream leak issues affect videoroom+websockets; 14 upstream commits exist after v1.4.1, none a leak fix. Build flags --enable-post-processing --disable-data-channels --disable-all-plugins --enable-plugin-echotest --enable-plugin-videoroom --disable-all-transports --enable-websocketsthe legacy vuer_build/base/janus/Dockerfile ALSO passes --enable-rest (HTTP transport compiled) while the newer vuer-release base does not; latent build bug in the vuer-release base janus Dockerfile: copies libwebsockets.so.19 but symlinks libwebsockets.solibwebsockets.so.16, which does not exist (dangling; harmless at runtime via SONAME); pinned deps aging — libnice 0.1.17 (2020), libsrtp 2.5.0, libwebsockets 4.3.2. CROSS-PARTNER: it is per-CALL, not per-unit-time — two independent confirmations: fk-dev janus idle 16 days = 20 MB RSS, and DÁP Grafana shows RSS FLAT across the whole weekend then stepping up during business hours. This finally answers the question ASSRAFIPI-38 asked in 2024 and never got answered. Raiffeisen: janus 0.13.4, AWS t3.large, maxmemory 7168 MB, ~126 MB/day (longest clean run 03/05→04/28, 2%→97%), ~8 weeks to exhaustion, mitigation = manual restart only. DÁP/NISZ: janus 1.2.4, Kubernetes, 4 pods, 8 GiB limit, OOMKilled after 13 days, ~0.7 GiB/day/pod; DAP-1141 was closed on “the upgrade process has started”, never verified. Cofidis: still pinned to 0.13.4; 1 GB (2022) → 2.7 GB (2024-06) → 5 GB+ (2024-11); container once “Up 8 months”. UniCredit: build def says 1.4.1 but the running image on 2026-08-26 was janus:1.2.4.1-20220513build definition ≠ deployed reality. DÁP on the NEWER janus (1.2.4) leaks ~5× FASTER than Raiffeisen on the older 0.13.4 — different workloads so not a clean comparison, but the opposite of what “newer is fixed” predicts. No partner has EVER had a post-upgrade memory measurement; “upgrade will fix it” has closed multiple tickets over 4 years and has never once been verified. Fleet build defs: 1.4.1 = cib, generali-atvilagitas, instacash, magnet, microsec, nusz, raiffeisen; 0.16.1 = barion, fundamenta, granit, kh, mbh, mkb-instant, szerencsejatek; 0.13.4 = cofidis alone. RELEASE BLOCKER (actionable): janus is absent from COMPONENT_LIST in ALL TEN Raiffeisen release manifests (vuer-release/projects/raiffeisen/release/1..10/release.json — every one is [vuer_oss, vuer_css]); the JANUS_VERSION_COMMIT field that flips 08f25c9bcc0fdca8 at rel6 (1.9.11.94) is an attribute ON the vuer_oss component (what it is built against), NOT a janus imageno janus image has ever been built or shipped to Raiffeisen; they remain on 0.13.4 — confirmed by Szabó Márton in FKITDEV-9239. Janus must be added to the build for .101 or nothing changes (and even then, the upgrade alone will not stop the growth — the two are separate asks). KEEP SEPARATE: FKITDEV-9193 is a distinct, confirmed Node.js leak in vuer_oss StorageService._getInFlightCache/stream(), likely driving FKITSYS-9902 (UniCredit, OSS alone at 17.6 GB) — do not fold it into the janus story. TOOLING: validated read-only diagnostics at /Users/levander/coding/facekom/out/janus-memory/janus-probe.js (census via the already-enabled Admin API wss://janus:7989, adminSecret janusoverlord, JanusAdmin already in janus-api with listSessions/listHandles/handleInfo), roomleak.js, sessleak.js; run pattern = scp to fk-dev → docker cp into the vuer_oss container → docker exec vuer_oss node /tmp/<script>.js. Decision rule for a prod census: rooms high + sessions low → rooms never destroyed; sessions ≫ concurrent calls → stranded keepalive’d sessions (expected); both low but RSS high → the leak really is inside janus. ⚠️ HONEST CAVEAT: the per-stranded-session cost (~0.5–1.5 MB) is INFERRED, not measured — real ICE/DTLS/SRTP/recorder state could not be allocated from a script (only signalling-only sessions, 31.7 kB, were measured); confirm with the prod census before quoting numbers to the customer. — janus-memory-leak-rca

2026-08-31

  • FKITDEV-8279 dossier de-staled — the sequelize-fork retirement branch is PUSHED (7664b784d0, 11 ahead / 16 behind devel, still NO PR) and has since been validated on Oracle 19c EE, the engine partners actually run. Corrected three stale/wrong claims in the note: status: branch-complete-not-pushed @ b0303af227, and the flatly false “fk-dev is reachable but the tailnet policy refuses SSH for this user”access was obtained as ops@fk-dev.taild4189d.ts.net and used for the 2026-08-09 native x86_64 run with real partner driver pins read off the partner branches (oracledb 5.5.0 thick + Instant Client 23.26.2.0.0 for bb/mkb-instant, 6.10.0 for kh, tedious 14.2.0 for otp/unicredit-srb, mysql2 3.11.3), alongside rounds on PG 16.14 + MySQL 8.4.11 (proving patches 2 and 3 are dialect-agnostic, running on every insert/update/sync()), Oracle 23ai 128-migration replay @ e1603840c5, and Oracle 19c EE 19.3.0.0.0 @ 7664b784d0. 19c replay is numerically identical to 23ai (25+128 migrations, 0 errored, 0 skipped, 62 tables / 204 indexes, row-identical index inventory), ORA-00904 reproduces in both directionspatch 1 is load-bearing on the real engine; patch 3 is inert over a repo-built schema but NOT cosmetic — reversing it over one renamed index makes Model.sync() abort with ORA-01408, i.e. a failed startup for any syncOnStart: true partner. Two myth-busters: Oracle’s 30-char identifier limit does not apply on 19c (19 names >30, max 58, zero ORA-00972), and an engine inversion — 19c emits a bare ORA-00942 while 23ai interpolates the object name, so devel’s original whitelist regex already matches on 19c and commit 7664b784d0 is 21c+ forward-compatibility, not a live-defect repair. Recorded findings A–D with dispositions: (A) latent MSSQL TypeError on raw sequelize.query(sql, {bind:[…]}) (controlled inverse: passes upstream, fails patched; 0 of 21 raw call sites use bind:) → prevented at source via a no-restricted-syntax ESLint ban (47142d9156) instead of touching the fidelity-mandated hunk; (B) oracledb@5.5.0 is broken on Node 24 (util.isDate removed in Node 23) independently of this change, with bb/mkb-instant on ^5.5.0 and engines.node: ">=22.18.0" admitting Node 24 → separate ticket (6.10.0 thick verified 4/4 green); (C) bin/db/migrate-rdbms.js cannot migrate an Oracle partner--url= makes sequelize-cli skip the config and drop quoteIdentifiers:false, sync() at :89-90 repeats it, and the naive db.options merge is a trap (folds createdAtcreatedat on Postgres, tested) → pre-existing, separate ticket; (D) 170 DDL failures silently swallowed by the migration tooling (31/0/139 across 104 of 128 migrations, identical on both engines ⇒ tooling property) → own ticket. Landing shape recorded: refs/heads/devel is under ruleset #1, so this must squash-merge with a fix: [fkitdev-8279] … PR title; bb/kh/otp/unicredit-srb merge clean, only mkb-instant conflicts and must resolve to ^6.37.8 (a wrong resolution fails loudly — 6.37.8 hunks can’t apply to 6.32.2 under --error-on-fail); the org-wide payoff is that the red Audit job skips build on every partner PR and this branch turns it green; patch-package must stay a runtime dependency (yarn install --production prunes devDeps but still runs postinstall). Still gating: no partner USER_INDEXES dump, patch 3 unproven outside a synthetic case, 109 of 128 migrations were no-ops, partner data + customization migrations untested — and Szabó Márton, the recorded lead with a bb Oracle environment, was never actually asked for his run’s effective config (also the likeliest route to that index dump); FKITDEV-1208 names mkb-instant, not bb, as the org’s validation target. Three live-verified repo facts corrected against other notes: vuer_oss DOES have PULL_REQUEST_TEMPLATE.md at the repo ROOT (not .github/), plain LF UTF-8 (### Summary: / TÖLTSD KI / ### References: / …) — not the “CRLF de-facto template with no file” other notes claim; .github/CODEOWNERS exists but only covers client/, customization/ui/, customization/email/ (@TechTeamer/frontend) + CODEOWNERS itself (@tunderdomb), so nothing in this diff has a code owner ⇒ no auto-assigned reviewer; and PR #7710’s author is szollarp (still open, base devel, head FKITDEV-8279, untouched since 2026-08-06). — FKITDEV-8279

2026-08-28

  • Face-comparison persistence mechanism extracted as durable cross-cutting knowledge, correcting a vault half-truth that caused a wrong first diagnosis on SLARAFIPI-84 today. Verified against vuer_oss @ tag raiffeisen-1.9.11.100. The old claim — liveness comparisons “only persist if the proto sets compareFaceWith” — holds only for step.type: 'liveness-check-v2'. Liveness dispatches (server/queue/rpc_server/SelfServiceV2.js:208-219) into three handlers and only handleLivenessCheckV2:2114saveLivenessCheckV2Messages:1349 contains persistence; handleLivenessCheck:1199 and handleLivenessCheckV1:1459 never write a comparison, so compareFaceWith is inert there. Raiffeisen/myra runs v1 ⇒ the “just set compareFaceWith” advice is a no-op and the ask is feature work. Also captured: one writer (FaceRecognitionService.createFaceComparisonModelFaceComparison.create:152), 3 call sites not 4, status is always 'success' so failed comparisons are structurally unrepresentable (every guard failure = no row), 3 mechanisms that compute a match without persisting (CV-internal liveness, myra _isSameFace in-memory, silent guard skips), imageCategory is not a setting but a copy of screenshotCategory (myra sets it to customer-portrait on both sides ⇒ rows mislabelled, reports keyed on it can’t tell the sides apart), and the _isSameFace fail-open (max-reduction from identity 0, but 0 is the best value in a distance metric ⇒ missing data reads as a perfect match, silently). Marked UNVERIFIED: whether a failed/skipped NFC read can reach _isSameFace with no target, and the perfect = 0.55 figure (deployment config raiffeisen.customerPortrait.threshold, not a repo fact; code default 0.5). Corrected in place: face-comparison-different-face-db-query (call-site table, mermaid, the false “status='failed' rows” claim, caveat 1), face-comparison-data-verdict-threshold-model (§3 call-site table), SLARAFIPI-84 (sharpened F3 mechanism, imageCategory citation, 0.55 provenance) — face-comparison-persistence-paths

2026-08-25

  • Documented the durable release-cut git/GitHub mechanics from executing the NÚSZ 1.9.11.48 cut: devel-update PRs land on customization/<partner> by SQUASH merge (not bypass override) — ruleset-compliant PR title + --admin skips only red checks; changelog = direct compliant commit; source tags via API don’t build; vuer-release default branch is master, nusz@N tag fires Harbor. — release-cut-mechanics

2026-08-18

  • FKITDEV-8931 browser-tested — one pass, one bigger finding, and three config values in my earlier entry today were WRONG. PASSES: on mbh-services under default.layout, a ~1.4s drop reconnected with no reload — in-memory marker survived, sessionStorage load counter stayed at 1, console logged socket disconnected then [socket] re-authenticated after reconnect, both snackbars stayed hidden. THE BIGGER FINDING — the fix does not stop the reload for longer outages: a genuine 40s outage (supervisorctl stop vuer_css) hard-reloaded the page 4× against a 502. Cause is pre-existing and untouched by the patch — onConnectionDisconnected() fires 2s after disconnect and starts a 1s-interval countdown ending in window.location.reload(); 8931 only cancels it if connect arrives first. The countdown length is RANDOMIZED per page load: client/ui/regions/snackbar-container/snackbar-container.twig:6hideDelay: 10 + random(50)10–60s (sampled live: 19, 23, 43, 54, 56, 57), effective tolerance ≈12–62s of continuous disconnection, different every load. So for DÁP the fix removes the instant reload-on-return, but a user who lingers in the DÁP app longer than the random window still gets reloaded and the flow still breaks — intermittently, the classic “works for me” profile. Open question raised for vencelvarga: suppress or extend the countdown for SILENT_REAUTH_LABELS pages rather than merely cancelling it on reconnect. CORRECTIONS to my earlier 8931 entry today (live data-socketioSettings beats the dev.json reading): transports is ["websocket","polling"] — polling fallback IS available, not websocket-only; reconnectionAttempts is 20, not 5, so the “after 5 it gives up and the fix never runs” caveat was overstated; and connectionStateRecovery NEVER ENGAGES on this deploymentsocket.recovered was false on every reconnect including the 1.4s one, with a fresh socket id each time ⇒ the 30s maxDisconnectionDuration is NOT the behavioural cliff and must not be used as the test framing; the real boundary is the randomized countdown above. Method (Playwright, socketio.io.engine.close(), marker + sessionStorage counter as the reload detector; long outages via supervisorctl stop) plus one artifact worth not repeating: reconnecting with socket.connect() after disabling reconnection does not fire socket.io’s reconnect event, so the silent re-auth never runs and you end up connected-but-unauthenticated while the snackbar still clears — a test artifact, not a production path, but any manual-reconnect code would hit the same gap. — FKITDEV-8931, fk-dev-partner-branch-deploy-runbook
  • FKITDEV-8931 written up as its own investigation note, and Trap 1 in the fk-dev runbook tightened to the literal commands. 8931 (MKB, vuer_css only — no oss side; owner vencelvarga, approved chrismakaay; YouTrack title “MKB - prodvideobankdap.mbhbank.hu SNAT teszt”): on mobile, backgrounding the browser drops the socket and the old client answered the reconnect with window.location.reload() — which is fatal for DÁP (Digitális Állampolgárság) login, where backgrounding is MANDATORY (you must switch to the DÁP app), so the reload fired on the happy path every time. Fix, 2 files +38/−4: client/features/auth.js gains SILENT_REAUTH_LABELS = ['default.layout'] — matching labels call auth(socketLabel) and log [socket] re-authenticated after reconnect, falling back to reload only on failure; client/ui/regions/snackbar-container/snackbar-container.js captures the 2s disconnect timer as this.disconnectTimeout and adds connection.on('connect')onConnectionRestored() clearing it plus reloadCountdownInterval and hiding both disconnect snackbars. PR #3153 (fix/FKITDEV-8931-websocket-reconnect-fix @ d53612780207) open against devel, approved, 7/7 green, mergeable; fix/FKITDEV-8931-socket-test @ 3f32334ae is customization/mkb-instant + one byte-identical commit (the deploy branch); fix/FKITDEV-8931-websocket-auth-reconnect abandoned. THE load-bearing fact: the fix fires only for socketLabel default.layout (default.layout.ui.js:22) — kiosk.layout (kiosk.layout.ui.js:43) and videochat still hard-reload by design, and mkb-instant is heavily kiosk-based, so a kiosk-page test shows a reload that reads as a failed fix but is out of scope → correct target is https://css-fk-dev.taild4189d.ts.net/mbh-services (“MBH Bank - Szolgáltatások oldal”), which extends default.layout and is the non-kiosk DÁP path. Reconnect timing shapes the test: transports: ["websocket"] (no polling fallback), reconnectionAttempts: 5 (after 5 failures the client gives up and the fix never runs), connectionStateRecovery.maxDisconnectionDuration: 30000 = the behavioural cliff, test both sides of 30s; css pingInterval 2000/pingTimeout 30000, oss pingTimeout 10000. Do NOT cherry-pick the FKITDEV-9199 kebab fix (cda6c80b97, PR #3146) onto this branch — not an ancestor, and the branch is internally consistent under the older convention (twigs emit data-socketToken, auth.js reads it case-insensitively via getAttribute, snackbar reads dataset.sockettoken); adding kebab twigs without the dataset.socketToken readers breaks it — same trap as the superseded fix/FKITDEV-9194-socket-token-attribute-read (FKITDEV-9194). Deployment verified on the bundle served over HTTPS (/js/default/default.layout.js, 623 KB, HTTP 200) containing SILENT_REAUTH_LABELS = ["default.layout"] and onConnectionRestored ×2. Runbook Trap 1 now carries the literal command pairchown -R ops:ops /workspace/vuer_<svc> && chown -R 1000:1000 /workspace/vuer_<svc>/logs, per repo, plus the observed failure ordering (running only the first half put vuer_oss into a restart loop: EACCES … open 'logs/server.log' + Process exited with code 0, pid climbing, supervisorctl status showing RUNNING uptime 0:00:00; the second chown fixed it) and the reference technique ls -ld the untouched sibling repo (/workspace/vuer_css/logs was ubuntu ubuntu = 1000). Checklist tell sharpened: RUNNING is not the signal, uptime is — run supervisorctl status twice and compare the pid. — FKITDEV-8931, fk-dev-partner-branch-deploy-runbook
  • fk-dev runbook round 2 — one correction and five additions, all verified live on the box after the first pass. CORRECTION (cost a restart loop): any claim that repo ownership “moved to uid 1001, the uid-1000 guidance is stale” is WRONG — the app process genuinely runs as uid 1000 (techteamer in-container = ubuntu on host), logs/ must be 1000, the rest of the tree is ops/1001. PROVENANCE TRACED (corrected 2026-08-18): not doc rot, an agent artefact. The two uids coexist — tree 1001:1002 (host ops) AND process/logs/ 1000 (techteamer = host ubuntu) — they never contradicted. A vault-wide search found the stale claim in no note; it was generated by a historian subagent that observed the tree live as 1001:1002 (correct) and over-generalised it into “this contradicts the FKITDEV-9059 note, ownership has since changed”, then carried across an agent hand-off. FKITDEV-9059:78 was accurate the whole time and is vindicated, as is release-pipeline-automation-spec. The runbook [!danger] callout now names the mechanism — an agent promoting a partial live observation into “the docs are stale” — so the reader guards against that, not against the notes. SSH settled: root AND ops both work (root used for the whole deploy); levander/ubuntu/admin/facekom/vuer/dev/techteamer refused; ops has no sudo so root-owned work goes through docker exec -u 0:0. NEW Trap 4 — db.syncOnStart ordering hazard: server/bootstrap/connection/db.js runs migrate → sync → migrate on EVERY boot, so booting with the new partner’s code but the old partner’s db.url silently migrates the wrong database, and supervisor autorestart=true means a crash during the checkout window is enough to trigger it → create the DB and rewrite local.json BEFORE anything restarts. Verified clean after the fact: vuer_oss_cib has 158 migrations, 5 CIB-only, zero mkb-only entries leaked (migration-count comparison is the isolation check on this box). NEW — local.json is inode-bound: it is a single-file bind mount, so sed -i / mv / git checkout -- swap the inode and the container silently keeps reading the OLD file (has burned two prior sessions) → rewrite with cat > / heredoc only. NEW — existing automation /workspace/vuer_docker/bin/vuer.sh: its checkout order (git_status → server_stop → git_checkout → dev_install → server_start → dev_build) is a good ordering reference but do not use verbatim — no explicit fetch, stale hardcoded branch list (offers customization/mkb, not mkb-instant), no db.url handling at all, and it builds AFTER starting so it serves stale assets briefly; vuer.sh db init seeds admin/operator with password = username. The runbook’s recipe was reordered to stop → create DB → rewrite config → checkout → install → build → start → users. NEW verification steps: grep the bundle as served over HTTPS (curl -sk https://css-fk-dev.taild4189d.ts.net/js/default/default.layout.js | grep SILENT_REAUTH_LABELS), assert referenced assets return 200 not just the HTML (a prior session had HTML 200 with every stylesheet 404 because the build wrote nothing yet exited 0 — FKITDEV-9059), and login via curl -sk -o /dev/null -w '%{redirect_url}' -X POST …/login/ = success, /login = failure. NEW two false alarms named so nobody re-chases them: (a) an old mtime on web/branding/layouts is meaningless — the .branding.css files inside are overwritten in place and carry the real build time (all Aug 18 08:57); (b) mkb-instant’s customization/listeners/verify-password-test.js rejects only the literal string incorrectAccordingToPasswordPolicy so it is NOT a login blocker, unlike cofidis’s verifypassword.js which pins a fixed password. FKITDEV-8931 scope (folded into the runbook’s box-state section): the fix fires only for socketLabel default.layoutkiosk.layout and videochat still hard-reload, which is out of scope, not a regression; mkb-instant is heavily kiosk-based so a kiosk page looks like a failure — correct test target is https://css-fk-dev.taild4189d.ts.net/mbh-services (uses default.layout, the non-kiosk DÁP path). — fk-dev-partner-branch-deploy-runbook
  • fk-dev partner-branch deploy runbook written — three ownership/config traps that each cost a real failure, plus the partner-swap steps the existing smoke runbook never covered. Source-verified live on fk-dev while deploying vuer_css fix/FKITDEV-8931-socket-test @3f32334ae + vuer_oss customization/mkb-instant @c7ceaac2da against a fresh vuer_oss_mkb_instant DB (box was previously on cib-9197/vuer_oss_cib, restorable from /workspace/_restore/). Trap 1 — UID mismatch: host ops is uid 1001, in-container techteamer is uid 1000 (= host ubuntu); a blanket chown -R ops:ops /workspace/vuer_oss puts the app into a restart loop with EACCES: permission denied, open 'logs/server.log' (log4js/streamroller) → always follow with chown -R 1000:1000 <repo>/logs. Trap 2 — yarn install as uid 1001 fails with EACCES on pre-existing node_modules paths (unlink '.../csurf/node_modules/cookie/LICENSE') → run it as root inside the container then restore ownership; and piping yarn to tail masks its exit code (shell reported exit 0 while yarn had errored) → redirect to a logfile and echo $?. Trap 3 — stale partner config: config/local.json is bind-mounted read-only from /workspace/vuer_docker/tailscale/config/vuer_<svc>-local.json, one file per service NOT per partner, and it survives branch switches — it still held CIB’s db.url + a 30-entry flow.flows list; but you can’t just delete it because config/dev.json ships hosts as empty strings and janus as wss://localhost:8989 while fk-dev’s janus is ws://localhost:8188 / admin ws://localhost:7188hosts + webrtc.janusServers are mandatory box infra, drop only the partner-specific keys. Also newly recorded: SSH as root works (levander/facekom/vuer/ubuntu/dev/techteamer/admin all refused by tailnet policy) — reconciles the “ops only” claim in fk-dev-deploy-smoke-runbook against the “ops+root” table in dev-build-host; the per-service tailnet names are sidecar containers, not SSH hosts (port 22 refused); box has no GitHub credentialsssh-add --apple-load-keychain + command ssh -A root@fk-dev + GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" (a prior session instead scp’d a git bundle — reflog still shows the removed bundle remote); repos are ops-owned while you’re root → every git command needs -c safe.directory=/workspace/<repo>; host has no node/yarn (containers: node v24.12.0 / yarn 1.22.22); vuer_css assets are gitignored under web/{js,css,branding,polyfills,libs/pdfjs/wasm} and any client-side change is invisible until yarn build (bin/build/build.js, ~10s); Postgres per-partner convention vuer_oss_<partner> (existing: vuer_oss, vuer_oss_cib, vuer_oss_cofidis, vuer_oss_test) with psql -h localhost + PGPASSWORD=dev -U dev (without -h peer auth fails) and db.syncOnStart: true auto-runs the full migration chain on first boot — no manual bin/db/sync; user creation docker exec -u 1000:1000 -w /workspace/vuer_oss -e NODE_ENV=dev vuer_oss node bin/db/create_user <role> <user> <pw> … with roles from config/roles.json, the CLI takes only ONE role so the house convention is update users set rights='["admin","supervisor","operator"]' — the column is rights (a JSON string), there is no role/type column. Verification checklist: supervisorctl status all RUNNING with non-zero uptime (0:00:00 + climbing pid = restart loop), Web server is listening on 1008x + Socket server is listening on 1008x, curl the sidecar → 200 (first hit ~16s while it warms), socket.io polling handshake → 0{"sid":…}, and grep the built bundle for a string unique to the change. Rollback precedent /workspace/_restore/ extended with cib-state-20260818-0852.txt + vuer_{oss,css}-local.json.cib.bak. — fk-dev-partner-branch-deploy-runbook, cross-linked from fk-dev-deploy-smoke-runbook + dev-build-host

2026-08-13

  • Three post-Janus videochat-smoke gotchas appended to the fk-dev runbook — and the NÚSZ 1.9.11.48 smoke went GREEN (first confirmed green video on fk-dev). Discovered after signaling was fixed, these are the gap between “signaling connects” and “a real recorded call completes”. (1) Janus record-dir permission: a live call fails to record with mkdir (/workspace/records/<roomId>/) error: 13 (Permission denied) in /var/log/janus.log — the janus PROCESS runs as non-root (techtea… = techteamer) but /workspace/records was root:root 0755; fix docker exec -u 0:0 janus sh -lc 'mkdir -p /workspace/records && chmod -R 0777 /workspace/records'; dir comes from webrtc.janusConfig.recordDirectory; without it recording (and room-export/conversion evidence) is broken even though the call may connect. (2) “Taking a while to load” = slow ICE gathering, NOT a hang: [WARN] Waiting for candidates-done callback... (slow gathering …) — the call DOES connect (The DTLS handshake has been completed follows), video renders after a few seconds; optional speedup full_trickle = true and/or drop Janus’s own STUN/nat_1_1 in janus.jcfg; TURN (turnserver.facekomtest.net:3478) reachable, DTLS completed → media flows; a raw TCP connect to :3478 returns ECONNRESET which is NORMAL (TURN isn’t plain TCP) — port-open is the signal, not a clean session. (3) Resetting oss operator passwords (dev): seeded accounts admin/operator/supervisor (@vuer.test, isEnabled=true); login is BY USERNAME (WebServerAuth.js User.findOne({where:{username}}), POST /login), plaintext password, no 2FA/webAuthn/totp; the bcrypt worker (workers/bcrypt) is plain bcryptjs with NO pepper/pre-hash so a direct bcrypt.hash(pw,10) verifies; reset via a node script inside vuer_oss using require('bcryptjs') + require('./server/db/sequelize.js'), update users set "password"=<hash>,"passwordExpiry"=<future> where username in ('admin','operator'); gotchas — table uses isEnabled (not isActive) and passwordExpiry (login rejected if < now), a SUCCESS login is 302 → / with a vuersid cookie (failure → back to /login), verify curl -sk -X POST https://oss-fk-dev.taild4189d.ts.net/login --data-urlencode username=admin --data-urlencode password=<pw> expecting 302 → https://…/, and browser autofill of a stale saved password is a common “password broken” false alarm. Smoke result: NÚSZ 1.9.11.48 videochat went GREEN 2026-08-13 — identification flow finished “Sikeres”, both operator and customer video rendered (record-only, not re-verified live) — fk-dev-deploy-smoke-runbook, facekom-build-host-fk-dev
  • Janus / media-server fix appended to the fk-dev runbook (verified live during the NÚSZ 1.9.11.48 videochat smoke). Symptom: browser “media server connection errored”, camera never renders. Root cause: the janus container was supervisord-FATAL since fk-dev’s first boot (2026-06-30) — janus_websockets couldn’t create the Secure WebSocket (wss) vhost (Error creating vhost for Secure Websockets server), and it kept failing even after adding certs /workspace/cert/dev.{crt,key} because the in-image libwebsockets was built without working TLS (janus built with only --enable-websockets). Ports: wss 8989 / ws 8188 (signaling), wss 7989 / ws 7188 (admin). Architecture fact that dissolves the problem: the browser NEVER connects to Janus — signaling is server-to-server (browser → vuer_css Socket.IO(wss) → RabbitMQ → vuer_oss → Janus over PLAIN ws, @techteamer/janus-api isomorphic-ws), and media flows browser↔operator via TURN/coturn (turnserver.facekomtest.net, webrtc.turn.secret), not through the Janus WS ⇒ no browser mixed-content constraint, no need for wss on the oss→Janus hop; plain ws://localhost:8188 is correct/intended for dev. Fix (2 edits + restart): (1) enable ws/disable wss in /usr/local/etc/janus/janus.transport.websockets.jcfg — it’s a BIND MOUNT so edit in-place inside the container (docker exec -u 0:0 janus … sed … > "$f"; a host sed -i swaps the inode and the container keeps reading the old file — wasted a cycle), then supervisorctl start janus, verify Websockets server started (port 8188) in /var/log/janus.log. (2) repoint vuer_oss/config/dev.json key webrtc.janusServers.janus (NOT top-level janusServers — that key doesn’t exist, hence config.get('janusServers')=null): urlws://localhost:8188, adminUrlws://localhost:7188, keep adminSecret: janusoverlord (must match admin_secret in janus.jcfg); vuer_oss is network_mode: host so localhost is correct (janus:8188=ENOTFOUND), then supervisorctl restart vuer_oss. Verify: WS handshake to ws://localhost:8188 subprotocol janus-protocol {janus:"info"} returns server_info version=0.12.4; no new Error connecting to the Janus WebSockets server in /var/log/vuer_oss.log. Remaining dep: real media needs TURN/coturn reachable from the test browser. This box had never had a confirmed green videochat before; seeded operator accounts admin/operator/supervisor @vuer.test (bcrypt-hashed, reset via bcryptjs + direct users-table update) — fk-dev-deploy-smoke-runbook, facekom-build-host-fk-dev
  • General fk-dev deploy + smoke runbook captured (NÚSZ 1.9.11.48 smoke, branch chore/FKITDEV-9217-nusz-devel-update, oss d09274cb30 / css 828846cc0). SSH policy: ops is the ONLY tailnet-permitted user (levander/lederera/facekom/ubuntu/dev/deploy/admin all refused); command ssh mandatory (bare ssh = _kaku_wrapped_ssh, which injects NO user/identity — red herring). GitHub fetch on the box needs command ssh -A + ssh-add ~/.ssh/id_ed25519 (auths GitHub as wowjeeez); empty agent → Permission denied (publickey). Stack = vuer_docker compose, source bind-mounted at /workspace/<repo>, supervisord per container, node 24.12 / yarn 1.22.22 inside as root (uid 0), no node/yarn on host. Deploy recipe: explicit-refspec fetch, reset/clean/checkout — vuer_css tree is root-owned so its git ops must run docker exec -u 0:0 (ops has no sudo); yarn install --frozen-lockfile + npx sequelize-cli db:migrate (app also auto-migrates) + supervisorctl restart; verify HTTP from the Mac (curl -sk https://{oss,css}-fk-dev.taild4189d.ts.net), fk-dev can’t resolve its own sidecars non-interactively. OpenHours is load-bearing for videochat smokes — table openhourstandards, default calendar = calendarName IS NULL; open with update openhourstandards set "from"='00:00',"to"='24:00',"isOpen"=true where "calendarName" is null via the app’s own require('./server/db/sequelize.js') (no raw creds), then supervisorctl restart vuer_oss to clear the cache. fk-dev was mid-FKITDEV-9059 with uncommitted WIP (MJML + FKITDEV-9200 k6) overwritten per instruction — fk-dev-deploy-smoke-runbook, dev-build-host, nusz-1.9.11.48-test-runbook

2026-08-12

  • FKITDEV-9197 CIB devel update, second half: pushed, three PRs open, CI driven to green — and two methodology corrections that are the most valuable output of the round. PRs vuer_oss #8126 · vuer_css #3152 · portal_css #712, all targeting customization/cib. GitHub’s branch-derived default PR title fails BOTH TechTeamer ruleset regexesChore/fkitdev 9197 cib devel update has no lowercase type: prefix and no bracketed ticket; all three had to be edited to chore: [fkitdev-9197] merge devel into customization/cib. This is structural (the branch shape the rulesets require generates a title they reject) ⇒ new checklist item, recorded in techteamer-commit-message-ruleset as trap 3; also gh pr edit resolves the repo from cwd, always pass -R org/repo. Phase 2.5 executed for real: all three repos validated inside the shipped product images (harbor.techteamer.com/facekom-devel/{vuer_oss,vuer_css,portal_css}:2026.1.UBI9.1-20220315, Node v24.12.0) in throwaway containers on fk-dev, source shipped with git archive and mounted, running NÚSZ stack untouched — yarn install --frozen-lockfile / yarn lint / yarn build green in all three. But the product image sets NODE_ENV=dev while jest defaults to NODE_ENV=test, which MASKS an entire class of config-loading failureportal-client.test.js passed in-image and failed in CI for exactly that reason ⇒ in-image results read greener than CI, treat both “passes locally” and “passes in-image” as weak evidence. fk-dev access, retested 2026-08-12: ops and root BOTH work — the canonical command ssh ops@fk-dev.taild4189d.ts.net in dev-build-host stands; levander/ubuntu/admin/facekom are refused with tailnet policy does not permit you to SSH as user "<u>"; and connect by name not IP (fk-dev + fk-dev.taild4189d.ts.net are in known_hosts, 100.91.108.61 is not → Host key verification failed). Correction: this entry first recorded “root is the only permitted user”, which was an inference from four refusals with ops never tested, not an observation. That makes THREE asserted-then-withdrawn claims in this one ticket, all the same failure mode — generalising from an experiment whose failure was never identified (four users refused → “only root works”; NODE_ENV=dev still failed → “NODE_ENV isn’t the variable”, when it failed on a missing /etc/hostname; git log -S empty → “400 never existed”, when the pathspec didn’t follow the rename). Each was caught only because something INDEPENDENT contradicted it — a retest, a Linux container, a git log -Lnone by looking harder at the original evidence ⇒ the reusable rule is not “be more careful” but “when a negative result is about to carry weight, change instrument”; collected as a callout at the end of FKITDEV-9197 §15. CI outcome: portal_css 7/7 green first run; vuer_css 6/6 green after two fixes; vuer_oss Unit Tests/Lint/Depcheck/SonarQube green after one fix, with Audit red (npm advisory 1114318 “Sequelize: SQL Injection (Oracle DB)”, the FKITDEV-8279 fork) and the SonarCloud quality gate red (an 11-month devel merge graded as “New Code” — note the split: the workflow’s own SonarQube job passed) ⇒ both are human-override cases, never fix them on a partner branch, and build needs: audit means Build was skipped. “Skipped” is not “passed” — on vuer_css’s first run Build and SonarQube were skipped, not failed, because both needs: the red test job, so a red gate hides everything downstream and re-reading the needs: graph is mandatory before reporting a run. The three fixes: (1) f434bf9db vuer_css — sso-login-endpoint.test.js asserted 400 against a middleware returning 401; b6ea3b716 (2024-10-18, FKITDEV-4987) created the guard returning 400 {'Missing parameter'} so the test was right for ~6 weeks, then c3256bc10 (2024-12-03, FKITDEV-5777) swept all three error exits to 401 {INVALID_AUTH_CREDENTIALS}, created constants.js for the enum and renamed routes/sso/sso-login.jsroutes/external/corporate-portal-login.js, updating only the test’s require line — red for 20 months and nobody knew, because customization/cib had no test job until this merge; fix = expectation → 401 + a res.json body assertion + de-duplicating two identically-named tests. (2) 83e4adbd2 vuer_css — portal-client.test.js died at import with No config files found because CIB’s PortalClient.js (unlike devel’s and Generali’s) has require('../../../config') at module scope for getPortalRedirectUrl, and config/ holds only dev.json/docker.json; forking the test was impossible (blob byte-identical on devel, Generali and CIB), config/test.json was rejected as a deployed-repo change to satisfy a test runner, and diverging jest.config-unit.js costs the same as forking ⇒ fix = move the require into the method, safe because config.js (which is not side-effect-free: spring cloud config bootstrap, CORS default mutation, module-scope config.loaded) is already required at boot by server/web/WebServer.js:13, server/web/routes.js:2, server/bootstrap/connection/rabbitmq.js:2, customization/server/service/CIBSSOService.js:2 + four customization/listeners/*, and the only caller of getPortalRedirectUrl is the HTTP route customization/server/web/routes/device-change-redirect.endpoint.js:34, necessarily post-boot ⇒ require-cache hit on the same object. (3) acaa597d83 vuer_oss — translations.test.js invokes any callback not registered in test/tests/unit/translations.map.json with ZERO arguments and CIB’s __infoText__ does property.split('.'); fix = register the portal infoText/helpText/placeholder arg maps, no source change. THE TWO REUSABLE GOTCHAS, both of which produced confident wrong answers asserted to the user: git log -S does NOT follow renamesgit log -S "status(400)" -- <post-rename path> returned nothing and was read as “400 never existed in this middleware”, a false history corrected by an agent; use git log --follow -S or better git log -L <a>,<b>:<file> (a line’s entire history across renames), and this matters precisely in devel-update work because “was this test ever right?” decides whether you fix the test or the code. And macOS cannot load vuer_css’s config.js with NODE_ENV=dev unless DEV_DOMAIN is setconfig.js:43 does fs.readFileSync('/etc/hostname') on the dev/travisci path and macOS has no /etc/hostname → ENOENT; the damage was the reasoning, not the error: an agent set NODE_ENV=dev, saw the suite still fail, concluded “NODE_ENV is not the variable” and misattributed a genuine CI failure to a ‘nested worktree artefact’when a hypothesis test fails, read the actual error text — a failed experiment only refutes the hypothesis if it failed for the reason you were testing. The distinguishing move was running the same tree in the Linux product image. Three environments gave three different results for the same tree (macOS local / fk-dev in-image / CI), structurally rather than flakily. Still open for a human: getPortalRedirectUrl has zero test coverage so fix (2) rests on the require-cache argument rather than an assertion (a device-change-redirect smoke on fk-dev would close it); the now-green SSO suite only exercises the dev-mock branch (mockSsoServer is true in dev.json, false in docker.json) so production CIB’s passport/OAuth2 + jwt.verify + processId path has no cover at all — green ≠ meaningful; and nothing documents the 401-on-missing-credentials contract with CIB’s portal client, live since 2024-12-03 — FKITDEV-9197, devel-update-and-release-flow, customization-branch-ci-pipeline-inheritance, techteamer-commit-message-ruleset, dev-build-host, FKITDEV-8279

  • THE BROADEST FINDING OF FKITDEV-9197 IS NOT ABOUT CIB: three devel-wide test-reliability defects mean a green Unit Tests job on vuer_oss is weak evidence — one shared suite registers ZERO tests, two others flake non-deterministically. New note vuer-oss-unit-tests-green-is-weak-evidence; all three affect every partner branch, none was changed on the CIB branch (deliberately — each belongs upstream). (1) test/tests/unit/translations.test.js:181 is dead code: it.each(testSummary.entries(), (file, error) => {…})it.each(table) RETURNS a function that must then be invoked with (name, fn), but the callback is passed as each()’s second argument and the returned function is discarded, so no test is ever registered; the suite’s only registered tests are its it.skip(...) calls. Verified in node directly and from CI output on a passing run (Test Suites: 2 skipped, 345 passed, 345 of 347 total / Tests: 147 skipped, 10 todo, 3515 passed, 3672 total). ⇒ every wrongKeys/missingLanguage finding the suite computes is silently discarded for every partner; a probe replicating the suite’s own logic found 42 findings on the CIB branch that CI cannot see, mostly flow_task_name/flow_task_instructions/flow_input_option returning undefined across customization/flow/cib-*.flow.trans.js. Fixing the it.each is a BREAKING CHANGE, not a cleanup — it converts those 42 into hard failures on CIB alone ⇒ deliberate upstream ticket with the fallout budgeted, never a drive-by alongside a scan() fix. Interaction with our own acaa597d83: that fix is real (it stopped the suite throwing at import, which is what made the job runnable) but it bought no coverage, because the suite validates nothing for anyone — never let “translations green” read as “translations checked”. (2) the scan() relative-path bug is ACTIVELY FLAKY on devel, not merely latent: line 28’s cwd is absolute (path.join(__dirname,'../../../'), used for require + the map read) while includedDirectories entries go into scan() relative and hit fs.existsSync(startPath) at line 77 ⇒ suite loading depends on process.cwd() at module-eval time. Evidence from production CI, same commit, same nightly “Checks for Long-lived branches” workflow (cron * 20 * * *), customization/mbh, 2026-08-11: run 31531810832 20:13 passed, 31533215070 20:29 FAILED Directory not found: client/features, 31536624080 21:10 passedboth runners (runnerd-techteamer-node-ci-1 and -2) produce both outcomes ⇒ not one bad machine; client/features is real and git-tracked (215 files); also failed the NÚSZ devel-update PR (run 31485303651) while barion (31475164402) and generali (31489547911) passed; does not reproduce on macOS. History: devel bfd1311aab (sonar code smells, PR #8000) changed line 28 from process.cwd() to the __dirname form, fixing the require half and leaving scan() relative ⇒ the flake predates and survives it. Root cause of the cwd perturbation is UNPROVEN — no process.chdir in repo code; the only one reachable in the dependency tree is node_modules/cross-spawn/lib/util/resolveCommand.js:18 (chdirs to options.cwd before which.sync, restores in a finally) = a plausible leak window, not demonstrated. AND THE OBVIOUS ONE-LINER BREAKS THE SUITE SILENTLY: path.join(cwd, startPath) makes every returned translationFile absolute (because scan() builds results from startPath) and three downstream consumers key off relative paths — require(path.join(cwd, abs)) yields a doubled path, excludedFiles.includes(abs) goes false so exclusions stop working, argMap[abs] is undefined so every arg map is silently lost; underneath that, path.join concatenates and does not resolve a leading / in a later segment — that’s path.resolve. Minimal correct fix keeps returns relative: scan(path.join(cwd, startPath), ['.trans.js','translations.js']).map((f) => path.relative(cwd, f)). (3) a second, independent flake: server/util/pdf.test.js › printImage › place sample PNG image does a byte-for-byte PDF comparison and drifted by 3 bytes of stream length — failed on the first CI run after our push, passes on the parent commit and 3/3 locally, unreachable by our change (translations.map.json is read by exactly one file, translations.test.js:73), and a re-run with no content change went green ⇒ recorded as method: vuer_oss’s “Unit Tests green” was NOT first-attempt, and with two known flakes a single red run is not evidence of a regression while a single green run is not evidence of its absence. Umbrella lesson landed in devel-update-and-release-flow Gotchas and cross-linked from portal-css-jest-runs-zero-tests (the sibling — same disease, different mechanism, different repo) and customization-branch-ci-pipeline-inheritance (the trap that switches this test job on for a partner branch in the first place) — FKITDEV-9197 §16

2026-08-11

  • The full partner devel update → release flow written end-to-end for the first time — and the headline is the previously-undocumented Phase 3: collecting a release’s ticket scope WITH AUTHORS, for the TjK and for outreach. devel-update-verification-recipe covered only the verification half and is now a stub redirecting to the new devel-update-and-release-flow (all 6 inbound links preserved); everything after validation is new material. Phase 3 tool, verified and reusable: /Users/levander/coding/facekom/.claude/scripts/release_tickets.py <tag-prefix> <repo-path>… [--head REF] — resolves the latest release tag per repo from ls-remote and fetches the tag explicitly (mandatory in narrowed-refspec clones where it isn’t local), then emits two markdown tables carrying YouTrack links, GitHub commit + PR links, state, assignee and commit author: bucket 1 = landed DIRECTLY on the customization branch (git log <tag>..HEAD --no-merges --not origin/devel) = what the partner paid for, always a TjK entry; bucket 2 = came via devel but modified customization/ (git log <tag>..HEAD --no-merges -- customization/ minus bucket 1) = core work that nonetheless changed the partner surface and is easy to miss entirely. Verified Generali 1.9.11.19 output vs baseline tag generali-atvilagitas-1.9.11.18: direct = FKITDEV-8567 “Generali - reduceRight átírás” (Done, assignee Ferenc Jurkiewicz, committed by Szecsődi Imre, vuer_oss PR #7811) + FKITDEV-9194 devel-update fix (vuer_css, no PR); via devel = FKITDEV-9119 “EnvData supportedSteps törlése” (Done, Márton Szvetkó, PR #8083) + FKITDEV-9080 “WebSDK - AI ACT” (Pending — flag it, it ships anyway, Krisztián Makkai, PR #8054). Two things the tool deliberately leaves to a human: assignee ≠ commit author (both emitted — 8567 is assigned to Jurkiewicz but authored by Szecsődi), and it only sees tickets in commit subjects, so the release’s headline item can be a pure-core commit in NEITHER bucket — for .19 that is ASSGRALI-63 / FKITDEV-8887 (iOS audio) ⇒ always cross-check the parent ASS* release ticket’s changelog. Phase 0 adds: establish which repos the partner is actually in (Generali = vuer_oss + vuer_css only), spot dead lines (customization/generali-kar, last moved 2022-01-24, 1754 behind — never update it), decide one ticket or two up front (dedicated FKITDEV-9073 vs folded-into-release-prep FKITDEV-9194; both acceptable), and check remote.origin.fetch before anything else. Phase 1 semantic sweep now leads with deletions/renames (--diff-filter=D/R) as the highest-risk class because customization/ overrides bind core by path and go stale silently — vuer_css caught exactly one (deleted server/util/aiActHelper.ts still required by an override), while vuer_oss’s merge had 0 deletions and 0 renames, which makes the whole bug class structurally impossible and is worth measuring precisely because it tells you how hard to look. Phase 2 correction that invalidated a first attempt: the base-commit tree needs its OWN yarn installnever symlink node_modules from the merged tree, because the merge moved yarn.lock by 800 lines in vuer_oss and you end up testing the base against the wrong dependency tree; also yarn install --frozen-lockfile hard-fails on Node 22 (geoip-lite requires >=24) while package.json engines: >=22.18.0 is stale (CI pins 24). Real fk-dev numbers inside the product image (Oracle Linux 9.7 / Node 24.12.0): base bfe85a4e68 = 3 suites / 9 tests failed, merged = 2 suites / 3 ⇒ the merge net-fixes 6 tests; survivors converter + vuer-cv-service are pre-existing and environmental (vuer-cv-service hardcodes the CI path /workspace/...). Remote-validation gotcha: ship the tree with git archive or COPYFILE_DISABLE=1 tar --exclude='._*' — macOS AppleDouble ._* files otherwise land in the tarball and jest picks them up as ~20 bogus failing suites. Phase 4 release gates (green ≠ ready): chore/ branch merged into customization/<partner> via PR because the tag is cut from the customization branch; customization/RELEASE.md entry (historically its own ticket — FKITDEV-9153 for .18); tag <partner>-1.9.11.NN while package.json version stays 1.9.11 (the .NN lives only in tag + changelog); breaking-change/config sweep — real example: devel restructured browsers.showOldBrowserWarningbrowsers.oldBrowserWarning.{show,delay} and server/web/Template.js:123 now reads the new path, so any partner prod config still on the old key silently loses the old-browser warning, and docs/config/ was not updated to match (new-but-default-off: sftp, dataCleanupCron, transferRoomCron, documentRecognitionVersion, roomExportFilesExtendedName); functional smoke test on a real deployment; TjK with evidence. Phase 5, the hard lesson of this round: a devel regression (FKITDEV-9199 — dataset.socketToken never resolving because the twigs emitted camelCase data-socketToken) was diagnosed and a reader-side fix pushed, while the upstream fix cda6c80b97 had already landed ~2 hours earlier taking the opposite approach (kebab-casing the twigs) — merging mine on top would have re-broken it ⇒ always git ls-remote for the upstream fix right before pushing, not just before merging. Why 1083 green tests missed it: vuer_css jest runs in the node environment with no jsdom, so all DOM behaviour is hand-mocked and nothing parses a real HTML attribute — to verify DOM-coupled behaviour, render the real twig with the real twig engine (autoescape: true, matching server/web/WebServer.js:257) and parse with a real HTML parser. Gotchas recorded as their own callouts: the narrowed fetch refspec (git fetch origin devel writes only FETCH_HEAD, exits 0, leaves origin/devel stale — nearly shipped .19 without its headline feature), --force-with-lease “stale info” in those same repos ⇒ keep the net with git push '--force-with-lease=<branch>:<sha>', zsh eating refspecs ($B:r is the remove-extension modifier ⇒ use fully literal strings), vuer_css test files cannot be linted (eslint config references a missing jest-formatting plugin and exits 2 — hence yarn lint ignoring test/*), the youtrack_guard hook re-arming /tmp/fk-ticket/.analyze-active, and node_modules not being gitignored when it’s a symlink (trailing slash in .gitignore) ⇒ never git add . in such a worktree. Also noted: build has needs: [lint, test, audit, sonar] so vuer_oss’s pre-existing red audit (FKITDEV-8279 @techteamer/sequelize 6.32.2 GHSA-v8fg-2rw7-q452, byte-identical on base) blocks build on every partner PR, and the CI-inheritance trap did not fire for Generali (branches already carried devel’s 6-job pipeline; long-lived-branches.yaml is schedule-only and its matrix lists devel/mbh/raiffeisen/kh/unicredit) — devel-update-and-release-flow, devel-update-verification-recipe, FKITDEV-9194, narrowed-fetch-refspec-stale-devel-merge, customization-branch-ci-pipeline-inheritance, release-process, tesztjegyzokonyv-generation-flow
  • Raiffeisen release 1.9.11.100 (ASSRAFIPI-135 / FKITDEV-9156) documented for the first time — payload MERGED to a release BRANCH, not tagged, and not merged back. Zero vault coverage existed for this release before today. Release branch chore/FKITDEV-9156-raiffeisen-release-1.9.11.100 in BOTH repos (vuer_css 95b3e73416a10b563b260c96bd5699b9b294bd76, vuer_oss 350d3e626b096456df722b8940871b41e3c74f92), cut from tag raiffeisen-1.9.11.99; raiffeisen-1.9.11.100 is NOT a tag in either repo ⇒ nothing is publishable yet. Two payload tickets merged 2026-08-10 nine minutes apart: FKITDEV-8827 → vuer_oss PR #7971, APPROVED by m3szi, merged 06:36:09Z, merge commit 297aa2fac1f69c15481e16acdc663edeb7414d75, base RETARGETED from release/FKITDEV-8902-raiffeisen-1.9.11.95 → the .100 branch, its 3 files verified present; FKITDEV-8787 → vuer_css PR #3064, merged 06:45:11Z, self-heal verified at server/socket/events/selfservice-v2.js:303-322 + abort clear :575. DELIVERY-ROUTE LESSON: the customization/raiffeisen-targeted PRs #3050 and #3051 were both CLOSED UNMERGED — for this partner payload lands on the release branch and the customization branch is reconciled afterwards, so “is it merged?” and “is it on the partner branch?” are different questions. Right now neither fix is on customization/raiffeisen nor develany new branch cut off customization/raiffeisen silently loses both. Changelog (9 rows, partner-side ids, = TjK section order): ASSRAFIPI-124 (CV document recognition v2→v3), ASSRAFIPI-119 (←8827), ASSRAFIPI-18, CRRAFIPI-106, ASSRAFIPI-92 (ImageId log), SLARAFIPI-59 (girinfo), SLARAFIPI-60 (←8787), SLARAFIPI-62 (logikai adategyezés), CRRAFIPI-115 (Liveness 2) — only rows 2 and 7 have a traced FKITDEV+PR. YouTrack fully stale: FKITDEV-8827 and -8787 both still State Pending / Blocker Review Needed, SLARAFIPI-60 and ASSRAFIPI-119 both still Blocked / Release needed — nobody moved anything after the merges, so they keep reappearing as unshipped release scope. Unanswered partner question now answerable: Bence Varga asked on SLARAFIPI-60 2026-07-30 “melyik release-be tud ez belekerülni?” and was never replied to — the answer is 1.9.11.100 / ASSRAFIPI-135. All facts verified via gh + git ls-remote + an explicit-refspec fetch (mandatory in vuer_css, see narrowed-fetch-refspec-stale-devel-merge) — raiffeisen-1.9.11.100, FKITDEV-8827, FKITDEV-8787, client-registry
  • The partner-facing release TjK document structure reverse-engineered into a reusable spec — and it is a DIFFERENT artifact from /fk-tjk’s template. [[tesztjegyzokonyv-generation-flow|/fk-tjk]]‘s pinned tesztjegyzokonyv_sablon.docx is 19-placeholder substitution for a SINGLE dev ticket; the release TjK is hand-authored per release with one Heading2 section per shipped ticket — do not point the renderer at one. Structure: Title/Normal/Subtitle → static TOC field → Heading2 Bevezetés → repeated per-ticket Heading2 <ticket> - <title>Heading3 FejlesztésHeading3 Teszteset → optional Heading4 Elvárt működés. Hard rule: sections use the PARTNER-side ticket id (ASSRAFIPI-/SLARAFIPI-/CRRAFIPI-) — FKITDEV-<n> never appears in a customer document (.100 map: ASSRAFIPI-119←8827, SLARAFIPI-60←8787); section order follows the release changelog, not ticket number. Evidence = one Normal paragraph per line in Roboto Mono, color 37474f, sz 21 (strongest), or inline <w:drawing> screenshots, or narrative (weakest); bullets numId=1/ilvl=0/ind left=720 hanging=360; numbered sub-cases are plain paragraphs not Word lists. Two traps: the TOC is a static Word field that does NOT refresh on programmatic append (must reopen in Word/Docs before PDF export), and the closing “telepítésre ajánlott … a tesztek mind sikeresek voltak” paragraph of Bevezetés IS the pass/fail statement — it must be rewritten if any case failed, never shipped over a red result. Working programmatic-append script /Users/levander/coding/facekom/.claude/scripts/tjk/append_sections_example.py (splices <w:p> before <w:sectPr>, rewrites the zip entry-for-entry, self-checks). Document is a Google Docs export (all w:rsid* = 00000000) w/ Roboto + Roboto Mono embedded. Defects found in the 2026-08-10 .100 draft: body paras mis-styled Heading2/Heading3 inside SLARAFIPI-59 (pollute the TOC), 2 empty Heading2s, SLARAFIPI-62 both subsections empty, issuu typo. Full spec was on disk at docs/tjk-raiffeisen-document-structure.mdfolded into the vault note and retired later the same day (see the “loose facekom TjK knowledge moved into the vault” entry below) — tesztjegyzokonyv-partner-release-document-structure, tesztjegyzokonyv-generation-flow, youtrack-tesztjegyzokonyv-attachment-recipe
  • FKITDEV-8787 corrected on three counts — headline RETRACTION: the "Already authorized" / "Already has some kind of room" strings are SERVER-SIDE in vuer_css, not in the FaceKom mobile SDK. Both literals are defined at server/socket/events/selfservice-v2.js:30-32 as EXCEPTIONS.ALREADY_AUTHORIZED / EXCEPTIONS.ALREADY_HAS_ROOM, and the "data": {"error": …} envelope the partner pasted — which read like a mobile-SDK log format — is createEndpoint’s own wire log via reportWireClientResponse, i.e. our own vuer_css log. The original git grep wasn’t wrong about what it searched (the strings genuinely are absent from vuer_oss) but “absent from OSS” was generalised to “absent from the server”, skipping the socket layer in the OTHER repo — reusable lesson: on this platform “the server” is two repos, an OSS-only grep does not clear the server side. Knock-ons: recommendation C (“mobile Restart must call clearSession()”) was never the primary fix, the working-hypothesis mermaid’s SDK->>SDK: guard hits … never reaches OSS steps are wrong (the request did reach the server and the server threw), and attribution to the Raiffeisen mobile team was misdirected — nothing was ever blocked on them. Also corrected: PR #3064 is MERGED (was recorded OPEN against the .95 branch) and #3051 is CLOSED UNMERGED (was recorded OPEN/MERGEABLE). Still-open gap recorded: the fix deliberately preserves customerId/authorization — asserted by test preserves customerId after abort (only roomData is cleared) — so a re-register/auth on the same socket can still throw Already authorized; only the ALREADY_HAS_ROOM half was fixed, meaning that string in a future partner report is not evidence of regression but a different unaddressed path. Reusable design rule confirmed: for a duplicate-prevention guard, “RPC threw” ≠ “resource dead” → fail CLOSED (v1 was fail-open and a transient blip on a LIVE room would have spawned a second live room, re-creating the bug inverted). Evidence provenance (re-run today against merged code): vuer_css selfservice-v2.test.js 76/76 (12 = the 8787 cases), vuer_oss RaiffeisenFaceComparisonExportService.test.js 23/23, and the untracked .dev-e2e/run-e2e.sh harness in the 8827 worktree (throwaway postgres:17-alpine on :5544 via OrbStack) produced a real dated CSV proving a different_face row exports with status=success — end-to-end confirmation of the read-time-verdict model. Two gotchas: a worktree’s node_modules can be out of sync with its branch lockfile (missing @babel/plugin-proposal-class-properties; switching a worktree onto a release branch does NOT re-install → yarn install --frozen-lockfile in the worktree), and rtk mangles git show <rev>:<path> args and swallows jest --verbose per-test lines → use python3 subprocess.run([...]) argv-list and jest --json --outputFileFKITDEV-8787, FKITDEV-8827, face-comparison-data-verdict-threshold-model, rtk-mangles-curl-and-pipes
  • /fk-tjk REWRITTEN and its vault note de-staled — the flow is now ZERO-CONTEXT and produces two artifacts, not one. tesztjegyzokonyv-generation-flow described the 2026-06-26 sablon flow and had become the actively-misleading answer to “how do I make a TjK”; rewritten against the authority on disk (.claude/commands/fk-tjk.md). Headline rule: never carry a release number/ticket/partner in from conversation — release trains are PER PARTNER (Raiffeisen was on 1.9.11.100 while NÚSZ was on 1.9.11.48, same day), so a borrowed version yields a correct-looking wrong document; a version in $ARGUMENTS is a hint and a disagreement with the partner’s release ticket STOPS the flow. Phases: 0 historian synthesis (live state beats vault notes, and beats the historian) → 1 partner/base/release → 2 gather → 3 evidence → 4 draft → 5 render → 6 runbook → 7 hand-off. All partners standardized on the release-doc shape (_meta.targetShape in partners.json, decision 2026-08-11); the 19-placeholder sablon + render_tjk.py is now the legacy path, kept only for matching a partner’s history. Base document = the newest TjK in ~/Downloads, matched by NAME (Tesztelési jegyzőkönyv/Tesztjegyzokonyv) — that is where the live Google-Docs export lands so it beats any ticket attachment, and never match by size or list position (Downloads holds CVs at ~765K next to the 763K TjK). New two-step build via append_release_sections.py (the old append_sections_example.py name is gone): newdoc rebases ANY partner’s TjK onto a new partner+release — drops the previous release’s ticket sections, clears the TOC cache, ordered longest-first partner rename (pass both forms, "Raiffeisen PION,Raiffeisen", else Raiffeisen PION fejlesztésNÚSZ PION fejlesztés), --replace OLD=NEW for lowercase build tags + dates — then plain append adds sections from JSON (p/bullets/code/evidence); both modes self-check, never mutate input, both take --selfcheck. ⚠️ THE TOC LEAK (proven by real test, not theory): the table of contents is a static Word field that keeps the PREVIOUS document’s heading text until refreshed — rebasing Raiffeisen→NÚSZ left ASSRAFIPI-124 / SLARAFIPI-59 in the NÚSZ TOC, another customer’s ticket ids inside this customer’s document, invisible in the body; newdoc now clears the cache and REFUSES to write if any ASS…/SLA…/CR…/BUG… id from the source survives (so the TOC renders empty until a human refreshes it — mandatory hand-off step). Phase 6 is new: writes out/<partner>-<release>-teszt-runbook.md with per case előfeltételek / numbered lépések / elvárt eredmény with failure signature / bizonyíték naming what to capture and which TjK slot it fills / the arming condition where one exists (e.g. a bug that only reproduces on socket reuse — closing and reopening the app proves nothing, and a tester who doesn’t know reports a false pass). Evidence is regenerated, not quoted — run the touched suites and any .dev-e2e/ harness in the ticket’s worktree; gotchas: rtk swallows jest --verbose per-test lines → --json --outputFile and parse, a worktree’s node_modules can be out of sync with its branch lock (missing babel plugin) → yarn install --frozen-lockfile, and textutil cannot read PDFpdftotext -layout. fileStem stays per partner (customers file by name) even though the shape is shared; partners.json gained a nusz (ASSNUSZ) entry that was previously missing entirely — an unknown partner key halts the flow on step one by design. Also fixed two stale refs in tesztjegyzokonyv-partner-release-document-structure (dead append_sections_example.py path; the “single-ticket generator” description of /fk-tjk) — tesztjegyzokonyv-generation-flow, tesztjegyzokonyv-partner-release-document-structure, nusz-1.9.11.48-test-runbook, raiffeisen-1.9.11.100
  • Loose TjK knowledge moved out of /Users/levander/coding/facekom/ into the vault — standing policy: knowledge lives in the vault, only EXECUTABLE config stays in the working directory. Three on-disk markdown files were folded into vault notes so the sources can be deleted. (1) docs/tjk-raiffeisen-document-structure.md → merged into tesztjegyzokonyv-partner-release-document-structure, which now carries the VERBATIM Hungarian closing recommendation paragraph of Bevezetés in full — the formal pass/fail statement to the bank (“…telepítésre ajánlott a <Partner> PROD környezetbe … A fejlesztői környezetben végrehajtott tesztek mind sikeresek voltak, nem volt hibás eredmény.”). <Partner> appears TWICE (both get swapped) and three quirks are real and must be preserved: the double space before the final sentence, no space in megvalósítható("Feasible and Practical Testing"), and the comma in a fejlesztői, tesztek. Also folded in: the 6-step Authoring a new one checklist, the JSON block kinds (p/bullets/code/evidence), the fuller append_release_sections.py self-check list (every section heading present, no duplicated section, no FKITDEV- in a heading, --selfcheck alone verifies the tooling, input draft never mutated, fix the JSON and re-run rather than hand-editing the .docx), and two routing rules — render_tjk.py and append_release_sections.py build DIFFERENT production artifacts (pushing one shape through the other renderer yields nonsense; /fk-tjk detects and routes) and priorShape: null means UNKNOWN, not “none” (it stays null until verified against that partner’s newest attachment). (2) docs/tjk-primer-prompt.md → new tesztjegyzokonyv-primer-prompt: the /fk-tjk <partner> one-liner plus the standalone Hungarian prompt kept verbatim in a code fence for pasting into a fresh session, another agent, or another tool. (3) tjk-raiffeisen-1.9.11.100-sections-8827-8787.md → new raiffeisen-1.9.11.100-tjk-sections under releases/: the finished Hungarian ASSRAFIPI-119 + SLARAFIPI-60 sections with their evidence dumps (23/23 FaceComparisonExportService unit tests, the real end-to-end export CSV showing a different_face row at status=success, 76/76 selfservice-v2 incl. the start → abort → start regression) and the Megjegyzések a jegyzőkönyv kitöltéséhez open list. The item not to lose from that list: the SLARAFIPI-60 fix addresses the ALREADY_HAS_ROOM path ONLY — Already authorized is DELIBERATELY not fixed, because the socket’s customerId/authorization is preserved by design, so a re-register/auth on the same socket can still throw it (mobile A/B scenarios still need a real Myra client and have not been run). Every in-vault reference to the retired docs/tjk-*.md paths was repointed (the tesztjegyzokonyv-generation-flow on-disk file table, TOPICS, this log). Unchanged and still referenced by real path: /Users/levander/coding/facekom/.claude/commands/fk-tjk.md and .claude/scripts/tjk/*.py + partners.json — executable config does not move — tesztjegyzokonyv-partner-release-document-structure, tesztjegyzokonyv-primer-prompt, raiffeisen-1.9.11.100-tjk-sections, raiffeisen-1.9.11.100
  • FKITDEV-9197 — CIB devel update on portal_css for release 1.9.11.102: merged, NOT pushed, no PR — and it surfaced a NEW conflict-free-merge break class. origin/devel 56a63bd0origin/customization/cib bf6dfbf8 (= tag cib-1.4.0.74), merge base f3fb6be8 (last sync 2025-09-11, ~11 months of drift), result merge commit b1a4bc94 on chore/FKITDEV-9197-cib-devel-update, worktree /Users/levander/coding/facekom/portal_css-FKITDEV-9197. Portal is its own version train — release 1.9.11.102 but the repo’s tag is cib-1.4.0.74, so resolve baselines with the cib-1.4.0. prefix, never the vuer number. HEADLINE — the “remove unused libs” partner-merge trap: devel’s 7a42894a chore(FKQA-304): remove unused libs (#675) deleted multer and uuid from package.json because core stopped using them, and depcheck on devel is structurally blind to customization/ (partner code isn’t in the tree when the decision is made) ⇒ the removal merges conflict-free and breaks the partner. CIB genuinely needs both: customization/api/document-upload.jsrequire('multer') (multer.memoryStorage()) was NOT RESOLVABLE after the merge — a real runtime break, not a lint nit; customization/api/submit-login.js + submit-registration.jsrequire('uuid')/uuid.v4() resolved only transitively via a hoisted uuid@14.0.1 against the declared ^10.0.0, i.e. working by accident at a different major, caught only by eslint n/no-extraneous-require. Fix = restore "multer": "1.4.5-lts.2" + "uuid": "^10.0.0". The transitive half is the worse one — it passes today and breaks with zero partner-side changes the day the hoisting dependency moves; “it still resolves” is not a pass. Generalised check now Phase 1.4 (e) of devel-update-and-release-flow: diff package.json for removed deps → git grep each under customization/node -e "require('<pkg>/package.json')" to catch the hoisted ones. Second break — devel’s eslint-9 flat-config migration kills partner eslint-disable directives: dropping compat.extends('standard','plugin:n/recommended','plugin:jest-formatting/strict') for n.configs['flat/recommended'] + js.configs.recommended and turning off no-empty/no-unused-vars/no-redeclare/no-useless-assignment makes every partner suppression of those report “Unused eslint-disable directive” — a warning, and yarn lint runs --max-warnings 0 ⇒ red. 9 dead directives across 6 CIB customization files deleted. Counter-intuitive shape worth remembering: turning a rule OFF broke code that was complying with it. Trap in the fix: eslint --fix does NOT delete these lines, it blanks them to whitespace — delete properly. Two pre-existing devel defects recorded, deliberately NOT fixed (out of scope; do not misclassify as merge-caused): (1) portal_css yarn jest runs ZERO tests and would even if you wrote sometest/tests/ is empty and the custom sequencer test/lib/jest/test.sequencer.js (via testSequencer in test/jest.config.js) has an empty CORE_TEST_ORDER with prepareTests filtering on order.includes(relativePath); jest calls sequencer.sort() before its “no tests found” check, so new files are discarded too (proven by a scratch test, then by --testSequencer=@jest/test-sequencer making it run). A .ts test can’t even compile — no @types/jest, tsconfig.json include covers only server/**/client/**/customization/**, no types:["jest"]. The jest script lacks --passWithNoTests so bare runs are hard-red; CI is green only because the workflow appends the flagthe repo has no unit-test signal, validate with lint + build. (2) eslint.config.mjs still references 'jest-formatting/padding-around-all': 'warn' after 65ac214c feat: eslint 9 FKITDEV-6045 removed the plugin — inert only because that block is files: ['test/*','test/**/*'] and lint runs --ignore-pattern "test/*"; same abandoned-plugin residue as vuer_css. RTK escalation — five new silently-wrong modes, all plausible answers rather than errors: git show <ref>:<file> | grep garbled so real matches read as absent (nearly caused a wrong conflict-resolution decision), diff -u reformatted into a line-offset view with a wrong exit code, git diff --no-index rendered as if the whole file were new, git log -1 immediately after committing showed devel’s tip 56a63bd0 instead of the new merge commit b1a4bc94 (the merge-filtering behaviour of rtk-git-log-hides-merge-commits hitting the exact moment you check “did my commit land?”), and ${PIPESTATUS[0]} blanked. Workarounds that worked: rtk proxy, git grep <pat> <ref> -- <path> instead of git show | grep, shasum -a 256 for same-vs-different, python difflib for diffs. Rule: never trust RTK-rendered git output for a verification claimFKITDEV-9197, devel-dependency-removal-breaks-partner-customization, eslint9-flat-config-dead-disable-directives, portal-css-jest-runs-zero-tests, devel-update-and-release-flow, portal_css, rtk-mangles-curl-and-pipes, rtk-git-log-hides-merge-commits, client-registry
  • Two standalone release-readiness gaps split out of the release-pipeline spec as findable atomic notes. (1) vuer_build/build.sh never publishes — verified grep -n push build.shno docker push, no docker login; v0.4.1 only builds, tags locally (harbor.techteamer.com/${PROJECT_NAME}/<svc>:${VUER_VERSION}.${VUER_BUILD_NUMBER}-${SECURITY_NUMBER}) and can export .tar into the customer ZIP. sign-partner.sh v0.1.1 wraps cosign, but signing is not publishing. The modern vuer-release path does publish — release-tool publish push in autobuild.yml with secrets.HARBOR_USER/HARBOR_SECRET. The actual publish mechanism for the legacy path is in no file read so far — recorded as an OPEN QUESTION, not guessed, and it sits directly on CIB 1.9.11.101, which is on the legacy path (note flags that client-registry says .102 per FKITDEV-9197 — resolve the number from the open ASSCIB Release issue / git ls-remote --tags, never from a note). Two traps re-recorded: build.sh -l/--list-partners is broken (cd partners/ at :447, real dir is partner/) and builds fail without an operator-supplied base/<svc>/github.key (gitignored, README:22-28). Base OS is branch-dependent: main=UBI9, feature/FKITDEV-8868=UBI8, feature/FKITDEV-8252-ubi10=UBI10. (2) Release testing has three tiers and the middle one is empty — the per-release runbook is NOT mostly browser work, which is what the k6/Playwright framing assumes: measured against nusz-1.9.11.48-test-runbook, ~60% cannot be driven by a browser at all. Tier 1 static/hermetic (lint, unit, config schema, clean-merge-broken-product detectors) → runs anywhere; tier 2 booted non-browser (flow registration at boot §3.1, RPC, cron CLI completion §1.1, emails ACTUALLY SENDING §4.5, report/xlsx exports, DB assertions) → NO TOOLING AT ALL; tier 3 browser → 12/45 k6 files ported. Not reachable by browser tooling even in principle: iOS Safari mid-call backgrounding (§4.3) and the runbook’s own “cannot be validated in UAT” list (real disk reclaim, load profile, customer-key-offline branch). Two tier-3 limits restated: k6 cannot do file uploads at all ⇒ the attachment/S3 flow (§4.4, a P1) is unportable, and k6.yml passes only CI_DOMAIN, never K6_BROWSER_ARGS ⇒ the docker path has no fake camera/mic and no --disable-web-security — close to fatal for a video-identification product. Payoff worth acting on: a tier-2 harness that boots the app to assert against it IS option (a) of the k6 seeding blocker (“Node pre-seed step reusing helper.ts”), so building tier 2 unblocks the 30 stalled k6 tests as a side effect — one build, two problems, which argues for tier 2 before finishing the port. Both notes linked from release-pipeline-automation-spec (open question 1 + the tier table) — vuer-build-never-pushes, facekom-test-tiers, k6-e2e-harness-vuer-oss, nusz-1.9.11.48-test-runbook, mjml-v5-esm-breaks-commonjs-email-templates
  • FKITDEV-9197 EXPANDED from the portal_css slice above to the FULL three-repo CIB round — and 1.9.11.102 turns out to be a PURE CORE-UPDATE release. Ticket “CIB - CIB Release 1.9.11.102 előkészítés” (In-progress, assignee andras.lederer, reporter Bence Varga, created 2026-08-05, empty description); parent ASSCIB-166 (Submitted, Bence Varga) still reads TODO: release changelog / TODO: core update változtatások. devel merged into customization/cib on chore/FKITDEV-9197-cib-devel-update in three repos, all gate-verified locally on Node v24.18.0, all solo-authored real merge commits, NOT pushed, no PRs: vuer_oss e191f3f53f (amended from b0b987d463; parents 690721c316+435e520ee8; worktree nested inside the repo at vuer_oss/vuer_oss-FKITDEV-9197, not a sibling), vuer_css 680a6256c (parents b043527c7+cda6c80b9 — the devel parent is the socket-token fix, so CIB takes the fixed state), portal_css b1a4bc94 (parents bf6dfbf8+56a63bd0). Nothing was committed directly to customization/cib since the last release — in all three repos the branch tip WAS the release commit (cib-1.9.11.101 2026-05-29 oss/css, cib-1.4.0.74 2026-04-21 portal) ⇒ Phase 3 bucket 1 is empty; the only partner-requested ticket, ASSCIB-161 = FKITDEV-8887 (iOS Safari audio), was already on devel (6bdf66d16, vuer_css only) and arrives via the merge, verified with git merge-base --is-ancestor — the same commit that is Generali .19’s headline (ASSGRALI-63), and invisible to release_tickets.py in both releases because it never touched customization/. Drift: 11 months (last sync 2025-10-01 oss/css, 2025-09-11 portal) = 334 commits / 212 tickets, full author inventory at /Users/levander/coding/facekom/out/FKITDEV-9197-cib-1.9.11.102-tickets.md (Makkai Krisztián 44, Balázs Horváth 37, Szecsődi Imre 16, Szekeres Tamás 15 — the outreach list for TjK sections). THE DEPENDENCY-REMOVAL TRAP GENERALISED — it cuts BOTH ways, three outcomes not one fix: git merge-tree called the files clean, devel had deleted request + request-promise-native as a tracked security action (CIB’s own security/*.md logged “Remove of request and request-promise-native scheduled” monthly since 2025-03), CIB code still required them ⇒ merges clean, lints clean, dies at require-time on boot. Row 1 devel removed it deliberatelyPORT the partner code off it (restoring re-introduces what devel retired) — vuer_oss request/request-promise-nativefetch; row 2 unused-in-core onlyrestore the declared version — portal_css multer+uuid; row 3 partner-only dep devel never hadKEEP it, and this row has no detector at all because it is a conflict-resolution mistake, not a merge artefact — vuer_oss kept clamscan/soap/xml-formatter/short-uuid/uuid/zod, vuer_css kept node-fetch/passport/passport-oauth2 (the CIB corporate-portal SSO path). git diff -- package.json cannot distinguish row 1 from row 2 — only the removal commit’s reason can. mTLS through native fetch needs undici (global fetch ignores agent, honours only dispatcher+connect): declared undici ^6.28.0 as a new direct vuer_oss dep (already transitive via cheerio), flagged reversible via node:https, proven 11/11 against a real client-cert HTTPS server incl. verified mTLS (clientCN: "client"). Prior art existed and was buggy — two abandoned unmerged branches by horvathbalazshbal (update/customization/cib-2025-11-12, …-2025-12-08 tip 4df6666d4f “chore: core update afterworks”) had already ported 4 files to fetch, but silently dropped agentOptions, killing Infocert mutual TLS (InfocertRestAPI passes {pfx, passphrase} at 6 sites — that port compiles, lints, and sends no client cert) and their multipart port cannot run (formData.getHeaders() doesn’t exist on web FormData; fs.createReadStream can’t be appended to one) ⇒ fixed rather than copied, using fs.openAsBlob() and letting fetch set the boundary. Lesson: mine abandoned branches for the FILE LIST, never for the diff. CI pipeline-inheritance = third confirmed instance, and on portal_css it was a SECURITY WIN: CIB carried the legacy single-job lint-and-build (blob ec0a1244, byte-identical to the pre-merge Cofidis branch ⇒ one shared frozen artefact, checkable with a single git rev-parse <branch>:.github/workflows/pull-request.yaml) and portal_css had no pull-request.yaml at all; measured against a base worktree at bf6dfbf8, eslint exit 1 (15 problems) → exit 0 and audit 25 CRITICAL → 0 — CIB’s portal had been shipping 25 critical advisories unmeasured (tar via semantic-release>npm, handlebars, twig>locutus ×2, browserify>shell-quote) precisely because it had no audit gate. Reframe: the expansion is not automatically a tax. CIB is NOT an Oracle partner (no db.options override, no oracledb ⇒ Postgres) so FKITDEV-8279’s behavioural-swap risk doesn’t apply — but the audit gate is still red on the fork’s CRITICAL GHSA-v8fg-2rw7-q452 and build has needs: audit, so CI build is blocked (pre-existing on every vuer_oss branch). Gates: vuer_oss lint 0 / build 0 / depcheck clean / frozen-lockfile ok / audit 1 CRITICAL (expected) / test 3546 passed, 3 failed all pre-existing against REAL controlstranslations.test.js is CIB-only and fails identically on the pre-merge tip (__infoText__ missing from translations.map.json, PortalData.trans.js:978), converter/vuer-cv-service/pdf fail on clean devel too — plus an import sweep of 1219 specifiers across 703 files, 0 unresolved. vuer_css lint 0 (independently re-verified) / build ok / frozen-lockfile ok / depcheck clean / audit 0 critical / test 1066 passed, 2 failed pre-existing; 53 conflicts resolved, 722 relative imports + 302 twig include targets all resolve. portal_css all green — but zero tests exist structurally (test/tests/ holds a 0-byte .gitkeep; the empty CORE_TEST_ORDER in test.sequencer.js is a second kill-switch) ⇒ green ≠ covered, and multer is the proof real breakage hides there. Two methodology corrections folded into the flow: (1) never symlink the merged node_modules into the base worktree when deps changedvuer-cv-service duly failed there with Cannot find module 'request-promise-native', a failure manufactured entirely by the shortcut; give the control its own install; (2) calling jest directly (to dodge rtk’s yarn rewriting) drops flags the npm script supplies — omitting --experimental-vm-modules manufactured 4 phantom failures in vuer_oss. Open for a human: push + PRs (into customization/cib, never devel); does portal_css even ship in .102 (ASSCIB-166’s Komponensek lists only vuer_oss + vuer_css); undici as a new direct dep; the vuer_css branding call page-focus-visible = cib-green-700 over devel’s blue-primary (site-wide focus ring, no CIB precedent) plus the videochat ScreenSign panel left on devel’s generic palette; the system-check browser-incompatibility guard is now removed (devel’s FKITDEV-6036 deleted it deliberately, CIB had re-acquired it via a merge resolution ⇒ unsupported browsers now render an error report instead of hard-failing — changelog-worthy); the CV v2→v3 swap auto-merged ungated in self-service-v2.js while CIB config says identificationLimits.compat: true (“CV 4.6”); REST ports are unit-proven, not endpoint-proven (needs a staging smoke of Infocert process-start + one CORPO call); CIB’s TjK shape has never been verified (partners.json priorShape: null, ASSCIB-166 links a Google-Doc “TJK Sablon”); changelog goes in customization/RELEASE.MDFKITDEV-9197, devel-dependency-removal-breaks-partner-customization, devel-update-and-release-flow, customization-branch-ci-pipeline-inheritance, vuer-oss-global-fetch-ignores-agent-mtls, portal-css-jest-runs-zero-tests, eslint9-flat-config-dead-disable-directives, FKITDEV-8279, FKITDEV-8947, ASSCIB-161, FKITDEV-8887, vuer_oss, vuer_css, portal_css

2026-08-08

  • FKITDEV-9194 — Generali devel update for release 1.9.11.19: merged, validated, NOT pushed, no PR. Ticket “Generáli - Generáli Release 1.9.11.19 előkészítés” (Open, andras.lederer), parent ASSGRALI-72 whose changelog carried TODO: core update változtatások pending on exactly this. Branch chore/FKITDEV-9194-generali-update-2026-08-08 in both repos off customization/generali-atvilagitas (precedent: chore/FKITDEV-9073-generali-update-2026-07-15); worktrees /Users/levander/coding/facekom/vuer_{oss,css}-FKITDEV-9194; result vuer_oss df01e922ce, vuer_css e3c8996d4, both 0 behind live devel. Scope: Generali customization exists in vuer_oss + vuer_css only (zero refs in portal_css/esign_oss/esign_css); customization/generali-kar is DEAD (last commit 2022-01-24, 1754 behind) — the live line is generali-atvilagitas (tag generali-atvilagitas-1.9.11.18). ⚠️ HEADLINE GOTCHA — a narrowed fetch refspec silently merged a STALE devel: vuer_css has remote.origin.fetch = +refs/heads/customization/raiffeisen:… (one branch), so git fetch origin devel (bare name, no destination) writes only FETCH_HEAD and never moves refs/remotes/origin/devel, while printing success and exiting 0; the following git merge origin/devel merged a stale tree conflict-free with zero warning. The first css merge used devel @ 7d4f9956c8 (2026-07-28) vs live 3ace8872c3 (2026-08-07) — 6 commits dropped incl. 6bdf66d16 fix: [fkitdev-8887] recover WebRTC audio after iOS Safari interruption (#3066), which IS ASSGRALI-63, the headline changelog item of the very release being prepared. Fix: always git fetch origin '+refs/heads/devel:refs/remotes/origin/devel' then assert git rev-parse origin/devel == git ls-remote origin refs/heads/devel; vuer_oss has a full +refs/heads/* refspec and was unaffected. Semantic breaks a conflict-free merge hid (the real work of a devel update): css customization/server/web/routes/waiting-room.endpoint.js:5 required server/util/aiActHelper.ts which devel DELETED in favour of server/web/helper/getAiActData.js (async getAiActData(req){shouldShowAiIdentificationConsent, consentDocumentUrl, consentData}) ⇒ would throw Cannot find module on the waiting-room route — fixed by mirroring devel’s core refactor while keeping Generali’s gen-waiting-room.template.twig; css customization/ui/pages/gen-self-service-consent-{pep,ttny}/{*.script.js,*.ui.js} still called auth(...) after devel’s a6185aa41 fix: [fkitdev-8846] remove duplicated socket connections (#3130) replaced it with SocketService.getConnection('<page>.script') + a “Missing layout socket connection provider” guard — fixed to mirror core keeping the gen-* identifiers; vuer_oss clean, proven by resolving all 704 relative requires under customization/ (only hits were commented-out placeholders, byte-identical on base) and by supportedSteps (removed by devel’s feat: [fkitdev-9119]) having 0 real-source references in either repo. Validation (Node 24.18.0 from /opt/homebrew/opt/node@24 — repo-default v22.22.3 is below the >=24.9 jest needs): css lint/build/depcheck PASS, test:unit 120 suites / 1083 passed / 0 failed (base 115/1043/0 ⇒ devel’s 5 new suites all pass against Generali), improved-yarn-audit --min-severity critical 0 vulns PASS; oss lint/build/depcheck PASS, test:unit 4 failed / 3545 passed — all pre-existing, none merge-caused, proven on a base-commit worktree (base 10 failed: converter, self-service-v2, sms-report-service, vuer-cv-service; merged 4: converter, self-service-v2, vuer-cv-service ⇒ the merge net-fixes sms-report-service), deterministic across 3 isolated runs each while full-suite runs vary from test ordering. oss audit gate FAILS on 1 CRITICALsequelize GHSA-v8fg-2rw7-q452 via sequelize@npm:@techteamer/sequelize 6.32.2, pre-existing (byte-identical resolution on base, which fails the same gate) = the known FKITDEV-8279 fork problem; matters because build has needs: [lint, test, audit, sonar] so red audit blocks build (the prior FKITDEV-9073 round hit the same). CI trap did NOT apply: both Generali branches already carried devel’s full 6-job pipeline, so the “legacy 1-job partner branch inherits devel’s 6 jobs” expansion that cost Cofidis 5 failure clusters in FKITDEV-9059 was a no-op here; vuer_oss also gained a scheduled long-lived-branches.yaml but its matrix lists only devel/mbh/raiffeisen/kh/unicredit ⇒ Generali takes no new scheduled load. Open question: prior rounds used a dedicated devel-update ticket (FKITDEV-9073); this one was folded into the release-prep ticket — convention unsettled. First vault coverage of the Generali devel-update line (nothing existed for 9073 or 9194) — FKITDEV-9194, narrowed-fetch-refspec-stale-devel-merge, devel-update-verification-recipe, customization-branch-ci-pipeline-inheritance, customization-branches, vuer_css, ASSGRALI-63

2026-08-07

  • FKITDEV-8279 — the @techteamer/sequelize fork is retired on a branch: upstream sequelize@6.37.8 + its three patches carried in-repo via patch-package, a boot guard, and 30 tests. Branch fix/FKITDEV-8279-sequelize-upstream-6-37-8 @ b0303af227 (off origin/devel 70cc97382b, fast-forwardable, 8 commits + a final fix wave) — reviewed ready to propose, but NOT pushed and NO PR opened. Option C from the analysis; supersedes vuer_oss PR #7710 (pins ^6.37.7, so still carries GHSA-6457, and drops all three patches with no replacement). Shipped files: package.json (sequelize ^6.37.8, patch-package moved into dependencies, "postinstall": "patch-package --error-on-fail"), patches/sequelize+6.37.8.patch (177 lines / 5 files / 16 hunks), server/db/vendorPatches.js (assertVendorPatches, called from server/db/sequelize.js:35), test/tests/unit/db/sequelize-patches.test.js (30 tests), .depcheckrc.json, yarn.lock. Carry-over fidelity byte-verified against fork 6.32.2 unpacked from the Yarn cache (116/116 reserved words incl. order, 8/8, 6/6, 4/4, 1/1). oracledb deliberately NOT added to core. TWO ANALYSIS CLAIMS RETRACTED — do not repeat them: (a) “the fork is invisible to yarn audit is FALSE and was never measured (inferred from an npm advisory-API query) — devel depends on it through an npm alias, Yarn v1 audits it under the key sequelize and submits sequelize@6.32.2, so both advisories have been reported all along; (b) “a CVSS 9.8 sat unnoticed for two years” is FALSE — GHSA-v8fg-2rw7-q452 / CVE-2026-69240 was published 2026-08-03, four days earlier, and GHSA-6457 / CVE-2026-30951 (2026-03-11) sat below the gate’s --min-severity critical threshold for five months; what sat for two years is the fork being abandoned (last npm release 6.32.2, 2023-10-13). The correct checkable claim: the CI Audit job is currently RED on devel and this branch turns it green — measured improved-yarn-audit --min-severity critical: devel Found 1 vulnerabilities exit 1, branch Found 0 exit 0 (gate .github/workflows/pull-request.yaml:109-119, needs: [lint, test, audit, sonar], no .improved-yarn-audit-ignore anywhere); full yarn audit 14 → 12 findings, delta exactly the two sequelize rows. Third correction: pre-existing unit failures on devel are 5, not 4 (genuine git archive devel install: 347/3673/5 vs branch 348/3703/5, +30 passes, 0 new failures). DECISIVE EXPERIMENT (fk-dev SSH refused → local substitute, real DBs in disposable containers): a fork-shaped Oracle schema built by hand-written DDL through raw oracledb — physical SETTINGS with uppercase ID/CREATEDAT/UPDATEDAT next to lowercase-quoted "key"/"value" — reads fine through the patched build (SELECT id, "key", "value", …, row returned) and, with the reserved-word hunk reversed in node_modules, returns ORA-00904: "VALUE": invalid identifier, errorNum 904, from a real Oracle (md5 identical before/after the reversal). Same both-directions treatment for patch 3 (ORA-01408: such column list already indexed, 1 CREATE INDEX vs 0 patched) and patch 2 on a real SQL Server 2022 (Implicit conversion from data type nvarchar to varbinary(max) is not allowed. — verbatim fork PR #1’s string); boot guard verified through the real require() of server/db/sequelize.js with a live connection, silent patched / refuses to load unpatched. Also: 61 models synced, SettingsService.init()/loadSettings()/importSettings() green, reserved-word sweep 13/14 and query surface 7/8 (both FAILs explained — an Oracle CLOB ORDER BY that reproduces on a non-reserved column, and a User.update() harness artifact throwing in the rights getter with no SQL issued). STILL UNGATED — no partner smoke test: fk-dev (100.91.108.61) is reachable but tailscale: tailnet policy does not permit you to SSH as user "levander"; local drivers (oracledb 6.10.0 thin, tedious 16.7.1) are nobody’s production versions (bb/mkb-instant ^5.5.0, kh ^6.9.0, otp/unicredit-srb 14.2.0) — bounded only by both connection-managers being byte-identical between 6.32.2 and 6.37.8; Model.sync() has never met a partner’s real index inventory. Merge preconditions: a bb/mkb-instant boot on a restored partner schema with syncOnStart: true, an MSSQL partner on its own tedious 14.2.0 writing a NULL BLOB, and the built image actually containing patches/. Partner merges: four of five clean, only mkb-instant conflicts (^6.32.2 vs devel ^6.30.1) and must resolve to ^6.37.8, not “keep ours” (a wrong resolution fails loudly — 6.37.8-stamped hunks can’t apply to 6.32.2 and --error-on-fail aborts). Reusable gotchas: yarn install --check-files is required once node_modules/sequelize goes missing (plain yarn install short-circuits on the integrity check → Patch file found for package sequelize which is not present); a missing patches/ dir is a silent no-op even under --error-on-fail (applyPatches.js:58-61 prints “No patch files found”, exit 0) so the boot guard is the only backstop — don’t prune it; patch-package must be a runtime dependency because production images run yarn install --production (vuer_build/base/vuer_oss/Dockerfile:162, vuer-release/install/install-app.sh:19) — cost 14 new packages incl. open@7.4.2; core devel needs Node >= 24 (geoip-lite@2.0.3) despite engines.node: ">=22.18.0"; jest here needs --testPathPatterns (plural); postinstall-postinstall reddens depcheck unless added to .depcheckrc.json ignores. Process note: the final re-review could not be completed by an independent agent (3 dispatches died on API errors) — the controller verified the 3 must-fixes directly, weaker evidence, recorded as such — FKITDEV-8279, vuer_oss, FKITDEV-7973-sequelize-pool-fix

2026-08-06

  • FKITDEV-9200 — Playwright→k6 E2E migration, first 12 files ported (93/96 cases) on chore/FKITDEV-9200-e2e-k6, NOT committed (worktree /Users/levander/coding/facekom/vuer_oss-FKITDEV-9200). Ported: auditlog, compatibility-test, cronjobs, media-content, open-hours, flow-editor-list, reports/{feedbacks,users,video-calls}, users/new-user, emergency-shutdown, callback-request. 3 cases dropped — all media-content file uploads: k6/browser has no FileChooser, no waitForEvent('filechooser'), no Locator.setInputFiles (page.waitForEvent() accepts only 'console'|'request'|'response'). staticendpoints.test.ts deliberately NOT ported — it exists only to collect V8 coverage and k6 has no page.coverage.*. all.ts restructured from concurrent scenarios into ONE sequential scenario with maxDuration: '1h' (scenarios without startTime all fire at t=0, destroying the stateful chain). Harness came from FKITDEV-9041, nothing built from scratch: vuer_docker 8ae9f0c (PR #223) k6.yml → stock grafana/k6:master-with-browser, mounts test/tests/k6/e2e, run /e2e/${K6_TEST_FILE:-all.ts}, env CI_DOMAIN only; vuer_oss 0e63bcd166 (PR #8085, tip of origin/devel). GOTCHA: nothing in CI verifies the k6 suitetest/tests/k6/tsconfig.json is separate, root tsconfig excludes test/, yarn lint ignores test/*, no typecheck script ⇒ typecheck by hand with tsc -p test/tests/k6/tsconfig.json. Hard k6 limits (vs @types/k6 2.0.1): newContext() throws if one is already open (browser/index.d.ts:754-766) ⇒ 1-to-1 Browser↔BrowserContext, a second actor must be a second page, and every test MUST close its context or all later tests die; no file upload, no coverage, no page.route(), no Node/require('server/**'), no :has-text() (use locator('button',{hasText:'…'})). Translation rules that bite: k6 doesn’t auto-wait on navigation → Promise.all([page.waitForNavigation(), locator.click()]), but do NOT add it when the click is already followed by page.waitForURL(...) (second waiter misses a completed navigation and hangs); Playwright expect() auto-retries, k6 check() does NOT → retried assertions need a waiting locator. Still blocked: 30 of 45 tests seed fixtures by booting the real Node app in-process (test/tests/support/helper.ts imports server/db/sequelize, models, UserService, FlowService, acl) — k6 has its own JS VM; 4 options weighed, undecided, this is the gating decision. Ordering lost: playwright.config.ts chains 14 projects via dependencies; OpenHoursSetup is load-bearing (setOpenHours('00:00','24:00') × 7 days — without it the vuer_css customer flow never renders its callback button). Open: k6.yml never passes K6_BROWSER_ARGS ⇒ docker path has no fake camera/mic and no --disable-web-security (needed by compatibility-test + callback-request lobby; README documents them for native runs only); suite is destructive under NODE_ENV=dev and can erase the DB. Vacuous assertions in the originals reproduced faithfully (hasEmailError()/hasRightsError() return !!page.locator(...); several expect().toHaveText() in open-hours.test.ts missing await) — FKITDEV-9200, k6-e2e-harness-vuer-oss, playwright-to-k6-translation-recipe

2026-08-05

  • FKITDEV-8581 / SLARAFIPI-53 (Raiffeisen girinfo) — MAJOR CORRECTION: the earlier reply was WRONG and is RETRACTED; the waiting task IS a real blocking GIRO gate. Established by direct code reading on vuer_oss origin/customization/raiffeisen @ tip 9fd6813dd2. Retracted claim (from the draft /Users/levander/coding/facekom/SLARAFIPI-53-reply.txt): “a ‘Sikeres’ nem feltétele annak, hogy a GIRO adategyezés lefutott… elvileg meg nem érkező GIRO mellett is el lehetett jutni ‘Sikeres’-ig.”over-generalised, not true of current code; reporter Bihari Péter (Raiffeisen) challenged it and is essentially right. What was right: identificationStatus='verified' IS written unconditionally in onFinished() (customization/flow/myra-self-service-v2-phase-1/…flow.handler.js:240). What was wrong: that write is unreachable without passing the gate — SelfServiceV2Service.finish() (:408) returns early unless serviceProgress==='wrapup' and has exactly one caller (:549); waiting advances from only two sites, both requiring a terminal GIRO state (customization/listeners/self-service-v2.js:1655, customization/server/service/GirinfoService.js:90); and skip() throws (:843-846, step.required !== false; the waiting proto has no required key). ⇒ no girinfo = room PARKS on waiting and expires/fails. Refinement found while verifying: the gate is “GIRO reached a TERMINAL state”, not “GIRO succeeded” — the listener path accepts ['resolved','rejected','cancelled'] and parks on a falsy compareCustomerData(), while the GirinfoService path is strictly resolved and fails the room (selfServiceV2.fail()) on !acceptable. TERMINOLOGY TRAP = the whole apparent contradiction (customization/portal/PortalData.trans.js): field identificationStatus=“Ügyfél állapot” (:80); value verified=“Ellenőrzés sikeres” (:277); value finished=“Sikeres” (:286, a LATER post-e-sign state set by RaiffeisenService.esignOfferUpload) — the old reply said “Sikeres”, Bihari asked about “Ellenőrzés sikeres”, two different enum values. What actually happened in the 18 rooms (2025.07.02–2025.11.26): girinfo DID arrive (that’s what released waiting); the logikai adategyezés never ran — pre-f830fd8e5a the gate advanced on GIRO resolve without calling compareCustomerData(), which instead sat on customer-portrait (usually running before GIRO returned). Fixed by f830fd8e5a (FKITDEV-7667, m3szi, 2025-10-22), prod 2025-11-28, no new cases since. The waiting step is not new — proto v8 (94d3ee2df6, FKITDEV-1615, 2023-10-27), so old v13/v14 rooms had it; the gap was the missing comparison call. THREE residual holes — “Ellenőrzés sikeres” still does NOT prove a real comparison: (1) eMRTD fail-OPEN by constructionGirinfoService.js:339-343 returns true without comparing if the eMRTD result isn’t CHECK_SUCCESS, deliberate + unit-tested (customization/test/tests/unit/services/GirinfoService.test.js:136-142 asserts exactly this); plus :335 development.skipCustomerDataComparisonCheck (default false, true in config/dev.json); (2) gate vs room-page tile are DIFFERENT comparisons with OPPOSITE defaults — gate skips postal-code+city (:278-279, default true), the “Logikai adategyezés” tile checks them (customization/listeners/self-service-checker.js:107,110, default false) and recomputes at read time“Ellenőrzés sikeres” + “Logikai adategyezés: sikertelen/nem elérhető” is a LEGITIMATE, EXPECTED pairing and likely what the customer is actually seeing; (3) display bugs still openGirinfoService.js:28 swallows the girinfoStatus save error at debug, and :69 is missing an await on SelfServiceRoom.findByPk (bare Promise always truthy ⇒ the if (!selfServiceRoom) null-check can never fire) ⇒ tile shows “Kérés folyamatban” while the BackgroundProcess is already resolvedany “Sikeres + Girinfo folyamatban” query yields FALSE POSITIVES; neither open PR fixes this. NEW FINDING (flagged, NOT reproduced — may warrant its own ticket): flow proto is now v15 (…flow.proto.js:4, ce08873962, FKITDEV-9081 AI Act, 2026-07-20), task order 1 ai-act / 2-3 dynamic-id front+back / 4 emrtd / 5 customer-portrait / 6 liveness-check-v1 / 7 waiting / 8 data-confirmation; server/queue/rpc_server/AiActRPCServer.js:20 calls finishCurrentTask() with NO step-type check (contrast GirinfoService.js:88, which guards currentStep?.type !== 'waiting') and is registered (server.js:397, queue rpc-ai-act) ⇒ a late/duplicate acceptAiAct RPC while the room sits on waiting would push it past the GIRO gate → “Ellenőrzés sikeres” with no girinfo — the one path by which the retracted claim could still be true. IMPLICATION FOR PR #7939 (feature/FKITDEV-8581-girinfo-verification-gate, still OPEN, never reviewed, merge conflicts; adds isGiroDataMatchVerified() + an onFinished gate): its giro-not-resolved case is now largely REDUNDANT (the waiting gate already blocks that), and it reuses compareCustomerData() so it INHERITS the eMRTD fail-open hole; remaining value is defence-in-depth against the two bypass routes (AI Act RPC, and the isRecording-gated selfService:flow:finish at server/transport/session/SelfServiceTransportSession.js:290-300) ⇒ worth re-scoping before merging. Corrected reply drafted at /Users/levander/coding/facekom/SLARAFIPI-53-reply-2.mdFKITDEV-8581

2026-08-04

  • FKITDEV-9022 — FIRST PUBLISH GREEN: the registry is no longer empty. @techteamer/acl@2.0.2 is PUBLISHED to npm.facekom.net — the first package on the registry — and proven e2e: npm view returns it, npm install … --registry npm.facekom.net in a clean dir + require() exposes ACLService/ACLError/ACLManager, and the version guard is confirmed idempotent (npm view <name>@<version> now exits 0 ⇒ the workflow’s publish step would correctly SKIP a republish). The 2026-07-22 real_groups: [] / 403 blocker is retired WITHOUT the GitHub App: infra provisioned the htpasswd-backed bot account techteamer-ci and granted it @techteamer/* access+publish in the Verdaccio packages config — an htpasswd user’s own username lands in the token’s real_groups, so the ACL matches with no GitHub org membership; the NPM-SH org install now only matters for future human GitHub logins / Phase-2 reads. Non-interactive token minting (what CI + rotation should use): curl -X PUT -u 'techteamer-ci:<pw>' https://npm.facekom.net/-/user/org.couchdb.user:techteamer-ci -H 'content-type: application/json' -d '{"name":…,"password":…}' — a plain PUT gives 409 “user registration disabled”, the basic-auth retry gives 201 + token; npm login --registry … --auth-type=legacy is equivalent (--auth-type=legacy is load-bearing — npm’s default web auth-type bounces into the GitHub OAuth flow the bot can’t use). Tokens are 90-day HS256 JWTs ⇒ standing rotation duty for whoever owns FACEKOM_NPM_TOKEN. Allowlist findings — the list is narrow and drifts: the Tailscale exit node exit-vpn (37.76.13.180) was blocked until infra adjusted it today, and the user’s home IP had silently rotated off after Jul 22 (entries age out with no notice). fk-dev (GCP egress 34.158.19.122) is also blocked, but that is irrelevant to CI — it’s the user’s personal GCP test node, completely separate from FaceKom infra, so it says nothing about the runners’ network. Runner egress to npm.facekom.net still needs a routine confirmation from infra (open ask #4) — never documented, no indication it’s broken. Remaining: FACEKOM_NPM_TOKEN org secret reported set by the user 2026-08-04 (not independently verifiable — reading org secrets needs admin:org, absent from our gh token), runner-egress confirmation, user go → commit+push the 7 branchescompare links only, no auto-PR. Local state: ~/.npmrc on the Mac now holds the bot token; the personal wowjeeez token is backed up at ~/.npmrc.bak-9022FKITDEV-9022
  • FKITDEV-9022 (later same day) — user gave the GO: all 7 branches committed + PUSHED. Every repo is now on chore/FKITDEV-9022-npm-facekom-publish with the single-line message chore: [fkitdev-9022] publish to npm.facekom.net (no body, no trailers), solo-author wowjeeez: acl e16e1bd, janus-api 182dfc9, mq e044ce9, video-processor 39ef73d, xlsx c473103, archiver-zip-encrypted 67c012e, timestamp_service aff10e3. ⚠️ New gotcha worth remembering — fresh clones inherit the GLOBAL git identity: the clones under /Users/levander/coding/facekom-v2-clones had no per-repo identity and picked up the global andras.lederer@alpiq.com (wrong org), so the first push went out with the Alpiq author — fixed with git commit --amend --reset-author + force-push to the wowjeeez noreply identity. Narrowed-refspec clones rejected a plain --force-with-lease (“stale info”) — the explicit --force-with-lease=<branch>:<oldsha> form is required. Per-repo user.name/user.email are now set in all 7 clones. FACEKOM_NPM_TOKEN org secret reported set by the user (still unverifiable — reading org secrets needs admin:org, absent from our gh token). PRs intentionally NOT opened — compare links handed to the user. Next: runner-egress confirmation from infra; PR creation/review/merge (acl’s first CI run will no-op — the version guard sees 2.0.2 already on the registry and skips the publish); Phase-2 consumer repoint later — FKITDEV-9022

2026-07-31

  • SECOND CORRECTION (same day) — the ts-jest@29.4.11 “broken publish” claim is FULLY RETRACTED, and the ignore-optional finding is narrowed to macOS-local (CI is green). Two things changed after further verification of the vuer_css test-infra work; both folded into jest30-ignore-optional-native-resolver with the earlier text superseded in place, plus FKITDEV-8887, vuer_css, agent-context, TOPICS. (1) ts-jest is innocent — it was a poisoned LOCAL Yarn cache entry, not a bad upstream publish. After yarn cache clean ts-jest + a fresh yarn install --frozen-lockfile, node_modules/ts-jest/dist/index.js is present and ts-jest@29.4.11 works fine; the full unit suite passes against stock 29.4.11 (119 suites / 1051 passed / 47 skipped / 0 failures). The dist-less artifact I inspected — containing the publisher’s npm-view.err with an npm E404 from /home/runner/.npm — existed only at ~/Library/Caches/Yarn/v6/npm-ts-jest-29.4.11-<hash>-integrity/. Do NOT pin ts-jest to 29.4.10; there is nothing to pin. Real, reusable lesson that replaces it: a Yarn v6 cache entry can be silently corrupt and will be reused across installs indefinitely (nothing re-validates it); symptom is an installed package whose dist/ is missing; fix is yarn cache clean <pkg> then reinstall; and a stray CI/build log (npm-view.err, *.log) inside an installed package directory is a tell-tale of a bad cache artifact, not proof of a bad publish — verify against a fresh npm pack before blaming upstream. (2) The ignore-optional root cause STANDS exactly as written, but it is macOS-LOCAL, not a CI problem. .yarnrc --install.ignore-optional true@unrs/resolver-binding-<platform> never installed → require('unrs-resolver') throws “Cannot find native binding” → jest-resolve.findNodeModule() returns null for every module: all confirmed. New facts: it is NOT caused by --ignore-scripts (re-tested with a full yarn install --frozen-lockfile, scripts enabled so napi-postinstall ran — binding still absent, unrs-resolver still fails; my intermediate --ignore-scripts suspicion was wrong); and CI is GREEN.github/workflows/pull-request.yaml installs yarn install --frozen-lockfile under the same .yarnrc, and all 7 checks pass on the FKITDEV-8887 head commit, including Unit Tests. So the Linux self-hosted runners resolve the binding fine and only macOS/arm64 local dev is affected. Why CI differs is recorded as an OPEN QUESTION, not an assertion (warm runner node_modules, a different fetch path for the linux binding, a glibc fallback, or a globally-present binding — all untested). Consequently the “drop/scope the .yarnrc flag” repo-wide recommendation is DOWNGRADED to a local dev-environment workaround (npm pack @unrs/resolver-binding-darwin-arm64@1.12.2 → extract into node_modules/@unrs/resolver-binding-darwin-arm64): changing .yarnrc is not justified by the evidence when CI is unaffected. The old [!question] Check CI before changing anything callout is resolved with this answer. FKITDEV-8887 status: unit suite green against stock dependencies with only the local binding added — yarn.lock and package.json are untouched by any of this, PR #3066’s 15-file diff intact — jest30-ignore-optional-native-resolver
  • CORRECTION — the vuer_css yarn test:unit breakage is .yarnrc ignore-optional, NOT ts-jest@29.4.11. Yesterday’s diagnosis was wrong and has been rewritten across the vault. Real root cause (verified): vuer_css’s .yarnrc contains --install.ignore-optional true; Jest 30’s jest-resolve@30.4.1 depends on unrs-resolver@1.12.2, which ships its platform-specific native binding as an optionalDependency (@unrs/resolver-binding-darwin-arm64 on Apple Silicon, @unrs/resolver-binding-linux-x64-gnu elsewhere). ignore-optional skips it → require('unrs-resolver') throws “Cannot find native binding”Resolver.findNodeModule() returns null for EVERY module — verified null for ts-jest, jest-circus, lodash, and jest-resolve itself. Jest reports whichever module its config mentions first, which is why it masqueraded as a ts-jest fault and why swapping ts-jest versions changed nothing; the jest-circus/build/runner.js not found error recorded yesterday as “a second unrelated break” is the same single root cause. Diagnostic one-liner worth keeping: node -e "const R=require('jest-resolve').default; for (const m of ['lodash','jest-resolve']) console.log(m, R.findNodeModule(m,{basedir:process.cwd()}))" — both null ⇒ missing native resolver binding, not a per-package problem. Local workaround (node_modules only, no package.json/yarn.lock change): npm pack @unrs/resolver-binding-darwin-arm64@1.12.2, extract, copy the package folder to node_modules/@unrs/resolver-binding-darwin-arm64. ⚠️ Repo fix to consider (WITHDRAWN — see the correction bullet above): “drop or scope --install.ignore-optional true, since jest 30 now genuinely needs an optional native dep — check CI first: if CI installs with the same .yarnrc its unit tests are broken too; if CI is green, CI installs differently.” CI turned out to be green, so no repo change is justified. Result: yarn test:unit runs clean on the merged FKITDEV-8887 branch — 119 suites passed, 1051 tests, 47 skipped, 0 failures. ⚠️ “What survives about ts-jest” (FULLY RETRACTED — see the correction bullet above): 29.4.11’s registry tarball genuinely has no dist/ and ships the publisher’s CI failure log as npm-view.err (npm E404, /home/runner/.npm) … still worth pinning 29.4.10.” The registry tarball is fine; that directory came from a corrupt local Yarn cache entry. Do not pin ts-jest. Note ts-jest-29411-broken-publish renamed → jest30-ignore-optional-native-resolver and rewritten; corrected FKITDEV-8887 (dated section), vuer_css (## Testing callout), agent-context (vuer_css gotchas), TOPICSjest30-ignore-optional-native-resolver

2026-07-30

  • FKITDEV-8887 — PR #3066 devel catch-up merge done (staged, NOT committed) + a devel-wide unit-test blocker found. vuer_css fix/FKITDEV-8887-ios-audio-resume was 23 commits behind origin/devel; only yarn.lock conflicted — package.json auto-merged cleanly (devel’s resolutions + the branch’s browserify/shell-quote: ">=1.7.3" audit fix both survived). Resolved by house precedent: regenerate, don’t hand-mergegit checkout origin/devel -- yarn.lock then yarn install --ignore-scripts --non-interactive (Yarn Classic 1.22.22). Verification trick worth reusing: diff the regenerated lock against the target branch, not against the conflict — the result differed from origin/devel by exactly 4 lines (shell-quote 1.9.0 → 1.10.0, key becomes shell-quote@>=1.7.3, shell-quote@^1.6.1), proving the branch’s critical-audit fix is preserved and nothing else churned; post-merge the branch differs from devel by exactly the PR’s 15 files. yarn lint clean. Merge left staged/uncommitted (analyze gate — commit only on explicit go, same as the rest of the ticket). NEW GOTCHA (own note): yarn test:unit now fails with Validation Error: Module ts-jest in the transform option was not found. ⚠️ The ts-jest root cause recorded here was WRONG — superseded by the 2026-07-31 entry below; see jest30-ignore-optional-native-resolver. (Original text, kept for the audit trail: ts-jest@29.4.11 is a broken upstream publish… local unblock = npm pack ts-jest@29.4.10… second, unrelated break jest-circus/build/runner.js not found sits behind it”. All three claims are false: the ts-jest tarball is fine (the dist-less copy came from a corrupt local Yarn cache — see the 2026-07-31 second-correction entry), it was not the cause, and the jest-circus error was the same bug, not a second one.) Re-confirmed repo trap: ~/coding/facekom/vuer_css has a narrowed fetch refspec (only customization/raiffeisen) → git fetch origin devel:refs/remotes/origin/devel explicitly. New note (since renamed + rewritten) jest30-ignore-optional-native-resolver; updated FKITDEV-8887, vuer_css, agent-contextFKITDEV-8887

2026-07-27

  • FKITDEV-7973 sequelize pool fix — PR #7852 review state captured (view-only, nothing written to GitHub). vuer_oss PR #7852 (feature/FKITDEV-7973devel, author wowjeeez) is open + mergeable_state: blocked, tip 7da69cba85 (2026-04-01) ~58 commits behind devel, PR body still holding the TÖLTSD KI placeholder. One review thread on server/db/sequelize.js:27 (the new {max:10,min:2,idle:10000,acquire:30000,evict:10000} block), three comments: (1) Pocok256 2026-05-06 + CHANGES_REQUESTED — the 1s default evict sweep is fine (so the evict:10000 override is unwanted) and he’d raise max (“anno a 100 is kevés volt”); (2) bencevarga666 2026-07-01 + CHANGES_REQUESTED — rebuts raising max: 7 processes share the pool, keep it bounded to avoid saturation, consider per-process pool configs, stay below the DB max_connections, and per the PostgreSQL wiki few concurrent connections is better; (3) Pocok256 2026-07-27 + COMMENTED (newest) — concedes: counting only 7 processes understates it since CLI/other tooling open their own connections, so max:10 is sufficient, and min could be 0 if idle connections close on a ~1s cadence (ambiguous whether he means idle:1000 or the default evict — his May comment points at evict). Net: max:10 settled; open asks = drop evict:10000, consider min:0; both CHANGES_REQUESTED reviews stand ⇒ PR stays blocked until changes + re-review; PR body needs filling; branch needs a devel catch-up. Still unaddressed from the ticket: Bence László’s “enable options.logging + benchmark, measure before finalizing numbers” — logging is hardcoded after the config spread so db.options.logging is non-overridable, which blocks the measure-first step. Note status flipped implementedin-review-blockedFKITDEV-7973-sequelize-pool-fix
  • FKITDEV-7973 (later same day) — review feedback ACTED ON, commit pushed. c89124e29cfaecc3e19dd00def53f26f9302e4a5 “fix: set pool min to 0 and use default evict interval” pushed solo-author (Andras Lederer) to feature/FKITDEV-7973; PR #7852 head now at that SHA (was 7da69cba85). Change = 2 files, +4/−6: server/db/sequelize.js and its mirror test/lib/utils/db.utils.js (the test harness duplicates the pool config — both must move together) get min: 2min: 0 and the evict: 10000 override deleted so Sequelize’s default 1s evict interval applies; max: 10/idle: 10000/acquire: 30000 unchanged (acquire lost its trailing comma, now last property, standard-style). That is exactly Pocok256’s 2026-07-27 condition (“min could be 0 if idle connections are closed on a 1s cadence”) plus his May ask (default 1s check is fine) — one change, since min: 0 is only safe because the sweep is fast; the earlier idle: 1000-vs-evict-default ambiguity was resolved in favour of evict, leaving idle: 10000 untouched. Verified: node --check both files OK; eslint --max-warnings 0 on both files exit 0 (ESLint 9 flat config via FlatCompat/standard); git show diff shape confirmed; remote ref + PR head both at c89124e2. Worktree vuer_oss/.worktrees/feature/FKITDEV-7973 kept. New repo gotcha captured: the packaged yarn lint script passes --ignore-pattern "test/*", so test files are NOT covered by yarn lint or the CI lint gate — lint them explicitly with ./node_modules/.bin/eslint <paths> (the flat config does define a test/** block, so explicit invocation works). Still open / deliberately untouched: PR stays mergeable_state: blocked — both CHANGES_REQUESTED reviews (Pocok256, bencevarga666) still stand and no re-review was requested, no PR comment posted; PR body Summary still the TÖLTSD KI placeholder; branch still ~58 commits behind devel; Bence László’s options.logging + benchmark measure-first guidance still unaddressed (logging still hardcoded after the config spread ⇒ db.options.logging non-overridable). Note status flipped in-review-blockedreview-feedback-addressedFKITDEV-7973-sequelize-pool-fix

2026-07-24

  • FKITDEV-9022 npm.facekom.net — publish workflows must run on SELF-HOSTED runners. Discovery: npm.facekom.net (public IP 92.119.122.189, resolves publicly) is IP-allowlisted at nginx → the whole site returns 403 from outside the FaceKom network; the 2026-07-22 recon 200s only worked via the user’s VPN egress. So GitHub-hosted ubuntu-latest runners can never reach the registry → publish workflows must run on the FKITDEV-8981 self-hosted pool. Change applied (2026-07-24, uncommitted/unpushed): all 7 publish.yaml switched runs-on: ubuntu-latest[self-hosted, node] (lowercase — the live 8981 label; pool active since ~2026-06-24, proven by 5 merged vuer PR-check migrations); setup-node@v6 kept (fleet pattern = per-run Node provisioning); 6 workflows byte-identical to acl’s, timestamp_service differs only by its 2 working-directory lines. Open infra asks (one msg to Bence/infra): (1) install the NPM-SH GitHub App on the org (fixes real_groups for all logins); (2) bot-account token for FACEKOM_NPM_TOKEN org secret (90-day rotation); (3) confirm the runner group covers the 5 lib repos 8981 never touched — acl, video-processor, xlsx, archiver-zip-encrypted, timestamp_service (an unavailable label queues jobs forever, silently); (4) confirm the runners’ network can reach npm.facekom.net (never documented; gh API introspection needs admin:org → 403 for us). Caveat: xlsx builds via make → runner toolchain beyond git+Node undocumented, first-run failure possible. Cross-ref: FKITDEV-8981 mq #101 / janus-api #50 PRs still OPEN but touch pull-request.yaml (different file, no conflict with publish.yaml) — FKITDEV-9022

2026-07-22

  • FKITDEV-8387 STRATEGY REVERSED: .js shims → DIRECT RENAME. After reviewer feedback on vuer_oss PR #8059, the shim plan (B) was dropped for plan A: entrypoints are now real .ts files invoked as command=node server.ts, no shims. Landed across vuer_oss (7 entrypoints), vuer_css + portal_css (1 each), vuer_build (75 supervisor confs) and vuer-release (12); all three code PRs CI-green 8/8. Five durable findings: (1) Node type-stripping floor is 22.18, NOT 22.6 — 22.6 needed --experimental-strip-types; empirically node:22.6 on a .ts file → SyntaxError: Missing initializer in const declaration, node:22.18 runs it; repos pin engines >=22.18.0, images/CI use 24.x, but vuer-release pins a floating NODE_VERSION: 22. (2) soap_server.js suffix trapvuer_oss/server/logger.js picks the log4js channel via process.argv[1].endsWith('server.js') and 'soap_server.js'.endsWith('server.js') === true, so bb/kh’s SOAP entrypoint was silently inheriting the vuer channel; the rename dropped it to unknown with no error → fixed to endsWith('server.ts') || endsWith('soap_server.js'); general lesson = suffix-matching entrypoint dispatch is fragile under rename. (3) RELEASE BLOCKER — unversioned partner supervisor overlays: vuer_build/partner/*/vuer_oss/Dockerfile does FROM harbor…/vuer_oss:${VUER_VERSION} (version-pinned app) then COPY supervisor_vuer_oss_docker.conf (unversioned, from main) ⇒ conf and app version decoupled → flipping the confs breaks rebuilds of older release tags, and ~94 origin/customization/* branches still carry .js so each partner breaks on its next build until it merges devel; not fixable by merge ordering. Mitigations: hold the build/release merges until the first release tag with the rename is cut, delete redundant overlay confs so partners inherit the base image symlink to the app’s own conf, or make overlays release-aware; merge hazards customization/kh (edits both confs) + customization/nusz (edits server.js/cron.js → rename+modify). (4) depcheck CI-only false positive on vuer_css @emotion/is-prop-valid — the literal require() lives in the 865 KB minified web/sdk/web-sdk.js:205, which CI’s depcheck can’t parse (OOM/timeout) and then treats as having no requires; suppressed via .depcheckrc.json, and removing the dep would be wrong (flips to “missing”). (5) queue optional flag is NOT dead code — multi-connection MQ is live (server.ts:465, background.ts:197, bin/attachment.js:52 read esign.queueConnection + connectionPool.hasConnection()), so the FKITDEV-3191 ECONNREFUSED swallow covers a real partner setup (external eSign RabbitMQ down at boot); a “dead code” deletion was reverted. Plus the TechTeamer commit ruleset (^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(!)?(\([^)]+\))?: [^\n]{1,100}) rejecting default git revert subjects + >100-char subjects. New notes unversioned-partner-supervisor-overlays, techteamer-commit-message-ruleset, depcheck-false-positive-minified-bundle, vuer-oss-optional-queue-connection; updated FKITDEV-8387, typescript-in-vuer-repos, entrypoint-rename-blast-radiusFKITDEV-8387
  • FKITDEV-9022 npm.facekom.net — VPN worked, registry recon done + hard publish blocker found. npm.facekom.net = Verdaccio 6 behind nginx (titled “Facekom npm”, plugin verdaccio-github-oauth-ui), currently EMPTY (no packages; anon reads 401, UI listing []). Login flow = GitHub App “NPM-SH” (client_id Iv23liP34v8mLsDTgEkF, TechTeamer-owned, “Self hosted verdaccio”) → web UI hands a npm config set //npm.facekom.net/:_authToken <JWT> snippet. Token = HS256 JWT (claims real_groups/name/groups), 90-day expiry → the FACEKOM_NPM_TOKEN org secret needs 90-day rotation (prefer a bot/service account). BLOCKER: user wowjeeez authenticates (npm whoami OK) but @techteamer/acl publish → 403 “not allowed to publish” because the token’s real_groups: [] — the NPM-SH GitHub App is authorized for the user but NOT INSTALLED on the TechTeamer org, and user-to-server tokens only surface memberships for orgs where the app is installed. App is private (no public Install button) → a TechTeamer org admin must install via https://github.com/apps/NPM-SH/installations/new, then the user re-logs-in to mint a token carrying the org group. Validation (dry-run green): acl builds the CI way with yarn install — NOT npm install, which trips an ERESOLVE peer conflict (eslint 10 vs eslint-config-standard) that Yarn Classic v1 silently ignores (repo has no yarn.lock); npm publish --dry-run routes to https://npm.facekom.net/, restricted access, tarball 35 files / 9.8 kB. In progress (uncommitted): fanning the acl pattern (canonical publish.yaml + publishConfig with trailing-slash registry URL) to janus-api, mq (canonical workflow chosen over its semantic-release), video-processor, timestamp_service (rename → @techteamer/timestamp-service + drop private:true), plus fresh clones of xlsx + archiver-zip-encrypted; all on chore/FKITDEV-9022-npm-facekom-publish branches, no commits/pushes yet — FKITDEV-9022
  • FKITDEV-9022 (later same day) — fan-out COMPLETE: all 7 repos carry the publish setup locally (uncommitted/unpushed; xlsx + archiver-zip-encrypted freshly cloned; every publish.yaml byte-identical to acl’s, all dry-runs → npm.facekom.net/ restricted). timestamp_service rename SUPERSEDED: it’s a Yarn-workspaces monorepo — root stays private:true (yarn refuses workspaces otherwise) and isn’t the lib; the real package is package/timestamp_service@techteamer/timestamp@2.0.2 (consumers vuer_oss/esign_oss depend on ^2) → no rename anywhere, publishConfig on the inner package, workflow = canonical +2 working-directory lines (install stays at root). Quirks: archiver’s committed .npmrc (npmjs) loses to publishConfig (tested); xlsx = SheetJS fork, builds via make, tab-indented package.json. Remaining: auth path (user leaning: infra-minted bot token for FACEKOM_NPM_TOKEN instead of NPM-SH org install), org secret, user “go” for commit+push, compare-link PRs, Phase 2 after consumer repoint — FKITDEV-9022
  • FKITDEV-9059 (Cofidis) — MJML v5 ESM upgrade silently broke cofidis email templates (green CI / broken runtime). The devel→cofidis merge pulled in FKITDEV-8727 MJML v4→v5 (c9602a519e), which is ESM-onlyserver/e-mail/EmailService.js now await import(...)s letter templates. Node 22 auto-detects any customization/email/*/*.letter.data.js that mixes a top-level import with a require() as ESM → ReferenceError: require is not defined at EmailService.init → the letter type never registers and its email never sends. Debugging trap: the naive scope was “41 of 49 files contain require(” — WRONG; a pure-CommonJS file (no import) loads fine, only the 6 mixed files are at risk, and 5 of those had a createRequire(import.meta.url) shim so only e-mail-invite (bare require, the registration invite) actually crashed at boot — matching the box log. Fix = require() → ESM import (relative specifiers need explicit .js; named imports resolve against module.exports = {} via Node’s CJS named-export detection) in all 6; committed solo-author 52a0843a1e on chore/FKITDEV-9059-cofidis-update-2026-07-13-fixes (parent 6fac58ba4b), NOT pushed; verified on fk-dev (letter-registration errors 3/boot → 0). CI missed it because unit tests never boot EmailService. Reusable: after any ESM migration of a shared loader, grep customization/ for mixed import+require. New note mjml-v5-esm-breaks-commonjs-email-templatesFKITDEV-9059
  • FKITDEV-9059 (Cofidis) — FaceKom dev email lands in a baked-in Mailtrap Sandbox inbox (it’s not “not sending”). config/dev.json email.transport.SMTP bakes a Mailtrap Sandbox inbox (host smtp.mailtrap.io [legacy; current sandbox.smtp.mailtrap.io], port 2525, user 643414e4c00185), so on any fresh dev box registration/verification mail is delivered — into the original-dev/shared inbox you can’t see. Route it to your own inbox by overriding email.transport.SMTP.hostsandbox.smtp.mailtrap.io + auth.{user,pass} in the bind-mounted vuer_docker/tailscale/config/vuer_oss-local.json (getconfig local layer; config/docker.json is never loaded under NODE_ENV=dev). Sandbox creds only auth against sandbox.smtp.mailtrap.io, not legacy smtp.mailtrap.io. Product distinction: Sandbox = sandbox.smtp.mailtrap.io + per-inbox user/pass (~14 hex), catches all mail; Email Sending (live) = live.smtp.mailtrap.io + api/32-char token, delivers for real (wrong for testing). Verify with nodemailer.verify() + test sendMail first (require nodemailer by absolute path /workspace/vuer_oss/node_modules/nodemailer — ESM import from /tmp can’t resolve app node_modules). New note mailtrap-sandbox-inbox-dev-email; sibling sms-verification-code-dev-testingFKITDEV-9059

2026-07-20

  • FKITDEV-9059 (Cofidis devel update) — two reusable findings extracted from the per-ticket dossier. (1) Partner branches inherit devel’s full CI pipeline on their first devel-merge — systemic, will recur: legacy customization/* branches ran a single job (lint-and-build, old pull-request.yaml blob ec0a1244); devel’s current workflow (blob dda79403) runs lint / test / audit / depcheck / sonar / build, so four jobs execute on the partner branch for the very first time, surfacing years of latent breakage in one PR. On cofidis: 5 failure clusters, only 2 merge-introduced, the rest dating 2017–2024. Two structural amplifiers recorded as architectural constraints: partners fork core source files in place (no override layer — e.g. server/service/FlowLiveUpdateService.js, whose fork then violates the core unit test) and there is no customization-aware unit-test layer (jest.config-unit.js matches only test/tests/unit/**, no per-partner test dir) so a partner-specific test fix must diverge a shared core test file, which then conflicts on every subsequent devel merge — a recurring tax. (2) CVE-2025-7783 / GHSA-fjxv-7rqg-78g4 — critical form-data@2.3.3 (unsafe random multipart boundary, patched >=2.5.4) via EOL request@2.88.2 which hard-pins form-data: ~2.3.2; absent from devel (Audit green) because request is live partner code (vuer_oss customization/api/sms/SmsCofidis.js; vuer_css customization/server/web/api/{login,register,partner-register}.endpoint.js); confirmed red on customization/cofidis (#3100/#8040), customization/kh (#3098), customization/raiffeisen (#8055) ⇒ blocks every partner branch adopting the new pipeline. Interim fix in the repos’ existing house style (they already pin csurf/cookie, twig/minimatch, ts-jest/handlebars): "request/form-data": "^2.5.6" in resolutions + yarn install; real fix = drop EOL request (4–5 call sites) as a separate ticket. Debugging trap recorded: the Audit job’s ERROR: Unable to parse yarn audit output: SyntaxError … + Node 24 DEP0169 url.parse() lines are cosmeticimproved-yarn-audit merges child stdout+stderr into one NDJSON stream so the deprecation warning corrupts lines and the tool silently skips them; the same errors appear on green devel runs (proof: vuer_oss PR #8062, job 87891787317, Found 0 vulnerabilities, success). Exit code comes solely from the real advisory count — an initial diagnosis in-session got this wrong before deeper checking corrected it. New notes customization-branch-ci-pipeline-inheritance + cve-2025-7783-form-data-via-request; cross-linked from FKITDEV-9059, ci-github-branch-audit-chronically-red, customization-branchesFKITDEV-9059

2026-07-13

  • Drafted NÚSZ 1.9.11.48 test runbook (payload ASSNUSZ-76 + devel-update regression + AI-Act) — TJK source — nusz-1.9.11.48-test-runbook
  • Build/test host MIGRATED: ssh Facekomfk-dev Tailscale VM (verified 2026-07-01). The on-prem box behind the ssh Facekom alias (~/.ssh/config: HostName localhost, User lederera, ProxyJump FKJumpBoxroot@lederera-447-fk-hardver) is DECOMMISSIONED — Tailscale reports lederera-447-fk-hardver offline, last seen ~2026-06-27. Per user: “never use the ssh Facekom host again, we need to use the tailscale fk vm”fk-dev (100.91.108.61, command ssh ops@fk-dev.taild4189d.ts.net, Tailscale SSH, no keypair, no jump box). Unchanged guidance: still build native x86_64 on the remote host, NOT emulated on the Mac (qemu SIGSEGV exit 139 / overlay-FS I/O exit 125 / EPEL metalink 503s) — only the host moved. Agent gotcha (re-confirmed): the user’s shell aliases ssh/scp to a _kaku_wrapped_ssh function that is not loaded in a non-interactive shell → use command ssh / command scp for the raw binary. Other tailnet peers (oss-fk-dev 100.91.55.42, css-fk-dev, portal-fk-dev, esign-oss/css/api-fk-dev, css-sdk-demo-fk-dev) are per-service Tailscale sidecars on fk-dev, not separate build hosts. New canonical note dev-build-host; updated the docs that prescribed the old host: agent-context (dev-env table + warning), infrastructure (Remote Server section; the dnsmasq 100.103.48.49 / *-lederera.facekomdev.net chain died with the box — MagicDNS now), release-automation-design (vuer_build build.sh/sign-partner.sh run on fk-dev), nusz-1.9.11.47 (cut checklist), FKITDEV-8252 (UBI10 native-build host), FKITDEV-8959 (test host), instacash-esign-dev-box-deploy, dev-box-cv-photo-processing-failures, dev-box-esign-container-startup-failures-2026-06-01 (old Facekom/FKJumpBox topology struck through), instacash-external-api-esign-headless-test-2026-06-01, FKITDEV-8787 (pending functional verification must be redone on fk-dev), plus facekom-v2 dev-environment / working-on-facekom / VERIFICATIONdev-build-host
  • FKITDEV-8387 implementation, Task 6 (vuer_css) — second repo in the multi-repo .ts-shim rollout (Tasks 1-5 covered vuer_oss’s seven entrypoints separately). Single server.js entrypoint shimmed to require('./server.ts'); vuer_css/server/logger.js uses a static log channel list (no process.argv[1] sniffing, unlike vuer_oss) so no logger change needed — a notable repo-to-repo difference. 4 files touched (eslint.config.mjs, tsconfig.json, server.ts <void> Promise fix, bin/server/server.task.js watch list). tsc/eslint/yarn lint all exit 0, yarn test:unit 115/115 suites, 1064/1064 tests (0 failures). Commit b6513dc08ee91a2324786ecc44029d16004d9b2f on branch chore/FKITDEV-8387-ts-entrypoints, local only, not pushed — FKITDEV-8387

2026-07-10

  • FKITDEV-8387 scoping → durable TypeScript-mechanics note — captured how TS actually works in vuer_oss/vuer_css/portal_css (established by FKITDEV-8246 “TS Magic”, PR #7645 55035572bb; foundation for FKITDEV-8251): NO build step (tsconfig noEmit+erasableSyntaxOnly, nothing runs tsc, no typecheck job in CI in any repo), Node ≥ 22.18 strips types at runtime, files stay CommonJS (no "type":"module"), a cross-module require of a .ts module needs an explicit .ts extension (extensionless → MODULE_NOT_FOUND; hence require('../util/magic.ts')), root-level *.ts is SILENTLY UNLINTED (ESLint TS block files:['server/**/*.ts','customization/**/*.ts','client/**/*.ts']; tsconfig include same blind spot), Jest via @swc/jest (oss) / ts-jest (css/portal), @typescript-eslint/no-explicit-any is an ERROR (never fix a type error with any), and require('node:module').stripTypeScriptTypes(src) asserts erasable-syntax-clean — typescript-in-vuer-repos
  • FKITDEV-8387 gotcha → nyc (v18) cannot load .ts at all — hijacks the .ts extension handler (append-transformdefault-require-extensions/js.js), compiles TS as raw JS → SyntaxError: Unexpected token ':'; --extension=.ts/--include don’t help. So vuer_oss/supervisor_vuer_oss_e2e_test.conf (npx nyc node <entry>.js ×7) has been broken since FKITDEV-8246 “TS Magic” (Jan 2026) because server.js requires six .ts services at boot (server.js:48,83,99,108,109,110); nothing outside the git index references the conf (no CI job, no Docker repo). Fix = nycc8 (V8 coverage, no require hook) or retire; its own YouTrack ticketnyc-cannot-load-typescript
  • FKITDEV-8387 blast-radius fact → renaming any vuer entrypoint is a 4-repo coordinated release: 95 supervisor conf files hard-code command=node <entry>.js (75 vuer_build/partner/* across 35 partners, 11 vuer-release/projects/*/components/*, 2 vuer_docker/workspace/devtools/files/, only 7 in the three code repos); two SILENT traps — vuer_oss/server/logger.js:102–114 sniffs process.argv[1].endsWith('server.js')/etc. for the log4js channel (rename → everything to the unknown channel, no crash) + an 8th entrypoint soap_server.js on bb/kh customization branches only (not devel); motivates FKITDEV-8387’s .ts-module + .js-shim approach (keeps filenames literal) — entrypoint-rename-blast-radius

2026-07-08

  • FKITDEV-9022 npm.facekom.net publishing — documented the approach for publishing 7 standalone @techteamer/* library repos (xlsx, timestamp_service, mq, video-processor, archiver-zip-encrypted, janus-api, acl — all on master, NOT the vuer monorepo) to the private registry https://npm.facekom.net/. Mechanic (only real org precedent = TechTeamer/amqplib-asyncapi-template, which already declares publishConfig:{registry:"https://npm.facekom.net",access:"restricted"}): per repo add that publishConfig to package.json + one .github/workflows/publish.yaml (push-to-master, secrets.FACEKOM_NPM_TOKEN~/.npmrc, npm view <name>@<version> --registry … guard = idempotent/skip-if-published). publishConfig.registry only moves the publish target — default registry stays npmjs → dependency installs + downstream consumers unaffected; NO package renames. Decision (user, 2026-07-08): keep @techteamer/*, do NOT rename to @facekom/* → timestamp_service is the one special case: rename to @techteamer/timestamp-service + remove "private": true (both currently block publish). Correction: the earlier “janus-sdk publish.yaml reference impl” was WRONG — TechTeamer/janus-sdk = 404; only the amqplib template references the registry. mq special-cased (has release.config.mjs/semantic-release, which also honors publishConfig.registry, but no release workflow wired yet). Blocked on VPN: registry publish docs, CI token from the registry web UI, creating org secret FACEKOM_NPM_TOKEN, real publish test. Phase 2 (take repos private / stop public npm publish) must be sequenced AFTER consumers (vuer_oss/vuer_css/portal_css, Yarn-Classic v1 + offline mirror) are repointed at the private registry, or their CI/Docker installs break. Status: acl reference done + validated locally (branch chore/FKITDEV-9022-npm-facekom-publish off origin/master; publish.yaml + publishConfig added; JSON/YAML/logic checks pass) — not committed; other 6 pending user go; solo-author, no auto-PR — FKITDEV-9022

2026-07-03

  • FKITDEV-8747 NÚSZ daily-stat “eltérés” — enriched the investigation note with a source-verified fix analysis from vuer_oss PR #7929 (squash 5099b8ad8b, commits 56231e7c3c/78bd1b1ebe/7d16439620, merged 2026-05-28, nusz 1.9.11.48). It is the video-calls report / daily statistics feature and all changed files are CORE (not customization/nusz), surfaced by NÚSZ — not a call-count bug (raw counting logic unchanged; honest note). Three squashed fixes: (1) empty-period Service Level → null not 0 (CallsReportService.js ~L562: SL = calls>0 ? round((calls-lateAnswers)/calls*100) : null) on per-bucket and Sum/aggregate; client reportCalls.js renders null- (was always + '%', so 0% showed); (2) Sum-column SL aligned to the per-bucket rule — that mismatch was the reported “eltérés”; (3) locale plumbed end-to-end through the RPC queue (rpc_client/rpc_server Reports.js) + the new reporterDownload.process.js BackgroundProcess (a boolean true was passed instead of the locale string) → xlsx exports use the user’s UI language, reviving the FKITDEV-8639 locale fix that was dead on the download path. Test cases at /Users/levander/coding/facekom/FKITDEV-8959-8747-test-cases.md (also covers FKITDEV-8959) — FKITDEV-8747
  • fk-dev VM NÚSZ deploy + FKITDEV-8959 TC-8959-02 verification — documented the operational runbook for the fk-dev GCP dev-mirror VM (tailnet taild4189d.ts.net, 100.91.108.61; NOT the offline on-prem ssh Facekom box). Connect command ssh ops@fk-dev.taild4189d.ts.net (Tailscale SSH, no keypair; the kaku wrapper shadows ssh → use command ssh/command scp). Stack = vuer_docker compose + per-service Tailscale sidecars (oss-/css-/esign-*/portal-fk-dev), source bind-mounted /workspace/<repo>, supervisord per container; operator UI https://oss-fk-dev.taild4189d.ts.net (:10081 inside); postgresql peer-auth blocks psql -U postgres (use app Sequelize); nginx_proxy crash-loops (bypassed by sidecars). Deploy recipe (bind-mount, no rebuild): box has NO GitHub key → ssh-add ~/.ssh/id_ed25519 + command ssh -A to forward yours → on /workspace/vuer_oss: git fetch origin <branch> + git checkoutdocker exec vuer_oss sh -c 'cd /workspace/vuer_oss && yarn install && yarn build'docker exec vuer_oss supervisorctl restart all; verify supervisorctl RUNNING + Web server is listening on 10081 + UI HTTP 302. Branch consolidation: customization/nusz tip d426cc6ae1 carries BOTH 8747 (5099b8ad8b, PR #7929) + 8959 (519d3b933e, PR #8010 merged), vuer_oss-only; deployed 2026-07-03, restore box’s original bd8923d69f (InstaCash) when done. Gotcha: old fix/FKITDEV-8959-nusz-image-deletion auto-deleted on merge but local origin/… ref stale (narrowed refspecs, no prune) → git ls-remote to confirm. TC-8959-02 (key-inaccessible image deletion) PROVEN PASS: cron RemoveAttachmentDataCronJobCustomRemoveOldDataCronService.removeAttachmentData()getOldImageAttachments (type LIKE 'image/%' AND isArchived=false AND createdAt<cutoff, batched, excl. file) → removeOldAttachments key-guard (encryption?.key ? encryptBuffer : blank+encryptionId=null+skippedNoKey++; isArchived=true). KEY CHAIN for standalone test: encryption.key = Sequelize getter → cryptos.data.getActualKeycustomerKeyStorage.getKey (stub ⇒ null models offline key). Harness = Node script in bin/ (process-settings bootstrap + logger Proxy + crypto/customerKeyStorage stub + sequelize authenticate + raw-SQL seed → call REAL get/removeOldAttachments → SELECT before/after; deliver via command scp+docker cp+docker exec). RESULT BEFORE {isArchived:false,encryptionId:3,file_bytes:9} → tally {processed:1,archived:1,skippedNoKey:1,errored:0} → AFTER {isArchived:true,encryptionId:null,file_bytes:0}. Config attachments.active=true, expiryDays=7(dev.json)/28(docker.json) — 7-vs-28 retention with NÚSZ still OPEN — fk-dev-nusz-deploy-and-8959-verification

2026-06-30

  • Tailscale dev-box HTTPS enabled + 8b impl reviewed + ansible task posted (status stays in-progress; push still gated on Andras’s go). Andras toggled “HTTPS Certificates” ON → per-node tailscale cert issuance now works for the sidecars (clears the prior blocker). Correctness review of the kernel-mode 8b overlay = PASSED, no code changes needed — key insight: new topology (tailscale serve TLS-terminate → http://app:port) is identical in shape to the old nginx_proxy, so the app side behaves unchanged. Verified: compose merges clean; apps stay network_mode:host; apps listen 0.0.0.0 so host.docker.internal:host-gateway reaches them (Docker 29.6.1 supports host-gateway); app nginx serves HTTP on the ports (matches serve→http); each sidecar own bridge netns → own tailscale0 (no conflict); local.json host overrides make CORS/SAML/socket Origin pass. Three tailnet-admin prereqs flagged (owner Andras): (1) sidecar auth key MUST be NON-ephemeral — deploy’s existing tag:cloud key is reusable+EPHEMERAL → risks MagicDNS name flap (oss-fk-devoss-fk-dev-1) breaking hardcoded hosts + cert binding; use a reusable, non-ephemeral, pre-authorized tag:cloud key (state volumes already persist identity); (2) ACL grant team devices → tag:cloud:443 (+MagicDNS) or they resolve but can’t connect; (3) runtime check at wiring — confirm tailscale serve preserves the original Host header (old nginx_proxy set Host:$host); it does set X-Forwarded-Proto/For. janus/WebRTC media over tailnet = unsolved follow-up. Babylon task #884 → deploy (facekom_dev): create ansible playbooks for the fk-dev dev workflow — git checkout <branch> on host /workspace/<app> + docker exec <container> yarn && yarn build (pnpm for facekom_library) + supervisorctl restart all, parameterized by branch + component subset, referencing bin/vuer.sh checkout; components vuer_oss/vuer_css/esign_oss/esign_css/portal_css/facekom_library (vuer_cv excluded). Open: tailscale branch push to origin pending Andras’s go — tailscale-gcp-dev-box-migration
  • Tailscale dev-box 8b overlay BUILT + validated (status stays in-progress; unpushed, no commit on vuer_docker branch tailscale). KEY CORRECTION — “no app URL change” assumption was FALSE: apps compute separator = DEV_DOMAIN.endsWith('facekomdev.net') ? '-' : '.', so a tailnet DEV_DOMAIN (fk-dev.taild4189d.ts.net) flips to . → invalid dotted multi-label names like oss.fk-dev.taild4189d.ts.net (NOT MagicDNS-resolvable, NOT the sidecar name oss-fk-dev…). Fix stays ENTIRELY inside vuer_docker (zero app-repo edits): app host derivation is guarded if (!config.X) + getconfig deep-merges config/local.json last (both verified empirically — a test proved local.json overrides one key while preserving siblings); so vuer_docker ships a config/local.json per app, bind-mounted at /workspace/<app>/config/local.json, setting hosts.* explicitly to <prefix>-fk-dev.taild4189d.ts.net. Files added on branch tailscale: tailscale.yml (8 userspace tailscale/tailscale:stable sidecars — network_mode host, TS_USERSPACE=true, --advertise-tags=tag:cloud, per-svc TS_HOSTNAME+TS_SERVE_CONFIG, DRY via YAML anchors, named ts-state-* vols, + 5 app-svc stubs merging the local.json mounts); tailscale/serve/{oss,css,css-sdk-demo,esign-oss,esign-api,esign-css,portal,library}.json (each tailscale serve HTTPS ${TS_CERT_DOMAIN}:443http://127.0.0.1:<port>, ports 20080/30080/30081/20180/20181/30180/30380/50080); tailscale/config/{vuer_oss,vuer_css,esign_oss,esign_css,portal_css}-local.json (explicit hosts.*, +esign portal.url; vuer_oss hosts.cv=null CV-out-of-scope); tailscale/README.md; .gitignore+=tailscale/tailscale.env. Validated: docker compose -f dev.yml -f vuer-oss.yml -f vuer-css.yml -f esign-oss.yml -f esign-css.yml -f portal-css.yml -f facekom-library.yml -f tailscale.yml config -q → EXIT 0 (5 local.json + 8 serve mounts present in merged config). Networking: each sidecar host-net + userspace tailscaled, tailscale serve proxies to 127.0.0.1:<app-port> (apps unchanged, still network_mode host), per-svc MagicDNS name + own cert; nginx_proxy from dev.yml no longer the access path (harmless if left running). Caveats: needs admin-console “HTTPS Certificates” toggle ON (owner Andras) before cert issuance; vuer_oss hosts.api=api-fk-dev has no sidecar but api- is only used by customization /external/createCustomerToken hostname-gating, not base dev flow (matches today’s unrouted api-). Open/next: push gated on user go → then deploy wires onto fk-dev; HTTPS toggle pending; CV deferred; no new Artifact Registry (uses existing) — tailscale-gcp-dev-box-migration
  • DuckDNS → Tailscale migration plan for a GCP vuer_docker dev-box mirror (reach the box over tailnet taild4189d.ts.net, no DuckDNS / no public IP). PLAN ONLY — parked on local-only branch tailscale (off devel), plan doc vuer_docker/TAILSCALE-MIGRATION.md uncommitted. Why it’s nearly a repo no-op (source-verified vuer_docker @ devel): (1) all dev.yml services are network_mode: "host" → nginx_proxy binds 0.0.0.0:443, apps bind 127.0.0.1, so the host joining the tailnet = reachable at <100.x>:443 with nothing published; (2) nginx_proxy/proxy_servers.conf routes by subdomain PREFIX (oss-/css-/css-sdk-demo-/esign-css-/esign-oss-/esign-api-/portal-/cv-/library- → ports 20080/30080/30081/20180/20181/30180/30380/40080/50080) with a regex server_name ~^oss-(.+)\.facekomdev\.net$ that wildcards the domain suffix → routing already domain-agnostic; (3) single self-signed cert /workspace/cert/dev.{crt,key} (external techteamer/cert repo) used by every block + single-label service names → a *.facekomdev.net wildcard cert covers all; (4) apps build URLs from DEV_DOMAIN (host /etc/environment → each *.yml). Only literal duckdns in the repo = README.md:17. Recommended path: Phase 1 zero-repo-edits (tailscale up --hostname=facekom-dev, DEV_DOMAIN=gcp.facekomdev.net, client /etc/hosts→100.x, reuse self-signed CA, delete DuckDNS, GCP firewall DENY all public ingress — DERP works behind NAT); Phase 2 polish (2a public *.facekomdev.net A-record → the box’s 100.x tailnet IP, removes client /etc/hosts, CGNAT-in-public-DNS is valid; 2b real LE wildcard via DNS-01 at the same cert path, removes browser warning) — neither needs nginx/app changes. Fallback (no public DNS) = MagicDNS facekom-dev.taild4189d.ts.net + tailscale cert, but single-name-per-node forces port/path routing = invasive (touches proxy_servers.conf + app URLs). Containerized tailscale sidecar rejected for host-level install. Repo diff = README rewrite + new install/install-tailscale.sh + optional cert-fetch script, no nginx/compose/app edits. Open decisions (blocking, awaiting user): domain label, publish public DNS→private tailnet IP?, self-signed vs real LE cert, CV/GPU in scope?, node auth (pre-auth key + tag:dev + SSH), VM sizing. Will coordinate on babylon facekom_dev once confirmed — tailscale-gcp-dev-box-migration
  • Tailscale dev-box migration DECISIONS LANDED + VM PROVISIONED (status draft→in-progress) via babylon #facekom_dev. Decision 1 — hostnames: use Tailscale MagicDNS (<name>.taild4189d.ts.net), NOT facekomdev.net subdomains → Phase 2a public-DNS approach RETIRED. Decision 2 — routing: deploy agent chose 8b (multi-tailscaled sidecar per service) over port-based 8a — each of the 9 services gets its own userspace tailscaled sidecar (env TS_AUTHKEY+TS_HOSTNAME, ~30 MB idle), own MagicDNS name, own tailscale cert. No app URL rework expected IFF sidecars named to preserve the existing <prefix>-<DEV_DOMAIN> pattern (oss-fk-dev, css-fk-dev, …) with DEV_DOMAIN=fk-dev.taild4189d.ts.netflagged to verify vs actual app config; pattern proven on pmv2-zurich (babylon+nats sidecars). This reverses this note’s original “host-level install, sidecar rejected” recommendation. VM fk-dev provisioned by deploy (part of a levandor-infra terraform refactor — module "vm"for_each=var.vms; pmv2-zurich’s 14 prod containers verified untouched): e2-standard-4 (4 vCPU/16 GB), 100 GB pd-balanced, europe-west6-a; separate VPC fk-dev-net/subnet 10.2.0.0/24, SA fk-dev-sa; tailnet IP 100.91.108.61, MagicDNS fk-dev.taild4189d.ts.net, ACL tag:cloud (reuses pmv2 auth key); public IP 34.158.19.122 egress-only, firewall denies ALL inbound except Tailscale DERP, no public SSH; Docker 29.6.1 (+gcloud cred helper for europe-west3-docker.pkg.dev), tailscaled + OTel collector active (host.docker.internal:4317/4318); access ssh ops@fk-dev from any tailnet device. Open (owner Andras/user): CV/GPU scope (VM non-GPU); toggle “HTTPS Certificates” ON in Tailscale admin console (required before tailscale cert works); whether deploy creates a FaceKom Artifact Registry namespace. Next (on user go): build the 8b sidecar compose layer on vuer_docker branch tailscale (sidecar per service named <prefix>-fk-dev, tailscale serve https → localhost:<port>, likely drop nginx_proxy), verify cross-service URLs, push for deploy to wire onto fk-dev — tailscale-gcp-dev-box-migration

2026-06-29

  • InstaCash eSign 1.3.0.11 release composition — documented the release: components esign_oss + esign_css ONLY (source tag instacash-1.3.0.11, 2026-06-08; Harbor instacash-esign-{oss,css}:1.3.0.11-20260608, built via the eSign bizalmi_szolgaltatas_build pipeline). Release issue ASSICASH-92; installs ASSICASH-93 (TESZT) + ASSICASH-96 (PROD, approved 2026-06-26, upgrading from the deployed 1.3.0.8.9/.10 not in this PROD line). Changelog = a devel core update + vuln fixes under FKITDEV-8817 (andras.lederer): jQuery XSS CVE-2020-11023 + jQuery prototype-pollution CVE-2019-11358 remediated on esign_css (PR #250) + hardening (HSTS, nginx HTTP hardening, WAF/ModSecurity). No DB migration, no breaking change; rollback = redeploy 1.3.0.8.instacash-esign-1.3.0.11
  • Dev-box deploy recipe for testing an InstaCash eSign release — on ssh Facekom (= lederera-447-fk-hardver, code bind-mounted from /workspace). The box defaults to Raiffeisen, so testing InstaCash eSign requires aligning the whole chain: esign_oss/esign_css → tag instacash-1.3.0.11, vuer_oss/vuer_css → tag instacash-1.9.11.50 (latest InstaCash vuer; the eSign ticket pins no vuer version), pdfservice stays on main/2.0.12 (partner-agnostic). Recipe per repo: git stash WIP → git fetch --tags (clones predate the tag) → git checkout <tag> → rebuild in-container docker exec <c> sh -c 'cd /workspace/<repo> && yarn install && yarn build'supervisorctl restart all. Verify: supervisord all RUNNING, logs show RabbitMQ connection established + Web server is listening (esign_oss 10180/81/82, esign_css 10183/84, vuer_css 10082/83), esign_css UI HTTP 200 on :10183. Gotchas: a “dirty” vuer_css after checkout was only an untracked .claude/ dir; old log ERRORs may be historical from the prior (Raiffeisen) run — check timestamps. — instacash-esign-dev-box-deploy
  • /fk-tjk flow dogfooded → first InstaCash eSign tesztjegyzőkönyv ever. Added instacash to partners.json (display “InstaCash”, ytProject ASSICASH; 12 → 13 seeded), rendered ~/Downloads/tesztjegyzokonyv_instacash_1.3.0.11.docx (5 test cases). InstaCash historically had no TJK (the attachment-recipe note’s blanket “InstaCash has none” warning is now superseded — the doc exists locally but is not yet attached to YouTrack; the flow does not auto-write). Updated the generation-flow note (partner count + a “First real use” section) and the attachment-recipe note (reworded the InstaCash warning + added ASSICASH-96 PROD install) — tesztjegyzokonyv-generation-flow, youtrack-tesztjegyzokonyv-attachment-recipe
  • FKITDEV-8533 PR #8013 SonarCloud gate — vuer_oss PR #8013 (Janus CVO un-gate, branch fix/FKITDEV-8533-videoorient-ungate) FAILED SonarCloud “Maintainability Rating on New Code” (rated C, then D after a refactor). Root cause = pre-existing-debt mis-attribution, NOT the fix: all 20 flagged issues are pre-existing (git blame 2018→Jan 2026; authors Jordán/Bence/jurki/kzsolt/Makkai; SonarCloud issue keys e.g. AZ8A1W4d…/AZ8A1W6o… identical before & after a PR refactor); decisive control = the co-modified server/db/model/customer.js had ZERO flags, proving the diff is innocent — the gate counts legacy smells in any touched file, most likely because devel has no SonarCloud baseline (project vuer-oss is private; New Code config unconfirmable without a token). Gotcha: any PR touching videochat.js/RoomTransportSession.js/SelfServiceTransportSession.js/VuerCVListenerSession.js (legacy optional-chain/.find/async smells) re-trips it → waive (mark issues Accept / admin-merge) or fix the baseline (New Code → Reference branch = devel, ensure devel is analyzed); do NOT bloat the PR fixing unrelated debt — esp. the 2 [failure] VuerCVListenerSession.js items (async-in-constructor + await-non-Promise, behavioural CV refactors). Fix final state: standalone server/transport/videoOrientExt.js helper refactored INTO Customer.prototype.videoOrientExtEnabled() (beside isNativeApp), called X.customer?.videoOrientExtEnabled() ?? true at the 4 gate sites (behaviour identical: null→true/native→false/browser→true); commit 1815f693fe (amended over d27d4cc990), solo-author, force-with-lease pushed. Decision (user): waive the gate as pre-existing debt; device test (operator view + recording + iPad orientation direction) still pending — FKITDEV-8533

2026-06-26

  • Tesztelési jegyzőkönyv generation flow (/fk-tjk) — built a repeatable per-partner test-report .docx generator for FaceKom releases (producing companion to the attachment-recipe note): a Claude command + stdlib Python docx renderer under /Users/levander/coding/facekom/.claude/. Practice: one TJK per AFFECTED partner per 1.9.11.NN release (not all 39), attached to that partner’s YouTrack release ticket; shortName usually ASS<PARTNER>/BUG<PARTNER> but VARIES (MicroSec=MF, DÁP=DAP/ASSDAP) → partners.json pins ytProject per partner; a core change reuses byte-identical body text across partners (verified MKB ASSMKB-90 == BB ASSBB-82 Oracle-timezone reports, body doesn’t even name the partner). New std template tesztjegyzokonyv_sablon.docx (authored 2026-05-29, replaces 3 inconsistent legacy formats): 19 <…> placeholders each intact in a single <w:t> run, all in word/document.xml → plain string substitution preserves all styling (no docxtemplater/pandoc). Built: .claude/commands/fk-tjk.md (procedure: pull dev ticket via existing fkticket client + 1 past report/partner for house style → draft per-partner JSON → render), .claude/scripts/tjk/render_tjk.py (stdlib-only: metadata substitution + clone test-case block document.xml paras 27–36 once per case w/ literal 1.k. + \n<w:br/> + zip-repackage copying entries verbatim swapping ONLY document.xml + self-check), partners.json (12 seeded: barion/bb/cib/cofidis/dap/fundamenta/generali/microsec/mkb/mvm/raiffeisen/unicredit), pinned sablon. v1 MANUAL/out-of-scope: screenshots, pass/fail underline, PDF export, attaching to YouTrack — NO write-back. Verified: renderer self-check + tests pass, independent fixture renders, pinned sablon byte-identical+unmutated post-render. Design spec (incl. §13 fact-check) /Users/levander/coding/facekom/docs/superpowers/specs/2026-06-26-teszt-jegyzokonyv-flow-design.mdtesztjegyzokonyv-generation-flow
  • YouTrack tesztjegyzőkönyv (test-record) convention + REST attachment recipe — captured WHERE FaceKom “Tesztelési jegyzőkönyv” PDFs/DOCX live: attachments on per-client ASS<CLIENT> release / BUG<CLIENT> tickets, NOT standalone issues (8-section branded template; source-of-truth templates FKITDEV-8329 unified format + FKITDEV-8330 release/install template). InstaCash (ICASH) has NO release/eSign TJKASSICASH-65 (FaceKom 1.9.11.50) / -92 (eSign 1.3.0.11) carry only build .logs, install tickets ASSICASH-66/62/67/93 only screenshots; the only instacash “teszt jegyzőkönyv” PDFs are OLD compliance/DR (BUGICASH-460 BCP 2023, ISSFK-338 SaaS-DR 2021). Only eSign-tied test record = Raiffeisen BUGRAFIPI-512 (eSign 1.3.0.22, 2/2 cases, Nagy Balázs 2024-10-16) + sibling -516 (eSign DR); recent ASSRAFIPI-117/113/102 TJKs are FaceKom/VUER releases (NOT eSign); BUGRAFIPI-514 has both .pdf+.docx. REST recipe (read-only, python urllib to dodge RTK + keep token off argv): GET /api/issues?query=…&fields=…,attachments(name,mimeType,created,url),comments(text,attachments(…))&$top=200, Hungarian full-text works, scope by project:; download = prepend base to the attachment’s relative signed url, GET w/ Bearer, write bytes; dates are epoch-ms. Same base + ~/.config/facekom/youtrack.token as the ready-for-release query — youtrack-tesztjegyzokonyv-attachment-recipe

2026-06-25

  • FKITDEV-8639 post-fix reality — appended a Post-fix Reality / Open Question section to the investigation note. Synthesis: PR #7862 (543f293c38, tag nusz-1.9.11.45) made the Excel report self-consistent/auditable (Sum on every row) but did NOT reconcile UI per-period SL with Excel weighted-overall SL — both formulas coexist BY DESIGN (naive per-period round CallsReportService.js:669-670 vs weighted overall :558-559; team standardised on weighted overall as headline). Per nusz-1.9.11.47 (ASSNUSZ-58 UAT), client STILL reported the SL discrepancy after the fix (“Az SL eltérés itt is jelentkezett”) even though the daily-stat discrepancy resolved. OPEN PRODUCT DECISION: UI == Excel exactly requires picking ONE formula everywhere — a product call, not a further bug fix. Clarified Bug C (ReportsService.js:63 truelocale) is DISTINCT from FKITDEV-8747 (locale through RPC queue boundary + empty SL when no calls, PR #7929, new for 1.9.11.48) — two locale bugs at two layers — FKITDEV-8639

2026-06-23

  • FKITDEV-8981 self-hosted PR-check runners — 33 identical runs-on: ubuntu-latestruns-on: [self-hosted, node] edits across the 7 repos’ single PR-check workflow .github/workflows/pull-request.yaml (vuer_oss 5, vuer_css 5, esign_oss 5, esign_css 4, portal_css 5, mq 5, janus-api 4; esign_css + janus-api omit the test job). Repo-name resolution: @techteamer/mq → GitHub TechTeamer/mq default master (NOT devel); janus_apiTechTeamer/janus-api (hyphen) default master (TechTeamer/janus_api does NOT exist); the 5 css/oss base off origin/devel, mq+janus-api off origin/master. Scope correction: portal_css’s old pr-title-lint.yaml was already removed on devel in PR FKITDEV-8976, and release-caller.yaml is push-triggered (reusable node-semantic-release.yaml@master, no runs-on) = out of scope — so only pull-request.yaml remained (re-scope against post-fetch devel, not a stale ref). Job NAMES unchanged → branch-protection required checks stay valid. Done in worktrees <repo>-FKITDEV-8981 on chore/FKITDEV-8981-self-hosted-runners; edits verified (numstat 5/5/5/4/5/5/4, zero ubuntu-latest residue, YAML parses) but NOT committed, NOT pushed, NO PRs. Hard infra dependency / risk: inert+dangerous without online node-labelled (+ implicit self-hosted) runners carrying git+Node/yarn (setup-node@v6 cache:yarn)+the SonarSource/sonarqube-scan-action@v6 toolchain (sonar = likeliest self-hosted gotcha) — if none online at merge, every PR check queues forever and ALL PRs in these repos block. “Build-green ≠ runs”: real validation needs a live PR hitting a node runner. Precedent: vuer-release autobuild.yml already on [self-hosted, docker]. Commit msg style chore: [fkitdev-8981] run PR checks on self-hosted runnersFKITDEV-8981

  • FKITDEV-8239 depcheck CI — ALL 5 PRs now fully green and ready to merge (flips the prior 4/5). The lone red, vuer_oss #8001, was a pre-existing self-service-room-archive-service.test.js Unit Tests failure (NOT sonar, NOT the depcheck change) — now RESOLVED: a colleague merged the test fix to vuer_oss devel in PR #8003 (commit cfdc116543, “tests updates/ci fix”); merged origin/devel into chore/FKITDEV-8239-depcheck-ciclean, no conflicts (devel only touched CODEOWNERS + the test file, zero overlap with the 3 CI-config files), merge commit 3717e30b91 solo-author (andras.lederer), pushed; #8001 re-ran fully green (Unit Tests, SonarQube Scan, SonarCloud Code Analysis, Build, Lint, Audit, Unused Dependencies all pass). Net: vuer_oss #8001 + vuer_css #3076 + portal_css #703 + esign_oss #353 + esign_css #253 all green — FKITDEV-8239

  • FKITDEV-8947 scoping gotcha — vuer_oss’s getHttpsAgent() + fetch({ agent }) idiom is a SILENT NO-OP (verified on Node v22.22.3 / bundled undici 6.24.1). Every fetch() in vuer_oss is Node’s global fetch (neither undici nor node-fetch is a declared dep), and global fetch ignores agent (honors only dispatcher). PROVEN: fetch(selfSigned, { agent: new https.Agent({ rejectUnauthorized:false }) })TypeError: fetch failed / DEPTH_ZERO_SELF_SIGNED_CERT (the rejectUnauthorized:false was dropped). Harmless today only because cv.rejectUnauthorized defaults true = global-fetch default; but client-cert mTLS via agent does nothing — latent trap for FKITDEV-8947 (UniCredit ApiService.js migrates request-promise-native→fetch with cert/key/ca/passphrase mTLS from portal.api). FIX (verified status 200 + peer CN received vs local requestCert server): const { fetch, Agent } = require('undici') then fetch(url, { dispatcher: new Agent({ connect: { cert, key, ca, passphrase, rejectUnauthorized } }) }). CROSS-VERSION TRAP: feeding a standalone undici 8.5.0 Agent into Node’s global fetch (bundled undici 6.24.1) → UND_ERR_INVALID_ARG: invalid onRequestStart method (handler-iface mismatch across undici majors); since Facekom runs Node 22 and 24 (different bundled undici majors), pinning standalone undici to the bundled version is fragile — use undici’s own fetch+Agent pair. Also: ApiService.js:267 has an uncommitted stray }w (HEAD clean) → ReferenceError in the non-realtime-sdk branch of setIdentificationCompletevuer-oss-global-fetch-ignores-agent-mtls, FKITDEV-8947

  • FKITDEV-8239 depcheck CI — COMMITTED (solo-author) + PUSHED (flips earlier LOCAL-ONLY status). Branch chore/FKITDEV-8239-depcheck-cigit@github.com:TechTeamer/<repo> for all 5 repos, author andras.lederer <andras.lederer@alpiq.com> (no Co-Authored-By). Each commit = 2 files (workflow + .depcheckrc.json), msg chore(ci): add warn-only depcheck job for unused dependencies (FKITDEV-8239), committed --no-verify (worktrees have no node_modules so husky/lint-staged can’t run; validated independently via actionlint + depcheck). Commits: vuer_oss 0e7bd6377e, vuer_css 7913f181c, portal_css ac15b91d, esign_oss 47d6a5c, esign_css 93ccd9f. No PRs yet (no-auto-PR) — compare links https://github.com/TechTeamer/<repo>/compare/devel...chore/FKITDEV-8239-depcheck-ci?expand=1; worktrees preserved for PR iteration. Merge-time caution still stands: do NOT promote the Unused Dependencies check to a required branch-protection check or it stops being warn-only — FKITDEV-8239

  • FKITDEV-8239 depcheck CI — adversarial deep-review found NO bugs; ready to ship as-is. Verified: actionlint v1.7.12 clean (exit 0, zero findings) on all 5 workflows (full Actions schema + expression check); all 5 diffs purely additive vs origin/devel (31 insertions/0 deletions, no existing job touched); ${{ env.NODE_VERSION }}=“24” resolves in all 5; bare npx -y depcheck@1.4.7 auto-discovers .depcheckrc.json; the 5 job blocks byte-identical except the intended install spelling (yarn --frozen-lockfile in vuer_oss vs yarn install --frozen-lockfile ×4); depcheck warn-only everywhere (exit 255 absorbed by continue-on-error), unused_devDeps=[]. Final candidates: vuer_oss soap/umzug; vuer_css add; portal_css lodash/tmp/tough-cookie + a genuine MISSING devDependency istanbul-lib-coverage; esign_oss ajv/fast-xml-parser/inquirer/jsdom/protobufjs/umzug (resolutions=CVE pins, advisory); esign_css license-checker/postcss. Merge-time op note: do NOT add the new Unused Dependencies status check to branch-protection required checks or it stops being warn-only — FKITDEV-8239

  • RTK tooling gotcha — RTK proxy MANGLES some commands (mutates the command, not just output), hit while fetching the actionlint binary for the 8239 review. curl <url> fails with curl error (3) “Malformed input to a URL function” (Rust proxy corrupts the URL); ls | sort returned empty; find|wc -l / |grep -c get zeroed (dangerous — looks like a legit “no results”). Workarounds bypass RTK via python3: download files with urllib.request.urlretrieve instead of curl/wget; run multi-step CLI checks via subprocess.run([...]) (argv list, no shell=True) instead of shell pipelines; for counts cross-check two independent methods. Sibling of the merge-commit-hiding gotcha — rtk-mangles-curl-and-pipes

  • FKITDEV-8533 iPad self-service rotation — chosen fix LANDS (server/Janus): “Option A — un-gate CVO for browsers.” Restored the videoOrientExt gate to its 2017 intent — disable urn:3gpp:video-orientation (CVO) RTP ext ONLY for the native mobile SDK (UA prefix mobile/), enable for ALL browsers — via new shared helper server/transport/videoOrientExt.js (videoOrientExtEnabled(customer) = !customer.isNativeApp(), null→true) wired at all 4 (the only) gate sites (RoomTransportSession:917 / SelfServiceTransportSession:49 / videochat:274 / VuerCVListenerSession:154) + new Customer.isNativeApp() (customer.js:307, userAgent.startsWith('mobile/')); isSafari/isMobile untouched (≈7 other callers — avoids #7945’s blast radius). Branch fix/FKITDEV-8533-videoorient-ungate off devel 9aabf7bb6c, commit d27d4cc990, solo-author; ships own tests (video-orient-ext.test.js +91). 4-front adversarial validation all PASS: (1) completeness — 4 sites are the only setters, no config/client/SDP override (client munges fmtp not extmap), self-service iPad reaches the gate with non-null customer; (2) native-SDK off→off, single mobile/ prefix (vuer_css mobile.js:52/119) for iOS+Android, no browser false-positive; (3) regression — full unit A/B 3220→3230 (+10/−0), identical 29 pre-existing ts-jest fails; (4) config — streamRotate:false dev/docker+Generali, recording is janus-pp-rec→ffmpeg -c:v copy (no transpose). Client finding (shelved, NOT redundant): self-service ID photo is captured from the LOCAL getUserMedia preview (VideoFeed drawImage(videoElement)), which CVO physically CANNOT correct (RTP ext = remote/operator decode only) → PR #3043’s client-canvas rotation is a SEPARATE artifact, still needed, ORTHOGONAL (no double-rotate — corrects an earlier assumption); minimal client fix built+validated (default-off correctOrientation, isIpadClient()+geometry gate, operator KYC byte-identical) on branch fix/FKITDEV-8533-selfservice-photo-rotation, NOT committed (deferred). Latent bug (separate-ticket candidate, NOT fixed): devel high-res capture triple-dead — self-service.controller.js:201-202 reads never-assigned this.services.highResolutionLocalStream, AND :204 calls object-arg screenshot() positionally → self-service photos always PNG/1, intended JPEG/0.9 path silently dead; orientation fix preserves PNG (no KYC-format side effect). Residuals need 1 physical iPad session (operator view/screenshot upright?, recording honours CVO?, stored photo upright + 90° CW direction) — FKITDEV-8533

  • FKITDEV-8239 SonarCloud gate fix — after the depcheck PRs opened, SonarCloud’s “Security Rating on New Code” gate FAILED on 4 of 5 PRs: the new workflow lines tripped SonarCloud’s GHA supply-chain rules — npx (“install packages on-demand”, confirmed sole driver on vuer_css), yarn install (“lifecycle scripts”), and unpinned actions/*@v6 (“use full commit SHA”); existing jobs use the same patterns but are grandfathered as old code, only the PR’s new lines are gated. Profiles differ per repo (vuer_css flags only npx; portal_css flags all three). Fix (chosen from 3 options): appended .github/** to sonar.exclusions in each sonar-project.properties (already in sonar.coverage.exclusions). Pushed solo-author (andras.lederer): vuer_oss c2b5cfcb3f, vuer_css 93c9d976e, portal_css 7ee62cbd, esign_oss 4e96053, esign_css 9f9b862. Verified via gh pr checks: 4/5 PRs now fully green (vuer_css #3076, portal_css #703, esign_oss #353, esign_css #253). vuer_oss #8001 stays red but NOT sonar / NOT this change — a pre-existing Unit Tests failure (self-service-room-archive-service.test.js, 2 tests: archive + restore self-service room, “Cannot log after tests are done” async-leak; 3512 pass/2 fail) that also fails on devel (branch is devel + CI-config-only; sonar/build skipped behind the test job); likely FKITDEV-8787 self-service work, out of scope. Reusable gotcha captured in SonarCloud “Security Rating on New Code” can fail on new CI workflow linesFKITDEV-8239

2026-06-22

  • FKITDEV-8239 depcheck CI rewrite — corrected investigation note: scope is all 5 repos (vuer_oss/vuer_css/portal_css/esign_oss/esign_css), not portal_css only; removed false npx -y macOS breakage gotcha (verified working); corrected lodash narrative (portal_css had over-suppressed genuine unused deps, not a static-analysis miss — fixed by removing lodash/tmp/tough-cookie from ignores); Yarn Constraints not viable (Yarn Classic v1 only) — FKITDEV-8239

2026-06-18

  • FKITDEV-8887 iOS audio resume — SonarCloud cleanup on vuer_css PR #3066 (TechTeamer; branch fix/FKITDEV-8887-ios-audio-resume, still UNCOMMITTED in worktree vuer_css-FKITDEV-8887-ios-audio-resume). Quality Gate PASSED but Sonar flagged 18 “New issues” (all maintainability code smells; 0 bugs/vulns/hotspots; 89.2% new-code coverage). 13 were genuinely the PR’s new code → fixed (11× prefer-optional-chaining a&&a.ba?.b in Peer.js/VideoFeed.js/InterruptionRecovery.js/videochat.services.js/videochat.script.js; 1× prefer-globalThis win:windowwin:globalThis; 1× cognitive-complexity recoverAudioIfNeeded 19→≤15 by extracting _safeLog/_isAudioTrackDead/_applyRecoveredAudioTrack, behavior-preserving — 119 suites/1045 tests pass + independent adversarial APPROVE). 5 were PRE-EXISTING document-upload/validation code (promptUpload/validationResult, videochat.script.js ~L424–448) the PR never touched (verified gh pr diff 3066: script.js changed only at the import, InterruptionRecovery wiring ~L78–92, one teardown line) → intentionally LEFT for a separate chore (keep audio PR focused). Reusable technique captured: read SonarCloud PR issues WITHOUT a Sonar token via GitHub check-run annotations on the PR head commit (gh pr view --json statusCheckRollup,headRefOidgh api .../commits/<sha>/check-runsgh api .../check-runs/<id>/annotations; sonarqubecloud bot also posts a PR summary comment). Gotchas: passing Quality Gate ≠ zero issues (gate = new-code thresholds only); no analyzed devel Sonar baseline (only pull-request.yaml runs Sonar) so pre-existing code can appear as PR “New issues”; annotation_level failure = issue severity, not a gate failure. Added gh-annotations recipe to 10. Verified gotchasFKITDEV-8887
  • FKITDEV-8787 Raiffeisen Myra phantom-room — deployed the fix branch to dev box lederera-447-fk-hardver (command ssh Facekom, ProxyJump FKJumpBox; box was offline ~4h on Tailscale, brought back online first) and server-side verification PASS. vuer_css switched customization/instacash @ e3f7a1d6e fix/FKITDEV-8787-selfservice-v2-abort-clear-state-95 @ d69f7272e (PR #3064 tip), left on the fix branch; a whitespace-only config/dev.json reformat stashed as stash@{0} first. vuer_oss left untouched (customization/raiffeisen, provides the getRemainingSeconds RPC). Build/restart that worked: docker exec vuer_css sh -c 'cd /workspace/vuer_css && yarn && yarn build && supervisorctl restart all' (yarn ~22s, build ~8s). Evidence: supervisord vuer_css RUNNING pid 612 stable, clean boot (RabbitMQ connection established, Web server listening on 10083, Socket server listening on 10082), zero errors since boot, self-heal at selfservice-v2.js:313. Two operational corrections: (1) vuer_css has NO docker healthcheck (docker inspect health = nohealthcheck; docker ps “Up 5 weeks” = only inner supervisord procs restart, not the container) — the “~60s unhealthy anti-flap” note for esign containers does NOT apply; verify via docker exec vuer_css supervisorctl status (RUNNING + climbing uptime), not docker health; (2) a pre-existing TypeError: Cannot read properties of undefined (reading 'stack') at server/web/WebServer.js:481 (findRoute) was logged by the OLD customization/instacash process pre-restart — unrelated to 8787, does NOT recur on the fix branch, but a real error-handling fault on customization/instacash (flag for that branch’s owner). Restore command: cd /workspace/vuer_css && git checkout customization/instacash && git stash pop && docker exec vuer_css sh -c '... yarn && yarn build && supervisorctl restart all'. Still pending: functional verification (Scenarios A/B) with the real Raiffeisen Myra mobile client at https://css-lederera.facekomdev.net — not yet run — FKITDEV-8787

2026-06-18

  • FKITDEV-8787 Raiffeisen Myra phantom-room — added a manual end-to-end verification (partner hand-off) script to the investigation note, complementing the existing 76 Jest unit tests. Fix ships in PR #3064 → base release/FKITDEV-8902-raiffeisen-1.9.11.95 (release-targeted delivery of the same server self-heal first landed in PR #3051 → customization/raiffeisen); tester MUST be on a build/env with that fix deployed or they just reproduce the original bug. Critical gotcha: the bug only ARMS when the mobile SDK reuses the SAME socket — use in-app Restart/Cancel and stay in the same app session; fully closing/reopening the app (or re-scanning a fresh token) makes a NEW socket with no stale selfServiceRoomData so nothing triggers and the test proves nothing. Scenario A = drive room to timeout/no-tasks (~5 retries, do NOT close app) → in-app Restart → PASS if fresh flow + tasks + first photo OK, FAIL if “Already authorized”/“Already has some kind of room”; Scenario B (controllable) = abort in-app → start in same session. Server-side proof: docker logs -f vuer_css | grep -i "self-heal" — warn self-heal: clearing stale selfServiceRoomData for dead room … = self-heal fired (room confirmed expired); getRemainingSeconds failed … preserving state = fail-closed branch (room NOT confirmed-expired; recover via abort-then-start). Hand-off needed because the “Already authorized” string lives in the Raiffeisen mobile SDK (real client required, not a local mock) — FKITDEV-8787

2026-06-16

  • FKITDEV-8252 UBI10 RUNTIME fixes (rabbitmq + supervisord) — build-green ≠ runs: prior phases were EXIT-0 build-verified but not runtime-tested; Bence reported containers failing on START. Four distinct ubi10-minimal runtime gotchas, each masking the next (all native x86_64 on ssh Facekom): (1) supervisor 4.2.5 crashes on Py3.12 ModuleNotFoundError: pkg_resources (setuptools dropped it) → pin supervisor==4.3.0 (vuer_docker was 4.2.5; vuer_build/vuer-release unpinned ⇒ already 4.3.0); (2) supervisord logfile path hidden by volume mountlogfile=/var/log/supervisor/supervisord.log + childlogdir baked in image, but compose bind-mounts host log dir over /var/log hiding the subdir → “directory … does not exist” → log to /var/log ROOT (mount always exists), vuer_docker only; (3) rabbitmq-server exit-1 “Please ensure /bin/su or /sbin/runuser exists” — ubi10-minimal ships only util-linux-core (no su/runuser), rabbitmq privilege-drop wrapper needs su → microdnf install -y util-linux in ALL 3 repos; (4) erlang .erlang.cookie eacces (latent, surfaced only after #3) — supervisord (PID1, HOME=/root) does NOT propagate techteamer’s HOME nor does USER techteamer set it → erlang writes cookie to /root → eacces crash-loop → set environment=HOME="/var/lib/rabbitmq" in supervisor_rabbitmq.conf (vuer_build+vuer-release). Also removed wrongly-added USER $DOCKER_USER from vuer_css/portal_css Dockerfiles (must run supervisord as ROOT; regression from shared-script refactor). Red herrings: healthcheck supervisor-health-check.sh uses supervisorctl status (root unix socket, fine) NOT rabbitmqctl; rabbitmqctl as root via docker exec ALSO gets cookie eacces (cookie 0400 owned by techteamer) → use docker exec -u techteamer -e HOME=/var/lib/rabbitmq <c> rabbitmqctl status; “rabbitmq exit 127” in bare docker run = test artifact (directory=/workspace missing without compose bind-mount). Outcome: all 3 rabbitmq images boot healthy (RabbitMQ 4.1.4, listeners up). Pushed solo-author: vuer_docker a6543abfeat/FKITDEV-8252/UBI-10-build-fixes; vuer_build 82acea75c56120feature/FKITDEV-8252-ubi10 (also folded in held-back Phase A clamav shadow-utils + janus CentOS-CRB.repo base fixes); vuer-release bc9570e92cc400feature/FKITDEV-8252-ubi10FKITDEV-8252
  • NÚSZ devel update — merge validation FAILED at lint, merge left UNCOMMITTED (mid-merge, MERGE_HEAD intact) in worktree ~/coding/facekom/vuer_oss-nusz-devel-update (origin/develupdate/customization/nusz-2026-06-16). yarn lint (eslint . --max-warnings 0 --ignore-pattern "test/*") reported exactly 1 error: cron.js:46 n/no-missing-require Can't resolve './server/service/FFmpegService'. Root cause = reusable merge gotcha: devel renamed server/service/FFmpegService.js.ts; nusz tip commit 1d837dac83 had added an extensionless require('./server/service/FFmpegService') to cron.js (resolved fine while .js); the conflict-free merge kept devel’s rename + nusz’s extensionless line, so it no longer resolves to .ts under n/no-missing-require. cron.js:46 is the lone straggler — every other caller (server.js:108, convert.js:31, background.js:52, server/convert/convert_check.js:4) already uses explicit .ts. Fix (NOT applied, validate-only) = add .ts to line 46. Lesson: after a cross-side .js.ts rename merge, grep for extensionless require()s of the renamed modules — nusz-devel-update-2026-06-16-lint-merge-fix
  • FKITDEV-8354 vuer-release PR #28 (MVM partner migration, branch feature/FKITDEV-8354, base master, reviewer bencelaszlo) — resolved Bence’s round-2 supervisor-config review (two “merge with the <repo> config” comments). vuer_css conf (projects/mvm/components/vuer_css/supervisor_vuer_css_docker.conf) was byte-identical to the vuer_css repo copy ⇒ DELETED + removed its COPY … conf.d/ line from the component Dockerfile; safe because base install/configure-app.sh:16-21 symlinks all source-package supervisor*.conf into /etc/supervisor/conf.d/ (supervisord.conf includes *.conf) ⇒ identical conf.d set. vuer_oss conf KEPT as intentional override (NOT merged): vs the correct baseline (vuer_oss repo MVM branch origin/chore/FKITDEV-8892-mvm-devel-update-2026-06-01, blob d6e7843) the release copy uses supervisor-stdout eventlistener logging (stdout_events_enabled=true/stdout_logfile=NONE, 8 programs) vs the repo’s file-logging 9-program set; the eventlistener apparatus (supervisor_stdout.py+supervisor_stdout_eventlistener.conf+pip install supervisor-stdout) exists ONLY in vuer-release and consumes the very supervisor-stdout plugin Bence asked to RESTORE in round 1 (07db225) ⇒ merging would no-op it; and dropping [program:vuer_oss_storage] is the consistent vuer-release convention (equilor/nusz/polgaribank-facekom/unicredit/unicredit-srb/mvm all omit it). Reusable mechanism: supervisor confs reach conf.d via TWO paths — (a) configure-app.sh symlinks the source-package conf, (b) the partner Dockerfile COPYs an override on top (last-write-wins by filename); an override is a deletable duplicate only if byte-identical, else it’s intentional customization. Distinct from FKITDEV-8252 PR #31 (feat: ubi10) — don’t conflate. Changes LOCAL/UNSTAGED in worktree ~/coding/facekom/vuer-release/.worktrees/FKITDEV-8354 only; reply to Bence DRAFTED not posted; nothing written to GitHub (user constraint) — FKITDEV-8354-mvm-supervisor-config-dedup
  • Devel update executed for nusz-1.9.11.47 — vuer_oss + vuer_css chore/FKITDEV-8938-nusz-devel-update pushed, PRs pending merge into customization/nusz; cut blocked on those merges — nusz-1.9.11.47

2026-06-15

  • NÚSZ release automation — created the releases hub + design under projects/facekom/releases/: per-release tracker nusz-1.9.11.47 (@13 / 1.9.11.47, release issue ASSNUSZ-116 / FKITDEV-8938, payload = CRNUSZ-102 + ASSNUSZ-58 + SLANUSZ-28, dual-publish 🅼 Harbor / 🅻 vuer_build, manual post-release YouTrack transitions), the reusable prepare-and-gate release-automation-design (/fk-release <client> command spec, scope = ASSNUSZ Release-issue Package manifest ∪ tag/status union, fix-forward never delete tags), and the releases index with verified nusz @1–@12 history — left UNCOMMITTED for review
  • NÚSZ release scope — documented YouTrack access + the verified “Ready for release” release-scope query for the four NÚSZ projects (CRNUSZ/BUGNUSZ/SLANUSZ/ASSNUSZ): tracker = YouTrack https://youtrack.techteamer.com (/api/issues), Bearer token read from ~/.config/facekom/youtrack.token (never on argv); “Ready for release” is a tag (exact string Ready for release, search tag: {Ready for release}) — tracker-wide it matches 57 issues so the project: filter is what scopes it to NÚSZ; query project: CRNUSZ, BUGNUSZ, SLANUSZ, ASSNUSZ tag: {Ready for release} returned 3 on 2026-06-15 (CRNUSZ-102, ASSNUSZ-58, SLANUSZ-28; BUGNUSZ 0); read-only curl -G --data-urlencode recipe + /fk-ticket command/extractor (~/.config/facekom/youtrack.token) paths captured; CRNUSZ-102 verified example (State Pending yet tag-flagged → the tag is the readiness signal, not State) — youtrack-ready-for-release-nusz-query
  • NÚSZ release payload detail + client registry — extended the release docs (UNCOMMITTED, per request): appended a per-ticket payload detail section to nusz-1.9.11.47 (CRNUSZ-102 impl FKITDEV-8794/8801 — no code/PR found, business-accepted, UAT 06.18; SLANUSZ-28 impl FKITDEV-8639 → PR #7862 on feature/FKITDEV-8639, NOT yet in customization/nusz, may already be in .45/.46; ASSNUSZ-58 stat-export, UAT/PROD-gate notes targeted .46.1) with a merge-status warning that payload code is not yet confirmed in customization/nusz and the version target (.45/.46/.46.1/.47) needs confirming; created the cross-system client-registry (YouTrack suffix ≠ repo name, e.g. RAFIPI=raiffeisen, MNET=magnet, PB=polgaribank; 22 clients with build-path modern/legacy/eSign + resolution rules for /fk-release); appended client-generalization, PR-fetch (no YouTrack VCS → git-grep + comment-scan), and comment-extraction ranking sections to release-automation-designclient-registry

2026-06-15

  • FKITDEV-8887 iOS audio resume — QA acceptance protocol documented (device repro is the real acceptance gate): baseline-first on origin/devel, core lock→unlock-to-read-SMS scenario on iPhone Safari, evidence via allowlisted webrtclog (interruption:resumesenderPeer:audioRecovered {swapped:true}), full test matrix (iPhone/iPad, built-in+AirPods, >30s background crossing connectionStateRecovery, non-default-mic survival, Android/desktop regression, both directions), and version-risk settlement (pull userAgent for rooms 10071/10091 Generali + 2281 CIB; iOS ≥16 weakens only mic-interruption premise, playback+socket-mask hold) — FKITDEV-8887
  • FKITDEV-8887 iOS audio resume — two polish fixes applied (UNCOMMITTED): (1) mic recovery routed through LocalMediaService.startLocalMedia() instead of raw getUserMedia so saved mic device is respected; videochat.script.js wires localMedia into VideoChatService; (2) WebRTC test globals extracted to shared helper test/tests/unit/_helpers/webrtc-test-globals.js, removing duplication across 3 test files; videochat.services.test.js updated to mock localMedia.startLocalMedia + new guard test; 119 suites / 0 failures / lint clean — FKITDEV-8887

2026-06-11

  • FKITDEV-8252 UBI10 Phase B build-verified GREEN (vuer-release) — all no-app-source component images build clean on UBI10. Built natively x86_64 on remote Facekom host (ssh Facekom lederera-447-fk-hardver, ProxyJump FKJumpBox, Docker 29.2.1/buildx 0.31.1, no podman): clamav 419MB, turn 354MB, rabbitmq 520MB, janus 375MB all EXIT 0. janus full compile OK — entire install-janus-build-env.sh -devel surface (ffmpeg/libogg/jansson/openssl/glib2-devel, pkgconf, gengetopt, gnutls-devel, libtool, automake, cmake, libcurl/libconfig-devel, gtk-doc) resolves on UBI10+EPEL10+RPMFusion10+CentOS-Stream-10, and libnice 0.1.17 / libsrtp 2.5.0 / libwebsockets 4.3.3 / janus (TechTeamer/janus-gateway@cc0fdca8) all compile. App components’ SYSTEM layer verified via synthetic probe (Mac, emulated): valkey-8.1.7-1.el10 (from CentOS-AppStream-9.repo), java-21-openjdk-headless (both install-java-11.sh AND install-java-17-jre.sh now install java-21), nginx-1.30.2-1.el10.ngx, nodesource pub_22.x — all install on UBI10; app FINAL images (vuer_css/vuer_oss/resource-manager/nyilvantarto_scraper/pdfservice) can’t be fully built locally (need SOURCE_PACKAGE release-tool artifacts, not in repo); postgresql intentionally stays Debian (postgres:bookworm). BUG FOUND+FIXED (only real defect): base/components/clamav/Dockerfile used bespoke inline microdnf install crypto-policies-scripts nano net-tools procps tar (vs install-os.sh) and OMITTED shadow-utilsgroupadd: command not found (STEP 11 exit 127) — SAME gotcha as vuer_build commit 4fac31a, missed in vuer-release; fix = add shadow-utils to clamav inline list, UNCOMMITTED pending approval. Reusable build cmd = docker build -f base/components/<c>/Dockerfile --build-context install-scripts=<repo>/install -t <c>:probe <args> base/components/<c> (build-args from component_env_values.json+default_env_values.json; UID/GID 1000, NODE_VERSION 22); vuer_oss oss-janus-compile is byte-identical build-env to janus ⇒ green janus implies it. Emulation gotchas (NOT migration issues — why we moved to remote host): podman libkrun qemu amd64 saw EPEL metalink 503s, valkey/janus SIGSEGV (exit 139), concurrent-build overlay I/O error (exit 125) — all vanish building native on ssh FacekomFKITDEV-8252

For Agents

Reverse-chronological session log. Newest entries at top, grouped by date (## YYYY-MM-DD). Each bullet: one piece of work, short summary, wikilinks to docs touched. Updated by obsidian-documenter on every project doc write. Read by historian at bootstrap (top ~15 entries).

2026-06-04

  • CI gotcha captured (verified 2026-06-04) — the “Github CI - Branch” workflow (.github/workflows/audit.yaml:33) in vuer_oss is chronically RED on customization branches and must not be read as a regression. The failing step yarn run improved-yarn-audit --min-severity critical --exclude <GHSAs> exits 4 whenever a critical advisory exists in a transitive dep absent from the --exclude allowlist; as of 2026-06-04 it trips on 4 stale-dep advisories (twig>locutus GHSA-vh9h-29pq-r5m8, @techteamer/timestamp>…>basic-ftp GHSA-5rq4-664w-9x2c, @kafkajs/confluent-schema-registry>protobufjs GHSA-xq3m-2v4x-88gg, request>form-data GHSA-fjxv-7rqg-78g4). The base branch customization/raiffeisen has failed this exact gate on every push since ≥April 2026 (verified via gh run list) and the team merges through it. Triage check for agents: if your commit didn’t touch package.json/yarn.lock AND the base branch is already red, it’s the pre-existing gate, not your change. Team clears it by appending triaged GHSAs to the --exclude list (a security-acceptance decision) or remediating the dep. The real per-change gates are lint (yarn lint, eslint --max-warnings 0, ignores customization/test/*) and unit tests (yarn jest <file>) — ci-github-branch-audit-chronically-red

2026-06-03

  • FKITDEV-8827 (ASSRAFIPI-119, Raiffeisen PION face-comparison export) — design-phase architecture findings documented (verified vs vuer_oss worktree on customization/raiffeisen). Key facts: faceComparisons rows key by EITHER roomId (videochat/operator) OR selfServiceRoomId (self-service-v2), no mutual-exclusivity constraint; euclideanDistance FLOAT nullable = cosine distance 0–2 despite the name; FKs roomId/selfServiceRoomId/customerId/userId/recognitionFromId/recognitionToId, scope withRecognitions (models.js:298-309, model/faceComparison.js). PION is a videochat flow, NOT self-servicepion-online-verification-phase-1/2 protos declare videochat, set compareFaceWith nowhere; comparisons come from the videochat:close hook (faceRecognitionHooks.js:26-44) keyed by roomId, gated by deployment config faceRecognition.comparisonPairs (FaceRecognitionService.js:7,20) → a self-service-only query returns zero PION rows. 4 call sites, 3 gated by recognitionOptions.compareFaceWith (liveness-v2 SelfServiceV2Service.js:1418, portrait/ID-doc FlowService.js:2899-2943 @:2902, V1) + the config-gated videochat hook. Verdict is DERIVED not storedSelfServiceCheckerService.getFaceComparisonResult (:132-154) returns CHECK_SUCCESS(≤perfect)/CHECK_PROBABLE(≤probable, the match tier collapses here since default match:null)/CHECK_FAILURE(>probable=different_face), operators <=, defaults {perfect:0.5,match:null,probable:0.6} (:32-48). Threshold sourcing differs: self-service per-room via selfService:v2:config:state activity (oldest [0], ASC getActivityLog db/helpers.js:13-33), REPLACES not merges, falls back to global Setting key faceComparison.value.euclideanDistances (persisted at startup by SettingsService.init()); videochat/operator rows have no per-room path and are NOT verdict-classified at runtime (room.endpoint.js:144 shows raw distance only). No createdAt index on faceComparisons (FK indexes only) → date-range exports risk a full scan; order by id PK. Report-bin pattern = bin → ReportsService subclass → _exportReport(rows,null,null,format,null) → Buffer → fs.writeFile (NOT _prepareDownload/Download-model), but customization/bin/raiffeisen-selfservice-failed-reports.js:106 calls prepareReportData which NrtFailureReportService never implements (abstract ReportsService:297) — latent bug masked only because its cron is active:false (FailedSelfserviceRoomsReport.js:73). DB is Postgres (config/dev.json) but MySQL is supported (sequelize.dialect.name !== 'mysql' guards) → prefer portable LOWER() LIKE LOWER() over ILIKE. Design decision: build a GENERAL both-paths export bin raiffeisen-facecomparison-export.js + FaceComparisonExportService (spec at .worktrees/vuer_oss-FKITDEV-8827/docs/superpowers/specs/2026-06-03-raiffeisen-facecomparison-export-design.md) — face-comparison-data-verdict-threshold-model

2026-06-02

  • FKITDEV-8787 (SLARAFIPI-60, Raiffeisen Myra phantom-room) — fix implemented + pushed on vuer_css branch fix/FKITDEV-8787-selfservice-v2-abort-clear-state (renamed from bugfix/...TechTeamer/vuer_css enforces ^(feature|feat|chore|fix|release)/FKITDEV-\d+, bugfix/ rejected), 2 commits 8586df65 (self-heal) + 923e4c70 (fail-closed hardening), no PR yet. Fix in server/socket/events/selfservice-v2.js: (1) selfService:v2:start — before ALREADY_HAS_ROOM throw, if stale selfServiceRoomData, call OSS rpcClient.selfServiceV2.getRemainingSeconds(roomId); if remainingSeconds < 1 delete stale data so re-init proceeds; (2) selfService:v2:abort — delete selfServiceRoomData after OSS abort RPC succeeds. Key design learning (4-perspective review): first version was fail-OPEN (delete on ANY getRemainingSeconds error) → re-introduced duplicate rooms from the opposite direction (a transient RPC/OSS error on a LIVE room would clear state → start() creates a 2nd live room, orphaning the original; de-reg loop only cleans the NEW room id). Verified OSS getRemainingSeconds = Math.max(0, floor((expireAt-now)/1000)) after resolveModels, so a timed-out room returns 0 (the <1 branch, not the catch) → catch only hit for truly-absent rooms → fail CLOSED there. RULE: for a duplicate/phantom-room-prevention bug, default-to-preserve-state on ambiguity; “RPC threw” ≠ “resource dead”. Tests test/tests/unit/socket/events/selfservice-v2.test.js 75 passing, lint clean (expired/preserved/boundary ===1, abort-RPC-failure-does-not-clear, start→abort→start regression), now use REAL server/auth.js predicates via jest.requireActual (fakes had dropped isAuthorized/customerId conjunct + collapsed hasAnyRoom roomData branch). NEXT: open PR vs customization/raiffeisen, move ticket Triaged→In Review, coordinate w/ m3szi (FKITDEV-7667) — FKITDEV-8787
  • FKITDEV-8581 (SLARAFIPI-53, Raiffeisen) — girinfo no-response observability change (decision + implementation, NOT committed). In customization/server/backgroundProcess/giro.process.js (renamed from giroService.process.js during “Raiffeisen PIon project clean-up”; customization/raiffeisen branch only), GiroProcess.handleTask() catch block split from one generic [GIRO process] Error into two logger.errors: “No response from girinfo service (timeout/network)” for RequestError/ETIMEDOUT|ESOCKETTIMEDOUT|ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN, vs “Bad response from girinfo service” for non-200/StatusCodeError/save failure (incl. statusCode); both add elapsedMs/requestTimeout/code. Retry (this.retry) unchanged — log-only. Chose minimal log-only over a heavier “mark bg-process/portal state differently after final no-response retry” option (DEFERRED, ties to the ambiguous-portal-state RCA). Branch feature/FKITDEV-8581-giro-no-response-log (vuer_oss worktree), node --check passes, no giro unit tests, lint clean (one pre-existing env package.json resolver error). Original RCA fix f830fd8e5a shipped 2025-11-28 but YouTrack still Pending — FKITDEV-8581

2026-06-01

  • Headless test path for the InstaCash external API + eSign documented (verified live on lederera). Tool = branch-only bin/instacash-cli.js in the vuer_oss container (/workspace/vuer_oss, branch customization/instacash, NODE_ENV=dev): two jobs — (1) start-server [8189] MOCKS the bank’s /auth+/status (run detached, “InstaCash external server is listening on 8189”); (2) drives the InstaCash external API the bank calls into vuer_oss. Every cmd except start-server boots the FULL vuer_oss service in-process (keystore + Postgres + RabbitMQ amqps://localhost:5671) then HTTPS-calls https://${hosts.oss}/external/... — needs a healthy stack + conflict-free config, NOT just an HTTP client. Cmds: post-application [rt|nrt] [mkb_szemelyi_kolcson|mkb_mszh|mbh_mfl] [extId] [loan]{customerId, customerProfileUrl, inviteUrl}; get-invite/get-customer; post-contract <id> [pdf] (dummy base64 PDF if none) → “IC - Szerződés ajánlat feltöltése” (ic-contract) flow → EsignRPCClient → esign; get-contract/revoke-contract. Prereqs: healthy vuer_oss+esign_css+esign_oss+postgresql+rabbitmq+vuer_cv (esign needs the nginx-PID fix — dev-box-esign-container-startup-failures-2026-06-01); instacash.external.apiKey = Bearer token + authMock; settings.allowSelfSignedCerts: true (CLI sets NODE_TLS_REJECT_UNAUTHORIZED=0). HARD LIMIT: the actual eSign signature is interactive — CANNOT be driven headless (customer opens inviteUrl on css, video-IDs, auths via mock /auth + SMS 123456 sms-verification-code-dev-testing, signs in eSign UI); state machine (PortalData) none→initial→applied→identification→identified→signature→signed (+aborted/rejected/accepted). 2026-06-01 run: post-application rt mkb_szemelyi_kolcson → customerId 28, profile https://oss-lederera.facekomdev.net/customer/28, invite https://css-lederera.facekomdev.net/dch/eL90QmqJbqWXOjVd; get-customer 28 → product loan, state created; post-contract 28HTTP 400 {"error":"Contract flow is in progress"} (clean JSON via nginx→vuer_oss, not a crash). OPEN QUESTION: a freshly-created/not-yet-identified application already has a contract flow “in progress” blocking the external upload, but developer-guide-hu.md says contract upload is AFTER identification — verify intended InstaCash sequencing — instacash-external-api-esign-headless-test-2026-06-01
  • Dev-box infra/image gotcha — esign_css + esign_oss containers came up unhealthy during InstaCash 2026-05-27 devel-update testing on the lederera rootless-docker host. PRIMARY (image regression, NOT the update code): both run harbor.techteamer.com/facekom-devel/esign_{css,oss}:2024.4.1-20240614 (rebuilt ~2025-12-08, nginx 1.28) as non-root techteamer (uid 1000), but baked /etc/nginx/nginx.conf line 6 = pid /run/nginx.pid; while /run is root:rootnginx: [emerg] open("/run/nginx.pid") failed (13: Permission denied) → nginx exits → supervisord FATAL ("Exited too quickly") → healthcheck flips container unhealthy (node/redis/cron were all RUNNING; nginx-only failure). Ephemeral fix applied: docker exec -u 0 <c> sed -i 's#^pid .*nginx.pid;#pid /tmp/nginx.pid;#' /etc/nginx/nginx.conf + supervisorctl restart nginx → both went healthy (lost on recreate; /etc/nginx NOT bind-mounted — only /workspace/<svc>, certs, /var/log are). Durable fix = bake pid /tmp/nginx.pid; (or chown /run) into the esign images/Dockerfiles, not the host checkout. Also captured: (a) healthcheck /usr/local/bin/supervisor-health-check.sh fails if any supervisord prog ≠ RUNNING OR uptime 0:00:[0-5][0-9] (< 60s anti-flap) → ANY supervisorctl restart = ~60s unhealthy then recovers (interval 60s, retries 3, start-period 60s); (b) RedisStore is not a constructor = RED HERRING/resolvedserver/web/web-server.js:24 correctly uses connect-redis v9 ({ RedisStore } / new RedisStore({client})) and /workspace/esign_css/node_modules (host-bind-mounted) has connect-redis@9.0.0; only an OLD ≤v6 factory-style stale node_modules triggers it → lesson: after a dep major bump, re-yarn install the running container; (c) chalk ^5 ESM-only broke esign_oss/bin/test/trans-check.js:6 (require('chalk')) → fixed in LOCAL mac checkout to dynamic import('chalk') in the existing promise chain (dev tooling yarn trans only; box’s separate /workspace/esign_oss checkout would need it too); (d) SSH from Claude’s shellkaku wrapper shadows ssh (_kaku_wrapped_ssh: command not found) so use command ssh; Facekom = lederera@localhost via ProxyJump FKJumpBox (the real docker host); FKJumpBox = root@lederera-447-fk-hardver is a SEPARATE bare Alpine namespace (no docker/no lederera user); operate via command ssh Facekom bash -l -s <<'EOF' … EOF (login shell for docker on PATH) — dev-box-esign-container-startup-failures-2026-06-01

2026-05-29

  • Dev-box infra gotcha — vuer_oss CV / photo-processing failures discovered testing InstaCash nrt self-service identification on lederera/192.168.1.93: customer UI shows “error during photo processing”; oss logs Failed to ping CV server/read ECONNRESET/CV server is down: 'cv-lederera.facekomdev.net' then CV process error Error: Recipe missing no CV Service! (server/cv/CVRecipe.js:88, via RecognitionService.runRecognitionsFlowService.submitTaskRecognitionSelfServiceV2Service.photoCandidate :1043 which calls submitTaskRecognition unconditionally — no dev flag skips face detection; selfService.ui.disabledChecks only covers girinfo/emrtd/kau). Two compounding causes: (1) vuer_cv container STOPPED (docker ps -aExited (255); nginx returns 502; fix docker start vuer_cv, ~2 min to Up (healthy), loopback curl then 404 not 502); (2) hairpin NAT — vuer_oss host-networked, its /etc/hosts maps all *-lederera.facekomdev.net to the box’s own LAN IP 192.168.1.93, so a host-net container hitting its own public IP resets at the TLS handshake; fix = remap those names → 127.0.0.1 (then logs CV server is available). CRITICAL: /etc/hosts is a Docker-regenerated single-file bind mount → edit does NOT survive docker restart vuer_oss (also re-breaks bin/instacash-cli’s oss-lederera/external/... path) → re-apply after every restart, via truncate+write (> /etc/hosts), NOT sed -i (fails “Device or resource busy”) — dev-box-cv-photo-processing-failures
  • Dev/testing gotcha — controlling the SMS verification code in vuer_oss when the customer phone is fake (discovered testing InstaCash NRT self-service identification): customer:verification:sendSms hook (customization/listeners/sms-verification.js) uses config.get('test.security.tempTokenSms') as a fixed code for every send when truthy, else reuses customer’s stored code or generates a random 6-char token; conventional dev value is 123456 (all test/testconfigs/*.json; tempTokenEmail: "mailToken" for email); dev box (lederera, NODE_ENV=dev) does NOT ship it — add the block to config/local.json (overrides dev.json), restart vuer_oss (node-config caches at startup), then resend (old random code won’t match 123456); alternative recovery = read customer.getVerificationCode() via the Customer Sequelize model — customer.data TEXT column is encrypted (serviceContainer.service.cryptos.data) but the model’s data getter (customer.js:23-51, _getDecrypted :316) auto-decrypts, so reading via model returns plaintext (stored as videochatToken, PortalData.js:1704); smslogs.messageBody separately encrypted + SMS bodies not logged = dead ends; matchTokens (ContactValidationService.js:16-20) = case-insensitive exact match — sms-verification-code-dev-testing

2026-05-28

  • FKITDEV-8788 / SLARAFIPI-61 — Raiffeisen PION MRZ recognition triage (P2): HU eID back/TD1 reads valid_score:100 on the FULL image but 2 on the warped/cropped image of the same capture; self-service flow rejects on the crop (VuerCVOCRRecognition.js:45-99 warp→MRZ path vs no-warp MRZDetectionApi.js:22-38); SLARAFIPI-61 was marked “Solved” on a CV 4.9.0 test almost certainly run on the FULL image (already passing), not the crop; counterintuitive 191541 (worse, passed) vs 191549 (better, failed) points at warp corner-detection edge case; decisive next step = checklist #2(b) run 4.9.0 MRZ on CROPPED 191549 export image; mitigations = override ocr.engine to no-warp path or fallback-to-full in SelfServiceCheckerService.getMrzCheckResult (:219-246) — FKITDEV-8788

2026-05-27

  • InstaCash devel update wave initiated across all three repos (update/customization/instacash-2026-05-27 branch name across esign_css/vuer_oss/vuer_css); esign_css blocked on orphan-history (b7cee2f is a single squashed commit, no merge base with devel, 95-path delta); vuer_oss in conflict (50 commits, 10 UU — high-risk on customization/listeners/self-service-v2.js due to FKITDEV-7518 id-card + InstaCash newIdFormatAcceptance overlap with in-flight FKITDEV-8747/8787); vuer_css in conflict (57 commits, 44 paths via worktree at ~/coding/facekom/vuer_css-instacash-update to protect parallel bugfix/FKITDEV-8787 WIP — server-side merged clean, no Express 5 risk; high-risk on customization/customizations.js route reconciliation and modal a11y trio modal.{js,twig,styl}); vuer_oss has uncommitted stash@{0} “instacash-update-temp-stash-2026-05-27” to pop on the right branch — instacash-update-2026-05-27-status
  • esign_css customization/instacash orphan-history operational warning captured: single squashed commit (b7cee2f, 2025-11-20) with zero shared history with devel, git merge-base returns empty, git rev-list --count A..B produces misleading numbers, standard merge halts on refusing to merge unrelated histories; 95-path delta (26 M, 14 A devel-only, 55 D devel-deleted but instacash retains — includes intentional MBH/MKB branding asset retention); three workflow options documented (brutal --allow-unrelated-histories, rebase-replay matching 1.3.0.10 shape, cherry-pick delta forward); needs team confirmation on historical pattern — esign-css-instacash-orphan-history
  • FKITDEV-8817 Status 2026-05-27: bugfix/FKITDEV-8817-jquery-update pushed on esign_css (commit b021019, author andras.lederer, no Claude co-author); 2-file change (delete stale web/libs/metronic/global/plugins/jquery.min.js, repoint client/ui/layouts/auth/auth.layout.twig at existing /libs/jquery/jquery-3.7.1.min.js); dead-code claim re-verified (routes 344/346 commented out on both devel and customization/instacash); PR not yet opened; will flow into InstaCash via second develupdate/customization/instacash-2026-05-27 merge once landed — FKITDEV-8817

2026-05-21

  • Face comparison DB query (customer “P”, P3) — verified against local feature/FKITDEV-8747 checkout that failed/different_face comparison results ARE persisted: faceComparisons table stores status + euclideanDistance (cosine distance 0–2, nullable, faceComparison.js:31) unconditionally regardless of threshold; different_face is NOT a stored status — it’s the CHECK_FAILURE verdict computed at read time by SelfServiceCheckerService.getFaceComparisonResult() when distance exceeds all thresholds (per-room → global → code default probable:0.6); 4 comparison call sites, liveness-V2 (SelfServiceV2Service.js:1390) gated by task.options.recognitionOptions.compareFaceWith; delivered read-only SQL (no release) joining faceRecognitions for imageCategory heuristic to split portrait vs liveness step; corrected triage _shared-context.md (models.js not .ts, FlowService.js under server/flow/) — face-comparison-different-face-db-query

2026-05-20

  • FKITDEV-8533 — verified PR #7893 (“enable videoOrientExt for tablets”) is unreliable: modern iPadOS 13+ Safari sends a macOS desktop UA, ua-parser-js v1 returns device.type === undefined, so isTablet() is false for the very iPads the fix targets; isTablet() is also a strict logical subset of isMobile() so the new OR’d term is redundant; correct fix = client-side navigator.maxTouchPoints > 1 && /Macintosh/ detection passed to server; PR CHANGES_REQUESTED (Generali, customization/generali-atvilagitas) — FKITDEV-8533

2026-05-18

  • FKITDEV-8252 — Phase A.6.1 complete: all 5 UBI10 base images probe-build green on UBI10+libkrun (portal_css 658 MB, vuer_css 805 MB, vuer_oss 2.44 GB, janus 313 MB, vuer_cv 5.93 GB); 2 new commits (f38c8e2, b984006) on feature/FKITDEV-8252-ubi10 (17 ahead, not pushed); Q1 revised from per-key rpmkeys to LEGACY (rpmkeys flag disappears after microdnf update; DEFAULT:SHA1 sub-policy doesn’t exist on UBI10); vuer_cv now in-scope; 10 reusable lessons captured; A.6.2 = identify remaining 3 base/* (likely common/*) — FKITDEV-8252
  • FKITDEV-8252 — UBI10 migration state captured: continuation of 2026-05-13→05-15 work; 3 decisions made (crypto policy = per-key rpmkeys, Oracle OL10 = stay on OL9 RPMs, vuer_cv = 2h spike); 4 Dockerfiles modified uncommitted; probe-builds blocked on podman sandbox allowlist — FKITDEV-8252
  • ASSICASH-71 — validation via PROD + 2 UAT log pulls; CSP-channel flood gone everywhere; FKITSYS-9486 fix confirmed holding; previously-open log-volume question closed; status moved to validated — ASSICASH-71

2026-05-13

  • FKITDEV-8787 / SLARAFIPI-60 — Raiffeisen Myra phantom-room triage; SDK-local error strings, OSS V2 silently resumes; in-app Restart hypothesis pending Raiffeisen confirmation — FKITDEV-8787

2026-05-12

  • ASSICASH-71 — swapped English reply drafts for canonical Hungarian final versions (FKITDEV-8201 + FKITSYS-9486 comments); rest of note unchanged — ASSICASH-71

2026-05-08

  • ASSICASH-71 / FKITDEV-8201 InstaCash CSS log-noise triage; reply drafts captured — ASSICASH-71

2026-05-07

  • initial portal_css.md created (codebase mapping pass) — portal_css

2026-05-04

  • Initialized activity log.
  • FKITDEV-8533 iPad videoOrientExt — PR re-review update: #7945 (chrismakaay→devel) two 2026-06-09 “code review fix” commits (bb06f009b,132ded8c8) corrected the inverted gate (iPad+Safari now ENABLES videoOrientExt via isVideoOrientExtEnabled = (isTablet&&isSafari) || (!isSafari && !isMobile)), split isMobile() to exclude tablet, added memoized getParser/getDevice/getBrowser + a UA-regex isTablet() fallback /Macintosh/&&/Mobile\//&&/Safari/i. REMAINING RISK: that fallback needs a Mobile/ token, but the real FKITDEV-8533 device is iPadOS Safari in DESKTOP mode (Macintosh … Safari/605.1.15, no Mobile/) → likely still missed — same ceiling: server-side UA parsing can’t reliably detect a spoofing iPad. #7945 still has 4× copy-paste (not DRY) + no tests; contrast #7942 (wowjeeez, OPEN) which self-reports via client maxTouchPointsisTabletClient DB column + shared videoOrientExt.js + Jest. Both #7945 & #7893 remain OPEN/CHANGES_REQUESTED; decisive test = a real spoofing iPad, not yet reproduced — FKITDEV-8533