| 1 |
Columns in live trace |
Make the columns between each data source thicker |
N |
1 |
1 |
2026-08-15 17:34:17 |
2026-08-16 12:24:45 |
| 2 |
Live popup service description |
In the service popup, change the service description from: origin time; origin station …. To: next station departure time and station name …
And have the origin time and station in smaller text below it. |
N |
1 |
1 |
2026-08-15 17:39:15 |
2026-09-06 09:46:48 |
| 3 |
Trust source |
Show the trust source in the live trace in a coloured badge, don’t know how many source types there are. |
N |
1 |
1 |
2026-08-15 17:40:31 |
2026-08-16 12:24:45 |
| 4 |
live trace red for late |
In the full schedule in the live trace, have a simple lateness/earliness indicator eg +2 to the left of the current location, and if >10mins late change the green to red. Make sure it is signed +- |
N |
1 |
1 |
2026-08-15 21:49:33 |
2026-09-06 09:46:59 |
| 5 |
More liveness |
Can he maps in the popup be live |
N |
1 |
1 |
2026-08-15 21:50:41 |
2026-09-06 09:47:04 |
| 6 |
continue red hue |
Can the red hue used on the main map be shown on the popup map? |
N |
1 |
1 |
2026-08-15 21:51:50 |
2026-09-06 09:47:08 |
| 7 |
status clarity |
The basis of the status is anchored on departure and arrival, definitions for which follow.
If the service is activated and transposed onto a platform then the status is, or if a service has arrived at an intermediate station and not yet departed:
- At Platform <platform> in <station> and be shown as amber.
If the service has departed a station but has not arrived at the next stop (ie traversing a leg):
- Running to <stationAtEndOfLeg>
If the srvice has a arrived at the destination:
- Terminated at <destinationStation>
This is going to be good enough for out initial implementation, but will need to be revisited for cancellations etc.
DEPARTURE
The first of offset TD/Trust/Schedule+30s+lateness (if arrived < 2(tuneable) mins late) or wait for TD/TRUST
- Tunable indicates a tunable parameter that may be sunject a having in a control table.
ARRIVAL
First of offset TD or trust.
ARRIVAL |
N |
1 |
0 |
2026-08-15 21:55:08 |
2026-08-19 13:29:53 |
| 8 |
zoom detail levels |
consider different levels of detail at different zoom levels.
Also consider reflection of density when applying this. |
N |
1 |
0 |
2026-08-15 21:57:18 |
2026-08-16 19:34:43 |
| 9 |
Heat spots |
look at volume circles, clearing them to actual services as zoom level presents less dense picture |
L |
2 |
0 |
2026-08-15 21:58:16 |
2026-08-16 12:38:37 |
| 10 |
live indicator |
Indicate where the map or table is live or static. Maybe offer as a toggle, and if frozen, at what time? |
N |
1 |
1 |
2026-08-15 21:59:19 |
2026-09-06 09:47:31 |
| 11 |
stations with multiple trains |
show them as an asterisk (or something) where they have >1 services and link it to popup table of services. |
L |
1 |
0 |
2026-08-15 22:00:52 |
2026-08-16 12:38:46 |
| 12 |
station labels |
At certain zoom levels show station labels, maybe need a density check. |
N |
1 |
0 |
2026-08-15 22:01:52 |
2026-08-16 12:24:45 |
| 13 |
pasting screenshots |
add screenshot functionality to ideas register |
L |
1 |
1 |
2026-08-15 22:10:47 |
2026-09-06 09:47:38 |
| 14 |
routing |
add routing stuff here
York avoiding is a northbound issue only. |
N |
1 |
0 |
2026-08-15 22:11:06 |
2026-08-16 12:24:45 |
| 15 |
ideas priority |
have a priority for ideas? |
N |
1 |
1 |
2026-08-15 22:11:36 |
2026-08-16 12:24:45 |
| 16 |
buttons on ideas reg |
They are too intrusive
Also, if show completed is selected show them inline of id. |
N |
1 |
1 |
2026-08-15 22:13:37 |
2026-08-16 12:24:45 |
| 17 |
consists |
Not being done properly, changes maybe being upserted. |
N |
1 |
1 |
2026-08-15 22:14:21 |
2026-09-06 09:47:45 |
| 18 |
vstp |
check out its application, and P and O |
N |
1 |
1 |
2026-08-15 22:16:22 |
2026-09-06 09:47:48 |
| 19 |
s* in TD |
Thoughts here:
Create a separate shape table for s* messages, and research. |
N |
2 |
1 |
2026-08-15 22:17:31 |
2026-09-06 09:47:53 |
| 20 |
idea category |
Have idea categories, say:
Readabilty
Functionality
Functionality issues
New feature
Research
Infrastructure
Sticky notes?? |
N |
1 |
1 |
2026-08-15 22:22:44 |
2026-08-16 12:29:19 |
| 21 |
map defaults nav issue |
If you click a service, say in London, then do a live trace, when you go back it reorientates to default, ie c scotland |
N |
1 |
1 |
2026-08-15 22:39:50 |
2026-08-17 08:02:21 |
| 23 |
Ideas search |
Have a search option within ideas |
N |
1 |
1 |
2026-08-15 22:43:47 |
2026-08-16 12:24:45 |
| 24 |
md in ideas |
Make ideas md capable
Have a page edit button where the content page goes almost full browser. It has a toggle for code/reading both editable but format done in code |
L |
1 |
1 |
2026-08-15 22:44:23 |
2026-09-06 09:47:59 |
| 25 |
smtp from grm (code fails with 550) |
sender same as newsletter, recip me
cd /home/www-data/grm
sudo -u www-data ./venv/bin/python - <<'PY'
import smtplib
import socket
import ssl
from datetime import datetime
from email.message import EmailMessage
from dotenv import dotenv_values
config = dotenv_values("/etc/proj/proj.env")
def boolean(name, default=False):
value = config.get(name)
if value is None:
return default
return str(value).strip().lower() in {"1", "true", "yes", "on"}
host = (config.get("SMTP_HOST") or "").strip()
port = int(config.get("SMTP_PORT") or 0)
use_ssl = boolean("SMTP_SSL")
use_starttls = boolean("SMTP_STARTTLS")
require_starttls = boolean("SMTP_REQUIRE_STARTTLS")
require_auth = boolean("SMTP_REQUIRE_AUTH")
username = (config.get("SMTP_USER") or "").strip()
password = config.get("SMTP_PASSWORD") or ""
ehlo_domain = (config.get("SMTP_EHLO_DOMAIN") or "").strip() or None
sender = (
config.get("GRM_ALERT_EMAIL_FROM")
or config.get("FROM_EMAIL")
or ""
).strip()
recipients = [
address.strip()
for address in (config.get("GRM_ALERT_EMAIL_TO") or "").split(",")
if address.strip()
]
if not host or not port:
raise RuntimeError("SMTP_HOST and SMTP_PORT must be configured")
if not sender:
raise RuntimeError("GRM_ALERT_EMAIL_FROM or FROM_EMAIL must be configured")
if not recipients:
raise RuntimeError("GRM_ALERT_EMAIL_TO must be configured")
if use_ssl and use_starttls:
raise RuntimeError("SMTP_SSL and SMTP_STARTTLS cannot both be enabled")
if require_starttls and not use_starttls:
raise RuntimeError("SMTP_REQUIRE_STARTTLS is enabled but SMTP_STARTTLS is not")
if require_auth and (not username or not password):
raise RuntimeError("SMTP authentication is required but credentials are incomplete")
message = EmailMessage()
message["Subject"] = f"GRM SMTP test from {socket.gethostname()}"
message["From"] = sender
message["To"] = ", ".join(recipients)
message.set_content(
"This is a GRM operational-alert SMTP test.\n\n"
f"Host: {socket.gethostname()}\n"
f"Time: {datetime.now().astimezone().isoformat()}\n"
)
tls_context = ssl.create_default_context()
if use_ssl:
client = smtplib.SMTP_SSL(
host,
port,
timeout=30,
context=tls_context,
)
else:
client = smtplib.SMTP(host, port, timeout=30)
with client:
if ehlo_domain:
client.ehlo(ehlo_domain)
else:
client.ehlo()
if use_starttls:
client.starttls(context=tls_context)
if ehlo_domain:
client.ehlo(ehlo_domain)
else:
client.ehlo()
if require_auth or username:
client.login(username, password)
client.send_message(message, from_addr=sender, to_addrs=recipients)
print("GRM SMTP test sent successfully to:", ", ".join(recipients))
PY |
N |
1 |
1 |
2026-08-16 09:03:41 |
2026-08-16 12:24:45 |
| 26 |
reversers in service map |
Look at a mallaig-glq via Ft William, and Thurso/wick etc.
Where there is a reverse and a traverse along the same section, could that section be shown differently in some way? Alternating small dots of each colour? :) |
N |
1 |
1 |
2026-08-16 09:22:40 |
2026-09-06 09:48:06 |
| 27 |
long messages in ideas |
Can we, in the situation of a message > 5 lines, show the 1st 5 with an option to expand? |
N |
1 |
1 |
2026-08-16 09:30:48 |
2026-08-16 12:24:45 |
| 28 |
Expand and contract |
Only show expand on contracted ideas |
N |
1 |
1 |
2026-08-16 10:00:12 |
2026-08-17 07:52:19 |
| 29 |
Mobile screen size |
Can we stop ideas screen from zooming a small bit when edition |
N |
1 |
1 |
2026-08-16 10:01:03 |
2026-08-16 12:29:00 |
| 30 |
1Password integ |
Persist with trying to integrate 1Password for code fields |
N |
1 |
1 |
2026-08-16 10:11:58 |
2026-08-16 12:24:45 |
| 31 |
sumary of idea numbers |
In the ideas list, show shown and total incomplete |
N |
1 |
0 |
2026-08-16 12:41:33 |
2026-08-16 12:41:33 |
| 33 |
X icon on map |
It’s awful 😂 |
N |
1 |
1 |
2026-08-16 18:34:06 |
2026-09-06 09:48:16 |
| 34 |
Top white band on ios |
Can it be done differently? |
N |
3 |
1 |
2026-08-16 19:27:14 |
2026-08-17 07:51:57 |
| 35 |
Data retention |
Needs a review. |
L |
1 |
1 |
2026-08-16 19:33:04 |
2026-09-06 09:48:21 |
| 36 |
Minimap leg stations and TPs at zooms |
On the minimap, where the zoom level allow, show the LEG stations, maybe at deeper zooms show the non-stopper timing points. |
N |
1 |
0 |
2026-08-16 19:46:33 |
2026-08-16 19:46:56 |
| 37 |
Legend in live trace |
Popup describe the td and trust badges and anything else relevant |
N |
1 |
1 |
2026-08-16 21:22:38 |
2026-09-06 09:48:46 |
| 38 |
Update toc table |
Update, formalise and document.
There is stuff from nr:
https://assets.nationalrail.co.uk/e8xgegruud3g/2PHRyfp2mN2N0UUd6nyK0B/770a70c6c08296905136e2c1ef1ca06a/NRE_Feeds_Developer_Pack_v.01-05.pdf |
N |
1 |
0 |
2026-08-16 21:24:45 |
2026-09-06 09:49:49 |
| 39 |
Disappearing trains |
The phenomenon that a service can disappear off the map because of bbox is outside projected location or something like that. |
N |
1 |
0 |
2026-08-16 21:35:15 |
2026-08-16 21:35:15 |
| 40 |
Osmium tutorial |
https://osmcode.org/osmium-tool/manual.html
https://wiki.openstreetmap.org/wiki/Map_features
https://wiki.openstreetmap.org/wiki/Elements |
N |
4 |
0 |
2026-08-16 21:39:47 |
2026-08-16 22:32:02 |
| 41 |
Stats for user |
So some set of stats for the bbox, #services, #late, list in the bbox with links to summary popup eyc |
N |
1 |
1 |
2026-08-16 21:52:27 |
2026-09-06 09:50:11 |
| 42 |
Control table 🤷♂️ |
A table that probably has one row, control data like version, tunable parameters like refresh rates. Probably need to be clear about ui-v-server.
Some, but certainly not all env data. |
N |
1 |
0 |
2026-08-16 22:07:37 |
2026-08-16 22:08:42 |
| 43 |
URLs in ideas |
If an idea has a url change to a link to be opened in a new browser tab |
N |
1 |
1 |
2026-08-16 22:29:40 |
2026-08-17 08:02:07 |
| 44 |
API keys |
Selling the output generated by the secret sauce. |
L |
2 |
0 |
2026-08-16 23:19:29 |
2026-08-16 23:19:29 |
| 45 |
Tidy the live trace unmatched td |
In the Live Service Trace full view, Instead of one line per unmatched td, make each line a small pill, coloured as now, content being the badge and the area code, clickable as now to reveal full detail. These pills should be sequential on one line and wrap as required. The summary (separated) view should stay as is. Please apply to all current platforms. |
N |
1 |
1 |
2026-08-17 05:52:06 |
2026-08-17 07:48:20 |
| 46 |
TLDR of docs? |
So a summary:
How deep?
Who for?
Shit idea? |
L |
1 |
1 |
2026-08-17 07:22:41 |
2026-09-06 09:50:20 |
| 47 |
Passing to mac |
Nothing has been lost—the pull stopped safely. The local change is most likely Xcode recording your Personal Team in `project.pbxproj`.
Safest approach:
1. Close Xcode.
2. Preserve that local signing change:
```bash
git stash push -m "Mac Xcode signing" -- ios/GRM.xcodeproj/project.pbxproj
```
3. Pull again:
```bash
git pull --ff-only origin main
```
4. Confirm the checkout is clean:
```bash
git status --short
```
5. Reopen the project:
```bash
open ios/GRM.xcodeproj
```
6. If Xcode asks for signing again, select your Personal Team under **GRM target → Signing & Capabilities → Test**.
Don’t run `git stash pop`: the remote project file has also changed, so reselecting the team in Xcode is simpler and avoids a project-file conflict. The stash remains as a recoverable backup. Once the updated app builds successfully, we can remove that backup. |
N |
1 |
1 |
2026-08-17 08:20:30 |
2026-08-17 08:32:08 |
| 48 |
Better terminates service message in popup |
When the service popup is being used and the service is terminated a message is displayed saying this.
I'd like to make this look better and say:
This service has now terminated.
This system is a live system and when a system is terminated it is removed.
To see retained details of the service click here.
And for Click Here link to the RTT detailed page for the service, as was on the page before it was cleared. |
N |
1 |
1 |
2026-08-17 12:49:16 |
2026-09-06 09:50:26 |
| 49 |
Summary map not accurate |
Example, when a service is terminated very often the service is shown part way through the last leg.
I think I've picked a special case. I think that when the service leaves Drem Jn (I think) there are no signals down to NB and it used an approx 7min offset. However I think we pick up the TRUST message and act immediately without reference to time. |
N |
1 |
1 |
2026-08-17 16:11:38 |
2026-09-06 09:50:30 |
| 50 |
Retain service details (ANA2) |
Implement retaining all service details like ANA1 (HEAD/TD/TRUST) for 48 hours. Just tables for now. Lets call it ANA2, same as ANA1 but running as a permanently rotating archive.
The removal of the >48 records can be part of the general clean-up that runs every 10 minutes.
Can we start the planning for this? |
N |
1 |
1 |
2026-08-17 16:24:10 |
2026-09-06 09:50:34 |
| 51 |
Live facts show TT termination time |
On the facts/live page where the station is selected and a list is offered, can we change for example '0703 Edinburgh → Penzance' to '0703 Edinburgh → Penzance 9999' where 999 is the timetabled arrival time at the destination. |
N |
1 |
1 |
2026-08-17 16:28:29 |
2026-08-17 16:40:36 |
| 52 |
ID the service in expanded mini-map |
In the expanded minimap place a white pill, top left, usual style, with for example '0703 Edinburgh → Penzance 21:13' |
N |
1 |
1 |
2026-08-17 16:40:19 |
2026-08-17 16:52:56 |
| 53 |
Arr/dep defs. |
I think arrival is solved, td+offset for just about every observation was within seconds. Backup is trust, next is schedule +- late/earliness.
Departure is schedule+30s+arrival delay(if service arrived ok and ignore earliness) overridden by trust, overridden by td adjusted for offset.
It’s like one is a rough converse of the other. |
N |
4 |
1 |
2026-08-17 20:17:35 |
2026-09-06 09:50:38 |
| 54 |
Tagline and elevator |
The railway NOW
geoRailMaps — The Railway Now!
geoRailMaps is about the railway now. At its heart is a live map showing passenger services as they operate across the network, bringing together location, movement, route and operational information in one visual experience.
It isn’t primarily a journey planner or timetable app. Instead, geoRailMaps lets you explore what’s actually happening: where trains are, where they’re going, how they’re running and the railway around them.
Behind the map, live railway data is interpreted to create a continuously evolving picture of the network, complemented by useful background and contextual information.
Open the map. Explore the railway. Now. |
N |
4 |
1 |
2026-08-18 06:54:52 |
2026-09-06 09:50:48 |
| 55 |
Resilience |
? |
N |
1 |
0 |
2026-08-18 12:10:25 |
2026-08-18 12:10:25 |
| 56 |
SAST tools |
Checks for vulnerabilities in code and packages
https://www.geeksforgeeks.org/software-testing/static-application-security-testing-sast/
Reverse proxy, and controls that benefit |
N |
1 |
0 |
2026-08-18 12:10:48 |
2026-08-18 12:21:15 |
| 57 |
REST compliance |
? |
N |
1 |
1 |
2026-08-18 13:04:33 |
2026-09-06 09:50:56 |
| 58 |
Top lines in ios |
The top lines of the live trace display are being obliterated by the phones time and island thing. |
N |
1 |
1 |
2026-08-18 13:41:19 |
2026-09-06 09:51:00 |
| 59 |
Collapse live trace to times only |
Collapse the Live Service Trace to only TPs and the times only (offset where appropriate), retain the existing bold/not bold, exclude unresolved, just a clean list of times.
The close and Schedule buttons could be trimmed width wise and space found for a collapse/expand button even on mobile. |
N |
1 |
1 |
2026-08-18 14:17:50 |
2026-08-18 19:08:09 |
| 60 |
Shape offsets |
Shape offsets, use the shaped values in ANA*, and show in expanded TD panels. |
N |
1 |
1 |
2026-08-18 14:27:55 |
2026-08-18 20:20:23 |
| 61 |
Ideas categorisation |
Allow an idea to be multi categorised, use radio button for priority and tick boxes for categories, in some way 😄 |
N |
1 |
0 |
2026-08-18 14:31:50 |
2026-08-18 14:31:50 |
| 62 |
TD story teller |
For a service take all the TD records and assemble them into a story, from a set of written rules. As my own understanding progresses I’d like to adapt the presentation. I’d like to express my understanding in English and for Codex to write the code to achieve this.
So for example, an interpose into a so far not reported area could be an interpose into the new area, then duplicates, then a cb message to remove from old area. The same berth being recorded by 2 different area could be dual recoding towards a fringe.
What do you think? Wat would the English explanation look like ad what might the output look like.
I'd like it to be started by you creating the English explanation describing what td is telling us from what we understand so far to give me something to edit? |
N |
1 |
1 |
2026-08-18 14:37:27 |
2026-09-06 09:51:12 |
| 63 |
Build td area map |
Use the td saved data to project areas onto the map. |
N |
1 |
1 |
2026-08-18 15:23:36 |
2026-09-06 09:51:18 |
| 64 |
New td message -> headcode -> service approach |
## TD observation to service association
### Purpose
Associate a TD observation with one specific active service using the service’s ordered schedule, its current progress, the observation’s resolved STANOX, TD area, headcode and time.
The association must fail safely: ambiguous evidence does not change any service.
### Required TD evidence
A TD observation is eligible only when it has:
- a valid headcode;
- a supported message type, currently CA or origin CC;
- a uniquely resolved STANOX;
- a TD area;
- a valid event time.
### Candidate services
Begin with active services having the same headcode as the TD observation.
For each service:
1. Identify its last confirmed timing point and effective time.
2. Consider that current timing point and the next two ordered timing points.
3. For each timing point, select the relevant scheduled arrival, departure or passing time.
4. Predict its operational time by applying the service’s latest known earliness or lateness:
```text
predicted time =
scheduled timing-point time
+ latest known service variation
```
If no variation is known, use zero variation.
### Timing tolerance
Calculate the tolerance from the scheduled elapsed time between the last confirmed timing point and the candidate timing point:
```text
margin =
20% of scheduled elapsed time
```
Apply an initial minimum of two minutes and maximum of ten minutes:
```text
margin =
min(10 minutes, max(2 minutes, 20% of elapsed time))
```
The observation is temporally plausible when:
```text
predicted time - margin
<= TD observation time
<= predicted time + margin
```
The percentage and limits are explicit research parameters and may be revised using observed evidence.
### Candidate timing-point test
A timing point is a candidate only when all the following are true:
- the service headcode matches the TD headcode;
- the service was active at the observation time;
- the TD observation’s STANOX equals the timing point’s STANOX;
- the TD area is one of the areas associated with that timing point;
- the timing point is the current point or one of the next two;
- the observation falls within the calculated time window.
### Unique association rule
Apply the test to every active service with the same headcode.
```text
Exactly one candidate service and timing point:
associate the TD observation
No candidates:
leave the observation unassociated
More than one candidate:
leave the observation unassociated as ambiguous
```
GRM must not choose the nearest or most convenient candidate when more than one remains.
### Origin CC rule
Before the service has departed, use its origin as the current timing point and its scheduled departure as the relevant time.
A CC is origin evidence only when:
- it passes the unique association rule;
- its resolved STANOX is the service’s origin STANOX;
- its TD area is associated with the origin;
- it falls within the origin time window;
- it follows the relevant TRUST activation.
GRM then interprets the service as:
```text
At Platform: <origin>
```
This is a GRM operational interpretation. TD directly reports the train description in an origin berth, not the physical readiness of the train.
### CA rule
A uniquely associated CA supplies signalling-derived timing evidence at the matched timing point.
Where the reference evidence identifies its role, it may represent:
- arrival;
- departure;
- passing progress.
The CA evidence is considered alongside TRUST. Later evidence may confirm or refine the interpreted timing while preserving both observations and their provenance.
A successfully associated CA may advance the service’s confirmed timing-point anchor. It must not move the service backwards through its ordered schedule without separate reversal evidence.
### Separation of association and interpretation
Association answers:
> Which service and scheduled timing point does this TD observation most plausibly belong to?
Interpretation then answers:
> What state or timing fact does this associated CC or CA support?
Successful association does not, by itself, give every TD message a state-changing meaning. |
N |
1 |
1 |
2026-08-18 21:53:58 |
2026-09-06 09:51:33 |
| 65 |
Tunable parameters |
Yes—this is feasible, and a database-backed parameter catalogue fits GRM well. The important constraint is that it should contain deliberate tuning policy, not every numeric constant in the repository.
I found no existing hard-coded “add 20%” calculation. I did find several uses of “two”, but the prominent `stage_index + 2` is the documented X–Y–Z triplet model, so it is architectural rather than an ordinary tuning parameter. If the “2 forward / 20%” discussion concerned a new heuristic, those would be good first catalogue entries once their precise meaning is defined.
## Recommended design direction
I suggest each parameter record eventually contains:
- Stable key, such as `presentation.pre_departure_visibility_minutes`
- Category and affected component
- Typed value and unit
- Plain-language description of its effect
- Valid range
- Change application: immediate, worker restart, rebuild required
- Current revision and modification details
Code should retain a validated definition and safe default. The database supplies overrides. That prevents a missing or malformed row from stopping GRM and avoids a database lookup inside every calculation.
Workers should load a validated snapshot rather than repeatedly query individual values. Parameters affecting generated state—particularly route-cache settings—must record their configuration revision and trigger a controlled rebuild. Old and new routing policies must not silently coexist in one cache.
The separate live and test databases naturally provide environment-specific values.
## Strong initial candidates
| Suggested key | Current value | Effect |
|---|---:|---|
| `presentation.pre_departure_visibility_minutes` | 2 min | Shows an activated service shortly before its latest scheduled/Darwin departure estimate. [grm_pres_service.py:1171](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:1171) |
| `presentation.terminated_hold_minutes` | 2 min | Retains a normally terminated service before removal. [grm_pres_service.py:34](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:34) |
| `presentation.timetable_expiry_minutes` | 2 min | Removes non-class-5 services after final WTT arrival when stronger termination evidence is absent. [grm_pres_service.py:39](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:39) |
| `presentation.class5_expiry_minutes` | 60 min | Class 5 fallback lifetime after final WTT arrival. [grm_pres_service.py:35](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:35) |
| `presentation.stale_activation_minutes` | 180 min | Removes an activated service that never acquires an origin departure. [grm_pres_service.py:36](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:36) |
| `position.early_arrival_variation_factor` | 0.5 | Applies half of an early timing variation when estimating arrival; late variation is applied fully. [grm_pres_service.py:452](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:452) |
| `td_story.handover_window_seconds` | 60 sec | Experimental maximum interval between appearance in a new TD area and clearance from the former area. [td_service_story_service.py:7](C:/Users/andy/OneDrive/projects/grm/server/services/td_service_story_service.py:7) |
| `map.maximum_live_services` | 200 | Limits services returned within a map viewport. The value is currently duplicated in the API and UI. [map_api.py:167](C:/Users/andy/OneDrive/projects/grm/server/routes/map_api.py:167) |
| `map.minimum_live_service_zoom` | 5.0 | Suppresses live services below this map zoom. [map_api.py:111](C:/Users/andy/OneDrive/projects/grm/server/routes/map_api.py:111) |
| `map.late_highlight_minutes` | 10 min | Selects the more prominent late-running presentation. It is duplicated in browser code. [map.js:674](C:/Users/andy/OneDrive/projects/grm/html/static/map/map.js:674) |
| `archive.ana2_retention_hours` | 48 hr | Controls completed-service evidence retention. [ana2_archive_service.py:186](C:/Users/andy/OneDrive/projects/grm/server/services/ana2_archive_service.py:186) |
| `feed_retention.*` | Mostly 24 hr; Darwin shaped 2 days | Controls raw and shaped evidence retention per feed. [grm_cleanup.py:75](C:/Users/andy/OneDrive/projects/grm/server/scripts/grm_cleanup.py:75) |
These are the cleanest first tranche because they express operational or product policy and can change without redefining railway identity.
One discrepancy should be resolved before implementation: the documentation says a terminated service remains for “up to three minutes”, while the code uses two minutes with a 30-second cleanup cycle. That produces approximately two to two-and-a-half minutes, not three.
## Eligible, but guarded routing parameters
These are genuine candidates, but changing them requires regression evidence and generally a complete route-cache rebuild:
| Current value | Effect |
|---:|---|
| 20 m | Distance examined on each side of a graph node when measuring concentrated turns. |
| 25° | Deflection at which a movement becomes suspect. |
| 1.5× | Maximum alternative-route length ratio. |
| +1,000 m | Additional permitted alternative-route allowance. |
| 6 | Maximum alternatives attempted per suspect turn. |
| 500 m | Maximum distance when associating a location with a graph node. |
| 1 m | Maximum gap accepted when joining cached presentation routes. |
The first five are together in [grm_leg_route_graph_utils.py:21](C:/Users/andy/OneDrive/projects/grm/server/services/grm_leg_route_graph_utils.py:21); the graph-node association is at [grm_leg_route_graph_utils.py:203](C:/Users/andy/OneDrive/projects/grm/server/services/grm_leg_route_graph_utils.py:203), and continuity tolerance at [grm_pres_service.py:624](C:/Users/andy/OneDrive/projects/grm/server/services/grm_pres_service.py:624).
I would classify these as `routing_policy`, mark them `rebuild_required`, and introduce them only after the simpler presentation/status parameters prove the mechanism.
## Candidates I would keep outside this table initially
- Poll intervals, reconnect delays, database pool sizes, Kafka timeouts and systemd restart settings: deployment/runtime configuration, often needed before database access exists.
- Batch sizes: performance controls, better suited to command arguments or environment configuration.
- Authentication windows and TOTP steps: security policy, not general railway tuning.
- Graph-building tolerances: build-profile inputs requiring reproducibility, rather than live application parameters.
- UI dimensions, animation rates and debounce delays: frontend implementation choices.
- Timetable half-minute rules, 24-hour arithmetic, coordinate structure and STP ranking: domain/data-format rules or invariants, not tuning parameters.
- X–Y–Z look-forward depth: currently part of the documented route model and triplet cache identity, not merely a number to adjust. [grm_leg_window_service.py](C:/Users/andy/OneDrive/projects/grm/server/services/grm_leg_window_service.py)
My recommendation is to select approximately five parameters from the strong initial group, preferably all used by `grm-pres`, and use those to design the catalogue, validation, snapshot loading, test/live handling and change observability. Then routing and retention parameters can be added deliberately rather than designing an overly general framework upfront.
No code or documentation was changed. |
N |
1 |
1 |
2026-08-18 22:08:21 |
2026-09-06 09:51:37 |
| 66 |
Testing tunable values for routing. |
Yes. I would develop that idea as routing parameter profiles rather than individual “active value / shadow value” columns.
A profile makes several changes one coherent experiment. That matters because changing the deflection threshold and detour allowance together may behave differently from changing either alone.
## Proposed model
Have profiles such as:
- `production-baseline` — locked and currently active
- `experiment-2026-08-sharp-turns` — editable shadow copy
- `candidate-1` — tested and awaiting a decision
- `retired-*` — retained for provenance
Each profile contains the complete routing parameter set:
- Curve measurement distance
- Suspect-deflection threshold
- Alternative-route ratio
- Additional distance allowance
- Alternative-attempt limit
- Graph association distance
- Presentation continuity tolerance
A shadow profile would never be consulted by live routing or written into `grm_leg_route_cache`.
This is preferable to a shadow column because it provides:
- Atomic experiments involving several parameters
- Repeatable results
- Comparison with the exact production baseline
- Multiple experiments without overwriting each other
- A permanent record of what produced a route
- Safe, explicit promotion
## Three levels of testing
### 1. Fast algorithm tests
Run in seconds using the existing synthetic graphs.
There are already tests covering:
- Avoiding an implausible sharp crossing
- Permitting a reversal at a route boundary
- Retaining the only available route
- Rejecting an absurd detour even when its curvature is better
These are in [test_grm_leg_route_graph_utils.py](C:/Users/andy/OneDrive/projects/grm/tests/test_grm_leg_route_graph_utils.py).
They answer: “Have these values broken the fundamental routing rules?”
### 2. Named railway regression cases
Maintain a small, stable suite of real known examples:
| Example | Required outcome |
|---|---|
| Castlecary | Avoid the false grade-separated transfer |
| Anniesland–Westerton | Avoid the false crossing without selecting the 46 km detour |
| Paisley Gilmour Street | Select the route-facing platform group and preserve continuation |
| Stepps | Do not jump between parallel tracks |
| York | Do not join incompatible station anchors; preserve the documented avoiding-line behaviour |
| Waterloo | Do not make the accepted small residual materially worse |
Some Stepps and York continuity tests already exist in [test_grm_pres_route_merge.py](C:/Users/andy/OneDrive/projects/grm/tests/test_grm_pres_route_merge.py), but most named cases are currently documented evidence rather than automated real-graph fixtures.
A case should use a captured sequence of STANOX timing points rather than a current schedule ID. Schedule IDs and daily applicability are transient; the railway question being tested should remain stable.
### 3. National shadow build
Only after the quick suite passes:
1. Build the complete route cache into an isolated shadow generation.
2. Compare it with the active generation.
3. Report aggregate changes.
4. Review changed routes, particularly unexpectedly changed ones.
5. Promote only after explicit approval.
This is the stage that detects a parameter improvement at Castlecary inadvertently damaging somewhere never previously considered.
## What a comparison should report
For each known case, show baseline and shadow side by side:
- Resolved or unresolved
- Route length and percentage change
- Selected graph path changed or unchanged
- Number of suspect concentrated turns
- Maximum deflection
- Location-to-graph snap distances
- Continuation node changes
- Maximum gap between adjacent triplets
- Map geometry for visual comparison
- Pass, expected change, unexpected change or failure
Exact geometry equality can be useful while the graph is unchanged. The report should also include the graph fingerprint because node IDs and geometries could legitimately change after a graph rebuild.
The existing sequence diagnostic is a particularly good starting point: it already resolves a complete schedule without reading or writing the production route cache. [grm_leg_route_sequence_diagnose.py](C:/Users/andy/OneDrive/projects/grm/server/scripts/grm_leg_route_sequence_diagnose.py)
It would eventually need two additions:
- Accept a named parameter profile
- Produce baseline-versus-shadow comparison metrics
## Safe promotion
Promotion should not mean simply changing a flag while the old cache remains in use.
A safe sequence is:
```text
Editable shadow profile
↓
Fast algorithm suite
↓
Named railway regression suite
↓
National shadow cache build
↓
Comparison and human review
↓
Lock candidate profile
↓
Atomically activate profile and its completed cache generation
```
If the build or review fails, production remains untouched.
Every generated cache should carry at least:
- Parameter-profile ID
- Parameter-profile hash/revision
- Railway graph fingerprint
- Build time
- Build result summary
That preserves provenance and prevents routes built under different policies from being mixed unknowingly.
## Recommended first increment
I would start smaller than the full national-generation mechanism:
1. Make the routing functions accept an explicit immutable parameter object while retaining today’s values as defaults.
2. Create the production-baseline and editable shadow-profile model.
3. Convert the existing synthetic tests to run against an explicitly supplied profile.
4. Capture Castlecary and Anniesland–Westerton as the first two real regression cases.
5. Produce a baseline-versus-shadow JSON/GeoJSON report without touching the cache.
6. Add Paisley, Stepps, York and Waterloo once that workflow is proven.
That gives you a useful experimental laboratory before taking on cache generations and promotion. Your proposed “look forward 2” and “add 20%” values could then be placed in a shadow profile and evaluated as a coherent hypothesis rather than being introduced directly into railway behaviour.
No changes have been made. |
N |
1 |
0 |
2026-08-18 22:14:08 |
2026-08-18 22:14:08 |
| 67 |
What is grm_infra |
This table is used in the td shaping process, what’s that about and how did we get it? |
N |
1 |
0 |
2026-08-19 06:47:03 |
2026-08-19 06:47:03 |
| 68 |
In trace make the td details popup more explanatory than tabular |
In trace make the td details popup more explanatory than tabular, a bit like the journey story idea (idea 62) |
N |
1 |
0 |
2026-08-19 07:15:31 |
2026-08-19 07:15:31 |
| 69 |
Refactor grm-pres |
And yes, grm-pres is now carrying too many operational responsibilities. Its coherent core should be:
Maintain the live presentation service.
Interpret new evidence into persisted timing facts and service state.
The less natural responsibilities now embedded in it are:
ANA2 archival and deletion.
Historical timing-fact backfill.
Periodic housekeeping and expiry.
Position/map refresh.
The architecture I’d move toward incrementally is:
TRUST → grm-pres → live presentation + timing facts/state
↓ terminal-ready marker
ANA2 capture worker
↓ successful capture
remove live presentation
The important boundary is transactional responsibility: grm-pres marks a service ready for archival, while an ANA2 worker captures it and only then deletes/releases the live record. That preserves the “never remove before successful ANA2 capture” guarantee without blocking live TRUST processing. |
U |
1 |
1 |
2026-08-19 14:58:34 |
2026-08-20 11:41:01 |
| 70 |
Midnight crossers |
There are still some circumstances where this causes confusion.
For example, at 7am the EUS/INV sleeper is still running from the night before, the RTT link is as a result out of date, it uses today’s date. This undermines the 04:30-04:29 contentious. |
N |
1 |
1 |
2026-08-20 12:33:19 |
2026-09-06 09:51:58 |
| 71 |
Wobbly arrows |
Please address |
N |
1 |
1 |
2026-08-20 18:16:36 |
2026-08-23 17:45:59 |
| 72 |
Status trace improvements |
When a status decision is made, highlight the td or trust or wtt field that was used backgrounded in light green |
N |
1 |
1 |
2026-08-20 18:17:27 |
2026-09-06 09:52:05 |
| 73 |
Map findings |
When the dep time resorts to tt+delay+30 make sure it’s wtt that is used.
When a td is after a trust it jumps back to leg sart
Services get stuck at Pollockshaws West. |
N |
1 |
1 |
2026-08-20 19:41:55 |
2026-09-06 09:52:11 |
| 74 |
Implement schedule maturation |
Start analysing schedules to discover as yet undiscovered triplets for scheduling.
Whifflet is another perth |
U |
1 |
1 |
2026-08-20 20:07:38 |
2026-08-23 17:45:49 |
| 75 |
Stops to pickup/dropoff only |
If the pass tt has an arr only it’s drop only and reverse for pickup |
N |
1 |
0 |
2026-08-20 20:20:06 |
2026-08-20 20:20:06 |
| 76 |
Show us a leg |
Id legs with a dot bigger than the line and at certain zooms show the station name |
N |
1 |
1 |
2026-08-20 20:38:27 |
2026-08-26 17:40:39 |
| 77 |
Show us a leg |
Id legs with a dot bigger than the line and at certain zooms show the station name
And maybe have a pill with the station name ‘pointing’ to it. |
N |
1 |
1 |
2026-08-20 20:38:27 |
2026-08-26 17:40:32 |
| 79 |
Labels |
Should be ‘Next stop Haymarket’ and ‘At Px, Haymarket’ |
N |
1 |
0 |
2026-08-20 22:10:55 |
2026-08-20 22:10:55 |
| 80 |
TD misses |
I think we miss or mismatch TD messages.
Why, when we show a service leaving P10 at Waverley, are RTT and LDB showing 9, and showing as a change? |
U |
1 |
1 |
2026-08-21 13:05:11 |
2026-08-21 20:52:29 |
| 81 |
Times way off |
Times way of in this example.

This is not isolated. |
N |
1 |
1 |
2026-08-21 21:11:56 |
2026-08-22 09:01:08 |
| 82 |
Platform changes problem |



So the story is that RTT have established a platform change and we have not.
Interestingly
**SELECT * FROM `grm_smart` WHERE `TD`='EB' and `TOBERTH`='E444';**
resolves to p19 |
N |
1 |
1 |
2026-08-21 21:31:15 |
2026-08-22 09:01:01 |
| 83 |
Map Obs 22/8 |
Us:
RTT:

Live stuff: (same headcode)

eg:

This service??

same in infra. head_stages:
 |
N |
1 |
1 |
2026-08-22 09:15:33 |
2026-08-23 17:45:24 |
| 84 |
Notes for OTT stuff - mapping |
 |
N |
5 |
0 |
2026-08-22 10:29:53 |
2026-08-23 20:42:02 |
| 85 |
Snaps for leg summary naming |



One of them showed the wrong station then corrected it
Below yet to be actioned.


 |
N |
1 |
1 |
2026-08-23 18:47:45 |
2026-08-25 22:08:36 |
| 86 |
Fix latency |
Yes. We can render the green trains as soon as their data is ready, then fetch and add the station summaries asynchronously. That should restore the earlier perceived latency without removing the summaries. |
U |
1 |
1 |
2026-08-23 20:39:59 |
2026-08-25 22:08:27 |
| 87 |
Edit ideas improvement |
Click inside an ideas title or text to edit it. |
N |
1 |
1 |
2026-08-23 20:41:03 |
2026-08-28 05:47:01 |
| 88 |
User help pages |
They are started in md |
L |
1 |
1 |
2026-08-23 21:54:49 |
2026-09-06 09:52:23 |
| 89 |
Wtt times on multi station popup |
 |
N |
1 |
1 |
2026-08-23 22:10:34 |
2026-08-25 22:07:54 |
| 90 |
Train icon colour |
Colour to reflect at station terminated etc |
N |
1 |
1 |
2026-08-24 10:53:45 |
2026-08-25 22:07:40 |
| 91 |
Zoom for tp labels |
Change the starting zoom level on mobile for the tp labels |
N |
1 |
0 |
2026-08-24 11:07:40 |
2026-08-24 11:07:40 |
| 92 |
Select a station, somehow |
And a time radius, and see live and activated services planned to call there in that time radius on the map with the map bbox’ed to accommodate |
N |
1 |
0 |
2026-08-24 11:37:12 |
2026-08-24 11:37:12 |
| 93 |
Wrong platform and trace |



Better td understanding needed
Later, same journey

And the time at Camelon was great per td, but the map showed too early.
 |
N |
1 |
1 |
2026-08-24 18:08:20 |
2026-09-06 09:52:34 |
| 94 |
Logo |


Its: "C:\Users\andy\OneDrive\projects\grm\Codex Image 25 Aug 2026, 21_18_21.png" |
N |
1 |
0 |
2026-08-25 20:10:35 |
2026-08-25 20:19:38 |
| 95 |
Top right hand corner woes |

Not the worst example.
Maybe have the test have the i and a hamburger for the rest. All popup buttons and a close pill should be moved top left. |
N |
1 |
0 |
2026-08-25 22:06:56 |
2026-08-25 22:21:49 |
| 96 |
Times and cross midnight issues |
 |
N |
1 |
1 |
2026-08-25 22:21:27 |
2026-08-26 17:38:46 |
| 97 |
Structural review |
Yes. The review confirms your concern is useful and justified: the application has several strong foundations, but the main-map presentation has drifted away from the original “one railway model, several views” principle.
## The central finding
The current map does not project the complete live railway and then decide how to draw or group it.
Instead, it currently builds three separate populations:
- Moving and stationary map arrows are taken from a feed capped at 1,000 services.
- Station circles are built separately from `AT_PLATFORM` and retained `TERMINATED` services.
- `ACTIVATED` services appear only as optional popup rows when another service has already created a qualifying station circle.
That explains much of the behaviour you have been fighting. It is encoded in the API, browser, documentation and tests—not merely a temporary backlog symptom. See [map_api.py](C:/Users/andy/OneDrive/projects/grm/server/routes/map_api.py:128), [map_api.py](C:/Users/andy/OneDrive/projects/grm/server/routes/map_api.py:418) and [api.md](C:/Users/andy/OneDrive/projects/grm/docs/api.md:30).
This conflicts with your intended model: determine the complete data-led live railway first, then choose whether each service is represented individually or within a view-dependent grouping. Grouping and transport limits should not change membership.
## Current live evidence
At approximately 22:01 UTC tonight, production contained:
- 2,703 presentation services
- 1,137 `ACTIVATED`
- 423 `AT_PLATFORM`
- 971 `RUNNING`
- 172 `TERMINATED`
- No TRUST presentation backlog
- Only 23 service interpretations awaiting refresh
However, around 200 supposedly map-visible services had no usable route or position and therefore could not enter the map feed.
This means the source and status pipeline was substantially caught up, but the map was still losing services farther downstream. Waiting longer would not necessarily fix that.
## Highest risks
1. **The map’s definition of “the railway” is wrong for your intended product.**
The 1,000-service sample and separately constructed stationary circles alter what is represented. This is the most important issue to resolve.
2. **Map failures disappear rather than becoming visible problems.**
If route assembly fails, the map worker clears the service’s placement and tries again later. Around 200 services were in that condition tonight. There is no durable, readily visible explanation such as “missing route between X and Y.”
3. **The morning health report can give false reassurance.**
“Map supply” is green when there is at least one drawable service. It could therefore remain green with hundreds—or almost all—services missing. See [grm_database_health_service.py](C:/Users/andy/OneDrive/projects/grm/server/services/grm_database_health_service.py:180).
4. **`grm-pres` remains a major concentration of responsibility.**
Its 2,700 lines handle TRUST consumption, presentation creation, schedule matching, lifecycle cleanup, mapping support and a compatibility status pass. A change in one concern can delay or disturb the others.
5. **Two background paths still refresh status.**
The dedicated fair status worker is now the proper completeness mechanism, but `grm-pres` retains the older 100-service compatibility pass. That was deliberately transitional and is still present. Removing it would simplify ownership and workload, but would remove a fallback if the dedicated worker were not deployed or running.
6. **Refresh ownership remains scattered.**
The three maps now share the important movement and train-drawing code—good progress. But each screen still decides when and how to fetch its information. Live Status Trace, for example, owns separate two-second and five-second heartbeats. The selected popup owns a different combined five-second heartbeat. These values may be sensible, but the policy is distributed.
7. **Customer presentation depends on diagnostic machinery.**
The selected-service map and Live Status Trace use a module called [route_debug_whole_map.js](C:/Users/andy/OneDrive/projects/grm/html/static/js/route_debug_whole_map.js:41) and a `route-debug` API. It works, but it blurs the line between a customer feature and a diagnostic tool.
8. **The UI tests often prove that code text exists, not that it works.**
The 340 tests all pass, but there is no browser-driven test clicking a station circle, selecting a service and checking the popup. Many map tests search JavaScript for particular phrases. That explains how non-working station buttons could coexist with a green test suite.
9. **The empty TRUST queue is unnecessarily expensive to check.**
The live shaped TRUST table has about 812,000 rows but no index aimed at “unfinished rows.” One measured check examined 128,064 rows to find 32 unfinished ones. `grm-pres` can perform this check four times per second. This is a credible database pressure point, although not the sole cause of the map problem.
## What is in good shape
The application is not wholly suspect.
- Service-state interpretation has a central, well-tested owner.
- All three maps now share the same glide calculation and train renderer.
- Schedule publication is atomic: a failed rebuild leaves the previous schedule available.
- Termination and ANA2 capture are evidence-led rather than timetable-age shortcuts.
- Background status processing now has a fair sweep, useful progress logs and immediate selected-service refresh.
- The morning health framework is a good foundation; its thresholds need strengthening.
## Recommended route
I would not begin with a large rewrite.
1. **Make losses visible first.**
Report the full service funnel by state: acquired, shaped, presented, status-resolved, route-resolved and actually supplied to the map. Every missing service should have a reason.
2. **Correct the morning report.**
Red or amber should be based on completeness and age, not merely whether one service was drawable.
3. **Write down one map membership rule.**
My recommendation is your rule: the railway population is entirely data-led and complete; zoom, grouping, payload transport and drawing are presentation choices that must not remove members.
4. **Protect real journeys in a browser test.**
Cover national loading, station circles, activated rows, selecting a popup service, summary refresh, minimap continuity and Live Status Trace.
5. **Then simplify ownership incrementally.**
Retire the transitional `grm-pres` status pass after operational proof, extract customer route presentation from the debug module, and centralise refresh policy without forcing every view to use the same cadence.
No files or production data were changed during this review. The existing untracked image was left untouched. |
N |
1 |
0 |
2026-08-26 05:50:36 |
2026-08-26 05:50:36 |
| 98 |
Cancellations general |
This was mentioned in a vstp description as a shedule entry it would avoid updating:
a selected C cancellation schedule;
Is this a VSTP thang, or an STP/LTP description? |
N |
1 |
0 |
2026-08-26 09:01:20 |
2026-08-26 09:01:20 |
| 99 |
Displayed -v- in bbox |

So the 1000 limit in this case should be for displayed services, not rows returned.. |
N |
1 |
1 |
2026-08-26 09:58:43 |
2026-08-26 17:38:38 |
| 100 |
TP toggle |
Have a small pill toggle top left Turn off/on Timing points when at the appropriate zoom level. |
N |
1 |
1 |
2026-08-26 10:28:10 |
2026-08-26 17:38:28 |
| 101 |
Station popup on desktop |
Get it to fully present in dom |
N |
1 |
1 |
2026-08-26 10:29:11 |
2026-08-26 19:47:06 |
| 102 |
Debug box review |
Review ~~contentn maybe have a basic / extended~~ viewSpaces/ features displayed as white total : white live/ochre/red
And more |
N |
1 |
1 |
2026-08-26 10:33:06 |
2026-08-26 17:42:22 |
| 103 |
Splits / Joins / Consist changes en route |
Need research |
N |
2 |
0 |
2026-08-26 10:36:12 |
2026-08-26 10:46:50 |