The hard maxBounds added for the single-world look fought the zoom: with
the world smaller than the window the clamp dragged every zoom step into
a corner. The noWrap tiles already guarantee one world on their own, so
the bounds go — on both maps.
An FTx menu between View and Tools gathers FT Decodes, FT Map and the
Grid squares map — three views of the same UDP feed that were buried in
Tools. And the watchlist spot rows swap the elastic country column for
fixed widths, so band, mode and frequency read as columns instead of
starting wherever each country name happened to end.
The FT map wrapped the planet into a row of copies and showed Leaflet's
hard-coded grey beyond it. noWrap tiles inside hard bounds now, like the
grid-square map already did — and the container background override moves to
style.css so EVERY map's surround follows the theme's card surface instead
of #ddd (the grid map's per-div fix was losing to leaflet.css specificity).
A new FT Map tab (Tools menu, beside FT decodes): every station decoded in
the last half hour drawn as a great-circle arc from the operator's own
square, coloured by band the way PSK Reporter taught everyone to read it,
fading with age, one arc per call (its freshest sighting), a tooltip with
call/grid/SNR, the MainMap basemap picker and a legend of only the bands on
screen.
Performance was the open question and it is answered structurally: the panel
mounts only while its tab is ACTIVE (zero cost otherwise), the map renders
canvas (one element, not one node per arc), arcs are capped at 300, and
redraws follow the decode list — every period, not every frame.
spotEntityStatus says 'worked' when every grain is in the log; the
unconfirmed check compared its all-ledger verdict against the empty string,
so no band/mode/slot need ever dimmed however many unconfirmed QSOs stood
behind it — only the entity-level NEW, tested by map presence, behaved. The
check now runs for exactly the four needy statuses and asks for 'worked'.
Dimming the filled chip to a transparent background left its light
foreground text on nothing — an invisible badge in the row. Unconfirmed now
renders in the category's own hue, dashed border and text, like the extras
beside it.
The frontend caches statuses and only asks about unknown keys, so flipping
the chase mode left half the screen judged under the old rules until a
restart — which read as the mode not working. The backend now broadcasts an
invalidation and the panels re-ask as rows repaint. The entity badges also
say their name with a question mark, dashed, when the need is only a missing
QSL — the 50% opacity was invisible on a filled chip.
The unconf label was hard-coded to GRID? for every category — a prefix
worked-but-unconfirmed showed as a second grid badge beside the real one,
which read as impossible. Each badge now says its own name plus a question
mark. And the global Chase block moves above the Chase POTA/SOTA/grid
checkboxes, where its operator expected the master switch.
my_dxcc/my_cq_zone/my_itu_zone go through BulkSetIntField, not the string
column map — the guard flagged them as unwritable ever since they were
added, which is the drift it exists to catch, one package over.
The gap between worked and confirmed becomes visible everywhere. A Chase
setting on the DX Cluster page picks the mode; in new-plus-unconfirmed the
verdicts for DXCC/band/mode/slot, prefix, county and state are judged against
CONFIRMED-only ledgers built from the operator's chosen sources (LoTW, card,
eQSL, QRZ.com — HRDLog has no confirmation field in ADIF to offer), and a
need that exists only because a QSL never arrived is flagged Unconf: the
cluster and decode badges render it dimmed, the convention the grid hunt
introduced. The grid's own Chase selector folds into the global one; its
square-matching scope stays where it was, being grid-specific. One snapshot
key change rebuilds the cache when any of it flips.
The WAS gap made visible: a worked-states set joins the cluster status cache
(distinct states over the three US entities), the status entries carry a
NewState flag wherever the state resolves (log county first, ULS licence
second), and the decode panel gains the badge in its status column plus the
filter chip alongside NEW/BAND/MODE/GRID. Colour from the shared marker
palette, so the cluster can adopt it later without a second hue.
Between the locator and the country, per its operator: the two-letter badge
anchors the eye and the spelled-out name answers it — 'SD' alone is a quiz
for a European. The status-cell badge from the first pass moves here.
Plain text, not a badge — it is a fact, not an action — placed first so a
WAS chaser can scan the column edge. Shown whenever the status cache knows
the state (log county data or the licence address).
The voice keyer grows to F1-F12 — the UI was already data-driven, so the
count constant, the F-key range and the labels are the whole change.
And the preferences stop stuttering on a busy station: every spot batch,
decode batch and CAT snapshot re-rendered the entire App tree behind the
dialog — cluster grid, decodes panel, thousands of nodes — and the pointer
janked over the very panel the operator was trying to use. While Settings is
open the flushes park their batches in the pending refs (bounded) and CAT
repaints at most every two seconds; closing the dialog drains everything.
The panel now mirrors the decoder's own window line for line — the operator
compares the two side by side, and the SNR sort scrambled that
correspondence. The report is still right there in its column.
Three faults, one report. The slow poll asks ^TP — the KPA1500's ATU, which
a KPA500 (no ATU) never answers — and ask() dropped the whole connection on
any read timeout: a two-second stall and a reconnect every slow cycle, which
is why buttons lagged and the status read wrong. Worse, every serial reopen
toggled DTR/RTS — and those lines are the KPA500's POWER SWITCH (that is how
the Elecraft utility turns it on), so the amplifier obediently switched off
twenty seconds after its operator pressed nothing but Standby.
Silence is no longer a dead link (write errors still are), ^TP is never asked
again after one silence, the control lines are asserted once and held, and
the baud field becomes a list of the rates these amplifiers actually speak.
A connect that lasts 50 ms leaves nothing to say which answer the client
disliked — WSJT-X refusing to attach to the shared CAT was undiagnosable
without the full wire trace. The handshake is now always logged; steady-state
polling stays behind the trace switch.
Configure (message 15), mode field only, every other field sent as
no-change: an FT4 spot clicked while WSJT-X sits in FT8 lands the operator
ready to decode instead of staring at gibberish. Sent to every instance
heard this session — one already in the right mode treats it as a no-op —
and only for modes the decoder actually speaks (FT8/FT4/JT65/JT9/MSK144/
Q65/FST4); CW and SSB are none of its business. Toggle in the Connections
panel, on by default.
The great-circle arc to a polar entity (Franz Josef Land) peaks near 88°N;
fitting the raw arc points framed a band of tile-less white above 85°, where
Web Mercator ends. The camera's bounds are clamped to ±85° — the line still
draws to wherever it goes, only the framing stays where there is a map.
WSJT-X restates the same DX Call in every Status packet, and a spot clicked
in OpsLog put that call into the last-UDP memory (deliberately, for another
case) — so the guard let the decoder's next restatement straight through and
the entry snapped back to old news. The decoder's stream now only counts when
its value CHANGES; a clear over there resets the edge so re-selecting the
same station still lands. Explicit picks (N1MM, remote, spot relays) are
untouched.
Message 13 paints callsigns in WSJT-X/JTDX's own Band Activity window with
verdicts from the same cluster status cache that colours the spot grid:
watchlist pink, new DXCC green, new band for its entity orange. Deduplicated
per instance+call+verdict, one datagram each; a verdict that lapses (the
operator worked them) clears that call, and turning the option off clears
everything via the protocol's CLEARALL!. Off by default, switch in the
Connections panel.
Message 7 asks a program heard for the first time this session to replay the
decodes already on its screen, so the FT decodes panel starts full instead of
empty until the next period. Replayed lines arrive marked not-new and are
shown but never auto-answered — the auto-caller now checks, on top of its
30-second freshness gate.
The operator preferred the original's aesthetics. Adopted: the signature pink
callsign (a fixed identity colour, like the cluster palette), counters as
coloured pills, a quieter card surface with a hover, a stronger needed bar on
spot rows, and the lightning bolt back on the DXpedition badge. Everything
else stays on theme tokens.
The operator measured the whole table: 10 W showed 83, 12 W showed 100, 13 W
showed 8 — the bargraph is relative to a meter RANGE that flips at 12 W
(0-12 QRP, 0-120 above). A bar percentage was never watts; with the PC
setting choosing the range, it converts, and the console prints the watts
beside the bar.
One placeholder per id in a single IN (…) hits SQLite's bound-variable cap:
bulk field set died at 168 000 QSOs with 'too many SQL variables' (10 000
passed). One chunker now serves bulk set (text/int/extra/frequency), the
delete, the post-upload markers and the export-selection iterator — the last
collecting and sorting once at the end so its chronological contract holds
across chunks. 500 ids a statement keeps every backend far from any limit.
Tried on the real IC-7760: the magic packet wakes nothing; Icom's own
mechanism is the network-standby session plus the CI-V power-on, which
OpsLog already does. The MAC store and the WOL sender go, and the changelog
entry with them. The CI-V pump now says once per session that the client
pings are armed — invisible pings read as absent pings.
wfview sends a ping (0x07, 0x15 bytes, its own seq and a monotonic
timestamp) every 500 ms on every stream, and so does RS-BA1. OpsLog only
ever REPLIED to the rig's pings — and the loaner IC-7760 stopped serving
CI-V data about a minute into nearly every session while the transport
stayed alive: the rig had concluded nobody was listening. Scope, TX audio
and idle numbering were each eliminated in turn before wfview's source
settled it. Pings now go out on control, CI-V and audio alike.
Two lookups race when a second callsign is typed before the first answered,
and the slow one landed last: the grid showed the previous call's QSOs under
the new call's name — LU5AVM's contact filed under LW8ETV, screenshot in
hand. A request token now discards any response that is not the newest.
A 7760 switched fully off takes its LAN server down, and no session means no
console and no ON button — the one thing remote operation cannot tolerate.
The rig's MAC is learned from every login and persisted; when a dial finds
nobody home, the magic packet goes out to it before the next attempt. The
rig wakes into standby, the session opens, and the ON button does the rest.
The generic Freq write lands on the TX VFO when split is engaged: an FT-2000
moved B and left A — the receiver — behind, so a spot click QSYed the
transmitter and nothing audible changed; without split the same write moved A.
With split on (and the operator on MAIN), FreqA and FreqB are both written,
so the radio arrives on the spot whole, split left as the operator had it.
The inference tables knew FT8 on some bands and nothing on others: a 10.136
spot with a bare comment read as generic DATA — which is what every
skimmerless spot of a DXpedition's 30 m FT8 slot did. The standard FT8/FT4
windows are added on 30 m, 60 m, 80 m (FT4), 17 m (FT4) and 12 m, in BOTH
tables (backend band plan and frontend spot.ts), ahead of the wide segments
they sit inside — order is the mechanism there.
Every idle went out with seq 0, seven a second, interleaved with
properly-numbered data — where RS-BA1 and wfview draw idle sequence numbers
from the same counter as everything else. A rig that follows the sequence
tolerates the zeros for a minute or so and then stops serving CI-V data on
the stream: the shape of every dropout the loaner IC-7760 has shown, with the
scope and the TX path both since eliminated as causes. Idles now take the
next tracked seq and sit in the retransmit buffer like any other packet.
The 0x26 01 copy was fire-and-forget, and a real 7760's sub VFO kept
yesterday's mode with nothing to show why — refused, or sent with a stale
mode byte. The mode is read first when unknown, and both outcomes are
logged.
The console's thin home-made bars were the one holdout — every other panel
(Flex, Elecraft, the amps, the tuner) draws the same MeterBar. And the mode
badge said SSB, which on any band leaves the operator guessing which
sideband the rig is on: the panel now shows USB or LSB (the log keeps ADIF's
SSB).
It keeps 'not repeating' on a network rig and every guess at which guard was
tripping proved wrong. Each round now logs play / playing-flag / end / gap,
and every exit names its reason.
The blind kill at connect still left a real 7760 streaming — the selector
byte differs by model, and the result was discarded so a quiet failure looked
like a cure. Both forms go out now (a NAK costs one frame) and the outcomes
are logged. The power table also gains its third measured anchor: a real
200 W reads full deflection, so raw 213 is 200 W — not the printed face's
250.
Over the network the rig's mode read fails now and then and the CAT push
blanks the mode for a poll or two; the auto-CQ loop treated that blank as
'not a phone mode' and stopped after the first call. Only a KNOWN non-phone
mode stops the loop now.
The CI-V meters are point samples: between two SSB syllables a poll lands on
0 W and a perfect SWR, so a 150 W transmission read 0-10 W most of the time
and the SWR sat at 1.0. Power now decays like a needle and SWR holds its peak
then snaps to the live value — the same meterPeak the Yaesu and Kenwood
consoles already use. The readout column also widens so '180 W' stays on one
line.
TUNE (1C 01 02) started a cycle; nothing sent the 0 that puts the tuner back
through. An ATU chip beside SPLIT now toggles it, and the tuner state is read
on the slow front-panel beat so the radio's own TUNER button stays in sync.