Skip to content

Releases: code-hustler-ft3d/ibg-controller

v0.5.10

21 Apr 05:42

Choose a tag to compare

See CHANGELOG.md for details.

v0.5.9

19 Apr 18:19

Choose a tag to compare

See CHANGELOG.md for details.

v0.5.8

19 Apr 09:56

Choose a tag to compare

See CHANGELOG.md for details.

v0.5.7

19 Apr 09:49

Choose a tag to compare

See CHANGELOG.md for details.

v0.5.6

18 Apr 19:59

Choose a tag to compare

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_restart and the SIGTERM/SIGINT
    handler. See the CHANGELOG for the full causal chain.

Added

  • ALERT_CLEAN_LOGOUT log 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_SECONDS env var (default 15). Tune up if
    status=failed_timeout correlates with follow-up
    ALERT_CCP_PERSISTENT.
  • CLOSE_WIN <title_substr> agent command in
    GatewayInputAgent.java: posts WindowEvent.WINDOW_CLOSING via
    Toolkit.getDefaultToolkit().getSystemEventQueue(). Idempotent —
    OK on dispatch, ERR not_found on no match.
  • 10 new unit tests — test total 176 → 186, all green.

Docs

  • OBSERVABILITY.md — full ALERT_CLEAN_LOGOUT section 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.6

SBOM 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

18 Apr 17:17

Choose a tag to compare

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:
    1. 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.
    2. Extended SIGTERM grace for mid-life restarts: 20s → 30s
      (tunable via JVM_TEARDOWN_GRACE_SECONDS). Reduces the rate at
      which teardowns have to escalate to SIGKILL in the first place.
    3. ALERT_JVM_UNCLEAN_SHUTDOWN (WARNING) fires on every
      SIGKILL-escalated teardown so monitoring can correlate with
      subsequent ALERT_CCP_PERSISTENT and tune the cap for long
      IBKR tenant timeouts.

Added

  • ALERT_JVM_UNCLEAN_SHUTDOWN log 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 (default 30)
    • CCP_COOLDOWN_MAX_SECONDS (default 3600)
    • CCP_COOLDOWN_MULTIPLIER (default 1.5; set to 1.0 to 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.5

Image 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

18 Apr 13:00

Choose a tag to compare

Highlights

  • Release-image pipeline end-to-end. v0.5.3 exposed a bug: the release-image.yml workflow's release:published trigger never fired, because GitHub suppresses downstream workflow runs from GITHUB_TOKEN-originated events. Switched to push:tags in parallel with ci.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_dispatch input. Any past tag (including v0.5.3) can now be built retroactively: Actions → Release image → Run workflow → enter v0.5.3.

Community readiness

  • CONTRIBUTING.md with four "Adding a new..." walkthroughs (ALERT token, dialog handler, env var, IBC-key mapping).
  • Feature-request and question issue templates under .github/ISSUE_TEMPLATE/.
  • CODEOWNERS routes 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.4

Full details: CHANGELOG.md. Supply chain: SECURITY.md.

v0.5.3

18 Apr 12:20

Choose a tag to compare

See CHANGELOG.md for details.

v0.5.2 — ALERT_SHUTDOWN + UPGRADING.md + FROM_IBC matrix

18 Apr 12:13

Choose a tag to compare

[0.5.2] - 2026-04-18

Added

  • New ALERT_SHUTDOWN grep-contract log token (INFO-level)
    emitted from the SIGTERM / SIGINT handler. Format:
    ALERT_SHUTDOWN mode=<live|paper> signal=<SIGTERM|SIGINT> graceful=<true|false> reason="...".
    graceful=false means the Gateway JVM ignored SIGTERM for 15s
    and had to be SIGKILL'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 the ALERT_ 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 the 0.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 in UPGRADING.md.
  • Expanded docs/FROM_IBC.md unsupported-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.py knows 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

18 Apr 12:04

Choose a tag to compare

[0.5.1] - 2026-04-17

Added

  • New ALERT_LOGIN_FAILED grep-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_failure matches a bad-password launcher.log
    fingerprint (reason="bad-credentials" or
    reason="post-auth-no-progress"). Closes an observability gap:
    previously a stale TWS_PASSWORD (password rotated in the IBKR
    portal but not yet mirrored into the container env) would surface
    only as ALERT_CCP_PERSISTENT after the CCP streak hit its
    threshold — by which time the account could already be locked out.
    ALERT_LOGIN_FAILED fires 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_WARNING is now honored everywhere the controller
    dismisses disclaimers
    , not just opportunistically inside
    wait_for_api_port. Previously dismiss_post_login_disclaimers
    (called on initial login, after RESTART, and after re-auth)
    hardcoded a local SAFE_BUTTONS list and ignored the env var,
    contradicting README and FROM_IBC.md claims. The module-level
    SAFE_DISMISS_BUTTONS is now an ordered tuple built once at import
    (built-in defaults first, then BYPASS_WARNING additions in
    user-specified order) and consumed by both dismissal paths. Users
    who had BYPASS_WARNING set were only getting partial coverage
    before; no behaviour change for users on defaults.

Non-goals

  • ALERT_LOGIN_FAILED is 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_EXPIRED log 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_dialogs now recognizes the wording, classifies
    it as status=warning (parses days_remaining when the dialog
    reports it) or status=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 same ALERT_* 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.py one-shot migration tool: parses an
    existing IBC config.ini, maps each honored key to the equivalent
    ibg-controller env var, and emits env, docker, or compose output.
    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.md migration 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-matrix that builds the shipped
    Dockerfile against multiple UPSTREAM_IMAGE tags 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.