Releases: code-hustler-ft3d/ibg-controller
v0.5.10
See CHANGELOG.md for details.
v0.5.9
See CHANGELOG.md for details.
v0.5.8
See CHANGELOG.md for details.
v0.5.7
See CHANGELOG.md for details.
v0.5.6
v0.5.6 — clean UI logout attacks root cause of stranded CCP session slots
Why this release
v0.5.5 was containment: it made unclean teardowns rarer (30s grace,
ALERT_JVM_UNCLEAN_SHUTDOWN) and softened the blast when they happened
(adaptive cool-down scaling from 1200s → 3600s). It did not eliminate
the root cause — the controller was still asking the JVM to shut down
with SIGTERM and relying on Gateway's shutdown hooks to close the CCP
session slot server-side.
v0.5.6 attacks the root cause. Before any SIGTERM, the controller
now dispatches a WINDOW_CLOSING AWTEvent to Gateway's main window.
This fires Gateway's own WindowListener — the same code path as a
user clicking the X button — which performs an ordered CCP
session-close. If the clean close succeeds within
CLEAN_LOGOUT_TIMEOUT_SECONDS (default 15s), SIGTERM is skipped
entirely and no stranded slot is produced. If it fails (agent
unreachable, or JVM doesn't exit in time), the controller falls
through to v0.5.5's SIGTERM + grace → SIGKILL → adaptive cool-down
defenses. Strictly additive: best case, stranded slots stop
happening; worst case, same safety net as v0.5.5.
Fixed
- Stranded IBKR session slots — root-cause fix via UI-driven
clean logout in_teardown_jvm_for_restartand the SIGTERM/SIGINT
handler. See the CHANGELOG for the full causal chain.
Added
ALERT_CLEAN_LOGOUTlog token (INFO). Emission shape:
ALERT_CLEAN_LOGOUT mode=<live|paper> pid=<pid|none> status=<succeeded|failed_unreachable|failed_timeout> reason="...".
Part of the public stability contract.CLEAN_LOGOUT_TIMEOUT_SECONDSenv var (default 15). Tune up if
status=failed_timeoutcorrelates with follow-up
ALERT_CCP_PERSISTENT.CLOSE_WIN <title_substr>agent command in
GatewayInputAgent.java: postsWindowEvent.WINDOW_CLOSINGvia
Toolkit.getDefaultToolkit().getSystemEventQueue(). Idempotent —
OKon dispatch,ERR not_foundon no match.- 10 new unit tests — test total 176 → 186, all green.
Docs
OBSERVABILITY.md— fullALERT_CLEAN_LOGOUTsection with per-status operator guidance and recommended debounce.UPGRADING.md— non-breaking upgrade notes; when to tune the new env var.
How to pull + verify
docker pull ghcr.io/code-hustler-ft3d/ibg-controller:v0.5.6
cosign verify \
--certificate-identity-regexp '^https://github.com/code-hustler-ft3d/ibg-controller/\.github/workflows/release-image\.yml@' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/code-hustler-ft3d/ibg-controller:v0.5.6SBOM is attached to this release as sbom.spdx.json and to the image
as a signed cosign attest attestation. See SECURITY.md.
v0.5.5
Summary
Defensive fix for a CCP-lockout failure mode diagnosed on 2026-04-18:
a container was showing ALERT_CCP_PERSISTENT on both live AND paper
for 2+ hours despite no concurrent IBKR web or mobile session. Root
cause was a stranded self-session — _teardown_jvm_for_restart
SIGKILL'd the Gateway JVM at 20s without a clean CCP session-close,
so IBKR held the session slot server-side past the (then-fixed) 1200s
cool-down, and the next auth attempt from the same controller
silently dropped at CCP as if someone else were holding the slot.
No breaking changes. Upgrade by pulling v0.5.5 or rebuilding
from source. See UPGRADING.md §v0.5.5
for operator guidance.
Fixed
- Stranded session slot on SIGKILL teardown. Three-layer defence:
- Adaptive long cool-down (
_compute_adaptive_cooldown) scales
by restart-attempt index. Default progression is 1200s → 1800s →
2700s → 3600s (capped). Gives IBKR escalating quiet time to drain
any stranded slot before the next auth attempt. - Extended SIGTERM grace for mid-life restarts: 20s → 30s
(tunable viaJVM_TEARDOWN_GRACE_SECONDS). Reduces the rate at
which teardowns have to escalate to SIGKILL in the first place. ALERT_JVM_UNCLEAN_SHUTDOWN(WARNING) fires on every
SIGKILL-escalated teardown so monitoring can correlate with
subsequentALERT_CCP_PERSISTENTand tune the cap for long
IBKR tenant timeouts.
- Adaptive long cool-down (
Added
ALERT_JVM_UNCLEAN_SHUTDOWNlog token — part of the public
stability contract. Distinct from the existing controller-lifecycle
ALERT_SHUTDOWN(INFO-level); this one fires on mid-life JVM
restarts (CCP lockout escalation, monitor-loop recovery).- Three new env vars, all optional, all defaulted:
JVM_TEARDOWN_GRACE_SECONDS(default30)CCP_COOLDOWN_MAX_SECONDS(default3600)CCP_COOLDOWN_MULTIPLIER(default1.5; set to1.0to restore
v0.5.4 fixed-duration behaviour)
- 10 new unit tests (176 total, up from 166).
Operator quick reference
Signal you should care about: if you see ALERT_JVM_UNCLEAN_SHUTDOWN
followed by ALERT_CCP_PERSISTENT that doesn't clear after the
adaptive cool-down has hit its cap, raise CCP_COOLDOWN_MAX_SECONDS.
Pre-v0.5.5 manual remediation (if you're stuck and haven't upgraded
yet): docker stop the container → IBKR Client Portal → Settings →
User Settings → Manage Sessions → terminate any lingering TWS/Gateway/API
rows → wait 5 min → docker start.
Install
docker pull ghcr.io/code-hustler-ft3d/ibg-controller:v0.5.5Image is cosign-signed (keyless) and has a cosign-attested SBOM. See
SECURITY.md
for the verification recipe.
Full log: CHANGELOG.md § 0.5.5
v0.5.4
Highlights
- Release-image pipeline end-to-end. v0.5.3 exposed a bug: the
release-image.ymlworkflow'srelease:publishedtrigger never fired, because GitHub suppresses downstream workflow runs fromGITHUB_TOKEN-originated events. Switched topush:tagsin parallel withci.yml, with a poll-for-release step before SBOM upload. v0.5.4 is the first tag whose container image, SPDX SBOM, and cosign attestation all publish automatically. workflow_dispatchinput. Any past tag (including v0.5.3) can now be built retroactively: Actions → Release image → Run workflow → enterv0.5.3.
Community readiness
CONTRIBUTING.mdwith four "Adding a new..." walkthroughs (ALERT token, dialog handler, env var, IBC-key mapping).- Feature-request and question issue templates under
.github/ISSUE_TEMPLATE/. CODEOWNERSroutes review on the stability-contract docs (OBSERVABILITY.md,UPGRADING.md,CHANGELOG.md) and workflow edits.- Enhanced PR template with a "Why" section and expanded doc-update checklist.
- README badges for release version, release-image status, license, and cosign-signed.
Upgrade
No controller behaviour changes from v0.5.3. docker pull ghcr.io/code-hustler-ft3d/ibg-controller:v0.5.4 or pull :0.5 / :latest. See UPGRADING.md#v054.
Verify
cosign verify \
--certificate-identity-regexp '^https://github.com/code-hustler-ft3d/ibg-controller/\.github/workflows/release-image\.yml@' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/code-hustler-ft3d/ibg-controller:v0.5.4Full details: CHANGELOG.md. Supply chain: SECURITY.md.
v0.5.3
See CHANGELOG.md for details.
v0.5.2 — ALERT_SHUTDOWN + UPGRADING.md + FROM_IBC matrix
[0.5.2] - 2026-04-18
Added
- New
ALERT_SHUTDOWNgrep-contract log token (INFO-level)
emitted from theSIGTERM/SIGINThandler. Format:
ALERT_SHUTDOWN mode=<live|paper> signal=<SIGTERM|SIGINT> graceful=<true|false> reason="...".
graceful=falsemeans the Gateway JVM ignoredSIGTERMfor 15s
and had to beSIGKILL'd — points at a deadlocked Swing EDT, a
blocked native I/O call, or host resource starvation. Its absence
in the last ~N seconds of a container's logs before an exit is
itself a signal: the controller died without going through the
signal handler, i.e. unexpected JVM / interpreter crash rather
than operator-initiated restart. Sits at INFO deliberately so it
doesn't trip ERROR-level wake-someone-up grep filters, but remains
catchable via theALERT_prefix.
Full grep-contract:
docs/OBSERVABILITY.md. - New
docs/UPGRADING.md— version-to-version
upgrade workflow, rollback recipe, and per-version operator notes.
Fills a gap: the CHANGELOG lists what changed, not what an
operator needs to do to move from one tag to the next. Pre-1.0
version scheme is called out explicitly: minor bumps in the0.x
series are allowed to contain breaking changes, and every one that
does will be called out in the CHANGELOG's Removed / Changed
sections and inUPGRADING.md. - Expanded
docs/FROM_IBC.mdunsupported-IBC-keys matrix:
converted the old 6-bullet list into four grouped tables
(stay-on-IBC, no-op in headless Docker, config-shape mismatch with
workaround, handled implicitly) covering every IBC key
ibc_config_to_env.pyknows about. Gives IBC users evaluating a
switch a single place to confirm whether their setup has a clean
migration path.
v0.5.1 — IBC migration tooling + password-expiry + login-failed alerts
[0.5.1] - 2026-04-17
Added
- New
ALERT_LOGIN_FAILEDgrep-contract log token. Emitted when
Gateway surfaces a credential-rejection modal during in-JVM relogin
(reason="bad-credentials") or when the terminal-failure path in
_diagnose_login_failurematches a bad-passwordlauncher.log
fingerprint (reason="bad-credentials"or
reason="post-auth-no-progress"). Closes an observability gap:
previously a staleTWS_PASSWORD(password rotated in the IBKR
portal but not yet mirrored into the container env) would surface
only asALERT_CCP_PERSISTENTafter the CCP streak hit its
threshold — by which time the account could already be locked out.
ALERT_LOGIN_FAILEDfires on the first rejected attempt so
monitoring can page before the streak escalates. Format:
ALERT_LOGIN_FAILED mode=<live|paper> reason="<bad-credentials|post-auth-no-progress>" suggested_action="...".
Full grep-contract + dedupe guidance:
docs/OBSERVABILITY.md.
Fixed
BYPASS_WARNINGis now honored everywhere the controller
dismisses disclaimers, not just opportunistically inside
wait_for_api_port. Previouslydismiss_post_login_disclaimers
(called on initial login, after RESTART, and after re-auth)
hardcoded a localSAFE_BUTTONSlist and ignored the env var,
contradicting README andFROM_IBC.mdclaims. The module-level
SAFE_DISMISS_BUTTONSis now an ordered tuple built once at import
(built-in defaults first, thenBYPASS_WARNINGadditions in
user-specified order) and consumed by both dismissal paths. Users
who hadBYPASS_WARNINGset were only getting partial coverage
before; no behaviour change for users on defaults.
Non-goals
ALERT_LOGIN_FAILEDis a detection signal, not a corrective
action. The controller still retries login in the usual CCP-backoff
pattern after emitting the alert; stopping retries automatically
risks false positives on transient IBKR auth glitches. If the
alert fires repeatedly and the credentials are genuinely wrong,
the operator should stop the container to avoid account lockout.
[0.5.0] - 2026-04-17
Added
- Password-expiry dialog handler +
ALERT_PASSWORD_EXPIREDlog token.
Closes a real IBC-parity gap: Gateway/TWS surface a "Your password will
expire in N days" modal after login inside IBKR's rotation window, and
a "Your password has expired" blocker once the window closes. Without
a handler, the warning variant could silently pass through (no alert
to the operator before lockout) and the blocker variant would chew
through CCP retries on an auth that can't succeed.
handle_post_login_dialogsnow recognizes the wording, classifies
it asstatus=warning(parsesdays_remainingwhen the dialog
reports it) orstatus=expired(login-blocking), emits the stable
grep-contract line
ALERT_PASSWORD_EXPIRED status=<warning|expired> mode=<live|paper> [days_remaining=N] suggested_action="...",
and clicks OK/Continue/Acknowledge/Close to dismiss. External
monitoring (the sameALERT_*pipeline as v0.4.8/v0.4.9) can now
notify the operator to rotate the IBKR password before the account
locks out — a gap IBC's own PasswordExpiryWarningDialogHandler doesn't
close in the same structured way. - New
scripts/ibc_config_to_env.pyone-shot migration tool: parses an
existing IBCconfig.ini, maps each honored key to the equivalent
ibg-controller env var, and emitsenv,docker, orcomposeoutput.
Warns on unsupported IBC keys (FIX, CustomConfig, MinimizeMainWindow,
etc.). Lowers the "rewrite 50 lines of config" barrier for IBC users
evaluating a switch. - New
docs/FROM_IBC.mdmigration guide: IBC-key → controller env-var
mapping table, step-by-step cutover recipe, rollback path,
behaviour-difference notes (command-server auth, per-mode usernames,
CCP backoff semantics, observability endpoints). - New CI job
gateway-version-matrixthat builds the shipped
Dockerfileagainst multipleUPSTREAM_IMAGEtags and runs a
container-level module-load smoke test inside each. Catches breakage
in the AT-SPI / JRE-bridge wiring when the base image moves across
Gateway versions, without needing live IBKR creds.
Non-goals
- The blocking "password has expired" variant still can't be
auto-recovered by the software — rotation has to happen in IBKR's
web portal. v0.5.0 makes detection observable; it does not try to
drive the change-password dialog headless.