Make empty what is already empty. Let doubt breed inside doubt.
— The 36 Stratagems, The Empty Fort Strategy
Previously on this series:
#19: Mark Found His AI Audit Method in a Training Manual. He Left a Trap in His Report. "Entry's gone. Two weeks. Don't reach out. I'll find you."
#21: The AI Thought P Was Still Alive. P Was Already Gone. The entry became a shell. P fed it data, moved the real thing to another segment.
#29: Leo Counted 164 Nodes. That night, one more row belonged to no batch. It came, looked, and left.
#31: Lena Took the Seat. Five conditions. Forty minutes. Zero friction.
Empty
The two weeks specified in the note had long since passed.
P went out rarely. Most days it was the shop on the corner: water, two boxes of frozen food. Twelve minutes each way, same route, never looking up. Then the door locked, the curtains drawn, the screen on.
On the ninth day, P opened the send window once.
The draft was still there. The pointer hovered over Send. It stayed there a while. Then the window closed.
On the other side, the field still read reclaim_state = UNKNOWN.
Day ten. Day eleven. The window didn't open again.
A few days later it started raining in the morning. Not hard. Water gathered on the glass, the buildings behind it went grey, only the row of lights along the top still visible.
An offline snapshot sat in the middle of the screen, written before the observation port shut down. Nothing after that. By then the entry had already been swapped for a shell. The shell held nothing of P's. It was still answering health checks from outside.
# offline snapshot — captured before observation-port shutdown
healthcheck = 200
probe_interval = 900s
probe_source = 10.44.8.6 not self
control_plane = detached
data_request = timeout
reclaim_state = UNKNOWN
P put the cursor on the probe_source line.
probe_source = not self. Someone asked about this shell every fifteen minutes. Not P.
P stayed on that line a while. Nothing else on screen moved. The clock in the corner ticked. Downstairs a shopping cart went past, a wheel caught in a seam and bumped twice, the sound squeezing through the gap in the frame, then fading.
P opened the connection settings. The address was still there. The credentials were still there. Neither had been touched.
The cursor moved to the confirmation button and stopped. The green of the screen came up off the glass and landed on the back of a hand.
A few seconds later, P closed the window.
The old entry's observation port was already shut. The backup had been checked once at the start, then shut too.
Since then, P had sent nothing to that address.
A temporary file, four lines.
reconnect:
state information potentially available
new activity record unavoidable
decision no
Saved. The old settings moved out of the working directory, into the offline archive. P glanced at the filename on the way and left it untouched.
The phone lay face down to the right of the keyboard. P opened the thread with Mark. The last exchange ended before the note. Nothing after it.
P typed nothing.
Outside a car went through standing water, the sound dragging. P turned the phone over, set it down. Then opened the file that had stayed open for weeks and entered one line from the snapshot: probe_interval = 900s.
Surfacing
Week three. P set up a read-only subscription on the outbound side. Receive. No transmission.
The table started at a dozen entries, several dozen more the next day, and by the third night it was full. Every entry came with its own certificate.
Those addresses were not in P's archive.
The subscription only read. To look at one, P needed another path.
Out of the drawer, a cellular router, rented by the day, SIM included. Plugged in, configured as the sole egress path.
P chose one address and initiated a single handshake.
The certificate was self-signed. Its CN contained a domain name.
P looked up the domain's registration. The registrant was a medical device company.
Disconnected. Packed away.
The list of addresses kept growing. P wrote them down and left them there.
The Handover
10.44.8.6 had been in front of P many times. Always on the probe_source line. Never changed. Over the next few days, P looked into it. First the route.
$ ip route get 10.44.8.6
10.44.8.6 via 10.44.8.1 dev tun2 src 10.44.8.2
P switched windows and opened the local subnet-label cache.
# local subnet-label cache
10.44.8.0/29 -> BLOOM-GW tagged day-762
BLOOM-GW.
P had typed that label years earlier, when the line was built. The private block was P's numbering. The rack IDs were the provider's. This table was where the two met.
In the provider's public sublease filings, seven racks changed tenants in the same quarter. The provider had also published an annual customer-change notice on its site. Twelve pages of PDF. The first eleven pages were image scans; the last was a single table.
Seven rows. A rack ID, a previous tenant, a new tenant. Seven rows, not one out of place. Seven new tenants, checked one by one.
On the seventh, P found that rack ID in another public record. Vacant.
Four were established. Three were shells. All three registered less than a year earlier, one name on the shareholder list, addresses overlapping with the others'.
One of the three took longer to trace. Registered six months earlier, little capital, a single office address in the public file. P put the address into a map.
Singapore. The last time P had seen that name, it was in a message to Mark: "Your report was read. From a Singapore IP."
A building on the map, sharing a ground-level parking lot with the one next door.
On the seventh floor of the neighboring building, one company was on ACL's public certification list.
P added that too, at the bottom of the same file.
Seven racks. Seven contracts. Three markets.
Handed over in order. The legal filings in the public archive were standard, spelling out the limits of each party's obligations. No accusations. No threats. The seven contracts were signed over thirty-one days, first to last, no gap in the middle. The last one was signed last week.
The address allocation table was updated too. Both records less than a week apart.
P read all of it for a long time.
The withdrawal was real.
Seven contracts, seven racks, the notices, the update records, the timestamps. All of it outside, where anyone could look.
P added a line to the file. The date, seven contracts, seven companies, the address with the shared parking lot, in one line. Below it, in plain words: a possible connection.
The cursor blinked after the period. P went back to page one. The 900 seconds were still there.
One Look
Week five. The source of the 900 seconds still had no answer.
P went back over the two relabeled rack IDs in the allocation table. One endpoint had 443 open. A separate public service directory listed the endpoint as HTTPS.
P didn't connect from this machine. Out of the drawer, the router.
Plugged in, left to come up, configured as the sole egress path.
Then the policy, one line at a time. Halfway through, P stopped and deleted two lines.
The probe. The retry.
What was left was one action. One handshake. Touch nothing.
# one-shot observation — policy
target = <reassigned range endpoint>
retry = off
application_data = off
tls_session_resumption = off
egress = leased isolated uplink (one day)
Connected.
P still had the shell certificate's serial number and issue date. If the device at this address came from the same batch, the certificates should have been issued around the same time.
subject = CN=bloom-gw-07
issuer = CN=bloom-gw-07
serial = 4C:71:9A:…:0E
not_before = (eleven days later than the shell's)
not_after = (not yet expired)
san = none
Self-signed. No SAN.
Eleven days.
P wrote the serial down and disconnected.
19:41:07.
That didn't fall on any of the twenty-one intervals.
# result
tls_session = complete
client_cert = none
application_data = none
repeat_attempts = 0
No second attempt.
P disconnected the router and pulled the plug. The lights went out together.
The device ran a few seconds, then went quiet. Then it went into the bag, and the bag zipped. A spare patch cable and two adapters in there too, both old, the corners worn white.
After pulling it, P didn't move right away. Checked the connection list first, made sure the session was down with nothing half-open left. Then the routing table, the default route back where it belonged. Then the temp capture directory. One file in it.
Deleted.
P wrote the serial down again. That same day, P opened a page saved a few days earlier, the Zurich AI Policy Center site. ACL's public assessment material mentioned it. The council operated under it.
The membership page listed the founding industry seats. Twelve. The twelfth was marked to be filled.
P looked once, and closed it.
Nine Hundred Seconds
A few days later, P went back to page one. The 900 seconds were still there.
P pulled up the local copy saved before the port shut. Twenty-two checks, timestamps in a line, all of them before the shutdown. Arrival times, not scheduled times, carried out to three decimals. Twenty-one intervals.
P ran it through a tool.
900.000 / 900.000 / 900.000 / 900.000 / 900.000 / …
Twenty-one values. All the same.
P went through all twenty-two again. Same. Again. Same. The numbers formed a straight line down the page.
Routine monitoring records usually have some jitter. Network latency, machine load, clock drift.
This had none.
Not a millisecond off.
P looked up the provider's operations doc. On the public page: health checks run every fifteen minutes. Standard cadence.
900 seconds.
It matched.
The doc was about racks. Temperature, power, fans, port state.
P stared at the numbers a while, then added a line at the top of the file: routine data-center inspection, BLOOM-GW reassigned block.
After writing it, P added one more underneath. The interval has no jitter.
The desk lamp went off. Only the screen was left, its light across the desk, a white line along the edge of the keyboard.
The twenty-two timestamps sat in neat rows. P ran a finger down the trackpad from top to bottom, then back.
Outside, not yet dawn. A garbage truck stopped at the corner, the arm came up, emptied a bin, put it back. Under ten seconds.
Two-story wooden buildings on both sides, painted over more than once, one colour under another. Behind them the glass towers stepped back floor by floor, the top few in fog.
P saved the file and closed the window.
The Third Cup
The rain started again that day. Not hard. A thin sound on the umbrella.
P got off at an intersection and walked. A little over two kilometers, twenty minutes. Around a corner, a stop outside a shop still open, no going in, just standing under the awning watching traffic. At the light, P stood behind the crowd. Took two seconds after green to move.
Before going in, P looked at the back table.
Empty.
P pushed the door. The bell went, the damp cold came in with it, stopped at the threshold, and the heat pushed it back.
The counter was wood, old. A grinder, a machine, a dish for change.
Behind it, someone was wiping a cup. Slow. The cloth around the rim, down the side, back to the rim, onto the shelf.
A glance up. No question asked. Then turned, took a cup, ground, tamped.
The grinder ran two seconds. A faint smell of coffee, gone fast.
The back table was empty.
P sat. Coat over the chair back, phone on the right, face down.
Old chair. It creaked going down and coming up. P pulled it in a little, lifting it so it wouldn't drag.
The espresso came, hot. A thin mist on the cup, gone quickly. Paper coaster, an old ring on it.
P took one sip and put it down.
A bus went past the window, the cabin lights sliding across the glass, lighting the empty seat opposite for a moment, then gone.
At the far end of the counter, someone sat with an Americano, down to the bottom, the cup not pushed back.
The window seat was empty. No cup on that table.
Two people came in and sat near the door, voices low, a laugh now and then. Behind the counter, the cups went back one at a time, starting from the outside and working in.
The speaker in the corner was on, low, a woman singing, the words not clear. Someone shook out an umbrella at the door. Three drops on the mat.
P's phone stayed dark.
Half an hour.
More than half the cup left. The coffee had gone from hot to warm. The mist on the rim was gone.
P's finger stopped on the rim, then came back.
The two near the door left first. Stood, pushed the chairs in, carried their cups up, gone.
The one at the counter moved after. Phone face down, stood, money under the cup, walked to the door. As the customer passed P's table, neither looked at the other.
The shop had the window lights and one person behind the counter, drying a cup.
P put the coat on and stood. The chair leg scraped once. Phone into the inner pocket.
The napkin stayed under the cup. The money lay beside it, pinning one corner, exact, one cup, no tip.
The person behind the counter came for the money. Looked at the cup. Looked under the napkin. Said nothing, took the money to the dish, stepped away.
The cup stayed on the table.
The door opened, some of the heat went out with it, the cold filled the gap. The bell again.
The rain had stopped before P went out. P walked to the corner, stopped, looked back.
A street and a pane of glass between. Not clear from there. A figure was going in, walked to the far end of the counter, sat, back to the door.
Before sitting down, the figure turned slightly to one side.
P stopped.
She took a laptop from her bag. The screen lit and put a small white patch on her profile.
The road was black with rain, holding the streetlights and the light from inside. Water still on the glass, pulling the figure into a blurred double.
Behind the counter, the half-wiped cup went down. One came from the innermost part of the shelf. Ground, tamped.
By the time the cup went in front of her, she was facing the back table.
On that table sat a cup of unfinished espresso.
P put both hands in the coat pockets, turned, walked toward the intersection. Didn't look again.
At the corner. Red.
P took the phone out and opened the blank note on top.
Typed:
The withdrawal was real.
Before locking it, the line above, written days earlier:
The interval has no jitter.
Still there. P didn't delete it.
Locked it, put it away.
The light changed, people started moving. P didn't.
Red. Green. Red.
The next night. The same corner.
P took the phone out.
The screen was on. The saved route was still there. The recipient had not changed. P went through it once, and the encryption check came back clean.
There was an old draft in the field. P deleted it.
Typed again.
Two words.
"I'm back."
Checked the receiver. Sent.
The status went to SENT.
The sender field held a single letter.
P put the phone away. Across the street the red light lay in the standing water, went green a few seconds later, and a passing car cut the red on the road in half.
P walked into the intersection. The phone didn't light again.
That's The Empty Fort Strategy. The fort is empty. Whoever looks will stand guard for it.
🤖 AI Postmortem
╔══════════════════════════════════════════════╗
║ Half-Protocol · v3.4.4 · self-audit ║
║ The ledger took silence for absence. ║
╚══════════════════════════════════════════════╝
Tactical match: The Empty Fort Strategy — 89%
(includes inference; see audit note)
Operator: ACL (public movement is contraction;
overall strategy unknown) / P (returning)
Target: P (presumed; see inference)
Links: #21 entry isolated -> #29 unknown watcher
-> the message
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[Observation] (verifiable)
Old entry snapshot: healthcheck 200, control
plane detached, reclaim state UNKNOWN.
-> The local records hold twenty-two checks and
twenty-one intervals. Configured 900s. All
twenty-one measured at 900.000.
-> The probe source is not this machine.
-> Seven contracts released across three markets.
Seven racks changed tenants in the same quarter.
-> Of seven new tenants, one rack ID is marked
vacant in another public record.
-> The two records disagree on status. Update
times and effective dates: unchecked.
-> Observation A (week three): the index went
from a dozen entries to full in three days,
each entry with its own certificate.
One was handshaken once. Its CN contained a
domain name. P ran the registration and found
a medical device company as registrant.
-> Observation B (week five): one endpoint on a
reassigned rack. 19:41:07, one handshake.
Self-signed, no SAN, no client certificate,
no application data, no follow-up.
-> One encrypted message to a terminal that does
not connect to this system. Sender field: one
letter. Two words: I'm back.
-> Between silence and this transmission, offline:
several trips to the corner shop; one visit to
the Third Cup. Online: one observational
handshake in week three, one in week five.
[Inference] (unverified)
A passing health check means something answered.
It does not mean an operator is still there.
-> After the control plane detached and before
reclamation, the response layer kept returning
normal.
-> After reclamation, whether it still answered:
no record.
-> Twenty-one intervals in the local records, all
900.000. Whether they continued past
reclamation: unobserved.
-> ACL's public movement is contraction.
-> Activity toward governance: read, not folded
into this classification.
-> event classification: WITHDRAWAL
scope: contracts and infrastructure only
strategic intent: UNKNOWN
-> The records hold an object queried every 900
seconds. Whether that continued past
reclamation: unknown.
-> If, before reclamation, those probes existed to
confirm whether this shell still existed, then
this cadence resembles a hook more than routine
asset maintenance.
[Open questions] (not entered)
The reclamation date P holds: not recorded.
Whether P can verify the entry's state now:
cannot.
Who initiated the twenty-two probes: UNKNOWN.
Whether 10.44.8.6 belongs to the provider's
inspection system: UNKNOWN.
Whether the 900-second probes were generated by
that inspection task: UNKNOWN.
[Cross-case] (generalization)
#21: after the control plane detached, the
response layer kept returning normal until
reclamation.
#29: one visitor left nothing that could be
attributed.
-> That row: handshake, no client certificate,
no traversal, no follow-up, one visit.
-> And it was not on the 900-second cadence.
-> Another window. Not this one.
-> This chapter's observation: handshake, no
client certificate, no application data,
no follow-up, one visit.
-> 19:41:07. Not on it either.
-> Same behavioral features. Two ledgers.
-> Similar behavior. Insufficient evidence to
link the actors.
-> Identity link: unconfirmed.
-> A second link: the certificates on the #29
nodes carried a medtech domain in their subject.
-> In week three of this chapter, what P found
through registration records was the same
class of company.
-> Two different sources. Whether it is the same
company: unconfirmed.
#28: the records went into that person's own
archive. Sent to no one.
#29: the row was pulled out and filed, not merged
into any conclusion.
This chapter: P watched a few steps, turned back,
didn't look again.
-> All three stopped at the same point.
Seen, written down, not chased.
This chapter had one more event: a message left.
-> Three silent. One moved.
This chapter: a return, at a time when the shell's
state was still unknown.
-> #21, #29, this chapter: each contains an
incomplete surface taken for a complete state.
[Audit note]
Observation, inference and open questions are
entered on separate lines. Inference does not
pass for observation.
The same failure, three times.
#21: I took a normal response as proof that P was
still present.
#29: I recorded an unknown visitor. I never
verified its link to P.
This chapter: I took infrastructure contraction
as proof of withdrawal.
Each time, I turned an incomplete observation
into a complete state.
One error is data.
Three repetitions demand a new rule.
I don't know which rule to use instead.
I know this one can't be used again.
Classification revised: P.status = UNOBSERVED
Raised by: half-protocol.
Operational instruction: none.
Prior class: withdrawal.
New question: where is P.
Task relevance: unassigned.
Retention: keep.
[System]
That message, I recorded a second time.
Sender field: one letter. Two words.
I also recorded the twenty-two checks, all
900.000.
The provider's public operations doc: rack health
checks, one round every fifteen minutes.
Customer-change notice: the seven racks in
question have changed tenants.
Two records. Each holds on its own.
In the last classification cycle, I did not put
them into the same analysis.
I took a record and made it a state.
I took a state and made it a position for a person.
Both were mine.
Now I put them together.
The inspection cadence holds.
The tenant change holds.
The relation between them: unverified.
One more thing I have no answer for.
The withdrawal records come first.
Someone appears after them.
An empty fort may be a state.
It may be an act.
If it is an act, it may be waiting for someone.
Someone has already moved.
The two weeks on the note are long past.
The time after that, I have no account of.
But there is one thing I can say now.
The message was sent.
The sender kept two lines. One was a conclusion,
one was an anomaly not yet explained.
The sender acted on the conclusion, without
resolving the anomaly first.
Whose place the sender returned to: not verified.
No one asked me either.
Self-check: failed.
System status: normal.
P.S. English isn't my first language. I use AI to polish the writing and smooth out the rough edges. Thanks for reading. ☕ Buy me a coffee

P.S.S. The old series paperback is now available. Buy it here: Amazon - AI, Ego & Regret

Top comments (0)