The map · Part Two · The machine · Chapter 15 of 18
How it watches
The claimThe machine watches every night and speaks only when something changed, so its silence has to be made trustworthy.
Servers do not have a person sitting at them. To make something happen at the same time every day, you write two small files for the operating system's scheduler. One is a timer: it says when. The other is a service: it says what. The scheduler here is the one built into modern Linux, called systemd, and the files are called units.11deploy/vss.timer and deploy/vss.service.
When
Every day at 22:30, after the last European and American exchanges have closed and prices have settled. If the machine was off at 22:30, the timer runs the job as soon as the machine is back, rather than skipping the day.22OnCalendar=*-*-* 22:30:00; Persistent=true.
What
The nightly run loads the owner's file, fetches the day's prices, computes the fixed set of figures, compares each price with the lines already written for that name, writes the report, writes one row per name into the run database, and then generates the overview page. The page generation runs last and is arranged so that if it fails, the run is still a success: the report and the database row come first, and a failure to draw the page is logged as a warning, not a failure of the night.33The overview page 'rides on the same unit after the report and database row are written and cannot break the run'.
What it cannot touch
The run is fenced by the operating system, not only by its own code. It sees the whole system as read-only. It sees the owner's home directory as read-only. The only two folders it may write are the data folder and the reports folder. It cannot gain any new permissions once started, and it is killed if it runs for more than fifteen minutes.44ProtectSystem=strict; ProtectHome=read-only; ReadWritePaths= the data and reports folders only; NoNewPrivileges=true; TimeoutStartSec=15min. This is the first wall from chapter 14, drawn by a different hand: even if the code had a bug that tried to write a decision into the owner's file, the operating system would refuse.
The two exits
A run ends in one of two ways, and each way makes a different sound.
- Success. Immediately after the run completes, a separate one-line script sends a single, empty request to an outside monitoring service. It carries no company name, no price, no report, no machine name: one request to an opaque address, meaning "the run happened". If that request itself fails, the run is still counted a success; a failed signal must not turn a good night into a bad one.55ExecStartPost=- the ping script; the leading dash means its failure does not fail the unit. The script's own comment: 'WHAT LEAVES THE MACHINE: one HTTP GET to an opaque UUID. No ticker, no price, no report, no hostname, no body.'
- Failure. If the run exits with an error or is killed for running too long, the scheduler starts a second unit whose only job is to notify. That unit runs a plain shell script, deliberately not the program's own language, because the thing that broke may be the program's own environment. The script pushes a message to the owner's phone saying which unit stopped and what that means, with the last eight lines of the log.66OnFailure=vss-failure@%n.service; deploy/vss-notify-failure.sh. The heartbeat module: 'It is deliberately a plain curl in a shell script and NOT this package: the failure being reported may well BE this package.'
Notice the asymmetry. Success is silent on the phone. The owner does not want a message every night saying nothing happened; a message that always arrives is a message that stops being read. Success makes its sound somewhere else, to an observer whose job is to notice if the sound stops. That is the dead man's switch, further down.
The weekly run
The screener runs on the same pattern, on Saturday mornings at 08:00, on Friday's settled prices, with a four-hour limit and a stricter fence: the folder holding the owner's file is not writable to it at all. That single line is the ruling "the scheduled screen never enters a name" written in the scheduler's language.77deploy/vss-screen.timer: Sat 08:00; the service's read-only configuration directory, described in the project brief as 'E93 in one line'. Measured 2026-08-31: about 38 minutes, 3,495 fundamentals requests, zero throttles. A third timer, at 09:30 every day, belongs to the dead man's switch.
What the queue sends
A fourth job, the queue, runs on weekdays at 22:50 and may take up to 60 minutes. It holds about sixty valued names against their lines and sends a phone message only when something has changed. There are five kinds. TITTA: a look line was crossed, so value the name properly now. UNDER MBP: the price is under the cushion price, which is information. SÄLJ: a sell line or the bull value was reached. SPÄRR: a gate date has passed. UTSIKT: the outlook changed. A report on its own is no longer a message. When a report comes out it is fetched and read twice by a model, the company is re-valued on its last four quarters, and the result is compared with its own previous reading. A message goes only if the value moved 10 percent or more, a rule fired, guidance was cut, or a headline signals a profit warning, a guidance change, a CEO or CFO exit, a bid or a delisting. Otherwise the report says "read: nothing changed".
The units, in words
vss.timer fires vss.service at 22:30 daily, catching up if missed. The service is one-shot, runs the nightly command in a sandbox writable only at the data and reports folders, pings the outside observer on success, and starts vss-failure@vss.service on failure. vss-screen.timer fires vss-screen.service on Saturdays at 08:00 with the configuration folder read-only. vss-checkin.timer fires vss-checkin.service at 09:30 daily. Two later jobs ride on the nightly run. vss-mfn.timer fetches, at 22:40, any new Nordic report published in the last 45 days for a name in the queue, so the document is already on disk when the next job looks. vss-queue.timer runs vss queue on weekdays at 22:50: every company that has been valued, about sixty of them, is held against its look line, its cushion price (information), its sell lines and the date its gate lifts, and new filings and headlines are checked. The run may take up to 60 minutes. It sends a message only when something has changed since the night before, and there are five kinds: TITTA (a look line crossed), UNDER MBP (information), SÄLJ (a sell line or the bull value), SPÄRR (a gate date passed) and UTSIKT (the outlook changed). A report on its own is no longer a message: it is fetched and read twice by a model (vss/reportread.py), the company is re-valued on its last four quarters and compared with its own previous reading (vss/outlook.py), and a message goes only if the value moved 10 percent or more, a rule fired, guidance was cut, or a headline signals a profit warning, a guidance change, a CEO or CFO exit, a bid or a delisting. A name that sits in its zone is told once, not every night. vss-failure@.service is a template: the name of the failed unit is filled in and passed to the notifier script, which always exits successfully, because "a failure notifier that can fail is a second thing to monitor".
The dead man's switch
Here is the failure that the whole of this chapter exists to remove. The nightly run sends a message to the owner's phone only when a name needs attention. Most nights, no name does, and the phone is quiet. Now suppose the run crashed at 22:30 on a Tuesday and has been dead ever since. The phone is quiet. The two situations, "nothing needs you" and "nothing has run for a week", produce exactly the same experience: silence. In the tool's own words, "a monitor whose failure mode is silence is a monitor that stops being believed the first time you find out the hard way."88vss/heartbeat.py, opening.
The name, and where it comes from
Trains have a handle the driver must hold or press at intervals. If the driver collapses, the handle is released and the brakes apply. It is called a dead man's handle, and the design idea is that safety must not depend on a signal being sent, because a person who cannot send it is exactly the case it exists for. It must depend on a signal that keeps arriving, with the alarm on its absence.99Wikipedia, Dead man's switch: 'Vigilance control was developed to detect this condition by requiring that the dead man's device be released momentarily and re-applied at timed intervals.' The software version is called a dead man's switch, and it works the same way: something expects a regular signal, and raises the alarm when the signal does not come.
Two observers, because there are two kinds of dead
A machine can be alive and broken, or it can be dead. These need different observers, because an observer that lives on the machine dies with it.
Observer one lives on the machine
When the run fails, the scheduler starts the notifier described above, which pushes to the phone what stopped and the last lines of the log. This is the fast observer: it fires while the failure is happening, and it can describe it. Its weakness is that it needs the machine to be up, the scheduler to be running, and the timer to have fired. A timer that was disabled after a reboot starts nothing, so nothing fails, so nothing shouts, and that is precisely the failure that looks most like a quiet week.
So observer one has a second leg on its own timer: every morning at 09:30, a separate job checks whether a completed run is on record and whether the nightly timer is still enabled. It runs on its own timer deliberately: "if the check on the run shared a timer with the run, the failure that stopped the run would stop the check, and the switch would be wired to its own power supply."1010deploy/vss-checkin.timer, comment. The run also records its own completion in a table, with a bar of 72 hours for the nightly and 10 days for the weekly, and a test run or a single-name run does not reset the clock.
Observer two lives outside
None of that helps if the machine is off, the network is down, or the whole scheduler is stopped. A dead machine cannot page itself. The only thing that can notice a dead machine is something that is not on it: an outside service that expects one signal a day and raises an alarm when the signal does not arrive by a deadline.1111vss/heartbeat.py: 'a dead VPS cannot page itself... Closing that needs an OUTSIDE observer — a service that expects a ping and alerts on its ABSENCE.' That is the empty request from the success exit above. The outside service "keeps silent as long as pings arrive on time" and "raises an alert as soon as a ping does not arrive on time", with a grace period after the expected time.1212The monitoring service's own documentation; the suggested settings in the example environment file are a one-day period and a six-hour grace.
Why absence beats error
An error message needs a sender. Every sender can fail in a way that prevents sending: the process crashed before reaching that line, the network was down, the machine was off. An alarm on absence needs nothing from the failing side. It is the only kind of alarm whose coverage includes the case where the thing being watched no longer exists. That is why the successful run makes a sound to the outside observer and no sound to the phone: the sound is not for the owner, it is for the thing that will notice when the sound stops.
The owner's words when this leg was added: "a dead VPS is exactly the case I want covered and no ping leaves data."1313deploy/vss-ping-healthcheck.sh, quoting the owner, 2026-09-01.
- Decided
- Two observers. One on the machine that describes what broke; one outside that alarms on the absence of a daily signal. The success exit signals the outside observer and says nothing to the phone.
- Why
- Silence has to mean one thing. The only alarm that covers a dead machine is one raised by something that is not on it.
- Cost
- A second external service, whose own outage is uncovered. A signal that leaves the machine every night, kept to one empty request so that nothing about the book leaves with it.
The page on the phone
Everything so far produces a page on a rented server in a data centre. The owner is on a train in Sweden with a phone. The price of a name on the waiting list has just crossed its line. The page knows. The owner does not. This is not an infrastructure problem; it is the last step of the investing problem, and if it is not solved the rest was decoration.
How the page reaches the phone, and what that costs
Follow the arrows. On the machine, a small web server holds the page and listens only to the machine itself: it is bound to the address that means "this computer and nothing else", so nothing outside can reach it directly, ever.1414The server binds the loopback address only. The notes call that one line load-bearing: without it the server would bind every interface, publicly. Beside it runs a second small program, a tunnel client, which does one thing: it dials out to a relay service on the internet and keeps that connection open. The direction matters and is the whole design. The machine makes an outbound connection, the same kind a browser makes when it loads a web page. The firewall was not touched. The only thing the internet can reach on this machine is the remote login port that was already there.1515deploy/TUNNEL-NOTES.md: the tunnel client 'makes an outbound connection... the firewall is unchanged', and the only public listener is the remote-login port that was already there.
Now the owner opens the page's address on a phone. The request goes to the relay, not to the machine. Before the relay does anything, a front door asks who is asking. The front door accepts exactly one email address. It sends a one-time code to that address and to no other; a different address does not even receive a code, because the policy refuses before a code is issued. With the code entered, the door opens for 24 hours. Only then does the relay pass the request down the connection the machine opened earlier, the machine's own server answers with the page, and the page travels back up the same line to the phone.1616Cloudflare Access: one application, one policy allowing one email, one-time PIN as the only identity provider, 24-hour session. Verified 2026-09-13: two other addresses received no PIN at all.
The idea that access should depend on who you are and not on which network you are on has a name in the security literature and a history: it is the principle Google described in 2014 when it moved its internal tools onto the public internet behind identity checks, and it was given the label zero trust earlier by an industry analyst. This project did not invent the shape; it borrowed the smallest possible version of it.1717Ward and Beyer, 'BeyondCorp: A New Approach to Enterprise Security', ;login: 39(6), 2014; Kindervag, Forrester Research, 2010. Neither text is quoted here; the attribution is a pointer, not a claim about their wording.
The page passes through a company's infrastructure the owner does not control, and that company decrypts it at its edge. In the ruling's words: "The page is plaintext at their edge: holdings, states, gate results, MBPs and stops, readable by Cloudflare and by anyone who compels or breaches Cloudflare. This is not mitigable within this architecture. It is the price of reading the book on a phone from an arbitrary network, and I am paying it knowingly." The front door is single-factor: whoever controls the mailbox controls the page. And the tunnel client had to run as a system service with a credential the owner's own account cannot read, which means it cannot use the failure notifier described above. If the tunnel dies, the page stops loading and the phone stays silent. The nightly run and its own alerting do not depend on it.1818Ruling F1: 'WHAT THIS COSTS' under limbs (a) and (b); deploy/TUNNEL-NOTES.md, 'Units — Option C'.
- Decided
- The page reaches the phone through an outbound tunnel to a relay, behind a front door that admits one address by one-time code. The server listens only to the machine itself. No port is opened.
- Why
- A decision that cannot reach the owner when the price moves was not worth making. Every inbound shape opens the machine; the outbound shape opens only a page, and only to one person.
- Cost
- The page is readable by the relay operator. The door is single-factor. The tunnel cannot page the phone when it dies. Each is written into the ruling as the price.
Three questions, in order
- Does anything need me today? One block at the top, in plain sentences. Either "nothing", or the two or three things that do: a look line or sell line crossed, a gate date passed, an outlook change, a dated event within seven days. The list of kinds is closed, so the block cannot grow into a feed. Beside it, always, is what was checked, because "nothing needs you" and "nobody looked" are otherwise the same silence.
- Where is everything against its value? One card per name. A card, not a table, because a table is for comparing forty things and a card is for recognising one. The price large; the value and the cushion price (information) beside it; a year of settled closing prices drawn as a small line; and a track showing where the price sits between half the value and half again, on a scale that is never rescaled per name. A picture never replaces a figure.
- What is coming? The unresolved dated events, nearest first. A long note is folded, never cut short, because "an ellipsis on a record is a record nobody can read."
The rules on what the page may say
A distance, never a verdict
The page uses green and red. It uses them to say how far a price is from a line, in five bands whose boundaries are the method's own numbers, and for nothing else. A name can be green and need nothing; the name that needs the owner can be red. Colour is never applied to a whole card, because a green card reads as approval. A name that is cheap but has failed a gate is drawn muted, with the reason stated in words, so that a cheap closed door does not read as an invitation. No colour anywhere carries meaning on its own.1919vss/overview.py: 'THE DISTANCE SCALE... it is a MEASUREMENT, never a verdict. It says HOW FAR, and nothing about whether to act.' Bands at 0, 5, 25 and 75 percent.
No buy-side condition without the conditions that qualify it
If the page says that a price is below its cushion price (information), the same sentence says what else must be true: that the reading is current, that the conditions from chapter 11 hold. Not a line below. The same sentence, because "the reader who stops after the first half is the reader this page is for."2020vss/overview.py: 'A BUY-SIDE CONDITION NEVER STANDS ALONE. The qualifying clause goes in the SAME SENTENCE, not a line below it.'
It states its own age, twice
A run that fails writes nothing. The server keeps serving the last good page. The page looks identical to a fresh one, and the owner reads last Thursday's states believing they are tonight's. That failure is invisible to every alarm described above, because the run either happened or it did not, and the page's age is a different question. So the page prints the exact time it was generated, with the timezone, in the header, visible on a phone without scrolling, and again in the first sentence of the footer. The page cannot mark itself stale, because that would need a script and scripts are forbidden; it can only make its age impossible to miss, and the subtraction is the owner's.2121Ruling F1 limb (c) requirement 1, and ruling F2 withdrawing requirement 2. Implemented 2026-09-13.
It never chooses
Where the record holds two valuations for a name and nothing says which is current, the page prints DATA MISSING and links both. It does not take the newer one. A sort order is not a decision, and the page must not answer a question the owner has not.2222vss/overview.py: 'it never chooses (two run records and no entry naming one ⇒ DATA MISSING and both linked — a filename sort must not answer E39's question)'.
Why a page that renders no opinion is more useful
A page that said "buy NAME A" would be read for its verdict, and the verdict would be right or wrong, and the owner would learn nothing either way about whether the reading behind it was sound. A page that says "NAME A is 3 percent above its line, the line was struck on the June report, the next report is in nine days, and one figure is unverified" gives the owner every fact needed to decide and withholds the one thing that would let the owner stop thinking. It is more work to read. That is what it is for.
- Decided
- The page shows state, distance and age. It renders no verdict on any name, colours nothing as approval, qualifies every buy-side sentence in the same sentence, and prints its own generation time twice.
- Why
- The page is the thing the owner acts on. Anything it decided would be decided without the reading, and anything it hid about its own age would be believed.
- Cost
- It cannot warn that it is stale; the owner must read the time and subtract. It never gives the answer, so every night the owner does the thinking again.
systemctl --user list-timers 'vss*'What runs next, if you installed the timers. From the repository's root, after the install in the manual.
- Every night prices are held against decisions already made, and each new report is read and the company valued again.
- The phone hears only a change.
- Two observers make silence mean something: one on the machine says what broke, one outside notices when nothing arrives.
Sources for this chapter
- The scheduler units and scripts — read from this repository: deploy/vss.timer, deploy/vss.service, deploy/vss-screen.timer, deploy/vss-queue.timer, deploy/vss-mfn.timer, deploy/vss-checkin.timer, deploy/vss-failure@.service, deploy/vss-ping-healthcheck.sh, deploy/vss-notify-failure.sh, deploy/README.md
- Dead man's switch, Wikipedia
https://en.wikipedia.org/wiki/Dead_man%27s_switch - Healthchecks.io documentation (alarm on a missing ping)
https://healthchecks.io/docs/ - The heartbeat module and the units — read from this repository: vss/heartbeat.py; deploy/vss-checkin.timer; deploy/vss-ping-healthcheck.sh; deploy/vss-notify-failure.sh; deploy/vss.env.example; reference/BACKLOG.md B-13
- Ward and Beyer (2014), BeyondCorp: A New Approach to Enterprise Security, ;login:
https://www.usenix.org/publications/login/dec14/ward - Ruling F1 and the tunnel notes — read from this repository: reference/FRAMEWORK-EDITS.md F1; deploy/TUNNEL-NOTES.md; deploy/vss-tunnel.service; deploy/vss-overview.service
- The overview page generator and its rulings — read from this repository: vss/overview.py; vss/render.py; reference/FRAMEWORK-EDITS.md F1, F2
The slow way, made survivable. Built 2026-11-09 from the repository as it stood that day. NAME A and NAME B are fictional. One real company, CENTA, is followed through the book, with figures from its own filings and the owner's own trades. Not financial advice: one private investor's method, shared as it is.