Skip to content

feat(identity): reload the identity map without a server restart - #280

Merged
patroza merged 1 commit into
fork/identityfrom
feat/identity-map-hot-reload
Aug 1, 2026
Merged

feat(identity): reload the identity map without a server restart#280
patroza merged 1 commit into
fork/identityfrom
feat/identity-map-hot-reload

Conversation

@patroza

@patroza patroza commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Problem

IdentityService read T3_IDENTITY_MAP_PATH once at layer construction and captured
people in a closure. Adding or removing someone required restarting t3code-server.

Change

The map is re-checked on a 60s TTL (IDENTITY_MAP_RELOAD_TTL_MS) and applies in place.
Every read path (getSnapshot, listMapPeople, claim, requireOperateClaim,
resolveByJiraAccountId, isMapEnabled) now resolves a snapshot instead of a captured list.

Polls rather than watches: the map arrives over virtiofs from the host, where inotify
propagation isn't something to depend on. An ino:size:mtime fingerprint avoids
re-parsing an untouched file each TTL. Time goes through Clock, so the TTL is testable.

Safety

Reload can now fail in production where startup could not, so two rules:

  1. A re-read yielding no people never disables an enabled map. enabled === false
    turns the operate gate off entirely — a truncated or unparseable file would have
    failed open. The last good map keeps serving, marked healthy: false, and the next
    TTL retries (the fingerprint is deliberately not advanced).

  2. requireOperateClaim no longer deletes the claim of an absent person. Under
    layerPersisted that eviction is a deleteBySessionId — irreversible. A half-written
    file can parse as a valid map with a subset of people, so rule 1 alone doesn't cover
    it. Refusing operate is the gate; membership is re-checked on every operate, so a stale
    row grants nothing. This is a deliberate behaviour change.

Startup behaviour is unchanged: missing/empty map → feature off, and removing
T3_IDENTITY_MAP_PATH is still how you disable the gate.

Tests

New IdentityService.reload.test.ts, driving real files with TestClock:

  • an added person applies after the TTL, and not before it
  • an emptied file keeps the last good map, stays enabled, reports healthy: false, and recovers
  • a removed person is refused operate while their claim row survives, and works again once re-added

Gates: typecheck, lint (exit 0), fmt:check, full test — 2118 passed / 11 skipped.

Companion

Host-side staging (install in stage-secrets.sh, ops repo) truncates and rewrites in
place, and the guest reads that inode live. Nothing observed it mid-write before; a
reloading server does. An atomic temp+rename there is the other half of this — separate PR.

Targets the fork/identity overlay (PR #250) per AGENTS.md.

🤖 Generated with Claude Code

The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@patroza
patroza merged commit 4e3ec60 into fork/identity Aug 1, 2026
7 checks passed
@patroza
patroza deleted the feat/identity-map-hot-reload branch August 1, 2026 09:57
patroza added a commit that referenced this pull request Aug 1, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 1, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 1, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
omegent-app Bot pushed a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 2, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 3, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 4, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
patroza added a commit that referenced this pull request Aug 5, 2026
The server read T3_IDENTITY_MAP_PATH once at layer construction, so adding or
removing a person meant restarting t3code-server. The map is now re-checked on
a 60s TTL and applies in place.

Polls rather than watches: the map arrives over virtiofs from the host, where
inotify propagation is not something to depend on. An ino/size/mtime
fingerprint keeps an untouched file from being re-parsed every TTL.

Two safety rules, because a reload can now fail in production where startup
could not:

- A re-read that yields no people never disables an already-enabled map.
  `enabled === false` turns the operate gate off entirely, so a truncated or
  unparseable file would have failed open. The last good map keeps serving,
  marked unhealthy, and the next TTL retries.
- requireOperateClaim no longer deletes the persisted claim of a person who is
  absent from the map. A half-written file can still parse as a valid map with
  a subset of people, and that delete is not reversible. Refusing operate is
  the gate; membership is re-checked on every operate, so a stale row grants
  nothing.

Startup behaviour is unchanged: a missing or empty map still means the feature
is off, and removing T3_IDENTITY_MAP_PATH remains the way to disable the gate.

Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 3b2203f)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant