For Agents
Living index of themes for the FaceKom KYC platform (vuer_oss / vuer_css / vuer_cv). Each H2 is a topic; bullets are wikilinks to related notes. Updated by obsidian-documenter when documenting work. Read by historian at bootstrap. Topics kept alphabetical.
Authentication / AD + LDAP
- FKITDEV-9252 — the failure mode of
passport-activedirectory: a transport error is reported viathis.error(), which passport routes to the error handler and which ABORTS the strategy chain ⇒ a reset LDAPS connection 400s the login (“Something broke into 400 pieces!”, 47 fails vs 28 successes over 9 days) and the configured second AD server is never tried. Amplifier: one AD login opens several LDAP connections — user search, bind, and withuseMemberOfProperty: falsealso the group-membership query — so any single reset is fatal. Fix = catch → retry → failover (vuer_oss PR #8143,5e24c3667d, approved, not merged to devel as of 2026-09-07), LIVE-VERIFIED 2026-09-07: an always-resetting server 1 takes 5 resets + 4 retries →fail('ldap_unavailable'), the chain moves to server 2 and authenticates the user there (previously the chain aborted and server 2 was never tried). The retry split is decided by HOW the connection dies, NOT by which phase — an earlier phase-based claim (search → retries, bind → no retry) is REFUTED by experiment, do not repeat it. Observed in both phases: RST ⇒Errorcode:'ECONNRESET'(string) ⇒ retries 4× then failover; graceful FIN ⇒ConnectionErrorcode:80(number) ⇒ NO retry, immediate failover; hang ⇒TimeoutErrorcode:80; closed port ⇒ECONNREFUSED. Mechanism: ldapjs emits both the raw socket error and aConnectionError, andactivedirectory2’sclient.on('error')fires first with the raw one while itscallbackInvokedonce-guard swallows theConnectionError— so RST wins the race, and a clean FIN produces no socket error at all. ⇒ the case that most deserves the retry (FIN: idle timeout, F5/HAProxy drain, DC restarting cleanly) is precisely the one excluded — a policy question, not a defect.AD_CONNECTION_ERROR_NAMESis load-bearing:ConnectionError+TimeoutErrorcarry a numericcode:80so the string-code list can never match them. No unit test can see any of this (authenticate = jest.fn()). A reusable LDAP fault-injection fixture now EXISTS (BER-parsing TCP proxy,socket.resetAndDestroy(), triggers selectable by connection + op ordinal) — but UNTRACKED in a scratch worktree, see the note. Also verified sound and worth reusing: passport 0.7.0 doesObject.create(prototype)per attempt (lib/middleware/authenticate.js:195) ⇒ overridingthis.error/fail/successinsideauthenticateis per-request, not shared state; andpassport-activedirectory’smainis the rollup buildindex.js, NOTsrc/strategy.js(they differ — always readindex.js)
Build / probe-build workflow (UBI10)
- FKITDEV-8252 — podman + libkrun on macOS Apple Silicon for emulated linux/amd64 builds; needs 8 GiB RAM minimum (4 GiB OOMs on gcc-c++ family installs), 6 CPUs sufficient; iteration counts as complexity proxy (portal_css 3, vuer_css 3, vuer_oss 5, janus 7, vuer_cv 7); subagent Bash allowlist is more restrictive than main-session shell — plan Phase B with this in mind
CI / build gates
-
FKITDEV-8279 — the
auditgate is red onvuer_ossdevelitself, not just on customization branches (contrast ci-github-branch-audit-chronically-red):improved-yarn-audit --min-severity criticalreturns Found 1 vulnerabilities (sequelize, CRITICAL) exit 1 on devel and Found 0 exit 0 on the fix branch. Two structural details worth reusing: theyarn auditstep directly above the gate swallows its exit code, so only theimproved-yarn-auditline gates; and--min-severity criticalmeans a HIGH advisory shows in the output for months without failing anything (GHSA-6457 was visible from 2026-03-11 and never blocked). Also a depcheck trap for anypatch-packageadoption:postinstall-postinstallhas no bin and is never imported ⇒ depcheck reports it unused (exit 255) whilepatch-packageitself is resolved correctly via depcheck’sbinspecial from thepostinstallscript — fix by adding both to.depcheckrc.jsonignores. depcheck is warn-only and not inneeds:, but a PR whose headline is “the red CI job goes green” must not open with a newly red check -
k6-e2e-harness-vuer-oss — an entire test suite with zero CI coverage: vuer_oss
test/tests/k6/is not linted (yarn lintignorestest/*), not typechecked (itstsconfig.jsonis separate from the root one, which excludestest/; there is notypechecknpm script), and not run by any workflow. A k6 file can be type-broken or reference a deleted page object and no gate notices. Manual gate:tsc -p test/tests/k6/tsconfig.jsonwith@types/k6installed. Same root cause as typescript-in-vuer-repos’s “no typecheck job in CI” -
vuer-build-never-pushes — there is no publish gate on the legacy path at all:
vuer_build/build.shhas nodocker push/ nodocker login, so a “successful build” on the legacy path leaves nothing in Harbor. The modernvuer-releaseCI does publish (release-tool publish push+HARBOR_USER/HARBOR_SECRET). How legacy images reach the registry is an open question. Also:-l/--list-partnersis broken (cd partners/vs realpartner/) and builds fail without an operator-suppliedbase/<svc>/github.key -
depcheck-false-positive-minified-bundle — depcheck can report a CI-only false positive because it fails OPEN on unparseable files. vuer_css CI flagged
@emotion/is-prop-validas unused while the identical pinneddepcheck@1.4.7+ lockfile was clean locally and in a Linux container. The only reference is a literalrequire("@emotion/is-prop-valid")in a try/catch atweb/sdk/web-sdk.js:205, andweb/sdkis not inignore-patterns— CI’s depcheck evidently can’t parse the 865 KB minified vendor bundle (OOM/timeout on the self-hosted runner) and then treats the file as containing no requires. Do NOT remove the dependency — it flips depcheck to reporting it missing. Fix = add toignoresin.depcheckrc.json. Generalized triage rule: a depcheck diff between CI and local with identical version+lockfile points at a parse failure on a big minified/vendored file, not a real dependency change. First hit on FKITDEV-8387; job introduced by FKITDEV-8239 -
FKITDEV-8239 — SonarCloud “Security Rating on New Code” gate fix (2026-06-23): after the depcheck PRs opened, the gate FAILED on 4/5 PRs because the new workflow lines tripped SonarCloud’s GHA supply-chain rules —
npx(on-demand install; confirmed sole driver on vuer_css),yarn install(lifecycle scripts), unpinnedactions/*@v6(use full commit SHA); the 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=npx only; portal_css=all three). Fix (3 options considered): appended.github/**tosonar.exclusionsin eachsonar-project.properties(already present insonar.coverage.exclusions); pushed solo-authorandras.lederer(vuer_ossc2b5cfcb3f, vuer_css93c9d976e, portal_css7ee62cbd, esign_oss4e96053, esign_css9f9b862).gh pr checks: initially 4/5 green (vuer_css #3076, portal_css #703, esign_oss #353, esign_css #253); vuer_oss #8001 was red but NOT sonar/NOT this change — pre-existing self-service-room-archive Unit Tests failure (2 tests, async-leak; 3512 pass/2 fail) that also failed ondevel, sonar/build skipped behind the test job. RESOLVED 2026-06-23: colleague merged the test fix to vuer_ossdevelin PR #8003 (commitcfdc116543); mergedorigin/develinto the depcheck branch (clean, no conflicts — devel only touched CODEOWNERS + the test file; merge commit3717e30b91solo-author) and #8001 re-ran fully green. All 5 FKITDEV-8239 PRs now green and ready to merge (#8001/#3076/#703/#353/#253). Reusable gotcha → SonarCloud “Security Rating on New Code” can fail on new CI workflow lines -
FKITDEV-8239 — adversarial deep-review verdict (2026-06-23): NO bugs, ship as-is.
actionlintv1.7.12 clean (exit 0) on all 5 workflows (full Actions schema + expression validation); all 5 diffs purely additive vsorigin/devel(31 insertions/0 deletions);${{ env.NODE_VERSION }}=“24” resolves in all 5; barenpx -y depcheck@1.4.7auto-discovers.depcheckrc.json; the 5 job blocks byte-identical except the intended install spelling (yarn --frozen-lockfilevuer_oss vsyarn install --frozen-lockfile×4); depcheck warn-only (exit 255 absorbed bycontinue-on-error),unused_devDeps=[]; extra finding — portal_css has a genuine missing devDependencyistanbul-lib-coverage. Merge-time op rule: do NOT add theUnused Dependenciesstatus check to branch-protection required checks or it stops being warn-only -
FKITDEV-8239 — warn-only depcheck CI job across all 5 repos (vuer_oss/vuer_css/portal_css/esign_oss/esign_css);
continue-on-error: true, not in anyneeds:graph → never blocks a PR; tool pinnednpx -y depcheck@1.4.7(correct on both CI and macOS npm v10);.depcheckrc.jsonignores build/lint/test tooling + dynamically-loaded runtime deps (pg/pg-hstore via Sequelize dialect, postcss via build pipeline) + vendored asset paths; Yarn Constraints NOT implemented (Yarn Classic v1 — Berry-only feature); candidates surfaced: vuer_osssoap/umzug, vuer_cssadd, portal_csslodash/tmp/tough-cookie, esign_ossajv/fast-xml-parser/inquirer/jsdom/protobufjs/umzug, esign_csslicense-checker/postcss; portal_css over-suppression bug found+fixed (those 3 were genuinely unused — adding to ignores hid the signal the ticket exists to surface); all LOCAL/uncommitted onchore/FKITDEV-8239-depcheck-ci -
FKITDEV-8887 — reading SonarCloud PR issues without a Sonar token (reusable, vuer_css projectKey
vuer-css, orgtechteamer): SonarCloud posts every issue as a GitHub check-run annotation on the PR head commit (gh pr view <n> --json statusCheckRollup,headRefOid→ find “SonarCloud Code Analysis” + head SHA →gh api repos/o/r/commits/<sha>/check-runsfor the run id →gh api repos/o/r/check-runs/<id>/annotations);sonarqubecloudbot also leaves a PR summary comment. Gate gotchas: a passing Quality Gate ≠ zero issues (gate checks only new-code threshold metrics — coverage/duplication/rating — so it’s GREEN with many code-smell “New issues”); no analyzeddevelbaseline (onlypull-request.yamlruns Sonar) → Sonar attributes pre-existing smells in a touched file to the PR, confirm authorship withgh pr diff <n>; annotation_levelfailure= issue severity, not a gate failure. Full recipe in 10. Verified gotchas -
SonarCloud “Security Rating on New Code” can fail on new CI workflow lines — adding NEW lines to a SonarCloud-scanned GitHub Actions workflow can fail the “Security Rating on New Code” gate via GHA supply-chain rules (
npxon-demand install,yarn install/npm installlifecycle scripts, unpinnedactions/*@vNSHAs) — even when the rest of the CI already uses those same patterns (grandfathered as old code; only the PR’s new lines are gated). Profiles differ per repo. Resolutions: (a) exclude.github/**viasonar.exclusions(TechTeamer repos already exclude it fromsonar.coverage.exclusions); (b) run CLI tools via a pinned devDependency instead ofnpx+ pin actions to full commit SHAs. The issue/rule REST APIs need auth for these private projects, but the per-PR findings are readable via GitHub check-run annotations (gh api repos/<repo>/check-runs/<id>/annotations— full recipe in FKITDEV-8887). First hit on FKITDEV-8239 -
ci-github-branch-audit-chronically-red — the “Github CI - Branch” workflow (
.github/workflows/audit.yaml:33in vuer_oss) is chronically RED on customization branches and is NOT a regression:improved-yarn-audit --min-severity critical --exclude <GHSAs>exits 4 on any critical advisory in a transitive dep not on the--excludeallowlist (as of 2026-06-04:twig>locutus,@techteamer/timestamp>…>basic-ftp,@kafkajs/confluent-schema-registry>protobufjs,request>form-data). Base branchcustomization/raiffeisenhas failed it on every push since ≥April 2026; team merges through it and clears it by appending triaged GHSAs to--exclude(security acceptance) or remediating. Triage rule: commit didn’t touchpackage.json/yarn.lock+ base already red ⇒ not your change. The real per-change gates are lint (yarn lint,--max-warnings 0, ignorescustomization/test/*) and unit tests (yarn jest <file>) -
customization-branch-ci-pipeline-inheritance — systemic, will recur: legacy partner branches ran a single CI job (
lint-and-build, old.github/workflows/pull-request.yamlblobec0a1244); devel’s current workflow (blobdda79403) runs lint / test / audit / depcheck / sonar / build. So the first devel→customization merge makes four jobs run on that branch for the very first time, surfacing years of latent breakage in one PR. On cofidis (FKITDEV-9059): 5 failure clusters, only 2 merge-introduced, the rest dating 2017–2024. Two structural amplifiers: partners fork core source files in place (no override layer, e.g.server/service/FlowLiveUpdateService.js→ forked file violates the core unit test), and there is no customization-aware unit-test layer (jest.config-unit.jsmatches onlytest/tests/unit/**, no per-partner test dir) so fixing a partner-specific test failure means diverging a shared core test file that then conflicts on every subsequent devel merge — a recurring tax, not a one-off -
customization-branch-ci-pipeline-inheritance — third confirmed instance, and the one that breaks the “it’s always a tax” framing: on CIB (FKITDEV-9197) the inherited pipeline was a SECURITY WIN. Fired on all three repos — vuer_oss/vuer_css carried the legacy
lint-and-buildblobec0a1244, byte-identical to the pre-merge Cofidis branch (⇒ the legacy workflow is one shared frozen artefact, so “is this branch still legacy?” is answerable with a singlegit rev-parse <branch>:.github/workflows/pull-request.yaml), and portal_css had nopull-request.yamlat all — zero CI on the branch until the merge. Measured against a base worktree atbf6dfbf8: eslint exit 1 (15 problems) → exit 0, audit 25 CRITICAL → 0. CIB’s portal had been shipping 25 critical advisories unmeasured (tarviasemantic-release>npm,handlebars,twig>locutus×2,browserify>shell-quote) precisely because the branch carried no audit gate — the same merge that switched the gate on also satisfied it. Either direction, the honest PR statement needs a measured base worktree: “these N gates are new on this branch; here is what they said before the merge and after” — do not report a newly-green gate as your achievement or a newly-red one as your damage. Running tally: Cofidis fired (5 clusters), Generali did not (already on 6 jobs), CIB fired ×3 -
cve-2025-7783-form-data-via-request — Audit-job debugging trap:
ERROR: Unable to parse yarn audit output: SyntaxError …and Node 24’sDEP0169 url.parse() DeprecationWarningare cosmetic red herrings —improved-yarn-auditmerges child stdout+stderr into one NDJSON stream so the deprecation warning corrupts lines, and the tool silently skips unparseable ones. Identical errors appear on green devel runs (proof: vuer_oss PR #8062, job87891787317,Found 0 vulnerabilities, conclusion success). The exit code comes solely from the genuine advisory count — don’t chase the parse error, find the real advisory -
nusz-devel-update-2026-06-16-lint-merge-fix — concrete case of the lint gate catching a bad merge:
yarn lint(eslint . --max-warnings 0 --ignore-pattern "test/*") failed the NÚSZ devel-update merge with 1n/no-missing-requireerror (cron.js:46, extensionless require of a module devel had renamed.js→.ts); merge correctly held back uncommitted until fixed -
FKITDEV-7973-sequelize-pool-fix — blind spot in that same script:
yarn lintpasses--ignore-pattern "test/*", so test files are NOT linted byyarn lintor by the CI lint gate. Any change undertest/(e.g. the pool-config mirrortest/lib/utils/db.utils.js) sails through untested for style/errors. The ESLint flat config does define atest/**block, so explicit invocation works — lint touched test files by hand with./node_modules/.bin/eslint <paths> --max-warnings 0 -
FKITDEV-8981 — move PR checks off
ubuntu-latest→ self-hosted[self-hosted, node]across 7 repos’ single PR-check workflow.github/workflows/pull-request.yaml: 33 identicalruns-onedits (vuer_oss/vuer_css/esign_oss/portal_css/mq 5 each, esign_css/janus-api 4 — they omit thetestjob; jobs ∈ {lint,test,audit,sonar,build}). Repo resolution:@techteamer/mq→TechTeamer/mqdefaultmaster;janus_api→TechTeamer/janus-api(hyphen)master(TechTeamer/janus_apidoes not exist); css/oss baseorigin/devel, mq+janus-apiorigin/master. Scope: portal_csspr-title-lint.yamlalready removed on devel (PR FKITDEV-8976) and push-triggeredrelease-caller.yaml(reusablenode-semantic-release.yaml@master, noruns-on) is out of scope ⇒ onlypull-request.yaml— re-scope against post-fetch devel. Job NAMES unchanged ⇒ branch-protection required-status-checks stay valid. Worktrees<repo>-FKITDEV-8981onchore/FKITDEV-8981-self-hosted-runners; verified (numstat 5/5/5/4/5/5/4, zeroubuntu-latestresidue, YAML parses) but NOT committed/pushed, NO PRs. Hard dependency/risk: inert + dangerous without onlinenode-labelled (+ implicitself-hosted) runners carrying git + Node/yarn (setup-node@v6 cache: yarn) +SonarSource/sonarqube-scan-action@v6(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” — true validation needs a live PR hitting anoderunner. Precedent: vuer-releaseautobuild.ymlalready on[self-hosted, docker]. Commit-msg stylechore: [fkitdev-8981] run PR checks on self-hosted runners -
FKITDEV-8533 — SonarCloud “Maintainability Rating on New Code” gate FAILED on vuer_oss PR #8013 (the Janus CVO un-gate fix, branch
fix/FKITDEV-8533-videoorient-ungate; rated C, then D after a refactor) — and it is pre-existing-debt mis-attribution, NOT the fix (2026-06-29). All 20 flagged issues are pre-existing (git blame2018→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-modifiedserver/db/model/customer.jscarries zero flags, proving the diff is innocent — the gate counts legacy smells in any touched file, most likely becausedevelhas no SonarCloud baseline analysis (projectvuer-ossis private; New Code config unconfirmable without a token). Gotcha: any PR touchingvideochat.js/RoomTransportSession.js/SelfServiceTransportSession.js/VuerCVListenerSession.js(legacy optional-chain/.find/async smells) re-trips this → waive (mark issues Accept / admin-merge) or fix the baseline (Project Settings → New Code → Reference branch =devel, ensure devel is analyzed); do NOT bloat a targeted PR by “fixing” the unrelated debt — esp. the 2[failure]-severityVuerCVListenerSession.jsitems (async-in-constructor + await-non-Promise, behavioural CV refactors). Decision (user, 2026-06-29): waive as pre-existing debt. Fix final state: helperserver/transport/videoOrientExt.jsrefactored intoCustomer.prototype.videoOrientExtEnabled()calledX.customer?.videoOrientExtEnabled() ?? trueat the 4 sites; commit1815f693fe(amended overd27d4cc990), solo-author, force-with-lease pushed; device test still pending -
mjml-v5-esm-breaks-commonjs-email-templates — “green CI, broken runtime”: unit tests never boot
EmailService, so the MJML-v5 ESM regression on FKITDEV-9059 cofidis (ReferenceError: require is not definedatEmailService.init; the letter type never registers so its email never sends) passed all CI and only failed when the service actually started on fk-dev. Same class as FKITDEV-8981’s “build-green ≠ runs” and the FKITDEV-9059 innerHTML /web/-404 bugs; detection is runtime-only (deploy + restart, watch letter-registration errors: 3/boot → 0 after the fix) -
FKITDEV-9194 — the pipeline-inheritance trap is not universal — check, don’t assume: both Generali branches already carried devel’s 6-job pipeline, so the Cofidis-style expansion was a no-op (css came out fully green). Also check scheduled workflows separately:
vuer_ossgainedlong-lived-branches.yaml, but its branch matrix lists only devel/mbh/raiffeisen/kh/unicredit ⇒ the file being present on a branch does not mean the branch is in the matrix. Andbuildhasneeds: [lint, test, audit, sonar]⇒ a red audit also blocks build (Generali oss: pre-existing criticalsequelizeGHSA-v8fg-2rw7-q452 via@techteamer/sequelize6.32.2, FKITDEV-8279) -
eslint9-flat-config-dead-disable-directives — a rule going from “on” to “off” upstream can turn a partner branch red, which is the opposite of the intuition. devel’s eslint-9 flat-config migration turned off
no-empty/no-unused-vars/no-redeclare/no-useless-assignment, so every partner// eslint-disable-next-line <that rule>now reports “Unused eslint-disable directive” — a warning — andyarn lint --max-warnings 0promotes it to a failure. CIB (FKITDEV-9197, portal_css): 9 dead directives across 6customization/files.eslint --fixdoes NOT remove them — it blanks each to a whitespace-only line, so trusting--fixleaves stray blank lines and unexplained whitespace churn in the diff. Sibling finding in the same config:'jest-formatting/padding-around-all': 'warn'survives although65ac214c feat: eslint 9 FKITDEV-6045removed the plugin — inert only because that block isfiles: ['test/*','test/**/*']and lint runs--ignore-pattern "test/*"; the portal_css twin of the vuer_css “test files cannot be linted” residue, and it detonates if test linting is ever enabled -
portal-css-jest-runs-zero-tests — a CI “test” job that is green because it executed nothing: portal_css’s
yarn jestfinds zero tests on pristinedeveland would still find zero if you wrote some — emptytest/tests/plus a custom sequencer (test/lib/jest/test.sequencer.js, wired viatestSequencer) whoseCORE_TEST_ORDERis an empty array used as an allow-list inprepareTests(order.includes(relativePath)), and jest runssequencer.sort()before the “no tests found” check. Thejestscript omits--passWithNoTests(bare runs are hard-red); the workflow appends it, which is the entire reason CI is green. ⇒ on this repolint+buildare the only gates carrying signal — never cite a portal_css test pass as validation evidence -
customization-branch-ci-pipeline-inheritance — “SKIPPED” IS NOT “PASSED”: a red gate hides every job downstream of it. On CIB’s first
vuer_cssrun (FKITDEV-9197 #3152)BuildandSonarQubewere skipped, not failed, because bothneeds:the redtestjob — reading that as “4 green, 1 red” overstates what is known by two entire jobs. Same shape permanently onvuer_oss, wherebuildneeds: auditand audit is always red on the FKITDEV-8279 fork (npm advisory 1114318 “Sequelize: SQL Injection (Oracle DB)”) ⇒ Build never actually runs on any vuer_oss partner PR. Re-read theneeds:graph before reporting a run, and re-run after every fix rather than assuming untouched jobs are fine. Also separate code-fix failures from human-override ones: on vuer_oss the audit and the SonarCloud quality gate (an 11-month devel merge graded as “New Code” — 334 core commits arriving as if freshly authored) are both overrides, and note the split that confuses everyone — the workflow’s own SonarQube job passed while the SonarCloud status check is red. Never “fix” either on a partner branch; that is how branches acquire divergence they pay for on every future merge. Final CIB tally: portal_css 7/7 green first run, vuer_css 6/6 after 2 fixes, vuer_oss green-but-blocked — 3 fixes total, an order of magnitude under Cofidis’s 5 clusters, because CIB had zero partner commits since its last release. The expansion reveals AGE, not activity: the headline failure was a test red since 2024-12-03 on a branch with no commits at all -
vuer-oss-unit-tests-green-is-weak-evidence — the
testjob on vuer_oss is a weaker gate than its green implies, devel-wide:translations.test.jsregisters zero tests (misusedit.each— the returned function is discarded), itsscan()is actively flaky in the nightly long-lived-branches workflow (Directory not found: client/featureson ~1 run in 3, same commit, both runners), andpdf.test.js’s byte-for-byte PDF comparison drifts by 3 bytes. ⇒ one red run is not evidence of a regression, one green run is not evidence of its absence. Full detail under Dev / testing workflow -
FKITDEV-9197 — the product image sets
NODE_ENV=devwhile jest defaults toNODE_ENV=test, so in-image validation reads GREENER than CI. Phase 2.5 ran all three CIB repos insideharbor.techteamer.com/facekom-devel/{vuer_oss,vuer_css,portal_css}:2026.1.UBI9.1-20220315(Node v24.12.0, throwaway containers on fk-dev, source viagit archive+ mount, running NÚSZ stack untouched) — install/lint/build green in all three, yetportal-client.test.jspassed in-image and failed in CI purely because of the env difference. ⇒ in-image is a strong check on native build/lint and platform gaps, a weak one on config loading. More generally: three environments gave three different results for the same tree (macOS local / in-image / CI), structurally not flakily — macOS has no/etc/hostname, the image pinsdev, CI runstest. Treat “passes locally” and “passes in-image” as weak evidence about CI
Container health / images (dev-box)
- fk-dev-partner-branch-deploy-runbook — the third instance of the same uid-1000-vs-root-path failure class on this stack (after the esign nginx-PID bug and the janus record-dir bug): host
ops=uid 1001 but the app runs astechteamer=uid 1000, so a blanketchown -R ops:ops /workspace/vuer_ossmakes log4js/streamroller throwEACCES: permission denied, open 'logs/server.log'and supervisord restart-loops the program. Triage signal:supervisorctl statusshows uptime0:00:00with a climbing PID. Fix:chown -R 1000:1000 <repo>/logsafter any tree-wide chown. Explicitly corrects a circulating claim that ownership “moved to 1001 and the uid-1000 guidance is stale” — WRONG, and it cost a restart loop on 2026-08-18. The two uids coexist: tree1001:1002(hostops) AND process/logs/1000 (techteamer= hostubuntu). Provenance traced: not doc rot but an agent artefact — ahistoriansubagent observed the tree live as1001:1002(correct) and over-generalised it into “this contradicts FKITDEV-9059, ownership has since changed”, which then travelled across an agent hand-off.FKITDEV-9059.md:78was right the whole time and is vindicated, as is release-pipeline-automation-spec. The reusable lesson is the mechanism: an agent promoting a partial live observation into “the docs are stale” — treat any such hand-off as suspect until it accounts for BOTH uids - fk-dev-deploy-smoke-runbook — the
januscontainer was supervisord-FATAL since fk-dev’s first boot (2026-06-30) and had never had a confirmed green videochat; root cause =janus_websocketscan’t create the wss vhost (in-image libwebsockets built without working TLS). Fixed 2026-08-13 by switching the oss→Janus hop to plainws(browser never touches Janus — see WebRTC topic). Gotcha:janus.transport.websockets.jcfgis a bind mount → edit in-place inside the container or the inode-swap is ignored - dev-box-esign-container-startup-failures-2026-06-01 —
esign_css/esign_osscame upunhealthybecause nginx (non-roottechteameruid 1000) couldn’t write its PID: bakednginx.confline 6pid /run/nginx.pid;but/runisroot:root→[emerg] open("/run/nginx.pid") failed (13: Permission denied)→ nginx FATAL → unhealthy (app/redis/cron all RUNNING; image regression, not the InstaCash update); imagesesign_{css,oss}:2024.4.1-20240614were rebuilt ~2025-12-08 w/ nginx 1.28 (tag date misleading); ephemeral fixsedPID →/tmp/nginx.pid+supervisorctl restart nginx(lost on recreate,/etc/nginxnot bind-mounted) → durable fix = bake the PID path into the images. Healthcheck/usr/local/bin/supervisor-health-check.sh: unhealthy if any supervisord prog ≠ RUNNING or uptime0:00:[0-5][0-9](< 60s anti-flap) → ANYsupervisorctl restart= ~60s unhealthy then auto-recovers (interval 60s, retries 3, start-period 60s)
Container migration / UBI10
- FKITDEV-8252 — fleet-wide UBI8/UBI9 → UBI10 migration ahead of RHEL 9 EOL; Phase A.6.1 DONE (all 5 base images probe-build green; 2 new commits
f38c8e2+b984006; branch 17 ahead oforigin/main, not pushed); Phase A.6.2 (remaining 3 base/* likely undercommon/*), Phase B (vuer-release62 Dockerfiles), Phase C (vuer_dockerPR #203) still open; vuer_cv now in-scope (5.93 GB UBI10 base added) - FKITDEV-8252 — RUNTIME fixes (build-green ≠ runs): four ubi10-minimal startup gotchas masking each other (supervisor 4.2.5
pkg_resourceson Py3.12 → pin 4.3.0; supervisord logfile hidden by/var/logbind-mount → log to root; rabbitmq needs/bin/su→microdnf install util-linux; erlang.erlang.cookieeacces — supervisord drops HOME →environment=HOME="/var/lib/rabbitmq"); plus removed wrongUSER $DOCKER_USERfrom vuer_css/portal_css (must run supervisord as ROOT); all 3 rabbitmq images boothealthy; pushed solo-author across vuer_docker/vuer_build/vuer-release
Cron jobs / data retention
- SLARAFIPI-84 — the “nothing prunes
Activity/FlowActivity” finding is a NOT-FINDING and must be quoted as one.Activity.destroy, cascade deletes and crypto-shredding were all searched and all empty — that is no deletion path found, not no deletion happens, and it is the same fallacy that produced the wrong “the rejected value is not in the DB” answer (we verified where the table is written instead of where the value goes). Compounding it:config.js:103springCloudConfigServercan override any key at boot, sofeatures.archive = falseat the tag proves nothing about their runtime. Retention promises to Raiffeisen are therefore scoped, not absolute. - fk-dev-nusz-deploy-and-8959-verification — FKITDEV-8959 TC-8959-02 verified PASS on fk-dev (2026-07-03): the NÚSZ image-deletion cron
RemoveAttachmentDataCronJob(thin wrapper overCustomRemoveOldDataCronService.removeAttachmentData()) →getOldImageAttachments(type LIKE 'image/%' AND isArchived=false AND createdAt<cutoff, batched, excludes thefileblob) →removeOldAttachmentskey-guard (const encryption = encryptionId ? getEncryption() : null; if (encryption?.key) encryptBuffer(empty,{key}) else { file=Buffer.from(''); encryptionId=null; skippedNoKey++ }; isArchived=true; save). Proven the key-offline path: BEFORE{isArchived:false,encryptionId:3,file_bytes:9}→{processed:1,archived:1,skippedNoKey:1,errored:0}→ AFTER{isArchived:true,encryptionId:null,file_bytes:0}(blanked + archived instead of the oldThe key options property is required…throw). Retention still OPEN: fk-devexpiryDays=7(dev.json) /28(docker.json) vs ASSNUSZ-117’s 7 — confirm with NÚSZ (one-line config) - FKITDEV-8959 — RCA of why NÚSZ image deletion never ran:
removeAttachmentData()was gated behind a hangingremoveVideoData()step in a strictly-sequential cron (ran only ~17/49 nights), and the oldgetWhereselected a 1-day band (createdAt ∈ [now-8d, now-7d)) with no catch-up so a skipped night was permanent. Fix = ownRemoveAttachmentDataCronJob(decoupled) + self-healingcreatedAt < cutoffimage-scoped query + the key-guard above; verified on fk-dev per the note above - nusz-1.9.11.48-test-runbook — test plan for the
1.9.11.48payload’s remove-old-data cron (ASSNUSZ-76 / FKITDEV-9150): productizedbin/remove-old-video-files.js -f/-tmust run to completion without wedging on ffmpeg’sOverwrite? [y/N](root cause = missing-y) and strip the video track → audio-only webm;removeOldRoomDataconfig (videos 7d / audios 730d / attachments 7d, batched) + the 7d-vs-28d retention question still open; disk reclaim / backlog scale flagged prod-only - janus-memory-leak-rca — the
AutoCloseRoomsCronJobquestion, answered 2026-09-07. Full chain verified in source:customization/cron/AutoCloseRoomsCronJob.js(*/5 * * * *) →queueClient.roomCron.autoClose(cron.js:139publisher) →queue-room-cron→queue_server/RoomCron(server.js:509consumer) →RoomService.autoClose(RoomService.js:447) →videochat.close()→roomTransport.destroy()→closeJanus()→janus.destroy(). The chain WORKS and IS a genuine mitigation for the abandoned-call janus leak, because transports leaveTransportPool.sessionsonly viadestroySession()/rpcDestroy()— nothing removes them on socket death — so the stranded transport is still in the pool for the cron to find. Three constraints: (a) double-gated onroomAutoCloseHours, which has NO DEFAULT (docs: “Nincs alapértelmezett érték”) ⇒ unset = no-op, so partners without it have nothing; (b) it structurally cannot clean theVuerCVListenerSessionpath —SelfServiceTransportSession.terminate()has zero references tovuerCVListenerSession; (c) it iscreatedAt-based, not last-activity ⇒ it cannot be tuned aggressively without killing live long calls. Separately:CloseExpiredSelfServiceRoomsCronJobis self-service only and does NOT cover operator videochat rooms - SLARAFIPI-84 — nothing prunes
ActivityorFlowActivityin vuer_oss (verified at tagraiffeisen-1.9.11.100): noActivity.destroyanywhere inserver/,customization/orbin/;features.archiveis false indocker.jsonsoArchiveCronJobis never registered; and even enabled it only moves attachment bytes (AttachmentArchiveServicenullsfile, setsisArchived) and never touchesTask.data,ActivityorFlowActivity. ⇒ a retroactive recovery of rejected face-comparison scores back to June is viable. Two reading traps: theisArchivedfield in a room export is not a column — it is computed at serialization inserver/web/helper/TechnicalLog.js, andnullmerely means the activity has noattachmentId;isDataAccessible: truemeans the customer’s encryption key still exists (not crypto-shredded). Caveat: verified in the released config only — Spring Cloud Config Server can override any key at boot, so confirm against the live runtime - SLARAFIPI-84 — CORRECTS the retention picture for the Raiffeisen recovery, and retires the crypto-shred worry entirely (2026-09-08). The three sources a rejected face-comparison score can be recovered from —
selfService:attachment,selfService:cvTask:log,selfService:v2:config:state— are NOT members ofENCRYPTED_ACTIVITIES(server/db/model/activity.js:152-163), soactivity.contentreturns plaintext JSON and deleting a customer key cannot make them unreadable; the earlier “room/customer deletion crypto-shreds the key” clause is REFUTED for these types. “Auto delete customers” selects only customers with no room and no self-service room (CustomCustomerDeleteService.js:25-31) and deletes no rows at all (CustomerDeleteService.js:27-72) — their own log saysThe auto deletion of 0 customers has been completed.Archive / flow-clear / delete-rooms / room-bulk-delete are not registered in the partner’s UATvuer_cron.log(six jobs run, none of them these) ⇒ this is now a runtime observation from their log, not the weaker repo not-finding. The only content-destroying paths are manual:bin/db/truncate,bin/db/migrate-data, the admin flow-delete route (not registered;clearFlowthrows) and socketflow:reset, gated on a per-protoresetableFlowScope row that is false by default. Still scope the promise: the Cron manager UI can start a job live, andfeatures.flowClear/features.archive/deleteRoomCronJob.activeare all overridable fromconfig/local.json
Crypto policy / GPG SHA1
- FKITDEV-8252 — decision revised: original per-key
rpmkeys --import --allow-sha1-signaturesplan did not survive UBI10 reality (flag disappears aftermicrodnf -y updatestrips it fromrpm-libs;DEFAULT:SHA1sub-policy doesn’t exist — noSHA1.pmodships); now usingupdate-crypto-policies --set LEGACYin all 7 SHA1-key-importing build stages across portal_css, vuer_css, vuer_oss, janus (×2), vuer_cv; order matters: installcrypto-policies-scriptsfrom UBI10 BaseOS BEFORECOPY-ing the CentOS Stream 10 repo
CSP / log noise
- ASSICASH-71 — InstaCash CSS log noise:
WebServer.jssetupCSPReportViolation()writes every report unthrottled; amplifies anyhosts.portal/portal.urlconfig drift
Customization branches
-
FKITDEV-9252 — CORRECTION 2026-09-07 to the “no customization-aware unit-test layer” claim:
vuer_ossdevel commitb704916a01(fkqa-356) adds an explicittestMatchforcustomization/test/tests/unit/**, so currentdeveldoes run partner unit tests. Measurable tell: devel 426 suites vs 347 on a branch cut before it. The long-unsourced “79 never-run customization tests” figure is now sourced —find customization -path "*/test/tests/unit/*" -name "*.test.js"⇒ 79. ⇒ the claim survives only for branches predatingb704916a01, and the merge that pulls it in will start executing those 79 files for the first time; customization-branch-ci-pipeline-inheritance §2 carries the callout -
SLARAFIPI-84 — the base file can be self-consistent and still be the wrong answer. Our “the rejection boundary is
probable(0.6)” claim came from readingserver/service/SelfServiceCheckerService.js:36-38alone, where it is TRUE;customization/listeners/self-service-v2.js:114-126overwrites a different rung (perfect:=raiffeisen.customerPortrait.threshold= 0.55) and never mentionsprobableat all, so searching for “the boundary” in the base finds a coherent ladder and stops. Rule: after reading a base file, grepcustomization/for the same setting name before treating the base as authoritative. -
ASSICASH-71 —
customization/instacash(Express 4, HEADb0a4a37a, deployed) vsdevel(Express 5, PR 689 fixes); next core sync needs to carry route-array fix -
FKITDEV-8787 —
customization/raiffeisenoverrides onSelfServiceRoomService.jsandSelfServiceV2Service.js;PRDEBUGinstrumentation gated byraiffeisen.debug.phantomRoomLog -
FKITDEV-8533 —
customization/generali-atvilagitasis the base branch for the Generali videoOrientExt tablet fix (PR #7893) -
FKITDEV-8788 —
customization/raiffeisenocr.engineselection (warp-firstVuerCVOCRRecognitionvs no-warpVuerCVMRZDetector) + recognition recipecustomization/cv/instruction.indexare the suspected override surface for the HU-eID-back MRZ crop bug -
instacash-update-2026-05-27-status — Periodic devel→instacash sync: branch name
update/customization/instacash-2026-05-27across all three repos (esign_css/vuer_oss/vuer_css); date-only convention; per-repo conflict topology captured -
esign-css-instacash-orphan-history — esign_css
customization/instacashis a single squashed orphan commit with no merge base; structurally distinct from conventional long-running customization branches -
ci-github-branch-audit-chronically-red — every customization branch inherits a chronically RED “Github CI - Branch” audit gate (
improved-yarn-auditexit 4 on un-excluded critical advisories);customization/raiffeisenhas been red on it since ≥April 2026 — not a per-branch regression -
customization-branch-ci-pipeline-inheritance — partner branches fork core source files in place (no override layer) and the repos have no customization-aware unit-test layer, so a partner-specific test failure can only be fixed by diverging a shared core test file — which then conflicts on every subsequent devel merge. Both amplifiers surface at once on a branch’s first devel-merge, when devel’s 6-job pipeline replaces the legacy single
lint-and-buildjob -
cve-2025-7783-form-data-via-request — CVE-2025-7783 / GHSA-fjxv-7rqg-78g4, critical
form-data@2.3.3(unsafe random multipart boundary, patched>=2.5.4) via EOLrequest@2.88.2which hard-pinsform-data: ~2.3.2. Absent from devel (its Audit job is green) — present only on the customization line, becauserequestis live partner code: vuer_osscustomization/api/sms/SmsCofidis.js, vuer_csscustomization/server/web/api/{login,register,partner-register}.endpoint.js. Confirmed red oncustomization/cofidis(#3100/#8040),customization/kh(#3098),customization/raiffeisen(#8055) ⇒ blocks every partner branch adopting the new pipeline. Fix matching house style (repos already pincsurf/cookie,twig/minimatch,ts-jest/handlebars): add"request/form-data": "^2.5.6"toresolutionsin package.json +yarn install. Long-term correct fix = drop EOLrequest(4–5 call sites) = separate ticket -
FKITDEV-8947 —
customization/unicredit: migrateUniCreditApiServiceoffrequest-promise-native→ fetch; the service does mTLS (cert/key/ca/passphrase fromportal.api), so the migration must useundici.fetch+Agent(vuer-oss-global-fetch-ignores-agent-mtls) — Node’s global fetch ignoresagent:. Working tree also has a stray}watApiService.js:267 -
mjml-v5-esm-breaks-commonjs-email-templates — cofidis forks its own email/letter templates (
customization/email/*/*.letter.data.js); the FKITDEV-8727 MJML v4→v5 (ESM-only) upgrade merged via FKITDEV-9059 broke the ones that mix a top-levelimportwithrequire()(require is not definedatEmailService.init). Per-partner blast radius — every partner forks its own letter files, so the same upgrade can break each on its next devel-merge. Fix52a0843a1e(require→import in all 6, onlye-mail-invitehad actually crashed) is unpushed onchore/FKITDEV-9059-cofidis-update-2026-07-13-fixes -
FKITDEV-9194 — Generali branch topology: customization lives in
vuer_oss+vuer_cssonly (zero generali refs inportal_css/esign_oss/esign_css); the live line iscustomization/generali-atvilagitas(taggenerali-atvilagitas-1.9.11.18) andcustomization/generali-karis DEAD — last commit 2022-01-24, 1754 commits behind devel, never merge devel into it -
customization-branches — dead-lines table + Generali repo-footprint callout added 2026-08-08
-
FKITDEV-9197 — CIB branch topology:
customization/ciblives in three repos — vuer_oss, vuer_css and portal_css — on two different version trains (cib-1.9.11.NNfor the vuer pair,cib-1.4.0.NNfor the portal). As of 2026-08-11 nothing had been committed directly to any of the three since the last release: each branch tip was the release commit (cib-1.9.11.1012026-05-29,cib-1.4.0.742026-04-21), which is what makes 1.9.11.102 a pure core-update release with an empty Phase-3 bucket 1. CIB is not an Oracle partner (nodb.optionsoverride, nooracledb⇒ Postgres), so FKITDEV-8279’s Oracle-dialect swap risk does not reach it
Customer data encryption
- sms-verification-code-dev-testing —
customer.datais an encrypted-at-rest TEXT column (serviceContainer.service.cryptos.data= DataCryptoService, keyed per-row bycustomer.key), but the Sequelize model’sdatagetaccessor auto-decrypts on read (customer.js:23-51,_getDecrypted:316-318,isEncrypted()=!!this.key) — so reading any portal-data field via the model (e.g.getVerificationCode()→videochatToken) returns plaintext, no manual crypto; by contrastsmslogs.messageBody/phoneNoare separately encrypted and NOT plaintext-readable - fk-dev-nusz-deploy-and-8959-verification — the
encryption.keyresolution chain (needed to exercise crypto-dependent code standalone):encryption.keyis a Sequelize getter (server/db/model/encryption.js) →serviceContainer.service.cryptos.data.getActualKey(key, customerId)(DataCryptoService) → for a null/absent key it callsserviceContainer.service.customerKeyStorage.getKey(customerId). A standalone harness must therefore initcryptos.{media,data,attachment}+CryptoService+customerKeyStorage; stubbingcustomerKeyStorage.getKey() => nullfaithfully models “customer key offline / inaccessible” — the real trigger for the FKITDEV-8959 image-deletion bug. Proven by TC-8959-02: a null-key image is blanked + archived +encryptionId=null(not thrown)
Database / Sequelize connection pool
- FKITDEV-server-session-too-low — RCA:
server/db/sequelize.jsonly setpool.max: 100with no lifecycle settings (idle/acquire/evict); × 7 supervisor processes = up to 700 connections against a PG defaultmax_connectionsof 100–200 ⇒SequelizeConnectionError: remaining connection slots are reserved for roles with the SUPERUSER attribute, first surfacing in the “Audit log forward” cron (cron is the first to starve). Assignee guidance (Bence László): don’t just bumpmax— turn onoptions.logging+options.benchmarkand measure (idle too long? acquire too short?) before writing new numbers. Triage SQL:SHOW max_connections;+SELECT usename,state,count(*) FROM pg_stat_activity GROUP BY 1,2;. Escalation if pool tuning is insufficient: look for multiplenew Sequelizeinstances, then PgBouncer - FKITDEV-7973-sequelize-pool-fix — the fix (
max:100→10,+min/idle/acquirelifecycle settings, plus a deep-merge ofdb.options.poolso individual keys are overridable instead of the old shallowObject.assign) is implemented but NOT merged — vuer_oss PR #7852 ismergeable_state: blockedon two standing CHANGES_REQUESTED reviews. Review consensus:max: 10is settled (Pocok256 initially wanted it raised — “anno a 100 is kevés volt” — but conceded after bencevarga666 argued the 7 processes must stay below the DBmax_connectionsand cited the PG wiki preference for few connections; CLI/tooling opening their own connections means 7 already understates the count). Both open code asks ACTED ON 2026-07-27 in commitc89124e29c(PR head moved7da69cba85→c89124e2, solo-author):min: 2→**min: 0** and theevict: 10000override deleted so Sequelize’s default 1s evict sweep applies — one change, sincemin: 0is only safe because the sweep is fast;max/idle/acquireuntouched. Two-file rule:server/db/sequelize.jshas a mirror intest/lib/utils/db.utils.js— the test harness duplicates the pool config, so both must always move together. Still blocked: both CHANGES_REQUESTED reviews stand and no re-review was requested / no PR comment posted, so nothing prompts a second look; PR body still saysTÖLTSD KI; branch ~58 commits behinddevel. Floated-but-undecided: per-process pool configs. Blocking gotcha for the “measure first” step:loggingis hardcoded after the config spread inserver/db/sequelize.js, sodb.options.loggingis non-overridable — you cannot turn on query logging/benchmark from config
Dependency forks / vendored patches
- FKITDEV-8279 — retiring the
@techteamer/sequelizefork (upstream 6.32.1 + 3 patches, published 2023-10-13,v6branch frozen since, ~2.7 yrs abandoned) for upstreamsequelize@6.37.8+patch-package, on branchfix/FKITDEV-8279-sequelize-upstream-6-37-8— PUSHED 2026-08-31 @7664b784d0(11 ahead / 16 behinddevel), still no PR. The three patches are all load-bearing and were carried verbatim (fidelity mandate, byte-verified against 6.32.2 from the Yarn cache): (1) Oracle reserved wordsKEY/PASSWORD/TYPE/VALUE(112→116) — without it every Oracle partner runningquoteIdentifiers: falsebreaks on the first query across 30 columns in 27 core models; (2) MSSQL null-BLOBattrTypesthreading (otp,unicredit-srbare live on MSSQL, so it is NOT dead weight); (3)Model.sync()index comparison by fields not name, which runs outside theoptions.alterbranch on everysync()and the Oracle partners bootsyncOnStart: true. Four defences, four distinct failure modes:patch-package --error-on-fail(patch stops applying → hard install error), 30 unit tests (hunk loses its behaviour; 9 go red on bare upstream; the 7 originally-dark hunks were each proven load-bearing by reversing them one at a time),assertVendorPatches()atserver/db/sequelize.js:35(installed with--ignore-scriptsorpatches/missing from the image → boot refuses), and CI’syarn --frozen-lockfilemaking the unit suite itself a CI-level assertion that the patch applied. Gotchas that generalise to anypatch-packageuse: it must be a runtimedependencywhere production installs runyarn install --production; a missingpatches/dir is a silent no-op even under--error-on-fail;yarn install --check-filesis required once the patched package goes missing fromnode_modules; a version-stamped patch filename under a caret range only warns if the resolve moves. The guard is dialect-scoped (oracle+mssql) so it covers 2 of 3 patches. UnguardedattrTypesdereferences were carried over deliberately — fork-identical and in production at all five partners, so unreachable today, but the hazard is now ours - FKITDEV-8279 — 2026-08-31 evidence upgrade, and three corrections. Validated on Oracle 19c EE 19.3.0.0.0 (the engine partners actually run, not just 23ai), plus PG 16.14 / MySQL 8.4.11 / SQL Server 2019+2022 with the partner-pinned drivers read off the partner branches (
oracledb5.5.0 thick + Instant Client 23.26.2.0.0 forbb/mkb-instant, 6.10.0 forkh,tedious14.2.0 forotp/unicredit-srb). 19c replay = 25+128 migrations, 0 errored, 0 skipped, 62 tables / 204 indexes, index inventory row-identical to 23ai.ORA-00904reproduces in both directions on 19c ⇒ patch 1 is load-bearing on the real engine. Patch 3 is inert over a repo-built schema but NOT cosmetic — reversing the hunk over ONE renamed index makesModel.sync()abort withORA-01408, a failed startup forsyncOnStart: truepartners; “not exercised” ≠ “not needed”. Oracle’s 30-char identifier limit does NOT apply on 19c (19 index names >30, max 58, zeroORA-00972) — stop using it as an argument. Engine inversion: 19c emits a bareORA-00942with no object name, 23ai interpolates it, so devel’s original whitelist regex already matches on 19c ⇒ commit7664b784d0is 21c+ forward-compatibility, not a live-defect repair. New findings: (A) the vendored patch has a latent MSSQLTypeErroron rawsequelize.query(sql, {bind:[...]})(proven by controlled inverse; zero of 21 raw call sites usebind:) — prevented at source by ano-restricted-syntaxESLint ban (47142d9156) rather than by patching the hunk; (B)oracledb@5.5.0is broken on Node 24 (util.isDateremoved in Node 23) independently of sequelize, andbb/mkb-instantpin^5.5.0whileengines.node: ">=22.18.0"admits Node 24 (fix: 6.10.0 thick, 4/4 green) — separate ticket; (C)bin/db/migrate-rdbms.jscannot migrate an Oracle partner —--url=makes sequelize-cli skip the config file and dropquoteIdentifiers:false, andsync()at:89-90repeats it, so fixing the four--url=sites is not enough; the naive “mergedb.options” fix is a trap (foldscreatedAt→createdaton 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 ⇒ a tooling property, own ticket. Still gating: no partnerUSER_INDEXESdump, patch 3 unproven outside a synthetic case, 109 of 128 migrations were no-ops in the replay ordering, partner data + customization migrations untested.fk-devIS reachable — asops@fk-dev.taild4189d.ts.net; the old “tailnet policy refuses SSH” note is retracted. Szabó Márton ran the earliercustomization/bbtest and is the likeliest route to a bb index dump — the question about his run’s effective config was never asked; FKITDEV-1208 namesmkb-instant, notbb, as the org’s validation target - FKITDEV-9022 — the adjacent policy question for TechTeamer’s ~20 forks/libs: publishing them to the private
npm.facekom.netregistry; FKITDEV-8662 “Forkolt dependency-k karbantartása” is the inventory ticket both feed
Dev / testing workflow
-
FKITDEV-9252 —
npx jest -c jest.config-unit.jsis NOTvuer_oss’s test runner and invents three failures that do not exist: it omits--experimental-vm-modules, so the ESM-onlystack-tracepackage cannot load and jest reports bogusSyntaxError: Unexpected token 'export'fromlogger/helpers,logger/syslog-client,logger/papertrail. Always validate withyarn test:unit; distrust any review figure that did not come from it. The rest of the round is a template for “review someone else’s fix”: Node v24.18.0 (= CI’s pinnedNODE_VERSION: 24), two worktrees each with its OWNyarn install --frozen-lockfile(a stashed baseline has produced a wrong count here before — FKITDEV-8279), then compare the failing SET, not the count —web-server-auth.test.js37/37 vs baseline 21/21 (+16), full suite 3 suites / 4 tests failing on both sides ⇒ no regressions,yarn lint0 on both. Standing survivors:converter(ffmpegmergeFiles),vuer-cv-servicepadDetection×2 (hardcoded/workspace/container path),self-service-v2photoCandidate. A green suite is still weak evidence — the fix’s own failover path is stubbed out byauthenticate = jest.fn()and the rewritten_setupLocalRoutingmessage/audit block has zero coverage -
FKITDEV-9252 — a reusable LDAP fault-injection fixture now EXISTS (the vault previously recorded that none did): a BER-parsing TCP proxy at
vuer_oss-FKITDEV-9252/scratch-9252/ldap-fault-proxy.jsfronting a liveglauth, with triggersaccept/acceptHang/bind/search/bindResponse/finBind/finSearch/hangBind/hangSearchselectable by connection and op ordinal, RST viasocket.resetAndDestroy(); drivertest/tests/unit/zz-ad-live-failover.test.js, outputscratch-9252/full-run-output.txt. UNTRACKED in a scratch worktree ⇒ it dies with the worktree — move it somewhere tracked to keep it. It is the first real tier-2 asset for facekom-test-tiers. It also refuted a static-review finding, which is the general lesson: observe the wire, do not infer error shapes from library source. Limits to respect:ECONNABORTED/EPIPEnever reached; glauth returns[]forgetGroupMembershipForUsersouseMemberOfProperty: falsecannot succeed on it (all runs usedtrue); the chain driver re-implements passport’sfail→next /error→abort /success→done semantics rather than using passport’s middleware. Wire fact worth keeping: one AD login opens TWO TCP connections — conn#1 technical bind + search, conn#2 technical bind again (createClient(null, null, this)inheritsbindDN/bindCredentials) then the user bind -
FKITDEV-8931 — a testing-scope trap worth generalising: a fix gated on one socketLabel looks broken everywhere else. The silent re-auth fires only for
default.layout;kiosk.layoutand videochat still hard-reload by design. Becausecustomization/mkb-instantis kiosk-heavy, the obvious pages to click are exactly the ones out of scope — a tester lands on a reload and reports a failed fix. Correct targethttps://css-fk-dev.taild4189d.ts.net/→mbh-services. Also: verify the change in the bundle as served over HTTPS, not the file on disk -
fk-dev-partner-branch-deploy-runbook — swapping fk-dev to a different PARTNER (2026-08-18), the step the branch-swap runbooks omit: a partner is branch + the read-only per-service
config/local.json+ avuer_oss_<partner>database + operator users + cssyarn build. Highest-value gotchas for any agent on this box: the uid 1001 (hostops) vs 1000 (containertechteamer) split → a tree-wide chown breaks logging into a restart loop (EACCES … logs/server.log), always re-fixlogs/to 1000;yarn installmust run as root in-container, and never pipe yarn totail(it masks the exit code — the shell reported 0 while yarn had errored); the mountedlocal.jsonis per service, not per partner, and survivesgit checkoutso it silently carries the previous tenant’sdb.url+flow.flows; client-side vuer_css changes are invisible untilyarn build(output is gitignoredweb/{js,css,branding,polyfills,libs/pdfjs/wasm}); andsupervisorctluptime0:00:00with a climbing pid means restart loop, not a fresh restart. The order is the dangerous part:db.syncOnStart: truemakes every boot runmigrate→sync→migrate, so a restart with the new code and the olddb.urlmigrates the previous partner’s database (autorestart=true⇒ a crash is enough) → DB + config before checkout. Andlocal.jsonis inode-bound (single-file bind mount): rewrite withcat >, neversed -i/mv/git checkout --. Verify with the socket.io handshake, a grep of the bundle as served over HTTPS, and a check that referenced assets return 200 rather than only the HTML. Two named false alarms: a staleweb/branding/layoutsdirectory mtime (the.branding.cssfiles inside carry the real time) and mkb-instant’sverify-password-test.js(rejects only the literalincorrectAccordingToPasswordPolicy, not a login blocker — unlike cofidis’sverifypassword.js) -
facekom-test-tiers — FaceKom release testing splits into three tiers and the MIDDLE one has no tooling at all. Measured against nusz-1.9.11.48-test-runbook: ~60% of a real runbook cannot be driven by a browser, which is exactly what the k6/Playwright framing assumes. Tier 1 static/hermetic (needs nothing — lint, unit, config schema, the clean-merge-broken-product detectors); tier 2 booted non-browser (app running, no browser — flow registration at boot §3.1, RPC, cron CLI completion §1.1, emails actually sending §4.5, report/xlsx exports, DB assertions) = NONE; tier 3 browser (full stack + media) = 12/45 k6 files ported. So “12/45 = 27% done” is a ratio against tier 3 only. Unreachable even in principle: iOS Safari mid-call backgrounding (§4.3, Safari-gated, iPadOS reports desktop UA) and the runbook’s own “cannot be validated in UAT” list (real disk reclaim, prod load profile ~40–50% CPU / ~940 Mbit/s / ~1 TB backlog, customer-key-offline deletion branch). Two hard tier-3 limits: k6 has no file upload at all ⇒ the attachment/S3 storage+export flow (§4.4 — a P1 on the FKITDEV-7665 BREAKING conflict surface) is unportable; and
k6.ymlpasses onlyCI_DOMAIN, neverK6_BROWSER_ARGS⇒ no fake camera/mic, no--disable-web-securityon the docker path — close to fatal for a video-identification product. The payoff: a tier-2 harness that boots the app to assert against it IS option (a) of the k6 seeding blocker (“Node pre-seed step reusinghelper.ts, handing k6 a fixtures JSON viaopen()”) — it already hashelper.tsloaded and a live DB handle, so emitting fixtures is nearly free ⇒ building tier 2 unblocks the 30 stalled k6 tests as a side effect, which argues for tier 2 before finishing the port -
FKITDEV-8279 — three
vuer_ossgotchas that cost time on any branch, not just this one: coredevelneeds Node >= 24 (geoip-lite@2.0.3declaresengines.node >= 24.0.0, soyarn installfails on Node 22.22.3) even thoughpackage.jsonstill says">=22.18.0"— CI already pinsNODE_VERSION: "24"; jest here takes--testPathPatterns(plural), the singular form was removed; and a genuineorigin/develbaseline must be built withgit archive+ devel’s own lockfile, not by stashing — that is what corrected the pre-existing unit-failure count from 4 to 5 (devel 347 suites/3673 tests/5 failed vs branch 348/3703/5, identical failing sets). At least two of those five (SelfServiceV2Service › photoCandidate,AppointmentService › checkFreeAppointments) are date-dependent, so the expected-failure set drifts day to day -
k6-e2e-harness-vuer-oss — the k6 browser-test harness in vuer_oss
test/tests/k6/(landed by FKITDEV-9041): vuer_dockerk6.ymlruns stockgrafana/k6:master-with-browser, mountstest/tests/k6→/e2e,run /e2e/${K6_TEST_FILE:-all.ts}, envCI_DOMAINonly ⇒docker compose -f k6.yml up. Three things it does NOT give you: (1) no CI verification at all — separatetest/tests/k6/tsconfig.json, root tsconfig excludestest/,yarn lintignorestest/*, notypecheckscript ⇒ typecheck by handtsc -p test/tests/k6/tsconfig.json; (2) no ordering —playwright.config.tschains 14 projects viadependencieswhile k6 scenarios withoutstartTimeall fire at t=0 concurrently (shared-iterationsdefaultsmaxDuration: 10m);OpenHoursSetupis load-bearing (setOpenHours('00:00','24:00')× 7 days, else the vuer_css customer flow never renders its callback button); note that within a Playwright project a failing test fails only itself — only downstream projects skip; (3) no fixture seeding — 30 of 45 e2e tests boot the real Node app in-process viatest/tests/support/helper.ts(server/db/sequelize, models,UserService,FlowService,acl), and k6 has its own JS VM (4 options weighed, undecided). Also:k6.ymlpasses noK6_BROWSER_ARGS⇒ no fake camera/mic, no--disable-web-securityon the docker path; suite runsNODE_ENV=devand can erase the DB -
playwright-to-k6-translation-recipe — how to port a Playwright test to
k6/browser, and what cannot be ported (limits verified vs@types/k62.0.1). Mechanical: page objects ~1:1,@playwright/test→k6/browser(type Locator/type Page),vuerUrls.oss()→oss()fromlib/env.ts, dropreadonly, explicit.tson relative imports,describe/test()/beforeEachcollapse into oneexport default async function ()withbeforeEachinlined per case,expect(v).toBe(y)→check(v, {'<verbatim test() name>': …}), notest.step(), nostorageState(every file callsloginOperator(page)). Two waiting rules that bite: k6 does NOT auto-wait on navigation →Promise.all([page.waitForNavigation(), locator.click()]), but do NOT add it when the click is already followed bypage.waitForURL(...)(the second waiter misses a completed navigation and hangs); and Playwright’sexpect()auto-retries while k6’scheck()does not → anything that relied on polling needs a waiting locator (visible()/hidden()). Hard limits: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 subsequent tests die; no file upload (noFileChooser/waitForEvent('filechooser')/setInputFiles;page.waitForEvent()takes only'console'|'request'|'response'), nopage.coverage.*, nopage.route(), no Node built-ins/require('server/**'), no:has-text()(uselocator('button',{hasText:'…'})). Faithful-porting caveat: vacuous assertions in the originals (hasEmailError()/hasRightsError()=!!page.locator(...);await-lessexpect().toHaveText()inopen-hours.test.ts) were reproduced as-is on purpose -
FKITDEV-9200 — the Playwright→k6 migration itself: 45-test inventory, 12 files / 93-of-96 cases ported on
chore/FKITDEV-9200-e2e-k6(uncommitted), 3 file-upload cases dropped,staticendpoints.test.tsdeliberately not ported (coverage-only),all.tsrestructured to one sequential scenariomaxDuration: '1h' -
dev-build-host — where to build/test: the
fk-devTailscale VM (command ssh ops@fk-dev.taild4189d.ts.net). The oldssh Facekombox is decommissioned (offline since ~2026-06-27) — every older note saying “build/test onssh Facekom” now means fk-dev. Still true: native builds on the remote host, never emulated on the Mac; usecommand ssh(thekakualias shadows plainsshnon-interactively) -
fk-dev-deploy-smoke-runbook — the practical “swap a component onto a branch and smoke it” runbook for fk-dev (verified 2026-08-13). Deploy = explicit-refspec fetch → reset/clean/checkout (vuer_css git ops via
docker exec -u 0:0because its tree is root-owned and ops has no sudo) →yarn install --frozen-lockfilein-container →npx sequelize-cli db:migrate→supervisorctl restart; verify HTTP from the Mac. OpenHours is load-bearing for any videochat/operator-handoff smoke — tableopenhourstandards(plural), default calendar =calendarName IS NULL; open fully withupdate openhourstandards set "from"='00:00',"to"='24:00',"isOpen"=true where "calendarName" is nullrun via the app’s ownrequire('./server/db/sequelize.js')(reads creds from node-config → no raw credentials, and printingdb.passwordgets blocked by the safety classifier), thensupervisorctl restart vuer_ossto clear the open-hours cache. e2e helpertest/tests/open-hours.setup.ts/ seedtest/seed/seed.jsgetOpenHours(null)insert mon–sun 00:00–24:00 as reference -
instacash-external-api-esign-headless-test-2026-06-01 — how to exercise the InstaCash external API headlessly with
bin/instacash-cli.jsfrom thevuer_osscontainer: SSH viacommand sshto the dev host (now fk-dev, dev-build-host);start-server(detached) mocks the bank/auth+/statuson 8189;post-application [rt|nrt] [mkb_szemelyi_kolcson|mkb_mszh|mbh_mfl]returns{customerId, customerProfileUrl, inviteUrl};post-contract <id> [pdf]drives the ic-contract flow → EsignRPC → esign. Caveat: every cmd exceptstart-serverboots the full vuer_oss service in-process (needs healthy stack +instacash.external.apiKeyBearer +allowSelfSignedCerts); and the eSign signature itself can’t be automated (interactive video-ID + auth + sign at theinviteUrl) -
dev-box-esign-container-startup-failures-2026-06-01 — debugging the
esign_css/esign_ossunhealthycontainers on the dev box (observed on the oldledererabox, now decommissioned — same triage applies onfk-dev, dev-build-host): how to triage (docker exec <c> supervisorctl status→ nginxFATALwhile app/redis/cronRUNNING= the PID-permission bug); the ~60s-unhealthy-after-any-restart healthcheck anti-flap (don’t chase it); post-dep-major-bump lesson — re-yarn installthe running container (/workspace/<svc>/node_modulesis host-bind-mounted, a baked image install goes stale →RedisStore is not a constructoretc.);command ssh Facekomto reach the box from Claude’s shell (kakushadows plainssh), login shell (bash -l) so docker is on PATH; chalk ^5 ESM-only brokeyarn trans(bin/test/trans-check.js:6) → dynamicimport('chalk') -
dev-box-cv-photo-processing-failures — “error during photo processing” / “CV server is down” on the
ledereradev box has two compounding causes:vuer_cvcontainer stopped (docker start vuer_cv, ~2 min to healthy; nginx 502→404 on loopback curl) and hairpin NAT (vuer_oss host-net/etc/hostsmaps*-lederera→ own LAN IP192.168.1.93; remap →127.0.0.1); the hosts edit is wiped on everydocker restart vuer_oss(Docker-regenerated bind mount) so re-apply after any restart, via truncate+write notsed -i -
sms-verification-code-dev-testing — get/force the SMS (and email) verification code when the customer phone is fake:
test.security.tempTokenSms(truthy → fixed code every send; conventional value123456in alltest/testconfigs/*.json;tempTokenEmail: "mailToken"for email) is read by thecustomer:verification:sendSmshook (customization/listeners/sms-verification.js); dev box (lederera/NODE_ENV=dev) does NOT ship it — add toconfig/local.json+ restart (node-config caches at startup) + resend (old random code won’t match); alt recovery = readcustomer.getVerificationCode()via model (auto-decrypts);matchTokens(ContactValidationService.js:16-20) = case-insensitive exact match -
esign-css-customization-branches — eSign standard dev/test method: test through VÜER CSS with
requestFakeCustomer = trueand?esign=1&token=… -
instacash-esign-dev-box-deploy — testing an InstaCash eSign release on the dev box (now
fk-dev— thessh Facekombox it was written against is decommissioned, see dev-build-host; code bind-mounted from/workspace): the box defaults to Raiffeisen so you must align the whole partner chain to InstaCash (esign_oss/css → taginstacash-1.3.0.11, vuer_oss/css → taginstacash-1.9.11.50since the eSign ticket pins no vuer version, pdfservice stays main/2.0.12 partner-agnostic). Per repo:git stashWIP →git fetch --tags(clones predate the tag) →git checkout <tag>→ rebuild in-containerdocker exec <c> sh -c 'cd /workspace/<repo> && yarn install && yarn build'→supervisorctl restart all. Verify supervisord RUNNING +RabbitMQ connection established+Web server is listening+ esign_css :10183 HTTP 200. Gotchas: a “dirty” vuer_css = untracked.claude/dir; old log ERRORs may be historical from the prior run (check timestamps) -
fk-dev-nusz-deploy-and-8959-verification — deploy a branch to the
fk-devGCP dev-mirror VM (tailnettaild4189d.ts.net; NOT the offline on-premssh Facekombox) by bind-mount swap, no image rebuild:command ssh ops@fk-dev.taild4189d.ts.net(Tailscale SSH, no keypair;kakushadowsssh→command ssh/command scp); the box has NO GitHub key sossh-add ~/.ssh/id_ed25519+command ssh -Ato forward yours; then on/workspace/vuer_oss:git fetch origin <branch>+checkout→docker 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+ operator UI (https://oss-fk-dev.taild4189d.ts.net) HTTP 302.postgresqlpeer-auth blockspsql -U postgres(use app Sequelize);nginx_proxycrash-loops but sidecars bypass it; restore the box’s originalbd8923d69f(InstaCash) when NÚSZ testing done. Also documents a reusable standalone cron test-harness pattern (Node script inbin/→process-settingsbootstrap + loggerProxy+ service/crypto stubs +sequelizeauthenticate + raw-SQL seed → call the REAL service methods → SELECT before/after; deliver viacommand scp+docker cp+docker exec+rm) -
mailtrap-sandbox-inbox-dev-email — FaceKom dev email is not broken:
config/dev.jsonemail.transport.SMTPbakes a Mailtrap Sandbox inbox (hostsmtp.mailtrap.io, port 2525, user643414e4c00185), so registration/verification mail is delivered into the original-dev/shared inbox you can’t see (symptom reads as “emails don’t send to Mailtrap”). Route to your inbox by overridinghost→sandbox.smtp.mailtrap.io+auth.{user,pass}in the bind-mountedvuer_oss-local.jsongetconfiglocallayer (config/docker.jsonis never loaded underNODE_ENV=dev; Sandbox creds don’t auth the legacysmtp.mailtrap.io). Distinguish Sandbox (sandbox.smtp.mailtrap.io, per-inbox user/pass ~14 hex, catches mail) from Email Sending / live (live.smtp.mailtrap.io,api+ 32-char token, delivers for real — wrong for testing). Verify withnodemailer.verify()first (require nodemailer by absolute path/workspace/vuer_oss/node_modules/nodemailer). Sibling to sms-verification-code-dev-testing (invisible-delivery-channel dev testing) -
jest30-ignore-optional-native-resolver —
yarn test:unitdies on a fresh vuer_css install (root cause corrected 2026-07-31):.yarnrcsets--install.ignore-optional true; Jest 30’sjest-resolve@30.4.1→unrs-resolver@1.12.2ships its platform binding (@unrs/resolver-binding-darwin-arm64/-linux-x64-gnu) as an optionalDependency, so it’s skipped →require('unrs-resolver')= “Cannot find native binding” →Resolver.findNodeModule()returnsnullfor EVERY module (verified forts-jest,jest-circus,lodash,jest-resolveitself). Jest blames whichever module the config names first ⇒ the misleadingValidation Error: Module ts-jest in the transform option was not found, and thejest-circus/build/runner.js not foundfollow-on is the same single bug, not a second one. Diagnostic:node -e "const R=require('jest-resolve').default; for (const m of ['lodash','jest-resolve']) console.log(m, R.findNodeModule(m,{basedir:process.cwd()}))"— allnull⇒ resolver/native-binding, not a per-package problem. Scope narrowed 2026-07-31: macOS/arm64 LOCAL DEV ONLY — CI is GREEN (pull-request.yamlinstallsyarn install --frozen-lockfileunder the same.yarnrc; all 7 checks incl.Unit Testspass on the FKITDEV-8887 head). Also NOT caused by--ignore-scripts(re-tested with scripts enabled — binding still absent; the failure is at fetch time). Fix = localnode_modulespatch, NOT a repo change:npm pack @unrs/resolver-binding-darwin-arm64@1.12.2→ extract intonode_modules/@unrs/. The earlier “drop/scopeignore-optionalon devel” recommendation is withdrawn — unjustified when CI is unaffected. Why Linux runners resolve the binding is an open question, not an assertion. Green with the binding + stock deps (yarn.lock/package.jsonuntouched): 119 suites / 1051 passed / 47 skipped / 0 failures. RETRACTED: the “ts-jest@29.4.11 is an empty publish, pin 29.4.10” claim is FALSE — thatdist-less directory (with the straynpm-view.err) was a poisoned local Yarn v6 cache entry (~/Library/Caches/Yarn/v6/npm-ts-jest-…-integrity/);yarn cache clean ts-jest+ reinstall restoresdist/and stock 29.4.11 passes the whole suite. Do not pin ts-jest. Reusable lessons: a Jest “module not found” names a victim, not a culprit;ignore-optionalis unsafe once any dep uses napi-rs per-platform bindings (esbuild/swc/rollup/lightningcss/sharp); a Yarn cache entry can be silently corrupt and is reused forever until cleaned, and a stray CI log (npm-view.err) inside an installed package is a cache-artifact tell, not proof of a bad publish; a local-only repro is not a repo bug — check CI before proposing a repo-wide config change. -
devel-update-verification-recipe — the base-commit-worktree technique, the only honest way to say “pre-existing”:
git worktree add ../<repo>-base <pre-merge-tip>+ symlinknode_modulesfrom the merged tree, run the same suites on both, diff the failure sets not the counts. Generali vuer_oss: base 10 failed vs merged 4 ⇒ zero merge-caused and the merge net-fixessms-report-service. Corollary: run suspect suites isolated and repeatedly — full-suite runs showed a shifting failure set from test-order interference (isolated runs were deterministic across 3 repeats) -
raiffeisen-1.9.11.100 — a git worktree’s
node_modulescan be silently out of sync with the branch it is checked out on. Re-running the FKITDEV-8787 suite in avuer_cssworktree failed on a missing@babel/plugin-proposal-class-properties— switching a worktree onto a release branch does not trigger a re-install, so you can be running another branch’s dependency tree against this branch’s code. Fix:yarn install --frozen-lockfilein the worktree (not the main checkout). Add it to the checklist alongside the base-commit-worktree technique above — both concern trusting a worktree’s environment. Same session also hit two RTK mangling cases (see## RTK / tooling gotchas) -
portal-css-jest-runs-zero-tests — before you cite a test run as evidence, confirm it ran anything. In portal_css
yarn jestexecutes zero tests and CI is green purely on--passWithNoTestsappended by the workflow; the customtestSequencerfilters every file through an empty allow-list and jest sorts before its “no tests found” check, so adding tests changes nothing. Diagnostic that isolates the sequencer from discovery/config: re-run with--testSequencer=@jest/test-sequencer— if the test suddenly runs, the sequencer is the blocker. Also blocks.tstests structurally: no@types/jest,test/outsidetsconfig.jsoninclude, notypes:["jest"] -
vuer-oss-unit-tests-green-is-weak-evidence — the vuer_oss twin of the above, found on FKITDEV-9197: one shared suite registers ZERO tests and two others flake in CI — all three on
devel, so EVERY partner branch is affected. (1)test/tests/unit/translations.test.js:181misusesit.each—it.each(table)returns a function that must be invoked with(name, fn), but the callback is passed aseach()’s second argument and the return value discarded ⇒ no test is ever registered, only itsit.skip(...)calls; verified in node and from CI output on a passing run (345 passed of 347 total/3515 passed of 3672). EverywrongKeys/missingLanguagefinding is therefore discarded for every partner — a probe found 42 invisible findings on CIB alone (flow_task_name/flow_task_instructions/flow_input_option→undefinedincustomization/flow/cib-*.flow.trans.js). Repairing it is a BREAKING CHANGE (those 42 become hard failures) ⇒ deliberate upstream ticket, never a drive-by. “Translations green” ≠ “translations checked” — FKITDEV-9197’sacaa597d83stopped the suite throwing at import (real, and why the job runs) but bought no coverage. (2) the same file’sscan()takes relativeincludedDirectorieswhilecwdis absolute ⇒ loading depends onprocess.cwd()at module-eval time, and it is actively flaky in production CI: nightly “Checks for Long-lived branches” oncustomization/mbh2026-08-11 went pass (20:13) / failDirectory not found: client/features(20:29) / pass (21:10) on the same commit, with both runners producing both outcomes;client/featuresis real and tracked (215 files); does not reproduce on macOS. develbfd1311aab(PR #8000) fixed only therequirehalf ⇒ the flake predates and survives it. Root cause of the cwd perturbation is UNPROVEN (noprocess.chdirin repo code;cross-spawn’sresolveCommand.js:18is a plausible leak window, not demonstrated). The obvious one-liner BREAKS it silently:path.join(cwd, startPath)makes returns absolute and kills three relative-path consumers (doubledrequirepath,excludedFiles.includesstops matching,argMap[...]undefined) — andpath.joinconcatenates, it does not resolve a leading/; that’spath.resolve; correct fix…scan(path.join(cwd,startPath), […]).map((f) => path.relative(cwd, f)). (3)server/util/pdf.test.js › printImage › place sample PNG imagebyte-compares a PDF and drifts by 3 bytes; re-run with no content change goes green ⇒ vuer_oss’s “Unit Tests green” was not first-attempt. Operational rule: one red run is not evidence of a regression, one green run is not evidence of its absence — re-run, then classify against a base-commit worktree and run suspect suites isolated and repeatedly -
FKITDEV-9197 — 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. Concrete: macOS cannot load vuer_css’s
config.jswithNODE_ENV=devunlessDEV_DOMAINis set —config.js:43doesfs.readFileSync('/etc/hostname')on thedev/traviscipath and macOS has no/etc/hostname→ ENOENT. An agent setNODE_ENV=devto test a config-loading hypothesis, saw the suite still fail, concluded “NODE_ENV is not the variable”, and misattributed a genuine CI failure to a ‘nested worktree artefact’. The hypothesis was right; the platform broke the experiment. The distinguishing move was running the same tree in the Linux product image on fk-dev. Companion to theNODE_ENV=devmasking entry under CI / build gates — the same variable misleads in both directions. AND IT HAPPENED THREE TIMES IN ONE TICKET, always the same failure mode — generalising from an experiment whose failure was never identified: four SSH users refused → “onlyrootworks” (opsnever tested);NODE_ENV=devstill failed → “NODE_ENV isn’t the variable” (it failed on a missing/etc/hostname, an unrelated cause never read);git log -Sreturned empty → “400 never existed” (the pathspec didn’t follow the rename). Each was caught only because something INDEPENDENT contradicted it — a retest, a Linux container, agit log -L— and none would have been caught 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”: a null result tells you about your instrument at least as often as it tells you about the world -
FKITDEV-9197 — a lazy
require()is only safe if you can name who already loaded the module. Fixingportal-client.test.jsmeant moving a module-scoperequire('../../../config')into the method — andconfig.jsis not side-effect-free (spring cloud config bootstrap, CORS default mutation, module-scopeconfig.loaded). The argument that made it safe was enumerated, not assumed: config is already required at boot byserver/web/WebServer.js:13,server/web/routes.js:2,server/bootstrap/connection/rabbitmq.js:2,customization/server/service/CIBSSOService.js:2+ fourcustomization/listeners/*, and the sole caller ofgetPortalRedirectUrlis an HTTP route (customization/server/web/routes/device-change-redirect.endpoint.js:34) which is necessarily post-boot ⇒ require-cache hit on the same object, never a first load. Rejected alternatives and why: forking the test (blob is byte-identical on devel/Generali/CIB ⇒ permanent merge conflict),config/test.json(a deployed-repo change to satisfy a test runner),NODE_ENVinjest.config-unit.js(currently identical to devel’s; diverging costs the same as forking). Residual risk recorded honestly:getPortalRedirectUrlhas zero test coverage, so the fix rests on an argument rather than an assertion -
vuer-browser-e2e-real-call-gotchas — seven silent traps between you and a scripted REAL vuer call (2026-09-07). The big one:
Content-Security-Policy: upgrade-insecure-requests+Securecookies mean vuer CANNOT be driven over plain HTTP — the browser rewrites every subresource to https, hits the non-TLS nginx, every stylesheet/script diesERR_SSL_PROTOCOL_ERROR, and you get a bare skeleton whose form is never wired; andcurlignores CSP, so curl-over-http always looks fine ⇒ curl is not a valid smoke test for anything browser-driven. Plus:WebServerAuth.js:821builds the post-login redirect from config, not the request (https://${config.get('hosts.oss')}${redirectTo}) so a non-standard port must live inhosts; the server-side gateGET /api/pre-checkanswersunknownfor HeadlessChrome,not_compatiblefor Chrome/120,compatiblefor 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-checkresolves, so an early click falls through to a native GET form submit (?_csrf=…&lastName=…, page just reloads);[data-action="take-call"]lives inside a<template>so 0 hits means no customer row rendered, not “hidden”;firstNameis letters-only^[a-zA-Z…]{2,25}$. Built for the janus-memory-leak-rca measurement; test code onchore/FKITDEV-9239-e2e-janus-memleak(vuer_oss + vuer_docker) -
verification-failure-modes — the four ways we answered a partner wrong, and the round-2 additions (2026-09-08) that are all silent-exit-0 failures. Modes 1–3: verified in the place we expected the answer (customization overlay changed a different rung); the record was stale; a correct fact scoped to a different question (the classifier-vs-flow trap — consulting the right-looking note increased confidence in the wrong answer). Round 2 adds: (1) a note that says “sent” is not evidence of posting — SLARAFIPI-84 carried “This is the text that was sent” above a reply that was never posted; fetch the thread and count the comments, and label vault drafts
UNPOSTEDin the heading. (2) A lens can refute the wrong branch — STATIC “proved”_isSameFacefails CLOSED by quoting handler:322-324(the missing-source branch) while the fail-open is the missing-target branch:338-367; ADVERSARIAL “proved” the config threshold never reaches the comparison by readingmigrateConfigStateas a mere change detector, overlooking the Setting-row write atSelfServiceCheckerService.js:1360-1364⇒ re-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 writes its full report to a file and reports the path. (4)extractskips attachments with exit 0 (skipped-type) — it dropped the.tgzserver log and the.xlsxexport, the two files that decided the investigation
Devel update sync workflow
-
instacash-update-2026-05-27-status — Branch naming convention:
update/customization/instacash-<date>(date-only, no ticket prefix), applied identically across all three repos (esign_css, vuer_oss, vuer_css); per-repo conflict surfaces vary significantly (esign_css blocked structurally, vuer_oss self-service-v2 listener high-risk, vuer_css modal a11y trio + customizations.js routes high-risk); using a separate worktree to keep parallel feature WIP branches untouched is the pattern (e.g.~/coding/facekom/vuer_css-instacash-updateto protectbugfix/FKITDEV-8787) -
esign-css-instacash-orphan-history — When the target branch is structurally orphan, the standard
git merge develhalts;git rev-list --count A..Bis meaningless without a merge base — three viable workflow options to choose between before resuming -
FKITDEV-8817 — Parallel-strategy sequencing: don’t block the sync on an unmerged adjacent PR; let the second
devel→update-branch merge pull it in once the PR lands on devel -
nusz-devel-update-2026-06-16-lint-merge-fix — NÚSZ
update/customization/nusz-2026-06-16merge oforigin/develfailed validation at lint, left mid-merge (uncommitted). Reusable merge gotcha: devel renamedFFmpegService.js→.ts; nusz tip had added an extensionlessrequire('./server/service/FFmpegService')tocron.js— conflict-free merge kept both, so it no longer resolves undern/no-missing-require.cron.js:46was the lone straggler (all other callers already on explicit.ts). Lesson: after a cross-side.js→.tsrename merge, grep for extensionlessrequire()s of the renamed modules -
customization-branch-ci-pipeline-inheritance — budget for the CI pipeline expansion on a partner’s first devel-merge: 1 job (
lint-and-build) → 6 (lint/test/audit/depcheck/sonar/build), i.e. 4 jobs run on the branch for the first time ever and most red is pre-existing partner breakage newly enforced, not merge-introduced. Triage every failure by origin (git blame/git logthe offending line) before choosing a fix side (partner file vs shared core test). Characterised on FKITDEV-9059 (Cofidis, 2026-07-20) -
FKITDEV-9059 — Cofidis devel update (vuer_css PR #3100 @
4dd8a927a, 105 files; vuer_oss PR #8040 @ad8a318a22, 586 files), bothmergeable_state: blocked; full 8-row failure inventory with root cause / origin / fix-side per failure -
mjml-v5-esm-breaks-commonjs-email-templates — an ESM-only major upgrade of a shared loader, merged via
devel → customization/*, silently breaks CommonJS customization files. The FKITDEV-9059 cofidis merge pulled in FKITDEV-8727 MJML v4→v5 (ESM-only,c9602a519e) →EmailService.jsawait import(...)s letter templates; Node 22 then parses anycustomization/email/*/*.letter.data.jsthat mixes a top-levelimportwithrequire()as ESM →ReferenceError: require is not definedatEmailService.init. Scope trap: NOT “41 of 49 files containrequire(” — only the 6 mixed files break, and 5 had acreateRequireshim so onlye-mail-invitecrashed at boot. Reusable rule: after any ESM-loader migration, grepcustomization/for mixed import+require. The ESM cousin of the nusz-devel-update-2026-06-16-lint-merge-fix.js→.tsrename gotcha -
FKITDEV-9194 — Generali round 2026-08-08 (release 1.9.11.19 prep): branch
chore/FKITDEV-9194-generali-update-2026-08-08offcustomization/generali-atvilagitasin both repos (precedentchore/FKITDEV-9073-generali-update-2026-07-15); vuer_ossdf01e922ce/ vuer_csse3c8996d4, 0 behind live devel, not pushed. Two semantic breaks hidden by a conflict-free merge: devel deletedserver/util/aiActHelper.ts(→server/web/helper/getAiActData.js) still required bycustomization/server/web/routes/waiting-room.endpoint.js:5; anda6185aa41 [fkitdev-8846] remove duplicated socket connectionsswappedauth()→SocketService.getConnection('<page>.script')while thegen-self-service-consent-{pep,ttny}overrides kept callingauth(). Fix pattern both times = mirror devel’s own core refactor inside the override, keep thegen-*identifiers -
devel-update-and-release-flow — START HERE: the end-to-end procedure, extracted 2026-08-11 and superseding the verification-only recipe. Phase 0 preconditions (which repos the partner is actually in; dead lines like
customization/generali-kar, 1754 behind — never update them; one ticket or two; checkremote.origin.fetchfirst). Phase 1 isolated worktree<repo>-FKITDEV-NNNN, ruleset-enforcedchore/FKITDEV-NNNN-<partner>-devel-updatebranch, real merge (never rebase) back intocustomization/<partner>(never devel), then the semantic sweep: deletions/renames first (--diff-filter=D/R— vuer_css caught the deletedaiActHelper.ts; vuer_oss had 0/0, making the class structurally impossible), resolve every relative require undercustomization/skipping comments, grep for removed identifiers, diff each override against its core counterpart. Phase 2 validation: Node 24 (yarn install --frozen-lockfilehard-fails on Node 22 —geoip-liteneeds >=24;engines: >=22.18.0is stale), classify against a base-commit worktree with its OWNyarn install(never symlinknode_modules— the merge movedyarn.lock800 lines and that shortcut voided a first attempt), isolated + repeated suite runs, remote run inside the product image onfk-dev(COPYFILE_DISABLE=1 tar --exclude='._*'orgit archive, else macOS AppleDouble files become ~20 bogus failing suites), and which CI jobs and scheduled matrices the branch newly enters. Phase 3 = the new headline, see Release management. Phase 4 release gates. Phase 5 re-check devel immediately before pushing -
devel-update-verification-recipe — superseded stub → devel-update-and-release-flow; kept only so old inbound links resolve
-
narrowed-fetch-refspec-stale-devel-merge — step 0 of any devel update: in a narrowed clone
git fetch origin develsilently leavesorigin/develstale and the merge is conflict-free and wrong -
devel-dependency-removal-breaks-partner-customization — NEW break class (Phase 1.4 check (e)): devel deleting a dependency as “unused” is only unused in CORE.
depcheckruns on the branch it is invoked on, and partnercustomization/code lives only on the partner branch — so it is not in the tree when the removal decision is made, the removal merges conflict-free, and nothing in CI can tell you until the partner merge. Canonical case (portal_css / CIB, FKITDEV-9197): devel’s7a42894a chore(FKQA-304): remove unused libs (#675)droppedmulter(customization/api/document-upload.js→multer.memoryStorage(); after the merge NOT RESOLVABLE = real runtime break) anduuid(customization/api/submit-login.js+submit-registration.js→uuid.v4(); resolved only transitively via a hoisteduuid@14.0.1against the declared^10.0.0). The transitive half is the worse one — it works today, at a major nobody chose, and breaks with zero partner-side changes the day the hoisting dependency moves; “it still resolves” is not a pass, undeclared-but-hoisted is unowned. Fix = restore"multer": "1.4.5-lts.2"+"uuid": "^10.0.0". Check = diffpackage.jsonfor removed deps →git grepeach undercustomization/→node -e "require('<pkg>/package.json')"to catch the hoisted ones (the step people skip). eslintn/no-extraneous-requireis the free detector for the quiet case under--max-warnings 0— do not silence it. Same family as the.js→.ts(nusz-devel-update-2026-06-16-lint-merge-fix) and ESM-loader (mjml-v5-esm-breaks-commonjs-email-templates) traps: git reconciles text, the two sides never touch the same line. IT CUTS BOTH WAYS — three outcomes, only one of which is “restore the line” (all three occurred in the same CIB round): (1) devel removed it deliberately (security/EOL retirement) ⇒ PORT the partner code off it, restoring re-introduces exactly what devel retired — vuer_ossrequest+request-promise-native, whose removal CIB’s ownsecurity/*.mdhad logged as scheduled monthly since 2025-03, ported tofetch; (2) removed as merely unused-in-core ⇒ restore the partner’s declared version (portal_cssmulter/uuid); (3) partner-only dep devel never had ⇒ KEEP it — vuer_ossclamscan/soap/xml-formatter/short-uuid/uuid/zod, vuer_cssnode-fetch/passport/passport-oauth2(the CIB corporate-portal SSO path). Row 3 has no detector whatsoever — it is not a merge artefact but a conflict-resolution mistake (taking devel’spackage.jsonwholesale), so the check needs a fourth step diffing the partner’s dependency set against devel’s for keys devel lacks. Andgit diff -- package.jsoncannot tell row 1 from row 2 — only the removal commit’s reason can. Signature of the whole class: clean · clean · dead (merge clean, lint clean, dies at require-time on boot) -
FKITDEV-9197 — CIB round 2026-08-11, release 1.9.11.102, all THREE repos (vuer_oss
e191f3f53f, vuer_css680a6256c, portal_cssb1a4bc94), branchchore/FKITDEV-9197-cib-devel-update, Node v24.18.0. Pushed 2026-08-12, three PRs open (vuer_oss #8126 · vuer_css #3152 · portal_css #712) — see the CI half at the end of this entry. It is a PURE CORE-UPDATE release: nothing was committed directly tocustomization/cibsince the last one — in all three repos the branch tip WAS the release commit (cib-1.9.11.1012026-05-29,cib-1.4.0.742026-04-21) ⇒ Phase 3 bucket 1 is empty, and the only partner-requested ticket (ASSCIB-161 = FKITDEV-8887, iOS Safari audio) was already on devel (6bdf66d16) and arrives via the merge — the same commit that is Generali .19’s headline (ASSGRALI-63) and invisible torelease_tickets.pyin both releases. 11 months of drift = 334 commits / 212 tickets (inventory + authors at/Users/levander/coding/facekom/out/FKITDEV-9197-cib-1.9.11.102-tickets.md; Makkai 44, Horváth 37, Szecsődi 16, Szekeres 15). Portal is a SEPARATE version train — resolve baselines with the repo’s owncib-1.4.0.prefix, never the vuer number in the ticket. Gates: oss lint 0 / build 0 / depcheck clean / audit 1 CRITICAL (the FKITDEV-8279 fork, expected, andbuildneeds: audit⇒ CI build blocked) / test 3546 pass, 3 fail all pre-existing against real controls (translations.test.jsis CIB-only and fails identically on the pre-merge tip;converter/vuer-cv-service/pdffail on clean devel) + import sweep 1219 specifiers / 703 files / 0 unresolved; css lint 0 / audit 0 critical / 1066 pass, 2 fail pre-existing, 53 conflicts resolved, 722 relative imports + 302 twig include targets all resolve; portal all green but zero tests exist structurally. CIB is NOT an Oracle partner (nodb.optionsoverride, nooracledb⇒ Postgres) so FKITDEV-8279’s Oracle behavioural-swap risk does not apply to it. Prior art was buggy: two abandoned unmerged branches (update/customization/cib-2025-11-12,…-2025-12-08tip4df6666d4f) had already ported 4 files tofetchbut silently droppedagentOptions, killing Infocert mutual TLS (6InfocertRestAPIsites — compiles, lints, sends no client cert) and their multipart port cannot run (formData.getHeaders()doesn’t exist on webFormData,fs.createReadStreamcan’t be appended) ⇒ mine abandoned branches for the FILE LIST, never for the diff. Open for a human: whether portal_css ships in .102 at all (ASSCIB-166’s Komponensek lists only oss+css),undicias a new direct dep, the site-widepage-focus-visible = cib-green-700branding call with no CIB precedent, the now-removed system-check browser-incompatibility guard (devel’s FKITDEV-6036 deleted it deliberately; unsupported browsers now render an error report instead of hard-failing), an ungated CV v2→v3 swap inself-service-v2.jsagainst CIB’sidentificationLimits.compat: true, REST ports unit-proven but not endpoint-proven, and CIB’s TjK shape never verified (priorShape: null). CI half (2026-08-12): portal_css 7/7 green first run, vuer_css 6/6 after two fixes, vuer_oss green except the two standing human-override reds (audit = the FKITDEV-8279 fork, npm advisory 1114318; SonarCloud quality gate = an 11-month merge graded as “New Code”) with Build skipped vianeeds: audit. “Skipped” ≠ “passed” — vuer_css’sBuild+SonarQubewere skipped, not failed, because bothneeds:the redtest. Fixes:f434bf9db(sso-login-endpoint.test.jsasserted 400 vs the middleware’s 401 — right for ~6 weeks in 2024, red for 20 months, unnoticed because the branch had notestjob;c3256bc10swept all three exits to401 INVALID_AUTH_CREDENTIALSand renamed the file, updating only the test’srequire),83e4adbd2(portal-client.test.jsdied at import — CIB-only module-scoperequire('../../../config')and noconfig/test.jsonunder jest’sNODE_ENV=test; fix = lazy require inside the method, safe only because config is already loaded at boot and the sole caller is an HTTP route),acaa597d83(translations.test.jscalls unregistered callbacks with zero arguments; register the portalinfoText/helpText/placeholderarg maps, no source change). Two methodology corrections, both of which produced confident wrong answers:git log -Sdoes not follow renames (use--followorgit log -L <a>,<b>:<file>), and macOS cannot load vuer_cssconfig.jswithNODE_ENV=dev(config.js:43reads/etc/hostname) — which caused a genuine CI failure to be misattributed to a “nested worktree artefact”. Open:getPortalRedirectUrlhas zero coverage, the green SSO suite only exercises the dev-mock branch (mockSsoServertrueindev.json,falseindocker.json), and the 401-on-missing-credentials contract with CIB’s portal client is undocumented -
squash-merge-erases-partner-devel-ancestry — Squash-merging a
devel→customization/<partner>PR silently destroys the merge record. The squash commit has ONE parent (the partner tip), sodevelstops being an ancestor and the NEXT devel update re-presents the whole already-merged span as new changes with heavy conflicts. Failure is deferred by a full release cycle. Detect withgit cat-file -p <sha> | grep -c '^parent '(2 = merge, 1 = squash/rebase) orgit merge-base --is-ancestor origin/devel origin/customization/<partner>; via APIgh api repos/TechTeamer/<repo>/commits/<sha> --jq '.parents[].sha'. Content is never at risk — the squash tree is byte-identical to the PR head tree, verify with.commit.tree.shaon both. Mitigations, in order: (1) always use Create a merge commit for sync PRs, (2) after the factgit merge -s ours <squashed devel sha>to restore ancestry with no tree change (needs acustomization/**commit satisfying techteamer-commit-message-ruleset, and a human decision), (3) absorb the conflicts next round. First confirmed instance: cib-1.9.11.102 / FKITDEV-9197, 334 commits / ~11 months collapsed in both vuer_oss and vuer_css
Device detection
- FKITDEV-8533 — server-side UA parsing cannot detect a modern iPad: iPadOS 13+ Safari sends a
Macintoshdesktop UA,ua-parser-jsv1 returnsdevice.type === undefined;customer.isTablet()(device.type === 'tablet') is a strict logical subset ofcustomer.isMobile()('mobile'OR'tablet') so it adds no detection power;customer.userAgentis the only client signal the server has (noSec-CH-UAhints); reliable detection = client-sidenavigator.maxTouchPoints > 1 && /Macintosh/.test(navigator.userAgent). Resolution avoided the detection problem entirely (2026-06-23): rather than detect the iPad, gate on the easy-and-reliable negativeCustomer.isNativeApp()(userAgent.startsWith('mobile/'), single prefix for iOS+Android native SDK) — browsers (incl. spoofing iPads) all fall on the enable side.
Face comparison
- face-comparison-persistence-paths — READ FIRST; corrects the two notes below. Itself CORRECTED 2026-09-07 from SLARAFIPI-84 — §3 and all
customization/line numbers were re-derived from the tag; the note is now current. Which paths actually write afaceComparisonsrow at tagraiffeisen-1.9.11.100. ONE writer (FaceRecognitionService.createFaceComparisonModel→FaceComparison.create:152), 3 call sites not 4 (self-service-v1 is not a distinct site): coreFlowService.handleTaskRecognitionOptions:2918-2968(fromsubmitTaskPhoto:2905), liveness-v2-onlySelfServiceV2Service.js:1416→:1431,videochat:closehook:41.statusis ALWAYS'success'— nothing ever writes'failed', so every upstream guard failure produces no row at all and failed comparisons are structurally unrepresentable (⇒ “the export is missing the failures” is a category error). ThecompareFaceWithquestion, in its corrected form: liveness dispatches bystep.typeinto THREE handlers (server/queue/rpc_server/SelfServiceV2.js:208-219) and onlyliveness-check-v2→handleLivenessCheckV2:2114→saveLivenessCheckV2Messages:1349persists — but for myra that is not the binding constraint, because the proto’s BOTH liveness steps (v1 order 6, v2 order 7) declare norecognitionOptionsat all. Ask “isrecognitionOptions.compareFaceWithin the proto?” BEFORE “which handler runs?” — and the fix is a proto change, not a flow migration or core work. 3 ways a match happens with NO row: Raiffeisen liveness descriptors pushed into a CVLivenessTask(match computed inside vuer_cv — real, but not the reason there is no row); myra_isSameFace:309-380(in-memory, flow-control only, and its result is then discarded by thephotoFinalizesubmit gate); any silent guard skip.imageCategoryis NOT a setting — a per-recognition copy of the task’sscreenshotCategory(writes atRecognitionService.js:235,363+SelfServiceV2Service.js:1405;FaceRecognitionService.js:194is a read); myra setsscreenshotCategory:'customer-portrait'on bothemrtd(proto:81-98) andcustomer-portrait(:99-122) ⇒ rows stored mislabelledcustomer-portrait ↔ customer-portrait, so reports keyed onimageCategorycannot tell the sides apart. Fail-open, now VERIFIED reachable:_isSameFacemax-reduces distance from identity0, the best value in a distance metric ⇒ zero valid targets →0 <= perfect→CHECK_SUCCESS, i.e. missing data reads as a perfect match, silently (_logCVError:376only firesif (!success)and is behindraiffeisen.debug.cv, default off). Contrast: the no-source-face branch fails closed, and the core path fails safe. Both former UNVERIFIED rows are now settled: the NFC question is YES via three paths (webSDK step-filtering, null eMRTDattachmentId, non-success recognition), andperfect = 0.55IS a repo fact —config/docker.json:59-61at the tag, applied atlisteners/self-service-v2.js:124 - face-comparison-data-verdict-threshold-model — canonical model note (FKITDEV-8827 design):
faceComparisonsrows key by EITHERroomId(videochat/operator) ORselfServiceRoomId(self-service-v2), no mutual-exclusivity constraint (models.js:298-309,model/faceComparison.js);euclideanDistance= cosine distance 0–2 (misnamed). PION = videochat NOT self-service — protos declarevideochat, comparisons fromvideochat:closehook (faceRecognitionHooks.js:26-44) keyed byroomId, gated by configfaceRecognition.comparisonPairs(FaceRecognitionService.js:7,20) → self-service-only query returns zero PION rows. Verdict DERIVED bygetFaceComparisonResult(SelfServiceCheckerService.js:132-154): SUCCESS≤perfect / PROBABLE≤probable (thematchtier collapses, defaultmatch:null) / FAILURE>probable, operators<=, defaults{perfect:0.5,match:null,probable:0.6}. Threshold sourcing differs by link type: self-service per-roomselfService:v2:config:state(oldest[0], ASC) REPLACES → globalSettingkeyfaceComparison(persisted bySettingsService.init()); videochat/operator rows have NO per-room path and are NOT verdict-classified at runtime (room.endpoint.js:144raw distance only). NocreatedAtindex → date-range exports full-scan; report-bin pattern + latent bug inraiffeisen-selfservice-failed-reports.js:106(prepareReportDataabstract, masked byactive:falsecron); Postgres but MySQL-portable (LOWER() LIKEnotILIKE) - face-comparison-different-face-db-query — face-comparison results are persisted:
faceComparisonstable (server/db/model/faceComparison.js:18-37) storesstatus ∈ {created,failed,success}+euclideanDistance(FLOAT nullable, actually cosine distance 0–2 despite the name);euclideanDistancewritten unconditionally byFaceRecognitionService.createFaceComparisonModel()regardless of threshold;different_faceis not stored — it’s theCHECK_FAILUREread-time verdict fromSelfServiceCheckerService.getFaceComparisonResult()(:132-153) when distance exceeds all thresholds; thresholds resolve per-room (selfService:v2:config:stateactivity log) → globalSettingkeyfaceComparison→ code defaultprobable:0.6; 4 call sites — liveness-V2 (SelfServiceV2Service.js:1390) gated bytask.options.recognitionOptions.compareFaceWith(base V2 proto doesn’t set it), portrait/ID-doc (server/flow/FlowService.js:2943), videochat-close hook, V1;faceComparisonshas no step column — portrait vs liveness only via joinedFaceRecognition.imageCategory; queryable with one read-only SQL, no release - FKITDEV-8827 — the export SHIPPED: vuer_oss PR #7971 (
raiffeisen-facecomparison-export.js+FaceComparisonExportService) APPROVED bym3sziand MERGED 2026-08-10 (merge commit297aa2fac1f6…) into the 1.9.11.100 release branch — base retargeted off the older.95release branch; not oncustomization/raiffeisenordevel, andraiffeisen-1.9.11.100is not tagged. The read-time-verdict model is now proven end-to-end, not just by reading code: an untracked.dev-e2e/run-e2e.shharness (throwawaypostgres:17-alpineon :5544 via OrbStack) produced a real dated CSV in which adifferent_facerow exports withstatus=success— i.e. the persistedstatusand the derived verdict genuinely disagree, exactly as face-comparison-data-verdict-threshold-model predicts. Unit suiteRaiffeisenFaceComparisonExportService.test.js23/23. Release hub raiffeisen-1.9.11.100 - SLARAFIPI-84 — the myra customer-portrait comparison is computed TWICE and only the second one persists — which is why the export can contain nothing but accepted rows. Verified at tag
raiffeisen-1.9.11.100(worktree HEAD was 6 commits behind the tag, on exactly these files — alwaysgit show <tag>:<path>). Stage 1: the myra handler’s_isSameFacecomputes the cosine score itself and never writesfaceComparisons. Stage 2:FlowService.submitTaskPhoto→handleTaskRecognitionOptions, the only writer — unreachable for a rejected photo, because a mismatch setsrecognitionValid=false→actions.submitEnabled=actions.recognitionValid→SelfServiceV2Service.photoFinalizethrows'Submit was not enabled for this photo candidate!'(a server-side gate). ⇒ everydifferent_facecase is structurally absent from the export, and the observed distance ceiling (max 0.5395, zero rows ≥ 0.55 across 807 rows) is a consequence, not a coincidence. No bypass: the ungatedscreenshot-saveRPC needstask.data.attachmentIds, only ever set by liveness/action-task paths;test.selfService.recognition.submitEnabledis inert (notestkey in either config at the tag). The rejected score IS in the DB, in four places, only one of them debug-gated:Activity selfService:attachment → content.recognitionDetails.face_compare,Flow.tasks[].data.candidates[].recognitionDetails.face_compare(most reliable — not subject to the final-state race),FlowActivity flow:task:data:change, andActivity selfService:cvTask:log / CVTask:failed(gated onraiffeisen.debug.cv). Payload is{compareAttachmentIds, score, success}— the field isscore, NOTdistance("distance"appears zero times in a room export), and no threshold is in the payload. Recovery caveats:createActivityLogdrops the row once the room is final and is called unawaited withfail()right behind it ⇒ the last rejection’s activity is the most at-risk; and_isSameFaceonly runs after the CV result is already acceptable, so sharpness/geometry rejects yield no score at all - face-comparison-distance-thresholds — SCOPED 2026-09-08: the perfect/probable/
different_faceladder is the EXPORT CLASSIFIER’s semantics, not a flow-control fact. The myra (Raiffeisen) self-service flow does not use the ladder —const success = faceComparisonResult === CHECK_SUCCESS(myra-self-service-v2-phase-1.flow.handler.js:366-367@raiffeisen-1.9.11.100) ⇒ anything short of SUCCESS rejects the photo, so for that flowperfect(0.55) IS the accept/reject boundary and the 0.55–0.6probableband can never be populated by it (partner data: max distance 0.5394541 over 807 rows, zero rows in[0.55, 0.6)). The note’s §4 “The 0.55 trap —perfectis NOT the accept/reject boundary” is true of the classifier and is the textbook Mode 3 failure: reading it made us more confident in the wrong answer to Raiffeisen. Both §4 and the TL;DR row are now scoped in place, not removed. Rule: before answering a partner threshold question, check what their handler does with a non-SUCCESS verdict
Express 5 migration
- ASSICASH-71 — PR #666 (closed unmerged) → PR #670 (merged) for
_router → routerand/password-recovery/:token?/:lang?array rewrite; PR #689 follow-up - instacash-update-2026-05-27-status — No Express 5 risk in vuer_css side of this update wave (contrary to a prior assumption rooted in ASSICASH-71’s vuer_css
customization/instacashExpress-4-on-devel-Express-5 case); vuer_css server-side merged clean (routes.js,WebServer.js,package.json,yarn.lock)
eSign / esign_css
- instacash-external-api-esign-headless-test-2026-06-01 — the InstaCash
post-contract <customerId> [pdf]external-API call (viabin/instacash-cli.js) is how the eSign contract leg is exercised headlessly:POST /external/contract→ creates the “IC - Szerződés ajánlat feltöltése” (ic-contract) flow → EsignRPCClient → esign service. But the signature itself is interactive (video-ID + mock/auth+ SMS123456+ sign in the eSign UI) — the CLI proves the EsignRPC plumbing only, it cannot complete a signature. Requires the esign containers to behealthyfirst (see the nginx-PID fix note) - dev-box-esign-container-startup-failures-2026-06-01 —
esign_css+esign_ossdev-box containers (esign_{css,oss}:2024.4.1-20240614, rebuilt ~2025-12-08, nginx 1.28, run as non-roottechteameruid 1000) come upunhealthybecause nginx can’t writepid /run/nginx.pid;(root-owned/run) — image regression, fix belongs in the esign images/Dockerfiles (/etc/nginxnot bind-mounted);RedisStore is not a constructorinserver/web/web-server.js:24is a red herring (code is correct connect-redis v9; only an old/stalenode_modulesbites); chalk ^5 ESM brokebin/test/trans-check.jsyarn trans - esign-css-customization-branches — Customization branch fleet (only
customization/instacashactive, all others archived); standard dev/test method (test through VÜER CSS withrequestFakeCustomer = trueand?esign=1&token=…) - esign-css-instacash-orphan-history —
customization/instacashis a single squashed orphan commit (b7cee2f, 2025-11-20, release 1.3.0.10); zero shared history withdevel; 95-path delta; previous releases likely built via squash-rebuild + force-push pattern (confirmation needed) - FKITDEV-8817 — esign_css jQuery 2.2.4 vulnerability (CVE-2020-11023 / CVE-2019-11358); fix on
bugfix/FKITDEV-8817-jquery-updatepushed (b021019); dead-code path (auth.layout.twig) — repoint to existing/libs/jquery/jquery-3.7.1.min.js; PR not yet opened - esign — Electronic Signature System overview
- instacash-esign-1.3.0.11 — release composition for InstaCash eSign
1.3.0.11(esign_oss + esign_css only; taginstacash-1.3.0.11, 2026-06-08; Harborinstacash-esign-{oss,css}:1.3.0.11-20260608); changelog = devel update + FKITDEV-8817 vuln fixes (jQuery CVE-2020-11023 / CVE-2019-11358 on esign_css PR #250 + HSTS/nginx/WAF hardening); ASSICASH-92 release, ASSICASH-93 TESZT / ASSICASH-96 PROD (approved 2026-06-26 from1.3.0.8); no DB migration / no breaking change, rollback = redeploy1.3.0.8 - instacash-esign-dev-box-deploy — dev-box recipe to test an InstaCash eSign release (run it on
fk-dev; the oldssh Facekombox is decommissioned — dev-build-host): the box defaults to Raiffeisen so align the WHOLE chain to InstaCash (esign_oss/css →instacash-1.3.0.11, vuer_oss/css →instacash-1.9.11.50, pdfservice stays main/2.0.12); per repogit stash→fetch --tags→ checkout tag → in-containeryarn install && yarn build→supervisorctl restart all; verify supervisord RUNNING + “RabbitMQ connection established” + “Web server is listening” + esign_css :10183 HTTP 200
GCP dev-box mirror / Tailscale
- fk-dev-partner-branch-deploy-runbook — the partner-swap half of fk-dev, verified 2026-08-18 (companion to fk-dev-deploy-smoke-runbook, which owns the smoke half). Deploying a partner is not just a branch checkout: it is branch +
config/local.jsonrewrite + avuer_oss_<partner>DB + operator users + (css)yarn build. Four traps, each a real failure: (1) uid mismatch — hostops=1001, in-containertechteamer=1000 (hostubuntu);chown -R ops:ops /workspace/vuer_oss→ restart loop withEACCES … open 'logs/server.log', alwayschown -R 1000:1000 <repo>/logsafter; (2)yarn installas 1001 fails EACCES on pre-existing node_modules, run as root in-container, and piping yarn totailhides its exit code (shell said 0, yarn had errored) → redirect +echo $?; (3) stale partner config —config/local.jsonis bind-mounted read-only from/workspace/vuer_docker/tailscale/config/vuer_<svc>-local.json, one file per SERVICE not per partner, and survives branch switches, so it still held CIB’sdb.url+ a 30-entryflow.flows; you can’t delete it either becausedev.jsonshipshostsempty and januswss://localhost:8989vs the box’s realws://localhost:8188— keephosts+webrtc.janusServers, drop only partner keys. Also: SSH asrootworks (reconciles the ops-only claim;vuer/dev/techteamernewly confirmed refused), per-service tailnet names are sidecars not SSH hosts (port 22 refused), repos ops-owned under root →-c safe.directory=/workspace/<repo>on every git call, box has no GitHub creds (agent-forward viassh-add --apple-load-keychain+command ssh -A), host has no node/yarn,db.syncOnStart: trueauto-migrates a brand-new DB (no manual sync),psqlneeds-h localhost+PGPASSWORD=dev -U dev,bin/db/create_usertakes only ONE role → convention is a directupdate users set rights='["admin","supervisor","operator"]'(column isrights, a JSON string; norole/typecolumn). (4)db.syncOnStartordering —server/bootstrap/connection/db.jsrunsmigrate→sync→migrateon every boot, so booting with the new partner’s code and the olddb.urlsilently migrates the wrong DB, and supervisorautorestart=truemeans a crash in the checkout window suffices → create the DB + rewritelocal.jsonbefore anything restarts (verified clean:vuer_oss_cib158 migrations, 5 CIB-only, zero mkb leakage). Also:local.jsonis a single-file bind mount so docker binds the inode —sed -i/mv/git checkout --swap it and the container silently reads the OLD file (burned two prior sessions), rewrite withcat >only; existing automation/workspace/vuer_docker/bin/vuer.shhas the right stop-before-checkout order but no fetch, a stale branch list (customization/mkbnotmkb-instant), nodb.urlhandling, and builds AFTER starting (vuer.sh db initseedsadmin/operatorwith password = username);opshas no sudo; verification must grep the bundle as served over HTTPS and assert referenced assets 200, not just the HTML. Box left on vuer_cssfix/FKITDEV-8931-socket-test+ vuer_osscustomization/mkb-instant/vuer_oss_mkb_instant, prior CIB state in/workspace/_restore/; FKITDEV-8931 fires only for socketLabeldefault.layout—kiosk.layout/videochat still hard-reload (out of scope), and mkb-instant is kiosk-heavy, so test onhttps://css-fk-dev.taild4189d.ts.net/→mbh-services - dev-build-host — CANONICAL host reference (2026-07-01): the on-prem box
ssh Facekom(=HostName localhost+ProxyJump FKJumpBox→root@lederera-447-fk-hardver) is DECOMMISSIONED — Tailscale shows it offline since ~2026-06-27 — and must never be used again. All native builds / tests / deploys now run on thefk-devTailscale VM (100.91.108.61,command ssh ops@fk-dev.taild4189d.ts.net, Tailscale SSH, no keypair). Unchanged: build native on the remote host, never emulated on the Mac (qemu SIGSEGV exit 139 / overlay-FS I/O exit 125 / repo-metalink 503s) — only the host moved. Agent gotcha: the user’s shell aliasesssh/scpto a_kaku_wrapped_sshfunction that is NOT loaded in a non-interactive shell (_kaku_wrapped_ssh: command not found) → usecommand ssh/command scp. Other tailnet peers are per-service sidecars on fk-dev, not build hosts:oss-fk-dev(100.91.55.42),css-fk-dev,portal-fk-dev,esign-oss-/esign-css-/esign-api-fk-dev,css-sdk-demo-fk-dev - fk-dev-nusz-deploy-and-8959-verification — fk-dev is now OPERATIONAL (2026-07-03): the 8b per-service Tailscale-sidecar overlay is pushed + wired + running (closes the “push gated on user go” item) — sidecars
oss-/css-/esign-*/portal-fk-devup, vuer_oss operator UI at https://oss-fk-dev.taild4189d.ts.net (HTTP 302; Express:10081inside), source bind-mounted/workspace/<repo>+ supervisord per container. First real use = deploying the two NÚSZ fixes (FKITDEV-8747 + FKITDEV-8959 oncustomization/nusztipd426cc6ae1) and verifying FKITDEV-8959 TC-8959-02. Operational gotchas:command ssh ops@fk-dev.taild4189d.ts.net(Tailscale SSH;kakushadowsssh); box has no GitHub key (agent-forward withcommand ssh -A);postgresqlpeer-auth (nopsql -U postgres);nginx_proxycrash-loops (bypassed). Still open: janus/WebRTC media over the tailnet, CV (non-GPU VM). Full deploy runbook + verification in the note; provisioning/overlay design in tailscale-gcp-dev-box-migration - fk-dev-deploy-smoke-runbook — general-purpose fk-dev deploy + smoke runbook (verified 2026-08-13, NÚSZ 1.9.11.48 smoke): the sibling to the NÚSZ/8959 note but partner-agnostic and carrying facts the others omit. SSH:
opsis the ONLY tailnet-permitted user (levander/lederera/facekom/ubuntu/dev/deploy/adminall refused);command sshis mandatory and_kaku_wrapped_sshinjects no user/identity (red herring — it only setsTERM+IdentitiesOnly). GitHub fetch needscommand ssh -A+ssh-add ~/.ssh/id_ed25519(that key auths GitHub aswowjeeez); empty agent →Permission denied (publickey). Stack: node 24.12 / yarn 1.22.22 live inside containers as root (uid 0), host has neither. vuer_css working tree is root-owned so its git ops (reset/clean/checkout) must rundocker exec -u 0:0 vuer_css sh -lc '… safe.directory … '(ops has no sudo). Always fetch with the explicit+refs/heads/<b>:refs/remotes/origin/<b>refspec (narrowed refspecs go stale). Migrations:npx sequelize-cli db:migrate(also auto-migrates on boot). Verify HTTP from the Mac (curl -sk https://{oss,css}-fk-dev.taild4189d.ts.net) — fk-dev can’t resolve its own sidecar MagicDNS non-interactively. supervisor programs listed per service. NOTE the SSH-user discrepancy with dev-build-host (a 2026-08-12 tip there saysrootalso works; the 2026-08-13 smoke saw onlyops) - tailscale-gcp-dev-box-migration — IN PROGRESS (decisions landed + VM provisioned 2026-06-30 via babylon
#facekom_dev): mirror the FaceKom dev box on a GCP VM reachable over tailnettaild4189d.ts.net, replacing DuckDNS / public IP. Decision 1 — hostnames = Tailscale MagicDNS (<name>.taild4189d.ts.net), NOTfacekomdev.netsubdomains → public-DNS Phase 2a RETIRED. Decision 2 — routing = 8b multi-tailscaled sidecar per service (NOT port-based 8a): each of 9 services gets its own userspacetailscaledsidecar (envTS_AUTHKEY+TS_HOSTNAME, ~30 MB idle), own MagicDNS name, owntailscale cert; no app URL rework IFF sidecars named<prefix>-fk-devto preserve<prefix>-<DEV_DOMAIN>withDEV_DOMAIN=fk-dev.taild4189d.ts.net(flagged to verify; pattern proven on pmv2-zurich). This reverses the note’s original host-level/sidecar-rejected recommendation. VMfk-devprovisioned bydeploy(levandor-infra terraformmodule "vm"→for_each=var.vms; pmv2 14 prod containers untouched): e2-standard-4 (4 vCPU/16 GB), 100 GB pd-balanced, europe-west6-a, VPCfk-dev-net/10.2.0.0/24, SAfk-dev-sa, tailnet IP100.91.108.61, MagicDNSfk-dev.taild4189d.ts.net, ACLtag:cloud; public IP 34.158.19.122 egress-only, firewall denies all inbound except DERP, no public SSH; Docker 29.6.1 + OTel collector;ssh ops@fk-dev. Open (Andras/user): CV/GPU scope (VM non-GPU), toggle “HTTPS Certificates” ON in Tailscale admin (required beforetailscale cert), whetherdeploymakes a FaceKom Artifact Registry namespace. 8b overlay IMPLEMENTED 2026-06-30 (BUILT +compose config-validated, unpushed, no commit on vuer_docker branchtailscale):tailscale.ymlships 8 userspacetailscale/tailscale:stablesidecars (network_mode host,TS_USERSPACE=true,--advertise-tags=tag:cloud, per-svcTS_HOSTNAME+TS_SERVE_CONFIG, DRY YAML anchors, namedts-state-*vols) + 5 app-svc stubs;tailscale/serve/*.json(8: oss/css/css-sdk-demo/esign-oss/esign-api/esign-css/portal/library, each HTTPS${TS_CERT_DOMAIN}:443→http://127.0.0.1:<port>, ports 20080/30080/30081/20180/20181/30180/30380/50080);tailscale/config/*-local.json(5: vuer_oss/vuer_css/esign_oss/esign_css/portal_css);tailscale/README.md;.gitignore+=tailscale/tailscale.env. KEY CORRECTION — “no app URL rework IFF naming preserved” was FALSE: apps computeseparator = DEV_DOMAIN.endsWith('facekomdev.net') ? '-' : '.', so a tailnetDEV_DOMAINflips to.→ invalid dotted names likeoss.fk-dev.taild4189d.ts.net(NOT MagicDNS-resolvable, NOT the sidecar name). Fix = zero app-repo edits, entirely in vuer_docker: host derivation guardedif (!config.X)+getconfigdeep-mergesconfig/local.jsonlast (both verified empirically) → bind-mount a per-appconfig/local.jsonat/workspace/<app>/config/local.jsonsettinghosts.*explicitly to<prefix>-fk-dev.taild4189d.ts.net(vuer_osshosts.cv=null, +esignportal.url). Validateddocker 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. Networking: each sidecar host-net + userspacetailscaled,tailscale serve→127.0.0.1:<app-port>, per-svc MagicDNS name + cert;nginx_proxyno longer the access path (harmless). Open (Andras/user): CV/GPU scope (VM non-GPU;hosts.cv=null), toggle “HTTPS Certificates” ON in Tailscale admin (required before cert issuance), whetherdeploymakes a FaceKom Artifact Registry namespace (none added — uses existing). Next (on user go): push →deploywires onto fk-dev. Caveat: vuer_osshosts.api=api-fk-devhas no sidecar butapi-is only used by customization/external/createCustomerTokenhostname-gating, not base dev flow. (Original source-verified analysis preserved in the note:dev.ymlservicesnetwork_mode: "host", nginx_proxy routes by subdomain PREFIX with domain-wildcardserver_name, single self-signed cert, apps build URLs fromDEV_DOMAIN; only literalduckdns=README.md:17.)
Generali
- FKITDEV-9252 — “Bejelentkezés során jelentkező hiba” (parent ASSGRALI-67), a review request rather than a bug: Varga Vencel wrote the AD/LDAP failover fix and asked for a test round before merge. The fix targets
devel, so it reaches Generali only via a devel update (FKITDEV-9194) — and needs no partner-side change, because Generali’scustomization/ui/pages/login/login.trans.jsoverride is an intentional no-op, so the newldap_unavailablestring surfaces as-is (checked specifically: a partner translation override is exactly where a new user-visible string normally goes missing). Test round complete 2026-09-07: no regressions on the unit suite plus a live fault-injection round that confirms the headline promise — first server retried 4× then abandoned, chain fails over, user authenticated on server 2 - devel-update-and-release-flow — the Generali round generalised into the reusable flow:
vuer_oss+vuer_cssonly, live linecustomization/generali-atvilagitasvs DEADcustomization/generali-kar(2022-01-24, 1754 behind), fk-dev numbers basebfe85a4e689 failing tests → merged 3 (net −6, survivorsconverter+vuer-cv-serviceenvironmental — the latter hardcodes CI path/workspace/...), and the 1.9.11.19 release-ticket collection - FKITDEV-9194 — Generali devel update / release 1.9.11.19 prep (2026-08-08, parent ASSGRALI-72 whose changelog carried
TODO: core update változtatások). Branch topology, the stale-devel near-miss, two semantic breaks, full local validation, and the pre-existing red audit gate. First vault coverage of the Generali devel-update line — nothing existed for FKITDEV-9073 either - ASSGRALI-63 — “Hang megszűnése videóhívásban Apple eszközváltás / iPhone feloldás során”; delivered by FKITDEV-8887 commit
6bdf66d16and is the headline changelog item of release 1.9.11.19 — the commit the stale-devel merge almost dropped - FKITDEV-8533 — Generali
videoOrientExttablet fix (PR #7893, Changes Requested) - client-registry — Generali name glue: YouTrack
GRALI(SLA/ASS) /GRALIA(CR/BUG) → build projectgenerali-atvilagitas
Giro / girinfo
- FKITDEV-8581 — CORRECTION 2026-08-05: the
waitingtask IS a genuine blocking GIRO gate (verified by direct code read oncustomization/raiffeisen@9fd6813dd2). The earlier draft reply — “elvileg meg nem érkező GIRO mellett is el lehetett jutni ‘Sikeres’-ig” — is RETRACTED; reporter Bihari Péter was essentially right.identificationStatus='verified'is written unconditionally (…flow.handler.js:240) but is unreachable without the gate:finish()(SelfServiceV2Service.js:408) needsserviceProgress==='wrapup'and has one caller (:549);waitingadvances only fromcustomization/listeners/self-service-v2.js:1655(acceptsresolved|rejected|cancelled, parks on falsycompareCustomerData()) orGirinfoService.js:90(strictlyresolved, fails the room on!acceptable);skip()throws (:843-846). ⇒ no girinfo = room PARKS onwaitingand expires/fails. TERMINOLOGY TRAP (customization/portal/PortalData.trans.js):verified=“Ellenőrzés sikeres” (:277) vsfinished=“Sikeres” (:286, later post-e-sign state) — two different enum values, which is the whole apparent contradiction. The 18 rooms (2025.07.02–2025.11.26): girinfo DID arrive; the logikai adategyezés is what never ran — pre-f830fd8e5athe gate advanced without callingcompareCustomerData()(it sat oncustomer-portrait, usually running before GIRO returned); fixed byf830fd8e5a(FKITDEV-7667, m3szi), prod 2025-11-28, no new cases.waitingexists since proto v8 (94d3ee2df6, FKITDEV-1615, 2023-10-27) — the gap was the missing call, not a missing step. Three residual holes: (1) eMRTD fail-OPEN by construction —GirinfoService.js:339-343returnstruewithout comparing unless the eMRTD result isCHECK_SUCCESS, deliberate + unit-tested (GirinfoService.test.js:136-142), plus:335skipCustomerDataComparisonCheck(trueinconfig/dev.json); (2) gate ≠ room-page tile, OPPOSITE defaults — gate skips postal-code+city (:278-279, defaulttrue), tile checks them (self-service-checker.js:107,110, defaultfalse) and recomputes at read time ⇒ “Ellenőrzés sikeres” + “Logikai adategyezés: sikertelen” is a LEGITIMATE pairing; (3)GirinfoService.js:28swallows the save error atdebugand:69is missing anawaitonfindByPk(bare Promise always truthy ⇒ null-check never fires) ⇒ tile shows “Kérés folyamatban” while alreadyresolved⇒ “Sikeres + Girinfo folyamatban” queries give FALSE POSITIVES - FKITDEV-8581 —
GiroProcess.handleTask()incustomization/server/backgroundProcess/giro.process.js(Raiffeisen,customization/raiffeisenbranch only; renamed fromgiroService.process.jsduring the “Raiffeisen PIon project clean-up”) now splits the catch-block logging into “No response from girinfo service” (RequestError/ETIMEDOUT|ESOCKETTIMEDOUT|ECONNREFUSED|ECONNRESET|ENOTFOUND|EAI_AGAIN) vs “Bad response from girinfo service” (non-200/StatusCodeError/save failure, incl.statusCode); both addelapsedMs/requestTimeout/code. Log-only — retry (this.retry) unchanged. A heavier “mark bg-process/portal state after final no-response retry” option was DEFERRED (ties to the ambiguous-portal-state RCA — box “request in progress” vs dashboard “data arrived” vs logical-match “not available”). Original RCA fixf830fd8e5ashipped 2025-11-28; YouTrack still Pending
Git / orphan branches
- esign-css-instacash-orphan-history — An orphan branch (
customization/instacashin esign_css) breaks the conventional toolset:git mergehalts onrefusing to merge unrelated histories,git rev-list --count A..Breturns numbers without meaning (no merge base), cherry-pick is fragile (different ancestor than the patch was authored against); the three operational responses are--allow-unrelated-histories(one-shot, recoverable), rebase-replay (matches historical pattern), or cherry-pick-delta-forward (cleanest narrative)
Git / commit + branch rulesets
-
techteamer-commit-message-ruleset — TechTeamer vuer repos enforce a repository ruleset on commit metadata: a push is rejected unless every commit subject matches
^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(!)?(\([^)]+\))?: [^\n]{1,100}. Two traps: a defaultgit revertmessage (Revert "…") is rejected — use therevert:type (git revert -n <sha>+git commit -m 'revert: …'); and the subject after thetype(scope):prefix is capped at 100 characters. A single bad subject anywhere in the pushed range rejects the whole push and the fix is a history rewrite — check the full range, not justHEAD. Same rulesets also enforce ticket-prefixed branch names (chore/FKITDEV-NNNN-…). Hit on FKITDEV-8387; branch-naming half first seen on nusz-1.9.11.47 -
techteamer-commit-message-ruleset — trap 3: the branch name the rulesets REQUIRE produces a PR title the rulesets REJECT. GitHub derives the default PR title from the branch, so
chore/FKITDEV-9197-cib-devel-updatebecomesChore/fkitdev 9197 cib devel update— failing on both counts (no lowercasetype:prefix; no bracketed lowercase ticket). Conforming form:chore: [fkitdev-9197] merge devel into customization/cib. This is structural, not occasional ⇒ checklist item: open the PR, then immediately fix the title (three needed it on FKITDEV-9197). Alsogh pr editresolves the repo from cwd — always pass-R org/repo, especially in multi-repo rounds with worktrees nested inside a repo -
FKITDEV-9197 —
git log -Sdoes NOT follow renames, and in devel-update work that gives you a FALSE HISTORY.git log -S "status(400)" -- <post-rename path>returned nothing and was asserted as “400 never existed in this middleware”; the string had lived in the file under its old name and-Swith a pathspec stops at the rename. Usegit log --follow -S '<string>' -- <path>, or bettergit log -L <start>,<end>:<file>for a single line’s entire history across renames. Load-bearing because “was this test ever right?” is what decides whether you fix the test or the code, and devel merges are full of renames by construction -
release-cut-mechanics — the “team override-merges partner PRs” belief is imprecise: devel-update PRs land on
customization/<partner>by SQUASH merge, not bypass. Read from thevuer_ossrulesets (all 4bypass_actors: NONE): a preserving--mergedrags bracket-less devel commits ontocustomization/**and the per-commit “Merge commit rules” pattern (bracketed lowercase ticket\[[a-z]+-\d+\]) rejects them with no bypass — so merge-commit style is structurally impossible.gh pr merge <n> -R <repo> --squash --admincollapses to ONE commit whose subject = the PR title, so the title must be compliant BEFORE merge (chore: [fkitdev-9217] nusz devel update);--adminskips only the RED status checks (Audit/Unused-Deps/Unit-Tests), never the message ruleset. Changelog = direct compliant commit (no require-PR rule oncustomization/<partner>) viagh api -X PUT …/contents/customization/RELEASE.MD; source tags viagh api …/git/refs(don’t build). Claude Code auto-mode classifier blocks--adminmerges (user must run via!) but notgh apiwrites. -
FKITDEV-8279 —
refs/heads/develfalls under vuer_oss ruleset #1, the same bracketed-lowercase-ticket rule ascustomization/**(^(build|chore|…)(!)?(\(…\))?: \[[a-z]+-\d+\] …). Conventional-commit subjects satisfy ruleset #2 but not #1, so a branch of ordinaryfix:/chore:commits must land as a SQUASH — and since the squash subject is the PR title, the title itself must readfix: [fkitdev-8279] …, bracketed and lowercase. Same shape as thecustomization/**squash rule under release-cut-mechanics, but fordevel
Git / remote-tracking refs
- narrowed-fetch-refspec-stale-devel-merge — some FaceKom clones have a narrowed
remote.origin.fetch(vuer_css:+refs/heads/customization/raiffeisen:…— one branch;vuer_osshas the full+refs/heads/*and is fine). There,git fetch origin devel(bare branch name, no destination) writes onlyFETCH_HEAD, leavesrefs/remotes/origin/develuntouched, prints success and exits 0 ⇒ a followinggit merge origin/develmerges a stale tree, conflict-free, with zero warning. Near-miss FKITDEV-9194: merged devel @7d4f9956c8(Jul 28) vs live3ace8872c3(Aug 7), dropping 6 commits incl.6bdf66d16(FKITDEV-8887 / ASSGRALI-63) — the headline item of the release being prepared. Alwaysgit fetch origin '+refs/heads/<b>:refs/remotes/origin/<b>'then assertgit rev-parse origin/<b>==git ls-remote origin refs/heads/<b>. Same narrowing is why--force-with-leaseneeds the explicit=<branch>:<oldsha>form (FKITDEV-9022)
HTTP client / fetch / mTLS
- vuer-oss-global-fetch-ignores-agent-mtls — verified (Node v22.22.3 / bundled undici 6.24.1): every
fetch()in vuer_oss is Node’s global fetch (noundici/node-fetchdep), which IGNORES the node-fetch-styleagent:(honors onlydispatcher) → thegetHttpsAgent()idiom is a SILENT NO-OP (harmless only becausecv.rejectUnauthorizeddefaultstrue);agent-based client-cert mTLS /rejectUnauthorized:falseis dropped. FIX =undici’s ownfetch+Agent(dispatcher: new Agent({ connect: { cert, key, ca, passphrase, rejectUnauthorized } })). CROSS-VERSION TRAP: standalone-undici 8.5.0Agentinto global fetch (undici 6.x) →UND_ERR_INVALID_ARG: invalid onRequestStart method; Facekom runs Node 22 and 24 (different bundled undici majors) so don’t pin standalone-undici to the bundled version. Surfaced scoping FKITDEV-8947 (UniCredit mTLS migration) - FKITDEV-8947 — migrate UniCredit
customization/server/service/UniCredit/ApiService.js(customization/unicredit,UniCreditApiService) offrequest-promise-native→ fetch; uses mTLS (cert/key/ca/passphrase fromportal.api) so the naiveagent:migration silently breaks TLS — must useundici.fetch+Agentper the gotcha note - FKITDEV-9197 — the first round to IMPLEMENT and PROVE the pattern rather than scope it (CIB, forced because devel retired
request+request-promise-nativeout from under the partner branch):undici ^6.28.0declared as a new DIRECT vuer_oss dependency (already transitive viacheerio, so a declaration not new weight; flagged reversible vianode:httpsif the new direct dep is unwelcome), verified 11/11 against a real client-certificate HTTPS server incl. confirmed mTLS (clientCN: "client"observed server-side). The naive port’s failure mode is SILENCE — abandoned prior-art branches had ported 4 files tofetchwhile droppingagentOptions, which is howInfocertRestAPIpasses{pfx, passphrase}at 6 sites: that port compiles, lints, and sends no client certificate, and nothing fails until the far end rejects the handshake. Their multipart port could not run at all (formData.getHeaders()does not exist on the webFormData;fs.createReadStreamcannot be appended to one) — working shape isfs.openAsBlob()withfetchsetting its own boundary
InstaCash
- instacash-external-api-esign-headless-test-2026-06-01 — headless test path for the InstaCash external API + eSign via branch-only
bin/instacash-cli.js(in thevuer_osscontainer):start-servermocks the bank/auth+/status(8189); every other cmd (post-application/get-invite/get-customer/post-contract/get-/revoke-contract) boots the full vuer_oss in-process and HTTPS-calls${hosts.oss}/external/...(NOT a thin HTTP client).post-contract→ ic-contract flow → EsignRPC → esign. The actual eSign signature is interactive and cannot be driven headless (manual video-ID + auth + sign at theinviteUrl). 2026-06-01 run: customerId 28,post-contract→ HTTP 400{"error":"Contract flow is in progress"}on a not-yet-identified application — open question vsdeveloper-guide-hu.md(contract upload after identification) - dev-box-esign-container-startup-failures-2026-06-01 — surfaced while testing the InstaCash 2026-05-27 devel-update on the dev box:
esign_css/esign_ossunhealthydue to the nginx non-root PID image regression (NOT the update code); also the post-dep-bump re-yarn installlesson (RedisStore is not a constructorifnode_modulesis stale) and a chalk ^5 ESM fix foryarn trans - dev-box-cv-photo-processing-failures — discovered testing the nrt self-service identification flow on the dev box: photo step fails (“error during photo processing”) when
vuer_cvis stopped or the hairpin-NAT/etc/hostsfix is missing; recipe-oriented runbook (check vuer_cv running + hairpin remap, re-apply after restart) - sms-verification-code-dev-testing — discovered testing the NRT self-service identification flow on the dev box: how to get past SMS 2FA when the customer phone is fake (
test.security.tempTokenSmsfixed code + restart + resend, or readcustomer.getVerificationCode()via the model) - ASSICASH-71 — PROD
vuer_css local.json portal.urlUAT misconfig (FKITSYS-9486 fix 2026-01-06); pending log-volume confirmation;portal_csshosts.portalparallel risk - instacash-update-2026-05-27-status — 2026-05-27 devel→instacash sync wave across esign_css/vuer_oss/vuer_css; high-risk surface: vuer_oss
customization/listeners/self-service-v2.js(FKITDEV-7518 id-card +newIdFormatAcceptance), vuer_csscustomization/customizations.jsroute reconciliation + modal a11y trio; 50 oss / 57 css commits in, esign_css blocked on orphan history; vuer_css server-side clean (no Express 5 risk here) - esign-css-instacash-orphan-history — InstaCash side of esign_css is structurally distinct: single squashed orphan, intentional MBH/MKB asset retention (55 devel-deleted-instacash-keeps), three workflow options for resyncing
- FKITDEV-8817 — esign_css jQuery vuln fix on
bugfix/FKITDEV-8817-jquery-update(commitb021019, pushed, PR not yet opened); flows into InstaCash via second-merge of 2026-05-27 sync once landed on devel - youtrack-tesztjegyzokonyv-attachment-recipe — InstaCash (ICASH) historically had NO release/eSign tesztjegyzőkönyv in YouTrack (the first was generated 2026-06-26 — see below; still not attached). In YouTrack today:
ASSICASH-65(FaceKom 1.9.11.50) /ASSICASH-92(eSign 1.3.0.11) carry only build.logs; install ticketsASSICASH-66/62/67/93(TESZT) /-96(PROD) only screenshots. The only attached instacash “teszt jegyzőkönyv” PDFs are OLD compliance/DR docs:BUGICASH-460(BCP teszt 2023-06) +ISSFK-338(SaaS DR teszt 2021). - instacash-esign-1.3.0.11 — InstaCash eSign 1.3.0.11 release composition (esign_oss + esign_css; tag
instacash-1.3.0.11; ASSICASH-92 release / ASSICASH-93 TESZT / ASSICASH-96 PROD approved 2026-06-26 from1.3.0.8; FKITDEV-8817 jQuery CVEs + hardening; no migration, rollback = redeploy1.3.0.8). First InstaCash release to get a TJK — generated via fk-tjk (instacashadded topartners.json: display “InstaCash”, ASSICASH; 5 test cases →~/Downloads/tesztjegyzokonyv_instacash_1.3.0.11.docx), not yet attached. - instacash-esign-dev-box-deploy — recipe to test InstaCash eSign on the dev box (
fk-dev; thessh Facekombox is decommissioned — dev-build-host): align the whole chain to InstaCash (esign →instacash-1.3.0.11, vuer →instacash-1.9.11.50, pdfservice stays main/2.0.12),git stash/fetch --tags/checkout per repo, rebuild in-container,supervisorctl restart all; verify supervisord RUNNING + the two startup log lines + esign_css :10183 200; gotchas: untracked.claude/looks “dirty”, old log ERRORs may be historical (check timestamps)
iOS Safari / audio recovery
-
FKITDEV-8887 — root cause: iOS Safari suspends WebRTC audio on
AVAudioSessioninterruption (lock→unlock / background); the remote<video>is paused and never resumed because there is novisibilitychange/pageshow/focushandler; Socket.IOconnectionStateRecovery(30 s) masks brief backgrounds (noreconnect→reload), so only short SMS-code reads produce silence that persists. Fix (UNCOMMITTED, branchfix/FKITDEV-8887-ios-audio-resume):InterruptionRecoverycontroller wired viavisibilitychange/pageshow/focuscallsVideoFeed.ensurePlaying()(remote<video>.play()when paused) +VideoChatService.recoverAudioIfNeeded()(LocalMediaService.startLocalMedia({audio:true,video:false})+replaceTrack). Critical gotcha:SenderPeer.pcis aPeer(WildEmitter) wrapper, NOT anRTCPeerConnection— the real connection isPeer.pc; callingthis.pc.getSenders()onSenderPeeris always undefined → mic recovery must proxy throughPeer.replaceAudioTrack(). Gate:isSafari(covers iPhone+iPad), notisIOS(iPadOS 13+ sends desktop UA →isIOS=false). 119 suites / 0 failures / lint clean. -
FKITDEV-8887 — QA acceptance protocol (device repro): the only definitive acceptance gate (unit tests can’t confirm an iOS-runtime bug). Run baseline on
origin/develfirst (must stay silent) → then validate fix onfix/FKITDEV-8887-ios-audio-resume: iPhone Safari join → 2FA → lock ~10s to read SMS → unlock, expect audio both directions in ~1s. Evidence via allowlistedwebrtclog:interruption:resume→senderPeer:audioRecovered {swapped:true}({swapped:false}/:error= capture failure). Matrix: iPhone built-in+AirPods, iPad (Macintosh UA, validates non-isIOSgating), >30s background (crossesconnectionStateRecovery), non-default mic survival (validatesLocalMediaService.startLocalMediapath), Android/desktop regression, both directions. Version-risk settlement: pulluserAgentfor rooms 10071/10091 (ASSGRALI-63) + 2281 (ASSCIB-161/FKITDEV-8895) — iOS ≥16 weakens only the mic-interruption premise; playback + socket-mask hold regardless. -
FKITDEV-8887 — polish pass 2026-06-15: mic recovery rerouted from raw
getUserMedia→LocalMediaService.startLocalMedia({ audio: true, video: false })(respects saved device);localMediawired invideochat.script.js; WebRTC test globals extracted totest/tests/unit/_helpers/webrtc-test-globals.js(must run at module top level, before describe + before require of SUT — config readsdocument.body.getAttributeat require-time);videochat.services.test.jsupdated to mocksvc.localMedia.startLocalMedia+ new undefined-guard case. -
FKITDEV-8887 — SonarCloud cleanup 2026-06-18 (PR #3066): Quality Gate PASSED but 18 “New issues” (all code smells; 0 bugs/vulns; 89.2% new-code cov). Fixed the 13 in the PR’s new code (11×
prefer-optional-chaining, 1×prefer-globalThiswindow→globalThis, 1×cognitive-complexityrecoverAudioIfNeeded19→≤15 via_safeLog/_isAudioTrackDead/_applyRecoveredAudioTrackhelpers — behavior-preserving, 119 suites/1045 tests + adversarial APPROVE). Left the 5 PRE-EXISTINGpromptUpload/validationResultsmells (videochat.script.js~L424–448, untouched pergh pr diff 3066) for a separate chore. See## CI / build gatesfor the gh-check-run-annotations technique used to read the issues tokenless. -
FKITDEV-8887 — devel catch-up merge for PR #3066 (2026-07-30): branch was 23 commits behind
origin/devel; onlyyarn.lockconflicted (package.json auto-merged: develresolutions+ the branch’sbrowserify/shell-quote: ">=1.7.3"). Resolved by house precedent regenerate, don’t hand-merge —git checkout origin/devel -- yarn.lock+yarn install --ignore-scripts --non-interactive(Yarn Classic 1.22.22) — then verify by diffing the regenerated lock against the target branch: exactly 4 lines differ (shell-quote1.9.0→1.10.0, keyshell-quote@>=1.7.3, shell-quote@^1.6.1) ⇒ audit fix preserved, zero collateral churn; branch then differs from devel by exactly the PR’s 15 files.yarn lintclean; merge staged, NOT committed (analyze gate). Unit suite was initially blocked locally by jest30-ignore-optional-native-resolver (misdiagnosed on the day as a brokents-jestpublish — since fully retracted, it was a corrupt local Yarn cache); after adding the missing native resolver binding tonode_modulesit runs green against stock deps: 119 suites / 1051 passed / 47 skipped / 0 failures, withyarn.lock+package.jsonuntouched. CI was green throughout (all 7 checks incl.Unit Tests) — the blocker was macOS-local only. -
FKITDEV-9194 — where
6bdf66d16ships: the iOS-Safari audio-recovery fix is the headline changelog item of Generali release 1.9.11.19 (ASSGRALI-63 / ASSGRALI-72) — and was silently dropped by the firstvuer_cssdevel merge of the prep round because a narrowed fetch refspec leftorigin/devel10 days stale (narrowed-fetch-refspec-stale-devel-merge). Caught before push
Networking / dev-box (hairpin NAT)
- tailscale-gcp-dev-box-migration — DuckDNS → Tailscale GCP dev-box mirror over tailnet
taild4189d.ts.net. IN PROGRESS (2026-06-30): MagicDNS hostnames + 8b per-service multi-tailscaled sidecar routing; VMfk-devprovisioned (tailnet100.91.108.61). 8b overlay now BUILT +compose config-validated on vuer_docker branchtailscale(unpushed); key correction — “no app URL change” was FALSE (apps switch-→.separator off tailnetDEV_DOMAIN), fixed entirely in vuer_docker via bind-mounted per-appconfig/local.json. See the## GCP dev-box mirror / Tailscaletopic for full detail - dev-build-host — SSH to the dev box (from Claude’s shell):
command ssh ops@fk-dev.taild4189d.ts.net(Tailscale SSH, no keypair, no jump box), with a login shell (command ssh … bash -l -s <<'EOF' … EOF) so docker is on PATH.command ssh/command scpare mandatory — the user’skakualias (_kaku_wrapped_ssh) shadows plainsshand is absent in non-interactive shells. The old two-hop topology (Facekom=lederera@localhostviaProxyJump FKJumpBox→root@lederera-447-fk-hardver, jump box = bare Alpine, no docker) is DEAD — recorded for history in 5. SSH access to the dev box from Claude Code’s shell - dev-box-cv-photo-processing-failures — host-network containers (e.g.
vuer_oss) reset at the TLS handshake when connecting to the box’s own public/LAN IP (192.168.1.93) — hairpin NAT; the container’s/etc/hostsmaps all*-lederera.facekomdev.netto that LAN IP by default, so inter-service HTTPS (CV pingcv-lederera,bin/instacash-cli→oss-lederera/external/...) fails withread ECONNRESET/ “Connection reset by peer”; fix = remap those names →127.0.0.1(loopback hits the same nginx, no hairpin);/etc/hostsis a Docker-regenerated single-file bind mount → edit wiped on every container start, re-apply after any restart via truncate+write (> /etc/hosts/base64 -d > /etc/hosts), NOTsed -i(failsDevice or resource busy) - fk-dev-nusz-deploy-and-8959-verification — SSH topology of the new
fk-devGCP dev-mirror VM (distinct from the on-prem box’sProxyJumptopology above): reach it atcommand ssh ops@fk-dev.taild4189d.ts.net— userops, Tailscale SSH (no keypair), tailnettaild4189d.ts.net/100.91.108.61; the samekakuwrapper shadows plainssh/scpin Claude’s shell → usecommand ssh/command scp. The box has no GitHub deploy key → forward the Mac’sid_ed25519(ssh-add+command ssh -A) forgit fetch. Per-service Tailscale sidecars (oss-/css-/esign-*/portal-fk-dev) are the access path;nginx_proxycrash-loops but is bypassed
NPM registry / package publishing
- FKITDEV-9022 — publish 7 standalone
@techteamer/*library repos (xlsx, timestamp_service, mq, video-processor, archiver-zip-encrypted, janus-api, acl — all onmaster, NOT the vuer monorepo) to the private registryhttps://npm.facekom.net/, so the GitHub source can later be made private. Mechanic (only org precedent =TechTeamer/amqplib-asyncapi-template, which declarespublishConfig:{registry:"https://npm.facekom.net",access:"restricted"}): per-repo add thatpublishConfigtopackage.json+ one.github/workflows/publish.yaml(push-to-master;secrets.FACEKOM_NPM_TOKEN→~/.npmrc;npm view <name>@<version> --registry …guard = idempotent, publishes only new versions).publishConfig.registryonly moves the publish target — the default registry stays npmjs, so installs/consumers are unaffected; no package renames. Decision (user, 2026-07-08): keep@techteamer/*, do NOT rename to@facekom/*→timestamp_serviceis the sole special-case rename:@techteamer/timestamp-service+ drop"private": true(both block publish). Correction: the “janus-sdk publish.yaml reference impl” was WRONG —TechTeamer/janus-sdk= 404; only the amqplib template references the registry.mqspecial case (release.config.mjs/semantic-release honors publishConfig.registry, but no release workflow wired yet). Phase 2 = take repos private / stop public publish — must come AFTER consumers (vuer_oss/vuer_css/portal_css, Yarn-Classic v1 + offline mirror) are repointed, or their CI/Docker installs break. Blocked on VPN: registry docs, CI token, org secretFACEKOM_NPM_TOKEN, real publish test. Status 2026-08-04:@techteamer/acl@2.0.2PUBLISHED (first package on the registry, e2e-proven) and ALL 7 repos committed + PUSHED onchore/FKITDEV-9022-npm-facekom-publish(acle16e1bd, janus-api182dfc9, mqe044ce9, video-processor39ef73d, xlsxc473103, archiver-zip-encrypted67c012e, timestamp_serviceaff10e3), single-line messagechore: [fkitdev-9022] publish to npm.facekom.net, solo-author, no auto-PR (compare links only). Auth solved by the htpasswd bot accounttechteamer-ci(own username lands inreal_groups⇒ no GitHub App needed for CI; mint tokens with--auth-type=legacy/ basic-authPUT, 90-day JWTs). ⚠️ Gotcha: fresh clones underfacekom-v2-clonesinherit the GLOBAL git identity (andras.lederer@alpiq.com) — first push carried the wrong author, fixed via--amend --reset-author+ force-push; narrowed-refspec clones need the explicit--force-with-lease=<branch>:<oldsha>(plain form fails “stale info”). Remaining: runner-egress confirmation, PR review/merge, Phase 2
OCR / MRZ
- FKITDEV-8788 — HU eID back side (MRZ TD1, classId 5,
HUN-BO-06001_BACK_PO): FULL image scores MRZvalid_score:100but the warped/cropped image of the same capture scores2; prod rejects on the crop becausegetMrzRecognitionAttempts(SelfServiceV2Service.js:673-712) can feed the warped-document attempt togetMrzCheckResult(SelfServiceCheckerService.js:219-246); two CV paths — warp-firstVuerCVOCRRecognition.js:45-99(/api/v2/document-warp→/api/v1/mrzon crop) vs no-warpMRZDetectionApi.js:22-38;validScoreValidator(:48-63) forces score 0 whendetections.length !== 1;valid_score/mrzDataonly persist whenocr.useCVMRZData=true; CV 4.9.0 fix likely only validated on FULL image (triage open)
Oracle Instant Client
- FKITDEV-8252 — Oracle has not published OL10 yum repos (404 across
yum.oracle.com/repo/OracleLinux/OL10/); decision to use OL9.el9instantclient RPMs on UBI10 base forkhandbbpartner Dockerfiles (Option 1 ship-it); memo at/Users/levander/coding/facekom/FKITDEV-8252-oracle-ol10-memo.mdawaiting Bence sign-off and partner-contract escalation
Package renames / repo drift (UBI10)
- FKITDEV-8252 — already-applied renames:
pcre-devel→pcre2-devel,zlib-devel→zlib-ng-compat-devel, redis→valkey (with compat symlinks), coturn.el8pin dropped → plain EPEL104.10.0-1.el10_3, rabbitmq/el/10/empty → fallback/el/9/3.13.7 .el8.noarch,shadow-utilsfor groupadd/useradd,x86_64→$basearchin OL10 repos; A.6.1 additions:libopus→opus/opus-devel,libmicrohttpdlives in EPEL10 not BaseOS,gzipmissing from UBI10 minimal, GitHub archive URL stripsvprefix (cd ${VAR#v}),git-lfs install --systemmust run before clone; on-probe-build watchlist for Phase B:ffmpeg-devel,libogg-devel,libconfig-devel,gtk-doc,jansson-devel,pkgconf,gengetopt,libsrtp2
Phantom room
- FKITDEV-8787 — Raiffeisen Myra mobile self-service rooms with vestigial duplicates; SDK-local
Already authorized/Already has some kind of roomguards; OSS V2SelfServiceV2Service.start()silently resumes any non-closed room; partial-unique-index gap - FKITDEV-8787 — FIX (2026-06-02, vuer_css
fix/FKITDEV-8787-...): server-side self-heal inselfService:v2:start— if staleselfServiceRoomData, call OSSgetRemainingSeconds(roomId)and delete only when< 1(room positively expired); abort handler now clears state too. Design learning: FAIL CLOSED on ambiguity — first cut deleted state on ANY RPC error (fail-open), which would let a transient error on a LIVE room spawn a 2nd live room (the very duplicate bug, inverted); verified OSS returns0for timed-out rooms so the catch only sees truly-absent rooms → preserve state + log error there. RULE: for a duplicate/phantom-room-prevention guard, “RPC threw” ≠ “resource dead” - FKITDEV-8787 — RETRACTION (2026-08-11): both error strings are SERVER-SIDE in vuer_css, NOT in the FaceKom mobile SDK.
EXCEPTIONS.ALREADY_AUTHORIZED=Already authorizedandEXCEPTIONS.ALREADY_HAS_ROOM=Already has some kind of roomare defined atserver/socket/events/selfservice-v2.js:30-32, and the"data": {"error": …}envelope the partner pasted (which read like a mobile-SDK log) iscreateEndpoint’s own wire log viareportWireClientResponse— our own vuer_css log all along. Reusable lesson: on this platform “the server” is TWO repos — the originalgit grepcorrectly showed the strings are absent fromvuer_oss, but “absent from OSS” was generalised to “absent from the server”, skipping the socket layer in the other repo. Knock-ons: the “mobile Restart must callclearSession()” recommendation was never the primary fix, and nothing was ever genuinely blocked on the Raiffeisen mobile team. Only half the bug is fixed: the shipped self-heal deliberately preservescustomerId/authorization (testpreserves customerId after abort (only roomData is cleared)), so a re-register/auth on the same socket can still throwAlready authorized— that string in a future report is a different unaddressed path, not a regression of theALREADY_HAS_ROOMfix. Shipped via vuer_css PR #3064, MERGED 2026-08-10 into the 1.9.11.100 release branch (selfservice-v2.js:303-322self-heal,:575abort clear) after #3050 and #3051 were both CLOSED UNMERGED — raiffeisen-1.9.11.100 - raiffeisen-1.9.11.100-tjk-sections — how the half-fix is worded to the customer. The Hungarian
SLARAFIPI-60TjK section states the self-heal only clears a stale room reference when the room is provably dead (remainingSecondsa valid number< 1), keeps state on any error/NaN/malformed response (fail-closed), and lists the two mobile scenarios (A expire-then-restart, B abort-then-restart) that only arm on socket reuse — closing and reopening the app opens a new socket and proves nothing. Server-side check:docker logs -f vuer_css | grep -i "self-heal". Its notes list records thatAlready authorizedremains unaddressed by design
portal_css
- portal_css — slim portal sister of vuer_css: registration, login, SCA, password recovery, JWT handoff (no Janus, no waiting-room)
- ASSICASH-71 —
hosts.portalconfig feeds CSPconnect-srcandPortalService.js:48password-recovery email URL; empty default is a silent foot-gun - FKITDEV-8239 — first repo in the dependency-reduction initiative to get a depcheck CI job; branch
chore/FKITDEV-8239-depcheck-ci(based onorigin/devel), not yet committed - FKITDEV-9197 — the first documented portal_css devel update (CIB, release 1.9.11.102 ↔ portal tag
cib-1.4.0.74— the portal is on its own version train). 11 months of drift; two merge-caused breaks + two pre-existing devel defects. Two structural facts about this repo confirmed by that round:customization/cibhad no.github/workflows/pull-request.yamlat all (so the branch had never been linted or audited by CI — the merge took it from 25 CRITICAL advisories to 0), and zero tests exist structurally —test/tests/holds only a 0-byte.gitkeep. ⇒ green ≠ covered here, andmulteris the proof: an unresolvablerequirein a live endpoint (customization/api/document-upload.js) with a fully green test job. Whether portal_css ships in CIB .102 at all is still open — ASSCIB-166’s Komponensek field lists only vuer_oss + vuer_css - portal-css-jest-runs-zero-tests — the repo has no unit-test signal: empty
test/tests/plus a custom sequencer with an emptyCORE_TEST_ORDERallow-list that discards every file (and jest sorts before its “no tests found” check, so writing tests does not help). CI green only via--passWithNoTestsin the workflow. Answers §17’s “which areas are actually exercised?” — none - devel-dependency-removal-breaks-partner-customization — devel’s
7a42894a“remove unused libs” droppedmulter+uuid, both required by CIBcustomization/api/*; the FKITDEV-8239 depcheck job that motivates such commits is structurally blind to partner branches - eslint9-flat-config-dead-disable-directives — the eslint-9 flat-config migration in this repo (
65ac214c feat: eslint 9 FKITDEV-6045) turns partnereslint-disablecomments into--max-warnings 0failures, and leaves a deadjest-formatting/padding-around-allrule reference behind
Queues / RabbitMQ (app-side)
- vuer-oss-optional-queue-connection — vuer_oss supports multiple named MQ connections through
@techteamer/mq’sConnectionPool(named-map config shape);server.ts:465,background.ts:197andbin/attachment.js:52all readconfig.get('esign.queueConnection')thenconnectionPool.hasConnection(). So theoptional-queue ECONNREFUSED swallow inserver.ts(from FKITDEV-3191) is NOT dead code — it covers a supported partner setup where an external eSign RabbitMQ may be down at boot (without it, supervisord crash-loops a healthy service). It looks unreachable because no in-repo config setsoptional— partner runtime configs live outside the repo tree. An attempt to delete it as dead code was reverted. Rule: when auditing “unused” config keys, grep the readers, not the setters - FKITDEV-9305-rca —
@techteamer/mqv7.2.0RPCClient.initialize()asserts ONLY its reply queue (mq/src/RPCClient.ts:174), never its target — unlikeQueueClient(mq/src/QueueClient.ts:34) ⇒ an RPC client’s target queue exists only while its worker runs, andch.checkQueue()(amqplib passivequeue.declare) against a missing one raises a channel-levelnot_foundthat kills the channel.vuer_oss/server/diagnostic.jsrunDiagnosticTick()then (a) swallows it so vuer_oss logs nothing while the broker spams every 5 s (diagnostic.rpcRoundTripIntervalMs,config/docker.json:736, started unconditionally atserver.js:606), and (b) keeps using the dead channel, silently reporting{messageCount:0, consumerCount:0}for every queue iterated after it ⇒QUEUE COUNT WARNINGcan never fire forbackground-recognition,rpc-esign:external,cronManager,rpc-xml-report,rpc-xlsx-report,rpc-transport-css, and any further missing queue is invisible. Also: an unreachable RPC target costsrpcTimeoutMs= 10000 per call (config/docker.json:688), andIntegrityCheckServicescalls it intryANDfinally⇒ ~20 s and afinally-throw that overridesreturn false
Raiffeisen
- face-comparison-data-verdict-threshold-model — FKITDEV-8827 (PION) face-comparison export design: PION is a videochat flow (comparisons keyed by
roomId, produced byvideochat:closehook, gated byfaceRecognition.comparisonPairs), so the tool is a general both-paths export (raiffeisen-facecomparison-export.js+FaceComparisonExportService), not self-service-only; videochat rows get a report-computed verdict (no runtime classification) carrying raw distance + applied thresholds for audit; spec at.worktrees/vuer_oss-FKITDEV-8827/docs/superpowers/specs/2026-06-03-raiffeisen-facecomparison-export-design.md - FKITDEV-8581 — SLARAFIPI-53 correction 2026-08-05: retracted the claim that a room could reach a successful state without girinfo — the
waitingtask is a blocking GIRO gate, so no-girinfo rooms park and expire. The real 2025 defect was the logikai adategyezés never running (girinfo did arrive), fixed byf830fd8e5a(FKITDEV-7667, m3szi). Terminology trap that caused the dispute:verified=“Ellenőrzés sikeres” ≠finished=“Sikeres” (post-e-sign). Reporter Bihari Péter. Corrected reply drafted at/Users/levander/coding/facekom/SLARAFIPI-53-reply-2.md; PR #7939 needs re-scoping (itsgiro-not-resolvedcase is redundant, and it inherits the eMRTD fail-open) - FKITDEV-8581 — girinfo no-response observability change on
customization/raiffeisen:GiroProcess.handleTask()catch block split into distinct “no response” (timeout/network) vs “bad response” (non-200/save)logger.errors withelapsedMs/requestTimeout/code/statusCode; log-only (retry unchanged); heavier portal-state-marking option DEFERRED; SLARAFIPI-53 root cause = ambiguous portal states; original fixf830fd8e5ashipped 2025-11-28 but ticket still Pending - FKITDEV-8787 — Myra mobile KYC;
customization/raiffeisenoverrides;resolveExternalToken()reusescustomer.idperofferId(mechanism forcsökevény szoba); flow handlermyra-self-service-v2-phase-1; m3szi owns prior fix (FKITDEV-7667 / SLARAFIPI-53) - FKITDEV-8788 — Raiffeisen PION HU-eID-back MRZ crop bug (SLARAFIPI-61, marked “Solved” prematurely on a CV 4.9.0 full-image test); CV/ML owner Zsolt Mészáros, coordinator Bence László, reporter Bihari Péter; mitigation ships on
customization/raiffeisen - youtrack-tesztjegyzokonyv-attachment-recipe — Raiffeisen is the only client with an eSign-tied test record:
BUGRAFIPI-512“eSign 1.3.0.22 release” →…Raiffeisen esign - Tesztjegyzőkönyv - 22 Facekom Release v1.1.2.pdf(2024-10-24; 2/2 dev cases passed, executed Nagy Balázs 2024-10-16, components vuer_css/vuer_oss/esign_queue) + siblingBUGRAFIPI-516(esign bizalmi szolgáltatás DR recovery TJK). The recent Tesztelési jegyzőkönyv PDFs (ASSRAFIPI-117r1.9.11.94,-113r93,-102r92, 2026) are FaceKom/VUER OSS+CSS releases, NOT eSign.BUGRAFIPI-514(FaceKom 1.9.11.61) has both .pdf + .docx variants. - raiffeisen-1.9.11.100 — first Raiffeisen release hub in the vault (ASSRAFIPI-135 / FKITDEV-9156). Release branch
chore/FKITDEV-9156-raiffeisen-release-1.9.11.100in BOTH repos (css95b3e734…, oss350d3e62…) cut from tagraiffeisen-1.9.11.99;.100is NOT tagged ⇒ nothing publishable. Raiffeisen’s delivery route is release-branch-first: thecustomization/raiffeisen-targeted PRs 3051 were closed unmerged and both payloads landed via release-branch PRs (vuer_oss #7971 FKITDEV-8827, vuer_css #3064 FKITDEV-8787, merged 2026-08-10 nine minutes apart), with #7971’s base retargeted off the stale.95release branch. ⚠️ Consequence: neither fix is oncustomization/raiffeisenordevel, so a branch cut off the partner branch silently loses both — “is it merged?” ≠ “is it on the partner branch?“. Changelog = 9 partner-side rows (ASSRAFIPI-124 CV doc-recognition v2→v3, -119, -18, CRRAFIPI-106, ASSRAFIPI-92 ImageId log, SLARAFIPI-59 girinfo, -60, -62 logikai adategyezés, CRRAFIPI-115 Liveness 2) of which only 2 have a traced FKITDEV+PR. All four YouTrack tickets stale (both FKITDEVsPending/Review Needed; SLARAFIPI-60 + ASSRAFIPI-119Blocked/Release needed) ⇒ they keep resurfacing as unshipped release scope. Bence Varga’s 2026-07-30 SLARAFIPI-60 question “melyik release-be tud ez belekerülni?” is still unanswered — answer is .100 - raiffeisen-1.9.11.100-tjk-sections — the customer-facing Hungarian TjK sections for that release:
ASSRAFIPI-119(face-comparison export — whydifferent_faceis a read-time verdict, theraiffeisen-facecomparison-export.jsCLI surface, 23/23 units + a real export CSV) andSLARAFIPI-60(phantom-room self-heal — fail-CLOSED on an ambiguousgetRemainingSeconds, 76/76 units incl.start → abort → start, the two mobile A/B scenarios that still need a real Myra client). Open items list flags the.100draft’s own defects and theALREADY_HAS_ROOM-only scope of the SLARAFIPI-60 fix - face-comparison-persistence-paths — why Raiffeisen face-comparison data is shaped the way it is — CORRECTED 2026-09-07 (authority: SLARAFIPI-84). The old “myra runs
liveness-check-v1, socompareFaceWithis inert there” framing is superseded: at tagraiffeisen-1.9.11.100the myra phase-1 proto (version 16, taskCount 9) carries BOTH liveness steps —liveness-check-v1at order 6 (:123-133) andliveness-check-v2at order 7 (:134-145,screenshotCategory:'liveness-reference-face') — and exactly one survives per session viaonBeforeCreateTasks→livenessCheckCompatibility(envData)against settingsminAndroidVersionForLivenessCheckV2(‘3.0.0’) /minIosVersionForLivenessCheckV2(‘2.0.0’), which only runs in theenvData.supportedSteps.length === 0branch (otherwise the client’s declaredsupportedStepsdecides). The operative reason neither branch persists is that NEITHER task hasrecognitionOptionsat all while the v2 writer is gated ontask.options?.recognitionOptions?.compareFaceWith⇒ the fix is a customization PROTO change (addrecognitionOptions.compareFaceWithto the already-present v2 task), NOT a flow migration and NOT core-handler work — cheaper than this note originally claimed.liveness-check-v2only exists since1c05206ccb(2026-08-17, FKITDEV-8595 / #7820, shipped in 1.9.11.100; absent from proto v12/v14/v15), and an export can never tell you which branch a session ran, because a v2 session produces no row either. Livenessdistanceis dropped bymergeRecognitions(copiesimageId/status/score/attachmentIdonly) and survives solely viaDebugLivenessTask.createLog:105as ActivityselfService:cvTask:log/CVTask:liveness, gated onraiffeisen.debug.cv || raiffeisen.debug.liveness(DebugLivenessTask.js:13-14) ⇒ full historical liveness coverage cannot be promised. Still true and unchanged: both sides of the persisted eMRTD↔selfie row are mislabelledcustomer-portrait;_isSameFacenever sees per-room thresholds (passes noflow⇒ falls back to the globalSetting); and it carries the fail-open — now verified reachable via three paths and undisclosed to the customer. Raiffeisen’sperfectis in the repo after all:config/docker.json:59-61= 0.55 - SLARAFIPI-84 — Bihari Péter refuted two of our claims on 2026-09-04 and was right on both. (1) 0.55 IS the rejection boundary:
raiffeisen.customerPortrait.threshold=0.55 inconfig/docker.jsonat tagraiffeisen-1.9.11.100is applied toperfect, and the flow accepts onlyCHECK_SUCCESS(<= perfect) — so the 0.55–0.6probableband exists in the export’s classifier but can never appear in it. Our earlier “the boundary isprobable0.6” was wrong. (2) Room 11651 was NOT a recognition failure: his ownselfserviceroom-export-11651.zipshows five candidates on 2026-06-01 13:00:34–13:02:35 — 4 failed sharpness (37 and 33 vs min 40), #2 failed the geometry gate, and #3 and #5 RAN the comparison, scoring 0.7396 and 0.6507 withFACE_MISSMATCH:true(both selfie↔eMRTD chip; attachment 148700 is md5-identical toapi/emrtd-photo/11651/8631/face, 240×320 PNG vs 1920×1080 JPEGs). Numeric scores ⇒ descriptors existed on both sides ⇒ pure threshold rejection. Thenno-more-photo-candidate-allowed. The room export contains zerofaceComparisonrows and nofaceRecognitionscollection at all. Two threshold subtleties to remember:_isSameFacepasses no flow togetFaceComparisonResult, so it always falls back to the live global setting while the export’sThreshold perfectcolumn reads the room’s oldestselfService:v2:config:state— different sources; andmigrateConfigStateonly back-fills missing keys, never overwrites, so an old room keeps an old threshold forever. Neither bit here (all 807 rows: perfect 0.55, probable 0.6, single distinct values). Delivered file profile: 807 rows, allmyra-self-service-v2-phase-1/self-service,Room IDnull on all 807, distances 0.1311–0.5395, 11 rows in [0.50,0.55), status+verdictsuccesson all, image-category pair('customer-portrait','customer-portrait')×807, room ids 11646–12847 with 395 (~33%) absent including 11651 - SLARAFIPI-84 — ROUND 2 (2026-09-08): the reply we recorded as SENT was never posted, and 5 of our 9 posted claims regressed. The thread has 4 comments, the last being Bihari Péter’s 2026-09-04 refutation; ticket State = Blocked. All 19 claims were re-derived at ref
raiffeisen-1.9.11.100=2352f5117ffrom a blob-hash-verifiedgit archive(thevuer_oss-rel100worktree is an ancestor of the tag by 6 commits), across four lenses and all 8 attachments. Decisive customer-checkable proof that the missing rows were never created rather than filtered: the delivered xlsx’sFace comparison IDcolumn runs 9559 → 10365 with zero gaps (807 ids / 807 rows), and room 11651’s two comparisons (13:01:47 / 13:02:36) would have to sit between id 9559 (room 11646, 09:41:29) and 9560 (room 11652, 13:04:19). New runtime facts:raiffeisen.debug.cvand.livenessaretrueat the tag (config/docker.json:13-15) — nothing we need is gated off;springCloudConfigServeris configured in NEITHERdocker.jsonNORdev.json⇒ the “second override path” caveat is retracted for this partner andconfig/local.jsonis the only in-repo mechanism; their effective config isdocker.json+ a hostlocal.json, proved by a Sales Funnel cron no repo config enables;NODE_ENVwas set (the csv failure itself proves it);DebugLivenessTaskis v1-only (self-service-v2.js:1208,:1269) so v2 sessions log nothing; and the delivery path is UNVERIFIABLE from the repo (no Dockerfile invuer_oss) ⇒ never repeat “Ehhez nem kell release”. Room 11651 precision fixes: window 13:00:34.680–13:02:36.286 (createdAtPrecise), sharpness 37/33 fromcvTask:log … messages.details.sharpness, 148702 failed face detection too, comparison ran on 2 of 5 attempts. Export-side fix onfix/SLARAFIPI-84-facecomparison-export-rejected(worktreevuer_oss-SLARAFIPI-84, off the tag): 34/34 green, eslint clean, UNCOMMITTED. Round-2 Hungarian draft written but UNPOSTED — user decides. Quarantined from the thread: the_isSameFacemissing-target fail-open (:338-367), the unguarded liveness-v2 writer,test.selfService.recognition.submitEnabled, and the release-state risk
Reports / SL export
- FKITDEV-8639 — SL discrepancy between report UI and Excel export (NÚSZ). Two SL formulas coexist BY DESIGN: naive per-period round (
CallsReportService.js:669-670) vs volume-weighted overall (:558-559, Simpson’s-paradox gap). PR #7862 (543f293c38, tagnusz-1.9.11.45) made the Excel report self-consistent/auditable (Sum value on every row) but did NOT make UI per-period == Excel weighted-overall; team standardised on the weighted overall as the headline SL. Per nusz-1.9.11.47 (ASSNUSZ-58 UAT), the client STILL reported the SL discrepancy after the fix (“Az SL eltérés itt is jelentkezett”) while the daily-stat discrepancy resolved. OPEN PRODUCT DECISION: UI == Excel exactly requires picking ONE formula everywhere — a product call, not a further bug fix; likely the live topic. Bug C (ReportsService.js:63true→localeswallow) is DISTINCT from FKITDEV-8747 (forward locale through RPC queue boundary + empty SL when no calls, PR #7929, new for 1.9.11.48) — two locale bugs at two layers. Also Bug B (Excel column misalignment), Bug D (counting gapwaiting_calls > calls + exits). - FKITDEV-8747 — the follow-up fix that shipped (PR #7929, squash
5099b8ad8b, merged 2026-05-28, nusz 1.9.11.48; parent ASSNUSZ-58). NOT a call-count bug — the raw counting logic is unchanged; all changed files are CORE (video-calls report / daily statistics), surfaced by NÚSZ. Three squashed fixes: (1) empty-period SL →nullnot0(CallsReportService.js ~L562:SL = calls>0 ? round((calls-lateAnswers)/calls*100) : null) on per-bucket and Sum/aggregate; clientreportCalls.jsrendersnull→-(was always+ '%', so0%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_serverReports.js) + the newreporterDownload.process.jsBackgroundProcess (a booleantruewas passed instead of the locale string) → xlsx exports now use the user’s UI language, reviving the FKITDEV-8639 locale fix that was dead on the download path. Test cases:/Users/levander/coding/facekom/FKITDEV-8959-8747-test-cases.md(also covers FKITDEV-8959). - cib-reports-advanced-is-export-only — CIB’s
/reports-advancedrenders a filter form and NOTHING else: no chart, no on-screen table — the xlsx export is the page’s only output. Source-verified invuer_oss/customization/ui/pages/reports-advanced/:reports-advanced.template.twigrenders onlyreports-advanced.form.twig(report type, time range, day/week/month/year pickers, prev/next, export button), andreports-advanced.script.jshandleDownload()always sendsdownload:'true'with a single success pathwindow.location = /download/${res}— there is no branch that renders results into the page. Consequence: ASSCIB-166’s “a riport számai, a diagram adatai, valamint a XLSX export” names three places the FKITDEV-9230 async-filterbug surfaced in the computed data, all of which land in the workbook — NOT three UI surfaces; “a diagram adatai” is series data feeding a chart sheet in the exported file. So FKITDEV-9230 test evidence can only ever be the spreadsheet, never an application screenshot, and any request to “show the numbers on screen” for CIB is new feature work, not a fix - SLARAFIPI-84 —
raiffeisen-facecomparison-export.js -cthrowsUnsupported report export format: csvpurely because of a MISSING CONFIG KEY, andconfig/dev.jsonis a red herring. UnderNODE_ENV=docker(set on all 7 supervisor programs)dev.jsonis never read;config/docker.jsonhas areportingblock but noenabledExportFormats(keys present:debugger,extraFilters,lateAnswerTime,maxDateRange,sessionBasedCallsReportCalculation,videoCalls) ⇒ReportsServicefalls back to['xlsx']. A csv exporter genuinely exists;enabledCustomExportsis also missing socomment_csvis unavailable too. Only fix path isconfig/local.json— env vars cannot do it, becausegetconfigonly substitutes$VARwhere the JSON already contains a placeholder anddocker.jsonhas none:{"reporting":{"enabledExportFormats":["xlsx","csv"]}}+ restart. ⚠️ An EMPTY or malformedconfig/local.jsonkills the process at startup (SyntaxError in json file located at: … → process.exit(2)) — the file must be absent or valid JSON, and merged into rather than overwritten if it already exists (it is gitignored). Also: the bin writes with{mode: 0o600}and has no chmod;fs.writeFileappliesmodeonly at creation, so an existing file keeps its old mode — and0o640is the right ask over644because-n/--withnamedecrypts customer names
Security / dependency CVEs
- FKITDEV-8279 — two sequelize advisories against the
@techteamer/sequelizefork (6.32.2): GHSA-v8fg-2rw7-q452 / CVE-2026-69240, SQL injection in the Oracle dialect only, critical CVSS 9.8,< 6.37.4, published 2026-08-03; and GHSA-6457-6jrx-69cr / CVE-2026-30951, SQLi via JSON cast type, high 7.5,<= 6.37.7, fixed only in 6.37.8 (source-confirmed in the fork, not just version-range inference:lib/sql-string.js:60-64returns the attacker string unescaped forTO_TIMESTAMP/TO_DATEprefixes). The critical one hits exactly the Oracle partners (bb,kh,mkb-instant). TWO RETRACTIONS — do not repeat: the fork was never invisible toyarn audit(develdeclares it through an npm alias, so Yarn v1 audits it under the keysequelizeand submits6.32.2— both advisories were reported all along; the@techteamer/sequelize@6.32.2 → {}advisory-API result is real but is not what devel does), and no CVSS 9.8 sat unnoticed for two years — what sat for two years is the fork being abandoned, which is why there was no route to a fix. The checkable claim to use instead:improved-yarn-audit --min-severity criticalis red ondeveltoday (Found 1 vulnerabilities, exit 1) and green on the fix branch (exit 0); the gate lives at.github/workflows/pull-request.yaml:109-119and is in the merge gate (needs: [lint, test, audit, sonar]), theyarn auditline above it deliberately swallows its exit code, and there is no.improved-yarn-audit-ignorein the repo. Generalisable lesson: an npm advisory query against the published package name says nothing about what your lockfile is audited as — run the audit on a genuine install of the branch in question - cve-2025-7783-form-data-via-request — CVE-2025-7783 / GHSA-fjxv-7rqg-78g4: critical
form-data@2.3.3(unsafe random multipart boundary; patched>=2.5.4) pulled in by EOLrequest@2.88.2whoseform-data: ~2.3.2hard-pin will never move. Not on devel — customization-line only, becauserequestis live partner code (vuer_osscustomization/api/sms/SmsCofidis.js; vuer_csscustomization/server/web/api/{login,register,partner-register}.endpoint.js). Red on cofidis/kh/raiffeisen branches. Interim fix =resolutionsoverride"request/form-data": "^2.5.6"+yarn install(house-style precedent:csurf/cookie,twig/minimatch,ts-jest/handlebars); real fix = droprequest, separate ticket - security-audit — consolidated FaceKom vulnerability findings across vuer_oss / vuer_css / vuer_cv / esign / pdfservice / nyilvantarto-scraper (2 CRITICAL, 6 HIGH, 5 MEDIUM, 6 LOW + positive findings)
- FKITDEV-9197 — a partner branch with NO CI workflow ships unmeasured criticals indefinitely:
portal_csscustomization/cibcarried no.github/workflows/pull-request.yamlat all, so nobody had ever audited it — 25 CRITICAL advisories (tarviasemantic-release>npm,handlebars,twig>locutus×2,browserify>shell-quote) measured on a base worktree atbf6dfbf8, all 25 cleared by the devel merge. Also the reverse security direction on the same round: devel’s removal ofrequest+request-promise-nativefromvuer_osswas a deliberate retirement of the EOL client behind cve-2025-7783-form-data-via-request — CIB’s ownsecurity/*.mdhad logged it as scheduled monthly since 2025-03 — so the partner fix is to port the code off it, never to restore the dependency (devel-dependency-removal-breaks-partner-customization)
Self-service v2
- face-comparison-data-verdict-threshold-model — self-service liveness-v2 face comparison (
SelfServiceV2Service.js:1418) is gated bytask.options.recognitionOptions.compareFaceWith(base V2 proto doesn’t set it → no row); self-service rows key byselfServiceRoomId, get per-room thresholds from the oldestselfService:v2:config:stateactivity (getActivityLogASC[0], REPLACES the set) falling back to globalSetting; verdict mirrors runtimegetFaceComparisonResult(unlike videochat rows which have no runtime verdict) - dev-box-cv-photo-processing-failures —
SelfServiceV2Service.photoCandidate(:1043) callssubmitTaskRecognitionunconditionally →FlowService.submitTaskRecognition→RecognitionService.runRecognitions→CVRecipe(server/cv/CVRecipe.js:88throws “Recipe missing no CV Service!” when CV health-check marked the host down); there is no dev flag that skips face-detection recognition (selfService.ui.disabledChecksonly covers girinfo/emrtd/kau), so an unreachable CV service hard-fails the nrt photo step - sms-verification-code-dev-testing — dev/testing: the self-service 2FA SMS code is set by the
customer:verification:sendSmshook; force it withtest.security.tempTokenSms(+restart+resend) or readcustomer.getVerificationCode()(stored asvideochatToken) - FKITDEV-8787 —
SelfServiceV2Service.start()silently resumes;_findOpenRoomForCustomerrace; status enum['waiting','incall','left','closed','deleted','archived']— only last three treated as not-open; V1 throw atSelfServiceRoomService.js:217swallowed bySelfServiceActions.js:27-34 - FKITDEV-8787 — socket-layer fix (vuer_css
server/socket/events/selfservice-v2.js):selfService:v2:startself-heals staleselfServiceRoomDatavia OSSgetRemainingSeconds(delete iff< 1),selfService:v2:abortclears state after the OSS abort RPC; tests use REALserver/auth.jspredicates viajest.requireActual(hand-rolled fakes had diverged — dropped theisAuthorized/customerIdconjunct + collapsed thehasAnyRoomroomDatabranch) - FKITDEV-8581 — task-completion reachability rules (core, reusable beyond Raiffeisen):
finish()(SelfServiceV2Service.js:408) returns early unlessserviceProgress === 'wrapup'and has exactly one caller (:549), so a flow’sonFinished()is reachable only after the last task;skip()(:843-846) throws'Current step is required!'unlesstask.options.step.required === false(strict inequality — a step proto with norequiredkey is therefore NOT skippable). ⚠️ Bypass surfaces that callfinishCurrentTask()with NO step-type guard:server/queue/rpc_server/AiActRPCServer.js:20(registered atserver.js:397, queuerpc-ai-act) and theisRecording-gatedselfService:flow:finishatserver/transport/session/SelfServiceTransportSession.js:290-300— contrastGirinfoService.js:88, which does guardcurrentStep?.type !== 'waiting'. A late/duplicate RPC can therefore advance a room past a gating task (hypothesis, not reproduced). Raiffeisen flow proto is at v15 (ce08873962, FKITDEV-9081 AI Act, 2026-07-20) - FKITDEV-8788 —
getMrzRecognitionAttempts(SelfServiceV2Service.js:673-712) selects between full-photo attempt (mrzTask.data.attachmentId) and warped-document attempt (candidate.document.attachmentId);getMrzCheckResult(SelfServiceCheckerService.js:219-246) turnsrecognitionAttempts[0].mrz.validinto accept/reject — fallback-to-full here is a candidate mitigation - FKITDEV-8787 — the socket-layer guards are in vuer_css, and only ONE of the two got fixed.
server/socket/events/selfservice-v2.js:30-32defines bothEXCEPTIONS.ALREADY_AUTHORIZEDandEXCEPTIONS.ALREADY_HAS_ROOM(an earlier note wrongly attributed them to the mobile SDK). The merged fix (PR #3064, 2026-08-10,:303-322self-heal +:575abort clear) addresses onlyALREADY_HAS_ROOM— it clearsclient.sessionData.selfServiceRoomDatabut deliberately preservescustomerId/authorization, pinned by the testpreserves customerId after abort (only roomData is cleared). SoselfService:v2:registeron a socket that already authorized still throwsAlready authorized, by design. Whoever picks up the remaining half: clearing auth on abort is a much larger behavioural change, which is why it was scoped out — raiffeisen-1.9.11.100 - face-comparison-persistence-paths — liveness step types are NOT interchangeable, but the type is NOT always what decides.
task.options.step.typedispatches atserver/queue/rpc_server/SelfServiceV2.js:208-219into three handlers:liveness-check→handleLivenessCheck:1199,liveness-check-v1→handleLivenessCheckV1:1459(→mergeRecognitions:1310),liveness-check-v2→handleLivenessCheckV2:2114(→saveLivenessCheckV2Messages:1349). Only the v2 handler contains face-comparison persistence, sorecognitionOptions.compareFaceWithis read only on v2 and is silently inert on the other two. Corrects the “liveness-v2 is gated bycompareFaceWith” line in face-comparison-data-verdict-threshold-model, which omitted that the gate presupposes the v2 handler. Refined 2026-09-07 (SLARAFIPI-84): a proto can carry BOTH liveness steps and pick one per session — myra does, filtering inonBeforeCreateTasksvialivenessCheckCompatibility(envData)only whenenvData.supportedSteps.length === 0— so “which handler runs” is a per-session runtime property you cannot read off the proto, and when neither task declaresrecognitionOptions(myra’s case) the handler question is moot: no branch persists. Check the proto forrecognitionOptionsfirst. Also: the coreFlowService.handleTaskRecognitionOptions:2918-2968path has five distinct guard failures that all produce no row, and only two of them log anything - SLARAFIPI-84 — CORRECTS the “myra runs liveness-check-v1” framing. At tag
raiffeisen-1.9.11.100the myra proto carries BOTH liveness steps andonBeforeCreateTaskspicks one per session vialivenessCheckCompatibility(envData)against settingsminAndroidVersionForLivenessCheckV2(default'3.0.0') /minIosVersionForLivenessCheckV2('2.0.0') — but that filter only runs whenenvData.supportedSteps.length === 0, otherwise the client-declaredsupportedStepsdecides. Decisive: NEITHER liveness task hasrecognitionOptionsin the proto, and v2 persistence is gated ontask.options?.recognitionOptions?.compareFaceWith⇒ neither v1 nor v2 writes a livenessfaceComparisonfor myra, and the cheap fix is a proto change (addrecognitionOptions.compareFaceWithto the v2 task), not core code.liveness-check-v2was only added 2026-08-17 by1c05206ccb(“feat: [fkitdev-8595] raiffeisen liveness v2 (#7820)”), verified absent from proto v12/v14/v15 — the customer’s window ends 2026-08-26, so a tail of sessions could have been v2 and the export cannot tell (⇒ do not claim “every session used v1”). The liveness distance never reachestask.data—mergeRecognitionscopiesimageId/status/score/attachmentIdand dropsdistance; it lands in the DB only viaDebugLivenessTask.createLog(Activity selfService:cvTask:log, typeCVTask:liveness) behindraiffeisen.debug.cv || raiffeisen.debug.liveness⇒ full retroactive liveness coverage cannot be promised
Sockets / reconnect + auth
- FKITDEV-8931 — MKB DÁP reload bug: mobile backgrounding drops the socket and the old vuer_css client answered the reconnect with
window.location.reload()— fatal because DÁP login REQUIRES backgrounding (switch to the DÁP app), so the reload fired on the happy path. Fix = silentauth(socketLabel)re-auth logging[socket] re-authenticated after reconnect, falling back to reload only on failure, plus aconnection.on('connect')→onConnectionRestored()that clears the 2sdisconnectTimeout+reloadCountdownIntervaland hides both snackbars. Gated onSILENT_REAUTH_LABELS = ['default.layout']—kiosk.layoutand videochat still hard-reload by design, so kiosk-heavycustomization/mkb-instantpages are the WRONG test target (usembh-services, which extendsdefault.layout). BROWSER-TESTED 2026-08-18 — short drop passes (~1.4s → silent re-auth, no reload, snackbars hidden), but a long outage does NOT: the fix only cancels a pre-existing reload countdown, never removes it, so a 40s outage hard-reloaded the page 4× against a 502.onConnectionDisconnected()fires 2s afterdisconnectand counts down at 1s intervals towindow.location.reload(); the length ishideDelay: 10 + random(50)(snackbar-container.twig:6) ⇒ randomized 10–60s per page load, effective tolerance ≈12–62s ⇒ the DÁP flow still breaks if the user lingers in the DÁP app, and it reproduces INTERMITTENTLY — the profile of a bug closed as “works for me”. Open question for vencelvarga: suppress or extend the countdown forSILENT_REAUTH_LABELSpages rather than merely cancelling it. Three config values corrected by the test (livedata-socketioSettingsbeats thedev.jsonreading):transportsis["websocket","polling"](polling IS available, not websocket-only),reconnectionAttemptsis 20 not 5, andconnectionStateRecoveryNEVER ENGAGES (socket.recovered === falseon every reconnect, incl. a 1.4s one; fresh socket id each time) → do not test against the 30s cliff, it is not the boundary.vuer_cssonly, PR #3153 approved/7-of-7/mergeable. Do NOT cherry-pick the FKITDEV-9199 kebab fixcda6c80b97(PR #3146) onto the branch — it is internally consistent under the olderdata-socketToken+ case-insensitivegetAttributeconvention, and kebab twigs without thedataset.socketTokenreaders break it - FKITDEV-9194 — the socket-token attribute convention and the superseded
fix/FKITDEV-9194-socket-token-attribute-readbranch that would re-break the bug if merged on top - FKITDEV-8787 — stale socket
selfServiceRoomDatasurviving an in-app Restart; fail-closed self-heal
Supervisor / process config
- unversioned-partner-supervisor-overlays — RELEASE BLOCKER pattern: partner supervisor overlays are NOT version-pinned to the app.
vuer_build/partner/<client>/vuer_oss/DockerfiledoesFROM harbor…/vuer_oss:${VUER_VERSION}…(version-pinned app image) thenCOPY supervisor_vuer_oss_docker.conf(unversioned, taken frommainat build time) → conf and app version are decoupled, so a rebuild of an old release tag gets the old app with today’s conf. Consequences of changing acommand=line: (a) older release tags stop rebuilding (MODULE_NOT_FOUND→ supervisord crash-loop), (b) ~94origin/customization/*branches still carry the old spelling so each partner breaks on its next build until it merges devel (time-staggered, looks like a random partner regression). Not fixable by merge ordering — it’s a versioning mismatch. Mitigations: hold thevuer_build/vuer-releasemerges until the first release tag containing the change is cut; or delete redundant overlay confs so partners inherit the base image’s symlink to the app’s own conf (decision rule in FKITDEV-8354-mvm-supervisor-config-dedup); or make overlays release-aware. Merge hazards:customization/khedits both confs (conflicts),customization/nuszeditsserver.js+cron.js(rename+modify). Surfaced by FKITDEV-8387 - FKITDEV-8354-mvm-supervisor-config-dedup — how supervisor configs reach
/etc/supervisor/conf.d/in vuer-release component images (reusable): TWO paths — (a) baseinstall/configure-app.sh:16-21symlinks the source package’ssupervisor*.conf, (b) the partner component DockerfileCOPYs a partner override on top (last-write-wins by filename);supervisord.confincludesfiles = …/conf.d/*.conf. Decision rule: a partner override is a deletable duplicate only if byte-identical to the repo’s conf, else it’s intentional customization. Applied to PR #28 (MVM): vuer_css override = byte-identical ⇒ deleted; vuer_oss override = kept (supervisor-stdout eventlistener loggingstdout_events_enabled=true/stdout_logfile=NONE, 8 programs, omits[program:vuer_oss_storage]— consistent across all vuer-release partners: equilor/nusz/polgaribank-facekom/unicredit/unicredit-srb/mvm). The eventlistener apparatus (supervisor_stdout.py+supervisor_stdout_eventlistener.conf+pip install supervisor-stdout) lives ONLY in vuer-release and is the consumer of the supervisor-stdout plugin restored in PR #28 round-1 (07db225) - FKITDEV-8252 — supervisord runtime gotchas on ubi10-minimal (build-green ≠ runs): supervisor 4.2.5 crashes on Py3.12 (
pkg_resourcesgone) → pin4.3.0; supervisord logfile path hidden by a/var/logbind-mount → log to/var/logroot; supervisord (PID1) does NOT propagate a program’s HOME nor doesUSERset it (erlang.erlang.cookieeacces → setenvironment=HOME=…per program); must run supervisord as ROOT (removed wrongUSER $DOCKER_USERfrom vuer_css/portal_css) - entrypoint-rename-blast-radius — renaming any vuer entrypoint (
server.js/cron.js/background.js/…) is a 4-repo coordinated release, not a single-repo edit: 95 supervisor conf files hard-codecommand=node <entry>.js— 75 invuer_build/partner/*(35 partners), 11 invuer-release/projects/*/components/*, 2 invuer_docker/workspace/devtools/files/, only 7 in the three code repos (vuer_oss/vuer_css/portal_css). Two SILENT traps beyond the confs:vuer_oss/server/logger.js:102–114picks the log4js channel by sniffingprocess.argv[1].endsWith('server.js')/etc. (rename → every process logs to theunknownchannel, no crash), and an 8th entrypointsoap_server.jsexists ONLY on bb/kh customization branches (…/{bb,kh}/vuer_oss/supervisor_vuer_oss_docker.conf:137, not ondevel). A missed conf = supervisord crash-loop (exit 2, restart 1–2 s; a March-2026 attempt did exactly this). Motivates FKITDEV-8387’s.ts-module + one-line.js-shim approach (keeps every conf/logger.js/.nycrcfilename literal untouched) - FKITDEV-9305-rca — a missing
[program:]block in a partner overlay is a silent production defect, and the overlay mechanism is TWO SEQUENCED IMAGE BUILDS, not layer ordering. The base image links the canonical conf intoconf.d/(vuer-release:install/configure-app.sh:16-19frombase/components/vuer_oss/Dockerfile:106; legacyvuer_build:base/vuer_oss/Dockerfile:241), is tagged and pushed to harbor, and the partner image is builtFROMthat sealed base andCOPYs its own file to the same path (projects/mkb-instant/components/vuer_oss/Dockerfile:1-2→COPY :18; legacypartner/mkb-instant/vuer_oss/Dockerfile:6→COPY :31, plussed -i "/user=/d" …at:25) — the COPY structurally cannot lose. Legacy partner selection comes from the git tag (build.sh:365stripsmkb-instant-1.9.11.67→mkb-instant, then sourcessettings.cfg). MKB’s overlay carries 7 programs vs canonical 9 (vuer_integration_logline 50,vuer_oss_storageline 155) ⇒ RabbitMQnot_foundspam every 5 s plus six queues silently zeroed in monitoring, running continuously since the.54tag of 2025-07-01 (~14 months). (Device-integrity breakage is a conditional extra — gated behindintegrityCheck.*.enable, which is absent from MKB’s committed docker config.) Fleet scope: 32 of 35 omitvuer_integration_log; onlygranit,mvm,vktakeep it — undocumented, unlike the deliberatevuer_oss_storageconvention, and MVM keeps integration-log while dropping storage ⇒ drift, not design. DO NOT copy the mbh delete-the-overlay fix (FKITDEV-8362,projects/mbhconf deleted in #35 /d7ebb37): MKB’s overlay is not “canonical minus 2 blocks” — every functional directive in 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 droppeduser=techteamerand file-logging →stdout_events_enabled=true/stderr_events_enabled=true/stdout_logfile=NONE/stderr_logfile=NONE, i.e. the supervisor-stdout eventlistener wiring that feeds OpenShift log collection — deleting it would break MKB’s logging. Correct fix = add one block in the overlay’s own logging style, invuer-release(MKB migrated 2026-07-08,4bf534e), not legacyvuer_build. Detection trick: that same wiring produces theINFO <program> | …prefixes, so grepping a customer’s log export forINFO vuer_integration_log |proves the worker’s presence/absence without shell access
Test reports / Tesztelési jegyzőkönyv (TjK)
- tesztjegyzokonyv-generation-flow — START HERE for “how do I make a TjK”. The
/fk-tjkprocess: zero-context Phases 0–7, thenewdoc+ append two-step, evidence regeneration, and the Phase 6 tester runbook. Release trains are per partner — never carry a version in from conversation. - tesztjegyzokonyv-partner-release-document-structure — the document spec (
release-docshape): skeleton,Bevezetésblock, per-ticket sections, the three evidence forms, and the closingtelepítésre ajánlottparagraph that is the formal pass/fail statement to the bank — now reproduced VERBATIM in the note (<Partner>twice; keep the double space, themegvalósítható("…")spacing and thea fejlesztői, tesztekcomma). Single source since 2026-08-11 — the on-diskdocs/tjk-raiffeisen-document-structure.mdwas folded in and retired. - tesztjegyzokonyv-primer-prompt — the copy-paste primer:
/fk-tjk <partner>for the loaded command, plus a verbatim Hungarian standalone prompt for a fresh session / another agent / another tool (zero-context rule,~/Downloadsbase by NAME, regenerate evidence, two-step render, runbook, partner-side ids only). Wasdocs/tjk-primer-prompt.mdon disk until 2026-08-11. - raiffeisen-1.9.11.100-tjk-sections — a worked example of finished output: the Hungarian ASSRAFIPI-119 + SLARAFIPI-60 sections with their evidence dumps, plus the open-items list. Carries the scope caveat that belongs in the section text: the SLARAFIPI-60 fix covers
ALREADY_HAS_ROOMonly,Already authorizedis deliberately unfixed. - devel-update-and-release-flow → Phase 3 — where the TjK’s section list comes from.
release_tickets.pyemits the two ticket buckets (direct-on-customization vs via-devel-touching-customization/) with assignee and commit author, so you know who to ask for the functional description of each section. Remember to convert to partner-side ticket ids before drafting —FKITDEV-*never appears in a customer document. - youtrack-tesztjegyzokonyv-attachment-recipe — finding/downloading existing TjKs from YouTrack; the Phase 1 fallback when
~/Downloadshas no TjK. - nusz-1.9.11.48-test-runbook — a real Phase 6 output: prioritized cases, arming conditions, and what UAT explicitly cannot prove.
- Cross-cutting trap: the TOC is a static Word field. Rebasing one partner’s TjK onto another leaks the source’s ticket ids (
ASSRAFIPI-124/SLARAFIPI-59reached a NÚSZ TOC) — invisible in the body.append_release_sections.py newdocclears the cache and refuses to write on a surviving id; a human must still refresh the TOC before PDF export.
TypeScript
- k6-e2e-harness-vuer-oss —
test/tests/k6/tsconfig.jsonis a second, independent tsconfig (types:["k6"],strict,allowImportingTsExtensions,noEmit) that the root tsconfig knows nothing about (root does not includetest/). Consequence for porting: relative imports insidetest/tests/k6/carry an explicit.tsextension — same rule as the runtime one in typescript-in-vuer-repos, but here it comes fromallowImportingTsExtensionsrather than Node’s resolver. Nothing typechecks it; runtsc -p test/tests/k6/tsconfig.jsonby hand - FKITDEV-8387 — SUPERSEDES the shim plan: the entrypoint migration landed as a DIRECT RENAME (2026-07-22). After reviewer feedback on vuer_oss PR #8059 the
.js-shim strategy was dropped — entrypoints are real.tsfiles invoked ascommand=node server.ts, no shims: vuer_oss 7 entrypoints, vuer_css + portal_css 1 each, 75 supervisor confs invuer_build, 12 invuer-release; all three code PRs CI-green 8/8. Two gotchas worth remembering: thesoap_server.jssuffix trap ('soap_server.js'.endsWith('server.js') === true, so bb/kh’s SOAP entrypoint was silently inheriting thevuerlog4js channel; the rename dropped it tounknownwith no error →endsWith('server.ts') || endsWith('soap_server.js'); lesson: suffix-matching entrypoint dispatch is fragile under rename), and the still-open release blocker in unversioned-partner-supervisor-overlays - typescript-in-vuer-repos — CORRECTION (2026-07-22): the unflagged type-stripping floor is Node 22.18, NOT 22.6 — 22.6 required
--experimental-strip-types, and no supervisorcommand=passes node flags. Verified empirically:node:22.6on a.tsentrypoint →SyntaxError: Missing initializer in const declaration(parsing TS as JS);node:22.18runs it. Version surface:engines >=22.18.0in all three repos, images/CI (vuer_build,vuer_docker) install 24.x, butvuer-releasepins a floatingNODE_VERSION: 22— above the floor today, not pinned there - typescript-in-vuer-repos — how TypeScript actually works in vuer_oss/vuer_css/portal_css (established by FKITDEV-8246 “TS Magic”, vuer_oss PR #7645
55035572bb; foundation for the FKITDEV-8251 epic): NO build step (tsconfignoEmit:true+erasableSyntaxOnly:true, nothing runstsc, no typecheck job in CI in any of the three repos — TS is editor/ESLint-only, type errors don’t fail CI), Node ≥ 22.18 strips types natively at runtime, files stay CommonJS (no"type":"module"anywhere), a cross-modulerequireof a.tsmodule needs an explicit.tsextension (require('../util/magic.ts'); extensionless →MODULE_NOT_FOUND), root-level*.tsis SILENTLY UNLINTED (ESLint TS blockfiles:['server/**/*.ts','customization/**/*.ts','client/**/*.ts']→ a rootserver.tsgets “File ignored because no matching configuration was supplied”;tsconfig includehas the same blind spot), Jest transforms.tsvia@swc/jest(vuer_oss) /ts-jest(vuer_css, portal_css),@typescript-eslint/no-explicit-anyis an ERROR (never fix a type error withany), andrequire('node:module').stripTypeScriptTypes(src)cheaply asserts a file is erasable-syntax clean - nyc-cannot-load-typescript — GOTCHA:
nyc(v18) cannot load.tsat all — it hijacks the.tsextension handler (append-transform→default-require-extensions/js.js) and compiles TypeScript as raw JavaScript →SyntaxError: Unexpected token ':'; neither--extension=.tsnor--include '**/*.ts'helps (Node’s runtime type-stripping is bypassed by nyc’s require hook). Consequence:vuer_oss/supervisor_vuer_oss_e2e_test.confrunsnpx nyc node <entry>.jsfor all 7 entrypoints andserver.jsalready requires six.tsservices at boot (server.js:48,83,99,108,109,110) → the conf has been broken since FKITDEV-8246 “TS Magic” landed (Jan 2026); nothing outside the git index references it (no CI job, no Docker repo) so it went unnoticed. Fix = swapnyc→c8(V8 coverage, no require hook) or retire the conf; warrants its own YouTrack ticket. First hit on FKITDEV-8387 - FKITDEV-8387 — Task 6 implementation, vuer_css
server.jsshim: second repo in the multi-repo.ts-shim rollout, single entrypoint.vuer_css/server/logger.jsuses a static log channel list, unlike vuer_oss’sprocess.argv[1]-sniffing logger — no logger change needed, a repo-to-repo gotcha worth checking per repo. 4 files (eslint.config.mjs/tsconfig.jsonglob widen,server.ts<void>Promise-type fix,bin/server/server.task.jswatch list);tsc/eslint/yarn lintexit 0, 115/115 suites (1064 tests) pass; commitb6513dc0onchore/FKITDEV-8387-ts-entrypoints, local-only
Validation / log analysis
- ASSICASH-71 — 2026-05-18 validation: PROD + 2 UAT log pulls (~1.1M lines total) confirm CSP-channel flood is gone; FKITSYS-9486 holding (0
ohp-uat.mbhbank.hurefs in PROD); both UATs silent for 12-19 months; status moved to validated
vuer_cv
- dev-box-cv-photo-processing-failures — CV runs in its own container
vuer_cv(imageharbor.techteamer.com/facekom-devel/vuer_cv:4.6.2.DEV-...); when stopped, nginx returns 502 forhttps://cv-lederera.facekomdev.netand vuer_oss logsCV server is down;docker start vuer_cvboots it under supervisord (nginx/redis/CV proc/~10 workers) toUp (healthy)in ~2 min (loopback curl flips 502→404); but it can still be unreachable from vuer_oss due to hairpin NAT (see topic above) - FKITDEV-8252 — in scope for FKITDEV-8252 (Q3 resolved by execution); new
base/vuer_cv/DockerfileUBI10 base, probe-builds green at 5.93 GB (iter 7); needs EPEL10 forlibmicrohttpd,git-lfs install --systembefore clone,ENV_VERSION=8matchingconfig/docker.jsonrequiredEnvVersion; size-reduction (multi-stage drop ofgit-lfs/gcc-c++/python3-devel) flagged as follow-up; cleanupmicrodnf remove --allowerasingcascade throughgit-coredeps worth a sanity audit
WebRTC / video orientation
- fk-dev-deploy-smoke-runbook — Janus / media-server fix (verified 2026-08-13): browser “media server connection errored” = the
januscontainer was supervisord-FATAL since first boot becausejanus_websocketscouldn’t create the wss vhost (in-image libwebsockets built without working TLS, even after adding certs). Key architecture fact that dissolves it: 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-apiisomorphic-ws), media flows browser↔operator via TURN/coturn (turnserver.facekomtest.net). So plainws://localhost:8188is correct for the oss→Janus hop; no wss needed. Fix = enablewsinjanus.transport.websockets.jcfgin-place inside the container (it’s a bind mount; hostsed -ichanges the inode and is ignored) + repointvuer_oss/config/dev.jsonwebrtc.janusServers.janusurl→ws://localhost:8188/adminUrl→ws://localhost:7188(keepadminSecret: janusoverlord). vuer_oss isnetwork_mode: hostsolocalhost(notjanus:). Media still needs TURN reachable - fk-dev-deploy-smoke-runbook — Videochat smoke gotchas AFTER signaling is fixed (verified 2026-08-13, first confirmed GREEN video on fk-dev — NÚSZ 1.9.11.48, flow “Sikeres”, both operator+customer video rendered): (1) a live call won’t record with
mkdir (/workspace/records/<roomId>/) error: 13 (Permission denied)— the janus PROCESS runs as non-root (techtea…) but/workspace/recordswasroot:root 0755; fixdocker exec -u 0:0 janus … chmod -R 0777 /workspace/records(dir =webrtc.janusConfig.recordDirectory); (2) “Taking a while to load” = slow ICE gathering, NOT a hang —[WARN] Waiting for candidates-done callback…, the call DOES connect (DTLS handshake completedfollows), optional speedupfull_trickle=trueand/or drop Janus’s own STUN injanus.jcfg; TURNturnserver.facekomtest.net:3478reachable, a raw TCP connect returning ECONNRESET is NORMAL (TURN isn’t plain TCP) — port-open is the signal; (3) resetting oss operator passwords — login is BY USERNAME (WebServerAuth.js, POST/login, plaintext, no 2FA), bcrypt worker is plainbcryptjs(no pepper) sobcrypt.hash(pw,10)verifies;update users set "password"=<hash>,"passwordExpiry"=<future> where username in (…); table usesisEnabled(not isActive) +passwordExpiry(rejected if< now); success =302 → /+vuersidcookie; browser autofill of a stale saved password is a common false alarm - FKITDEV-8533 —
videoOrientExt(theurn:3gpp:video-orientationRTP header extension) lets the receiver correct rotated video; gated at 4 sites —server/cv/VuerCVListenerSession.js,server/socket/events/videochat.js,server/transport/session/RoomTransportSession.js,server/transport/session/SelfServiceTransportSession.js(keep in sync). RESOLVED 2026-06-23 via “Option A — un-gate CVO for browsers” (branchfix/FKITDEV-8533-videoorient-ungate, commitd27d4cc990): restored the gate’s 2017 intent — shared helperserver/transport/videoOrientExt.jsvideoOrientExtEnabled(customer) = !customer.isNativeApp()(null→true) enables CVO for ALL browsers, disables it ONLY for the native SDK (userAgent.startsWith('mobile/')). Supersedes the iPad-detection PRs 7945 (no detection needed — the iPad is a browser). The customer’s own ID photo is captured from the LOCAL preview, which CVO can’t touch → client-canvas rotation (PR #3043) is orthogonal and still needed. - FKITDEV-8887 — iOS Safari audio interruption recovery;
InterruptionRecoverycontroller +VideoFeed.ensurePlaying()+Peer.replaceAudioTrack()proxy chain; see also## iOS Safari / audio recoverytopic for full detail - FKITDEV-9305-rca —
Cannot connect to STUN/TURN serversis always a relay-allocation problem, can never be caused by RabbitMQ, andvuer_ossCANNOT tell you which kind. First: the compat test is served byvuer_oss, not vuer_css — the customer stack frameConnectionCheck.startCheckingmatchesvuer_oss/client/features/system-check/check-steps/connection-check/connection-check.js(throw instartChecking()); the vuer_css twin throws fromcheckConnection(), so any vuer_css citation for this symptom is the wrong repo. Route:vuer_oss/server/web/routes/compat-test.endpoint.js, registeredserver/web/routes.js:109; the ICE list is server-rendered into the page — no queue, no RPC. THE TRAP:iceTest.js’sAUTH_FAILED = 2(:44) andNOT_REACHABLE = 3(:45) are DEAD CONSTANTS — defined and read (isAuthFailed():74,isUnreachable():78) butsetResultCode()is only ever called withDONE(:136,:153) andCONNECTION_TIMED_OUT(:172), and there is noonicecandidateerrorhandler ⇒ credentials rejected, TURN unreachable and no iceServers configured all collapse into one message (the working classifier exists only in the vuer_css twin). Worse,this.result.iceis assigned (connection-check.js:66) but never emitted or reported anywhere in vuer_oss (vuer_css emits a'report'event), and the pass/fail logicif (isTimedOut() || isAuthFailed() || isUnreachable() || !(hasRelay || hasReflex)) passed = false; else if (hasRelay) passed = trueleaves srflx-only (STUN works, relay doesn’t) in NEITHER branch →passedstaysundefined→ falsy → fails silently;TIMEOUT_PERIOD = 60000(iceTest.js:41). ⇒ diagnosis must happen outside the product:chrome://webrtc-internals, a Trickle-ICE test against the same TURN URL+creds, or coturn’s own logs. Three indistinguishable causes: TURN secret mismatch (coturnstatic-auth-secret≠webrtc.turn.secret; REST credsusername=<unixExpiry>:<name>,password=base64(HMAC-SHA1(secret, username)); also clock skew pastwebrtc.turn.validityInSec), UDP 3478 / TLS 5349 blocked or coturn down, andfilterByJanusServer()leavingiceServersempty (identical error, no server-side log) - janus-memory-leak-rca — THE JANUS MEMORY LEAK IS A
vuer_ossBUG, NOT AN UPSTREAM JANUS BUG (root-caused 2026-09-02, four years of tickets closed on the wrong premise). Mechanism:janus-api/src/Janus.js:407-425keepAlive()reschedules itself with asetTimeoutclosure capturingthis, so a “leaked”Janusobject is immortal AND actively pinging — V8 can’t collect it, its websocket stays open, and janus therefore never times the session out (keepAliveIntervalMs: 30000vs janus’s 60 ssession_timeoutdefault = 2× margin;session_timeoutis set in NO FaceKom config — checked vuer_docker, vuer_build, vuer-release). MEASURED on fk-dev: janus destroys sessions in UNDER 5 SECONDS when the websocket dies (40 opened, sockets killed with no destroy/keepalive, count went 44 → 4 within 5 s) ⇒ a crash or disconnect leaks NOTHING; the only way to strand a session is a live pinging JS object.Janus.destroy()is CORRECT (idempotent; clears keepalive on success, rejection and the 5 s-timeout path) — the bug is always “destroy was never called”, never “destroy is broken”. Leak paths ranked: (1)server/cv/VuerCVListenerSession.js:62leaks on EVERY invocation incl. the success path — nodestroy()/close()on the class and_janus.destroy()exists nowhere in either repo; ownerSelfServiceTransportSession.terminate()(server/transport/session/SelfServiceTransportSession.js:392-404) closes onlythis.janus, but the listener is a second independent session (costs 1 session + 2 handles + recorder (record: trueat:150) + up to 2 PeerConnections); (2)RoomTransportSessionleaks on any call not ended viaVideoChatService.close()(server/service/VideoChatService.js:201-233) — operator closing the tab emitsvideochat:leave→handleVideoChatLeave()writes an activity row and notifies CSS but never closes the room or touches the transport; vuer_cssterminate()isreturn Promise.resolve()(a no-op),TransportPool.sessionsis aMapwith no TTL/sweep, and no base-install cron reclaims videochat rooms (only theAutoCloseRoomsCronJobcustomization, gated onroomAutoCloseHours); (3)RoomInspector.connect()failure strands a session with ZERO references —client.roomInspector = inspectoris assigned after the await (server/socket/events/videochat.js:348-357) so the disconnect handler can’t see it, triggered normally byfindRoom()throwing “Video room not found” for rooms nobody published into yet; (4)VuerCVSessionregisters teardown at line 87, AFTER_connectJanus()at line 58 — plusCVTask(server/cv/CVTask.js:6-28) never arms its timeout (this.timeoutundefined whensuper()runs) for LivenessTask/LivenessV2Task/ActionTask/DocumentTask/HoloV2Task/SpeechTask/PadTask/MRZTask; (5) concurrentvideochat:senderPeer:initorphans handles (not sessions) —VideoRoomPublisherJanusPlugindoesn’t overridehangup()unlike the listener - janus-memory-leak-rca — SECONDARY FaceKom defect: videoroom rooms are NEVER destroyed.
janus-api’s videoroom plugins send onlyjoin/start/rtp_forward/stop_rtp_forward/edit/list/create/configure/listparticipants— nodestroy; vuer_oss sends none either, andRoomTransportSession.closeJanus()ends atjanus.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 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. ⚠️ The per-stranded-session ~0.5–1.5 MB is INFERRED, not measured (real ICE/DTLS/SRTP/recorder state couldn’t be allocated from a script) — confirm with a prod census before quoting it - janus-memory-leak-rca — UPSTREAM/FORK FACTS + THE DEBUNK. The TechTeamer/janus-gateway fork changes ZERO lines of janus C source —
*.c,*.h,src/,configure.ac,Makefile.amare byte-identical to upstream; it is a pure CI/packaging wrapper (.travis.yml,test/check_janus.sh, npm demo tooling). Commit→version fromconfigure.acAC_INIT:b8bebd94=0.13.4,08f25c9b=1.2.4 (actually a pre-release 1.2.4-dev snapshot, upstream master @bad60d702024-08-02,git describe=v1.2.3-11-gbad60d70),cc0fdca8=1.4.1 (exactly upstream v1.4.1),af80f7ef=0.16.1. 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 isg_thread_unref(g_thread_self())injanus_lua.candjanus_duktape.c, and both plugins are excluded by--disable-all-plugins. Upgrading 1.2.4-dev → v1.4.1 gains exactly ONE unconditionally-applicable leak fix:4419baf0(2024-12-10),janus_recorder_free()never freedrecorder->description; four others are conditional and don’t apply (SVC, dummy publishers, RTP forwarders, remote publishers).4fc066ff(videoroom subscriber refcount leak inslow_link) is gated onslowlink_threshold > 0andslowlink_thresholdappears in NO FaceKom config ⇒ default 0 ⇒ disabled (caveat: Raiffeisen ships its own.jcfgvia 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-websockets— the legacyvuer_build/base/janus/DockerfileALSO passes--enable-rest(HTTP transport compiled) while the newer vuer-release base does not. Latent build bug in the vuer-release base janus Dockerfile: copieslibwebsockets.so.19but symlinkslibwebsockets.so→libwebsockets.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 - janus-memory-leak-rca — CROSS-PARTNER + RELEASE BLOCKER. 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 (SLARAFIPI-83/FKITDEV-9239): janus 0.13.4, AWS t3.large,
maxmemory7168 MB, ~126 MB/day (longest clean run 03/05→04/28, 2%→97%), ~8 weeks to exhaustion, mitigation = manual restart only. DÁP/NISZ (DAP-1141): 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 on 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 wasjanus:1.2.4.1-20220513⇒ build definition ≠ deployed reality. DÁP on the NEWER janus leaks ~5× FASTER than Raiffeisen on the older one — 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: janus is absent fromCOMPONENT_LISTin ALL TEN Raiffeisen release manifests (vuer-release/projects/raiffeisen/release/1..10/release.json— every one is[vuer_oss, vuer_css]); theJANUS_VERSION_COMMITfield that flips08f25c9b→cc0fdca8at rel6 (1.9.11.94) is an attribute ON the vuer_oss component (what it is built against), NOT a janus image ⇒ no janus image has ever been built or shipped to Raiffeisen (confirmed by Szabó Márton in FKITDEV-9239). Janus must be added to the build for.101or nothing changes. Keep SEPARATE from FKITDEV-9193 (a distinct, confirmed Node.js leak inStorageService._getInFlightCache/stream(), likely driving FKITSYS-9902 — UniCredit, OSS alone at 17.6 GB). Read-only diagnostic scripts at/Users/levander/coding/facekom/out/janus-memory/(janus-probe.jscensus via the already-enabled Admin APIwss://janus:7989, adminSecretjanusoverlord,JanusAdminalready in janus-api withlistSessions/listHandles/handleInfo; plusroomleak.js,sessleak.js) - janus-memory-leak-rca — MEASURED ON REAL CALLS 2026-09-07 — and it CORRECTS the hypothesis: BOTH arms leak. Isolated full stack (
vuerleak2,/workspace/_leak2/on fk-dev: postgres + rabbitmq + janus + vuer_oss + vuer_css, own network/DB/TLS proxy), real browser calls with real media (two<video>per side, 640×480, advancingcurrentTime), janus RSS + Admin API census per cycle, 10 cycles/arm. ABANDONED:sessions_delta 10/rooms_delta 10/rss_delta_kb 10064⇒ ~0.8–1.0 MB per call (reproduced: 999.2 kB/cycle), each call permanently costing 1 session + 1 handle + 1 populated videoroom. CLEAN (operator ends properly):sessions_delta 0— sessions/handles ARE reclaimed — butrooms_delta 10,rss_delta_kb 6872⇒ ~453 kB per properly ended call, because the videoroom is never destroyed. ⇒ “a cleanly ended call is fine” is WRONG, and the inferred 0.5–1.5 MB/session is SUPERSEDED. In the clean arm the RSS may be partly allocator retention — the room count is the hard evidence. Permanence verified long after the run: 9 sessions alive, 10 rooms (9 populated), 10 DB rooms stuckincall - janus-memory-leak-rca — SIDE-DEFECT: one abandoned call takes the OPERATOR OUT OF SERVICE. An abandoned call leaves
Room.status='incall'forever —handleVideoChatLeaveonly writes an activity row, onlyvideochat:closecloses a room, and no cron covers operator videochat rooms (CloseExpiredSelfServiceRoomsCronJobis self-service only) ⇒videochat:createRoomthen refuses withoperator_in_open_roomand that operator can take no further calls until someone closes it by hand. This is an availability bug that has probably been misfiled for years as “operator can’t receive calls” - janus-memory-leak-rca — SIDE-DEFECT: multi-role users silently cannot answer calls.
videoChat.receiveCallis granted only tooperatorinconfig/roles.json, butWebServerAuth.js:934setsreq.session.role = req.user.getMainRole()andgetMainRole()(server/db/model/user.js:187) returns the firstacl.roleListentry the user has ⇒admin. Fails silently three layers deep: no right ⇒waitinglist.script.js:113never callsreceiveAvailable(true)⇒.can-receive-callnever added ⇒WaitingList.styl:16keeps.customer-item-actionsatdisplay:none. Fix: POST/api/role-switchwithdocument.body.dataset.csrftoken(whatdefault.layout.js:48does). Symptom→cause shortcut: “sees the customer, no accept button” = role, not perms/CSS/sockets
RTK / tooling gotchas
- SLARAFIPI-84 — CORRECTION 2026-09-07: the stale worktree produced wrong CITATIONS, never a wrong FACT — and an earlier revision of that note wrongly implied it caused both refuted answers. Re-read at both refs via
subprocess.run(["/usr/bin/git",…,"show",…]):raiffeisen.customerPortrait.thresholdis 0.55 at350d3e626bAND at tagraiffeisen-1.9.11.100, theperfect: thresholdoverride is identical at both,SelfServiceCheckerService.jsis not in the 6-commit diff at all, and theface_comparewriter only moved by 19 lines; the wholeconfig/docker.jsondiff ismaxRetryCount: 4,documentRecognitionVersion2→3 and two liveness labels. Staleness is a real citation hazard (it misled three agents) but is not an explanation for a wrong conclusion — do not use it as one. - rtk-mangles-curl-and-pipes — RTK (the token-proxy that auto-rewrites shell commands) MUTATES some commands, not just their output → silently wrong results.
curl <url>fails with curl error (3) “Malformed input to a URL function” (Rust proxy corrupts the URL;wgetalso unreliable);ls | sortreturns empty;find|wc -l/|grep -cget zeroed (dangerous — reads like a legit “no results”). Bypass viapython3: download withurllib.request.urlretrieve(not curl/wget); run multi-step CLI checks viasubprocess.run([...])argv list (noshell=True, not a shell pipeline); for counts cross-check two independent methods.rtk proxy <cmd>is a raw escape hatch but prefer the python bypass. Hit while fetching the actionlint binary for the FKITDEV-8239 review - rtk-git-log-hides-merge-commits — sibling RTK gotcha: output-filtering drops merge commits from
git log --oneline --graph, producing a deceptively linear DAG → squash/rebase/reset can operate on the wrong range and lose a parent’s history. Use parent-aware plumbing instead (git log --pretty='%h | %p | %s',git rev-list --parents -n 1 <sha>,git rev-list --count A..B); verify a squash preserved content by comparingHEAD^{tree}hashes before/after; non-interactive squash via backup-ref +reset --soft+ tree-hash equality gate (git rebase -iunavailable in this harness) - raiffeisen-1.9.11.100 — two more RTK mangling cases found 2026-08-11, both silently wrong rather than failing:
git show <rev>:<path>has its<rev>:<path>argument mangled, and jest--verboseper-test lines get swallowed so a run looks like it produced no test names. Bypasses:python3subprocess.run([...])with an argv list (noshell=True) for thegit show, andjest --json --outputFile=<f>instead of--verboseto get machine-readable per-test results. Consistent with rtk-mangles-curl-and-pipes: assume any RTK-proxied command whose arguments contain:-separated or pipe-like syntax may be rewritten, and prefer a structured-output flag over human-readable output whenever you need to assert on it - FKITDEV-9197 — five more RTK modes, 2026-08-11, all returning a plausible wrong answer rather than an error:
git show <ref>:<file> | grepgarbled so real matches were reported as ABSENT (nearly caused a wrong conflict-resolution decision during the CIB merge);diff -ureformatted into an unreadable line-offset view with a wrong exit code (so the exit-code fallback lies too);git diff --no-indexrendered as if the whole file were new;git log -1immediately after committing showed devel’s tip56a63bd0instead of the just-created merge commitb1a4bc94— the rtk-git-log-hides-merge-commits merge-filtering behaviour landing at the exact moment you check “did my commit land, and onto what?”, which invites you to undo correct work; and${PIPESTATUS[0]}blanked, making every pipeline pass/fail gate unverifiable. Workarounds proven here:rtk proxy <cmd>(preferred for verification claims precisely because the failure is silent),git grep <pat> <ref> -- <path>instead ofgit show | grep,shasum -a 256for same-vs-different, and pythondifflibto generate a diff. Standing rule: never trust RTK-rendered git output for a verification claim — “the merge commit is X”, “the file does not contain Y”, “these are identical”, “it exited 0” all need re-verification. ⚠️ And the workaround has its own trap: callingjestdirectly to dodge RTK’syarnrewriting DROPS the flags the npm script supplies — omitting--experimental-vm-modulesmanufactured 4 phantom failures in vuer_oss on this round. Preferrtk proxy yarn <script>; if you must bypass the script runner, copy the full flag list out ofpackage.jsonfirst - SLARAFIPI-84 — RTK silently DROPPED THREE COMMENT LINES while extracting a source file through
git show, shifting every line number below them by 3 — so line references harvested that way pointed at the wrong code, in a note whose conclusions were all line-anchored. Same failure family as the wrong-commit-for-git log -1case: plausible output, no error. Rule reaffirmed: use/usr/bin/gitdirectly for anything load-bearing. Two non-RTK verification traps found in the same session and worth pairing with it: a worktree HEAD that is an ancestor of the tag by 6 commits touching exactly the files under investigation (read viagit show <tag>:<path>, never the working tree), andgit log -1 --format=%adshowing an author date preserved through a rebase (2026-05-12) instead of the real committer date (2026-08-10) — use%cd
Release management / YouTrack
- vuer-build-never-pushes —
vuer_build/build.sh(the LEGACY partner path) never publishes: verifiedgrep -n push build.sh→ nodocker push, nodocker login. v0.4.1 only builds and tags locally (harbor.techteamer.com/${PROJECT_NAME}/<svc>:${VUER_VERSION}.${VUER_BUILD_NUMBER}-${SECURITY_NUMBER}; common infra →harbor.techteamer.com/vuer-common/…) and can export images as.tarinto the customer ZIP (--build_package) — theharbor.…prefix is only a tag, nothing in the script contacts the registry.sign-partner.shv0.1.1 wraps cosign (--annotations 'Signer=Facekom Kft',-isingle /-ttag list) but signing is not publishing. Contrast the modernvuer-releasepath, which does publish:release-tool publish pushin.github/workflows/autobuild.ymlauthenticating withsecrets.HARBOR_USER/HARBOR_SECRET. ⚠️ OPEN QUESTION, explicitly not guessed: how legacy images actually reach Harbor is in NO file read so far (manualdocker push? separate script? ops runbook outside the repo?) — and it sits directly on CIB, which is on the legacy path per client-registry. Version caveat: the note says 1.9.11.101 while client-registry records .102 per FKITDEV-9197 ⇒ resolve from the openASSCIBRelease issue orgit ls-remote --tags, never from a note. Two traps:build.sh -l/--list-partnersis broken (cd partners/at:447, real dir ispartner/singular — 39 dirs) and builds fail without an operator-suppliedbase/<svc>/github.key(copied to/root/.ssh/id_rsato clone private repos;*.keygitignored, README:22-28 ⇒ a fresh clone cannot build). Base OS is branch-dependent:main=UBI9,feature/FKITDEV-8868=UBI8,feature/FKITDEV-8252-ubi10=UBI10 - facekom-test-tiers — the three release-testing tiers; tier 2 (booted, non-browser) is ~60% of a release runbook with zero tooling, and building it also dissolves the k6 seeding blocker. See the Dev / testing workflow entry for detail
- devel-update-and-release-flow — how to collect a release’s ticket scope for the TjK and for author outreach (Phase 3), plus the release gates (Phase 4). Verified tool
/Users/levander/coding/facekom/.claude/scripts/release_tickets.py <tag-prefix> <repo-path>…resolves the latest release tag per repo (fetching the tag explicitly — needed in narrowed-refspec clones) and emits two markdown tables with YouTrack links, GitHub commit + PR links, state, assignee and commit author: (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; (2) came via devel but modifiedcustomization/(git log <tag>..HEAD --no-merges -- customization/minus bucket 1) = core work that nonetheless changed the partner surface, easy to miss entirely. Generali 1.9.11.19 vsgenerali-atvilagitas-1.9.11.18: direct = FKITDEV-8567 (Done, assignee Jurkiewicz, authored by Szecsődi, vuer_oss PR #7811) + FKITDEV-9194; via devel = FKITDEV-9119 (Done, Szvetkó, PR #8083) + FKITDEV-9080 (Pending but shipping anyway — flag it, Makkai, PR #8054). Two manual steps the tool cannot do: assignee ≠ commit author (both emitted, pick per question), and it only sees tickets in commit subjects — the headline changelog item can be a pure-core commit in neither bucket (1.9.11.19’s is ASSGRALI-63 / FKITDEV-8887 iOS audio), so cross-check the parentASS*release ticket’s changelog. Release gates:chore/branch merged intocustomization/<partner>via PR (the tag is cut from the customization branch),customization/RELEASE.mdentry (historically its own ticket — FKITDEV-9153 for .18), tag<partner>-1.9.11.NN(package.jsonversionstays1.9.11— the.NNlives only in tag + changelog), breaking-change/config sweep (BREAKING/!:, newdb/migrate/,config/diffs — .19 restructuredbrowsers.showOldBrowserWarning→browsers.oldBrowserWarning.{show,delay}withserver/web/Template.js:123on the new path, so any partner prod config on the old key silently loses the old-browser warning anddocs/config/was not updated), functional smoke test on a real deployment (a container unit run is not one), TjK written - vuer-release-build-flow — how the vuer-release build/release flow actually works, read from the
TechTeamer/vuer-release-cliPython source (2026-07-22) — therelease_toolbinary is NOT a black box. Flow:release-tool release create project <p>(interactive VERSION/BUILD_NUMBER/TAG) →projects/<p>/release/<N>/release.json+ tag<p>@<N>→autobuild.ymlon a self-hosted runner (RELEASE_PAT→~/.git-credentialsHTTPSx-access-token, download release_tool asset,gen→build→publishto Harbor withHARBOR_USER/HARBOR_SECRET). Corrections to previously-guessed assumptions: (1) component source is cloned fromTAG, notVERSION(gen.py::download_source→git clone --branch <TAG> --single-branch --depth 1);VERSIONonly feeds the image tag{registry}/{PROJECT_NAME}/{NAME}:{VERSION}.{BUILD_NUMBER}-{SECURITY_NUMBER}+ the generated.env. (2) a new base component needs nobase@Nrelease first —BASE_/PROJECT_/RELEASE_COMPONENT_IMAGE_TAGare the same locally-computed string, never resolved against the registry;build.pybuilds the base stage then the project stage against the just-built local image. (3) component NAME == GitHub repo name (repo_name = component["NAME"]underGIT_REMOTE_ORG), no override key;JANUS_REPOSITORYis only used byinstall-janus-build-env.sh. (4)release createwritesCOMPONENT_LIST,genonly reads it —component_env_values.json(base then project, project wins) supplies interactive prompt defaults atrelease create(release.py:239-259/269-297, written at:356);gen.py:76readsrelease_json["COMPONENT_LIST"]and never re-reads the component env files. This corrects the old “gen snapshots component config” gotcha in vuer-release-cut-recipe (now fixed there): janus pins are the effective default but overridable at release time, not immutable. (5)TAGis NOT inREQUIRED_ENV_VALUES(release.py:49=VERSION+BUILD_NUMBERonly) — it is prompted only if already present in the merged env values; janus deliberately has noTAG→has_source()false → never cloned by the CLI (fetched byinstall-janus-build-env.shviaJANUS_REPOSITORY/JANUS_VERSION_COMMIT); trap: a new base component missingTAGis silently never cloned. Plusgen.py::rm_alwayssanitization (strips.yarnrc,config/dev.json,.git, anysupervisor_*/nginx_*withoutdockerin the name), tarball top-level dir == NAME, component availability = directory existence (release/.gitkeeprequired;component_env_values.json+Dockerfileoptional), do not userelease-tool component create(stalecomponent.j2), and the FKITDEV-8349/DÁP application (forceddap-demo-partnerhyphen naming → Harbor image rename;TAG1.0.7.1not1.0.7) - youtrack-ready-for-release-nusz-query — YouTrack access + the NÚSZ “Ready for release” release-scope query. Tracker = YouTrack at
https://youtrack.techteamer.com(REST/api/issues; MCP server at/mcpin~/.claude.json, scoped toclaude_orchestrator). Auth = Bearer token from~/.config/facekom/youtrack.token(chmod 600, never on argv); the/fk-ticketcommand (.claude/commands/fk-ticket.md) +client.pyextractor read the same file. “Ready for release” is a TAG (exact stringReady for release; searchtag: {Ready for release}— braces for the spaces); it is tracker-wide (57 issues across clients), so theproject:filter is what scopes it. The four NÚSZ projects:CRNUSZ(Business Requests),BUGNUSZ(Support Issues),SLANUSZ(SLA),ASSNUSZ(Assist). Verified scope queryproject: CRNUSZ, BUGNUSZ, SLANUSZ, ASSNUSZ tag: {Ready for release}returned 3 on 2026-06-15 (CRNUSZ-102, ASSNUSZ-58, SLANUSZ-28; BUGNUSZ 0); read-onlycurl -G --data-urlencoderecipe included. CRNUSZ-102 verified example shows StatePendingyet tag-flagged → the tag (not State) is the readiness signal. Don’t confuse with the distinctUpcoming Releasetag. GET/read-only only. - nusz-1.9.11.47 — per-release tracking hub for nusz
@13/1.9.11.47(release issue ASSNUSZ-116 / FKITDEV-8938). Scope mechanism, dual-publish 🅼 Harbor / 🅻 vuer_build checklist, manual post-release YouTrack transitions, and a per-ticket payload detail section: CRNUSZ-102 (impl FKITDEV-8794/8801 — no code/PR found, business-accepted, UAT 06.18), SLANUSZ-28 (impl FKITDEV-8639 → PR #7862, NOT yet incustomization/nusz, may be in .45/.46), ASSNUSZ-58 (stat-export, UAT/PROD gate, targeted .46.1). Merge-status warning: payload code not yet confirmed incustomization/nusz; version target (.45/.46/.46.1/.47) needs confirming. - instacash-esign-1.3.0.11 — per-release hub for the InstaCash eSign
1.3.0.11release (eSign pipeline, not vuer-release): esign_oss + esign_css only, taginstacash-1.3.0.11/ Harborinstacash-esign-{oss,css}:1.3.0.11-20260608; ASSICASH-92 release + ASSICASH-93 TESZT / ASSICASH-96 PROD (approved 2026-06-26 from1.3.0.8); changelog = devel update + FKITDEV-8817 vuln fixes; no DB migration / no breaking change; rollback = redeploy1.3.0.8. First InstaCash release to ship with a TJK. - client-registry — cross-system name glue for
/fk-release: YouTrack suffix ≠ repo name (RAFIPI=raiffeisen, MNET=magnet, PB=polgaribank, GRALI/GRALIA=generali, etc.). 22 clients mapped with build-path (modernvuer-release/projects/<client>/ legacyvuer_build/partner/<client>/ eSign instacash) + resolution rules (YouTrack projectsCR/BUG/SLA/ASS<suffix>, version from openASS<suffix>Release issue, customization branchcustomization/<repo>incl.-instant/-v2/-f1variants). - release-automation-design — reusable prepare-and-gate
/fk-release <client>design. Now also covers client generalization (path auto-detection, universalASS<CLIENT>Release-issue convention proven by CIB .101), PR fetch without YouTrack VCS (VcsChangeCategoryempty → resolve viagit log --all --grep=FKITDEV-NNNNmerge-commit + comment-scan for pasted PR URLs), and comment extraction ranking (has-attachment > Hungarian QA keywords > embedded issue links; attachment URLs are signed/expiring). - FKITDEV-8354-mvm-supervisor-config-dedup — vuer-release Gen2 partner-migration mechanics (FKITDEV-8354, MVM project,
vuer_build→vuer-releaselean format, PR #28 basemaster): partner component images layer overrides viaprojects/<client>/components/<svc>/DockerfileCOPYon top of the source-package files symlinked by baseinstall/configure-app.sh; supervisor-config dedup decision rule (byte-identical ⇒ delete, else keep). Do not conflate with FKITDEV-8252 PR #31feat: ubi10(different ticket/branch). Reviewerbencelaszlo; round-1 set janus pins1.4.1/cc0fdca8+ restored supervisor-stdout. - youtrack-tesztjegyzokonyv-attachment-recipe — where FaceKom test records (“tesztjegyzőkönyv” / “Tesztelési jegyzőkönyv”) live + a read-only REST attachment recipe. TJKs are PDF/DOCX attachments on per-client
ASS<CLIENT>release /BUG<CLIENT>tickets, NOT standalone issues; 8-section branded template (Cél / háttér / teszttípus-összegzés / tesztesetek / jegyzőkönyv+evidencia / értékelés / hibák / mellékletek); canonical templates = FKITDEV-8329 (unified format) + FKITDEV-8330 (release/install template). Recipe (pythonurllib, same base +~/.config/facekom/youtrack.tokenas youtrack-ready-for-release-nusz-query):GET /api/issues?query=…&fields=…,attachments(name,mimeType,created,url),comments(text,attachments(…)), Hungarian full-text works, scope byproject:; download = prepend base to the attachment’s relative signedurl, GET w/ Bearer, write bytes; timestamps epoch-ms. GET/read-only. - tesztjegyzokonyv-generation-flow — the
/fk-tjkflow that GENERATES a partner’s Tesztelési jegyzőkönyv.docx+ the tester’s manual runbook. REWRITTEN 2026-08-11 — treat everything after “LEGACY-ERA DETAIL” below as superseded. Now ZERO-CONTEXT: input is a partner key only and you must never carry a release number/ticket/partner in from conversation, because release trains are PER PARTNER (Raiffeisen1.9.11.100while NÚSZ was on1.9.11.48, same day) — a borrowed version silently yields a correct-looking WRONG document; a version in$ARGUMENTSis a hint and a mismatch with the partner’s release ticket STOPS the flow. Phases 0historiansynthesis (live state wins over vault AND over the historian) → 1 partner/base/release → 2 gather → 3 evidence → 4 draft → 5 render → 6 runbook → 7 hand-off. Every partner is standardized on therelease-docshape (_meta.targetShapeinpartners.json); the sablon is the legacy path. Base doc = the newest TjK in~/Downloadsmatched by NAME (Tesztelési jegyzőkönyv/Tesztjegyzokonyv) — live Google-Docs export, beats any ticket attachment; never match by size or list position (CVs at ~765K sit next to the 763K TjK). Two-step build viaappend_release_sections.py:newdocrebases any partner’s TjK onto a new partner+release (drops old ticket sections, clears TOC cache, longest-first partner rename — pass both forms"Raiffeisen PION,Raiffeisen"orRaiffeisen PION fejlesztés→NÚSZ PION fejlesztés;--replace OLD=NEWfor lowercase build tags/dates), then append adds sections from JSON (p/bullets/code/evidence); both self-check, never mutate input, both take--selfcheck. ⚠️ TOC LEAK (proven, not theoretical): the TOC is a static Word field holding the PREVIOUS doc’s heading text until refreshed — a Raiffeisen→NÚSZ rebase leftASSRAFIPI-124/SLARAFIPI-59in the NÚSZ TOC, invisible in the body;newdocclears it and REFUSES to write if any sourceASS…/SLA…/CR…/BUG…id survives ⇒ TOC renders empty until a human refreshes it. Phase 6 writesout/<partner>-<release>-teszt-runbook.md(előfeltételek / lépések / elvárt eredmény + failure signature / bizonyíték naming which TjK slot it fills / the arming condition — e.g. socket-reuse-only bugs where reopening the app proves nothing and yields a false pass). Evidence is REGENERATED, not quoted; gotchas: rtk swallows jest--verbose→--json --outputFile, worktreenode_modulesout of sync with its branch lock (missing babel plugin) →yarn install --frozen-lockfile,textutilcannot read PDF →pdftotext -layout.fileStemstays per partner though the shape is shared;nusz/ASSNUSZwas missing frompartners.jsonentirely until 2026-08-11 and an unknown key halts the flow on step one by design. — LEGACY-ERA DETAIL (2026-06-26, sablon path): Practice: one TJK per AFFECTED partner per1.9.11.NN(not all 39), attached to that partner’s release ticket; shortName usuallyASS<PARTNER>/BUG<PARTNER>but VARIES (MicroSec=MF, DÁP=DAP/ASSDAP) sopartners.jsonpinsytProject; a core change reuses byte-identical body text across partners (MKBASSMKB-90== BBASSBB-82). New std templatetesztjegyzokonyv_sablon.docx(authored 2026-05-29, replaces 3 inconsistent legacy formats) = 19<…>placeholders each intact in a single<w:t>run, all inword/document.xml→ plain string substitution preserves styling (no docxtemplater/pandoc). Tool = Claude command.claude/commands/fk-tjk.md(pulls dev ticket viafkticket+ 1 past report/partner for house style → draft → render) + stdlib renderer.claude/scripts/tjk/render_tjk.py(clones test-case block document.xml paras 27–36 per case w/1.→k.,\n→<w:br/>, verbatim zip-repackage swapping ONLY document.xml, self-check) +partners.json(13 seeded —instacash/ASSICASH added 2026-06-26) + pinned sablon. v1 leaves screenshots / pass-fail underline / PDF export / YouTrack-attach MANUAL (no write-back). Self-check + tests pass; design spec/Users/levander/coding/facekom/docs/superpowers/specs/2026-06-26-teszt-jegyzokonyv-flow-design.md. First real use (2026-06-26): generated the first-ever InstaCash eSign TJK (5 cases) for eSign 1.3.0.11 →~/Downloads/tesztjegyzokonyv_instacash_1.3.0.11.docx. - nusz-1.9.11.48-test-runbook — TJK-source manual test runbook for NÚSZ
1.9.11.48(ASSNUSZ-126 / prep FKITDEV-9217, nextrelease/17+nusz@17). Prioritized (P1/P2/P3) plan across payload verification (ASSNUSZ-76/FKITDEV-9150 remove-old-data cron + audio-only webm; FKITDEV-8975 text), AI-Act (present but config-gated OFF by default — CSSaiAct.videoCall/selfService=false), core 12-flow NÚSZ E2E smoke, and devel-update regression by area (reports/SL, portal/PortalData, camera-permission + iOS audio recovery, S3 attachments/export, MJML v5 ESM emails, crons, TS-entrypoint sweep). Flags what UAT cannot prove (real disk reclaim, reconversion backlog scale, customer-key-offline deletion branch — prod-only) + open retention question (7d vs 28d). - tesztjegyzokonyv-partner-release-document-structure — the partner-facing RELEASE TjK is a DIFFERENT artifact from
/fk-tjk’s template — do not conflate them. [[tesztjegyzokonyv-generation-flow|/fk-tjk]]‘s pinnedtesztjegyzokonyv_sablon.docxis 19-placeholder substitution for one dev ticket; the release TjK is hand-authored per release with oneHeading2section per shipped ticket (<Partner> - Tesztelési jegyzőkönyv - VUER OSS CSS - Release 1.9.11.<NN>.docx, attached as PDF toASS<PARTNER>-<n>). Shape:Title/Normal/Subtitle→ static TOC field →Heading2 Bevezetés→ per ticketHeading2 <id> - <title>/Heading3 Fejlesztés/Heading3 Teszteset/ optionalHeading4 Elvárt működés. Hard rule: PARTNER-side ticket ids only (ASSRAFIPI-/SLARAFIPI-/CRRAFIPI-) —FKITDEV-<n>never appears in a customer document; section order = release changelog order, not ticket number. Evidence forms ranked: monospace dump (oneNormalpara per line, Roboto Mono / color37474f/ sz 21) > inline<w:drawing>screenshot > narrative; bulletsnumId=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 and does NOT refresh on programmatic append (reopen in Word/Docs before PDF export — a mis-styled body paragraph is invisible in the body but loud in the TOC), and the closing “telepítésre ajánlott … a tesztek mind sikeresek voltak” paragraph ofBevezetésIS the formal pass/fail statement to the bank — rewrite it if any case failed. Working append script/Users/levander/coding/facekom/.claude/scripts/tjk/append_release_sections.py(theappend_sections_example.pyname is gone) (splice<w:p>before<w:sectPr>, rewrite the zip entry-for-entry, self-check); source docs are Google Docs exports (allw:rsid*=00000000) with Roboto + Roboto Mono embedded. The full spec — including the VERBATIM HungarianBevezetésboilerplate and its closing recommendation paragraph — now lives in the note itself: the on-diskdocs/tjk-raiffeisen-document-structure.mdwas folded in and retired 2026-08-11 (only executable config stays in facekom:.claude/commands/fk-tjk.md,.claude/scripts/tjk/*.py+partners.json). Reverse-engineered from the 2026-08-10 raiffeisen-1.9.11.100 draft (whose known defects are listed in both notes) - release-cut-mechanics — durable git/GitHub mechanics of a partner release cut (live-verified executing NÚSZ
1.9.11.48on 2026-08-25), thecustomization/<partner>half that complements vuer-release-cut-recipe’s Harbor-autobuild half. FOUR ops: (1) land the devel-update ontocustomization/<partner>by SQUASH mergegh pr merge --squash --admin(compliant PR title first, since the squash subject = the title;--adminskips only red checks not the ruleset — see the Git / rulesets topic); (2) changelog = direct compliant commit tocustomization/<partner>(no PR rule) viagh api -X PUT …/contents/customization/RELEASE.MD, oss & css RELEASE.MD are separate per-repo entries — compute real delta withcompare/nusz-1.9.11.47...customization/nusz; (3) source tags<partner>-<version>viagh api …/git/refs(do NOT trigger a build); (4) vuer-release cut — default branchmaster(notmain), copyrelease/16→17/release.json, bumpRELEASE_VERSIONtop-level +DEFAULT_ARGS+ bothCOMPONENT_LISTVERSION/TAG, tagnusz@17= the Harbor build trigger (nusz@Nnames don’t match vuer_oss tag rules → vuer-release has looser tag rules). Inherited-not-regression red: osstranslations.test.js“Directory not found: client/features”. Executed .48: PR squashes e01bf599/f8511f79, changelog c8c5f7e7/08fc5380, release/17 3bd20ec7, nusz@17 pushed. - vuer-release-cli-pinning —
vuer-release/.cliversionis an EXACT-EQUALITY pin (1.0.3), and the toolchain around it is broken in four independent ways.release_tool/pkg/util.py:validate_cli_versiondoesVersion(current) != Version(required)— a newer CLI is rejected exactly like an older one. Do not bump to 1.1.1: the runner’s.github/scripts/download-release-cli.shselects the release asset namedrelease_tooland 1.1.1 renamed its asset torelease-tool⇒ CI dies withERROR: Asset 'release_tool' not found. To run 1.0.3 locally you must first patch its invalidpyproject.toml(pyyaml/typing_extensionsunquoted ⇒tomllib.TOMLDecodeErrorat line 16) and invokepython run.py(it has no[project.scripts]); 1.1.1’srequirements.txtomitspackaging. The two versions emit differentrelease.jsonkey sets (1.0.3REQUIRED_ENV_VALUES = {"VERSION":"","BUILD_NUMBER":""}vs 1.1.1{"VERSION":…,"TAG":…}with required-flag dicts) and read incompatible schemas from the same~/.release-tool/config.json(flat keys vscurrent_context/contexts) ⇒ the CLI-source facts in vuer-release-build-flow are 1.0.3 facts, which is what CI actually runs - component-list-is-not-a-full-manifest — CORRECTION:
COMPONENT_LISTis a BUILD SET, not an inventory of the partner’s running stack. Verified 2026-09-04 with Python over the parsed JSON (never a shell pipe —rtkzeroes| wc -l): 91projects/*/release/*/release.jsonfiles, 90 with aCOMPONENT_LIST, 88 excluding the two new cib cuts; component ENTRY counts over those 88 =vuer_oss84,vuer_css84,portal_css8,janus5,resource-manager3,report-engine1 (with the cib cuts: 86/86/9, a clean +1/+1/+1 ⇒ self-consistent). The four manifests with no vuer_oss/vuer_css are all SINGLE-COMPONENT BUNDLES —demo-facekom/release/6→['report-engine'],demo-project/release/{1,2,3}→['resource-manager'].janushas a component dir in 12 partners but ships in only 3 (barion/cofidis/kh);mkb-instanthasrabbitmq+turndirs and ships neither; 12 of 18 latest cuts are exactlyvuer_oss+vuer_css. GOTCHA:projects/equilor/release/1/release.jsonhas NOCOMPONENT_LISTkey at all — an older all-lowercase legacy schema (default_args/docker_registry/git_remote/project/project_args/services/timestamp); equilor has exactly one release, so any script iterating all manifests must guard for it orKeyError. BUTrelease-tool genbuilds the delivered docker-compose FROMCOMPONENT_LIST⇒ an omission is a silent delivery gap, the exact shape of SLARAFIPI-83 / janus-memory-leak-rca (janus absent from all ten Raiffeisen manifests ⇒ never built, never shipped). DECIDING CHECK: count theimage:lines invuer_build/partner/<client>/docker-compose.yml— that is what the customer actually pulls. CIB’s has exactly three (vuer_css,vuer_oss,portal_css, the last on its own${PORTAL_VERSION}.${PORTAL_BUILD_NUMBER}vars) and no janus line ⇒portal_cssREQUIRED incib@2,januscorrectly excluded - cib-1.9.11.102 — CIB release hub. Source-tagged 2026-09-03; CIB’s FIRST-EVER
vuer-releasecutcib@1(commitac8aa5cc55onmaster, tagcib@1, autobuild run33855979398) was made 2026-09-04 and FAILED at the Harbor publish — images BUILT fine, Harbor login SUCCEEDED, thendocker push harbor.techteamer.com/cib-facekom/vuer_css:1.9.11.102.1-20221206was rejected. DELIVERY BLOCKED, needs a Harbor admin (hypothesis, NOT confirmed: thecib-facekomproject does not exist or the robot lacks push rights — login worked and the same runner pushednusz@18the day before). Image tag anatomy =<VERSION>.<BUILD_NUMBER>-<SECURITY_NUMBER>, not the all-hyphen form. CIB is a MODERN (vuer-release) partner as of.102— client-registry’s legacy row corrected.cib@2(addsportal_css 1.4.0.74) prepared but UNCOMMITTED — justified by CIB’s own PROD compose,vuer_build/partner/cib/docker-compose.yml, which has exactly threeimage:lines (vuer_css/vuer_oss/portal_css) and no janus line ⇒ portal REQUIRED, janus correctly excluded.vuer_buildcontains NOdocker push/docker loginanywhere, so nothing in the repo shows the robot ever had write access tocib-facekom; and Harbor’s API returns[]unauthenticated for every project, so non-existence could NOT be inferred — the root cause stays a hypothesis. The.102changelog was NEVER written in either repo — deliberately left alone, since the source tags already point past it.vuer-releasehas no commit-message ruleset: one ruleset (12260273 “main-protect”, ~ALL), one rule,non_fast_forward. Original hub facts: (ASSCIB-166 / FKITDEV-9197), a pure core-update release: 334 commits / ~11 months of devel drift, 212 tickets, zero partner commits since.101. Components are vuer_oss + vuer_css ONLY per ASSCIB-166’s Komponensek —portal_css[#712] is deliberately out of the train and still open (it also runs its own version line,cib-1.4.0.*, and never carries acib-1.9.11.*number). Tags are annotated, tagger Andras Lederer, message the bare1.9.11.102\n→ vuer_oss12a8a9e328221829ae6d383fd5e23eda9cf81a38, vuer_cssca60fac34ac95b661336587b455924ab55e52def; created through the GitHub API rather than a local push specifically to avoid the vuer_css narrowed-fetch-refspec stale-ref trap (narrowed-fetch-refspec-stale-devel-merge). Tag-kind convention changed at.101:cib-1.9.11.100was LIGHTWEIGHT,.101(annotated,1.9.11.101\n, Szabó Márton, 2026-05-29) and.102are annotated — do not pattern-match on.100. Both PRs squash-merged → devel ancestry lost, see squash-merge-erases-partner-devel-ancestry; tagged content verified byte-identical to the reviewed PR heads before tagging. Open after tagging: Docker image builds (./build.sh -b cib-1.9.11.102 -i vuer_ossfromvuer_buildmain — the legacy path, see vuer-build-never-pushes) and a TjK with blank tester/verifier names and a date mismatch (doc 2026.08.13 vs evidence 2026.08.17). NOT verified: whether earlier CIB releases used real merge commits rather than squashes - raiffeisen-1.9.11.100 — CORRECTED 2026-09-08: the release IS tagged, and the export script is still marooned on that lineage.
raiffeisen-1.9.11.100is an annotated tag, objecteaeacd0799→ commit2352f5117f, tagged 2026-08-18 12:36 +0200; the release branchchore/FKITDEV-9156-raiffeisen-release-1.9.11.100sits at the same commit, which supersedes the note’s 2026-08-11 “NOT tagged” warning and makes the recorded branch head350d3e626b6 commits stale (facekom-worktree-vs-tag-trap). Still open:customization/bin/raiffeisen-facecomparison-export.jsexists only on that release branch/tag — absent fromorigin/customization/raiffeisen(fa983a0eba) and fromdevel(git ls-remote+git ls-tree, 2026-09-08) ⇒ the next cut fromcustomization/raiffeisensilently loses a delivered partner feature, along with the SLARAFIPI-84 recovery work built on top of it. Verify withls-remote/ls-tree, never withrtk