[PR #204] [CLOSED] Phase 0 #116

Closed
opened 2026-09-25 12:04:24 +02:00 by thegame_1980 · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/Vateron-Media/XC_VM/pull/204
Author: @obscuremind
Created: 9/25/2026
Status: ❌ Closed

Base: main ← Head: main


📝 Commits (10+)

  • 12257af docs(design): add the MAIN ↔ LB API communication design spec
  • 44fda47 Merge pull request #7 from obscuremind/claude/main-lb-api-communication-r0bdpp
  • 71108b2 fix(logs): import every spooled activity and client-request row
  • 091660f Merge pull request #8 from obscuremind/claude/main-lb-api-communication-r0bdpp
  • 7464754 fix(logs): update only existing lines and bound import batches by size
  • 8ef2440 fix(stream): read connection rows for disallow_2nd_ip_con in Redis mode
  • a936d8f fix(stream): move the disallow_2nd_ip_con Redis decision into acceptedLineIP()
  • 7ee9e71 fix(users): publish FPM worker pids so Redis reaping spares LB viewers
  • 6bc29e8 fix(users): date a remote worker pid by its last write and tell idle pools from unknown
  • f8f3ca3 fix(watchdog): correct bandwidth totals, rps, producers and fatals

📊 Changes

227 files changed (+14050 additions, -1048 deletions)

View changed files

📝 .gitignore (+1 -0)
📝 Makefile (+57 -29)
➕ docs/adr/0004-cluster-api.md (+126 -0)
📝 docs/en/administration/server-diagnostics.md (+27 -1)
📝 docs/en/builds/build_system.md (+56 -25)
➕ docs/en/development/cluster-seams.md (+54 -0)
📝 docs/en/development/streaming-subsystem.md (+45 -2)
📝 docs/en/guides/cli-tools.md (+25 -2)
📝 docs/en/guides/dev-workflow.md (+1 -1)
📝 docs/en/guides/feature-flags.md (+1 -0)
➕ docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md (+1131 -0)
📝 lb_configs/nginx.conf (+4 -6)
📝 mkdocs.yml (+2 -0)
📝 src/Cli/Commands/CacheHandlerCommand.php (+5 -3)
➕ src/Cli/Commands/ClusterInitCommand.php (+46 -0)
📝 src/Cli/Commands/CreatedCommand.php (+6 -4)
📝 src/Cli/Commands/DelayCommand.php (+5 -2)
📝 src/Cli/Commands/FanoutSyncCommand.php (+12 -4)
📝 src/Cli/Commands/LbInstallFlow.php (+32 -2)
📝 src/Cli/Commands/MonitorCommand.php (+8 -7)

...and 80 more files

📄 Description

This PR starts work on the MAIN ↔ LB API communication plan. Under the plan, LB nodes stop connecting to MAIN's MySQL and Redis, and every exchange moves to a signed, encrypted cluster API. Node tokens derive from the licence and rotate on an interval set in Settings.

docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md adds the design as supplied: revision 3 of the condensed plan plus 28 consistency corrections. It is the source of truth for the phases (0–11) and decisions D1–D21.
Phase 0 ("fix prerequisite defects, add legacy-backed seams and gates; no behaviour change") lands on this branch as separate commits, each with its own unit tests. It fixes five defects:
Log-import crons keep only one spooled row per node per minute (ActivityCronJob, LinesLogsCronJob).
In Redis mode, disallow_2nd_ip_con throws a ValueError in live.php (and a TypeError for HMAC identities).
servers.php_pids stores PHP-FPM master pids, so in Redis mode MAIN's cron:users kills live PHP-served viewers on LBs.
SystemInfo/watchdog telemetry: bandwidth totals, requests-per-second, the stream-producer count and two fatals that stop the heartbeat.
OPENSSL_EXTRA can differ between MAIN and LBs. The fix adds verification, provisioning, a repair command and a 10-minute dual-accept window.
The rest of Phase 0 follows on this branch: MAIN-only gates for crons, the LB build manifest, stop-gaps for proxy_api.php and the SSH credential file, and the legacy-backed seams (SignalDispatcher, NodeRpc/NodeActions, the stream seams, LogSink, lazy DB, audit hooks).
Type of change
Bug fix
New feature
Refactor / cleanup
Documentation
Build / CI / tooling
Checklist
Code follows the project conventions (see .github/instructions/php-conventions.instructions.md).
Added/updated tests for the change where applicable.
Documentation updated where applicable (docs/, README).
Verification per commit: php tests/phpunit.phar -c tests/phpunit.xml.dist (baseline 892 tests green) and make gates. PHPStan and phpcs were not run: this environment could not install the dev tools.

Phase 0 of the MAIN ↔ LB API communication plan (docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md, merged in https://github.com/obscuremind/XC_VM/pull/7): fix prerequisite defects, add legacy-backed seams and gates. Nothing changes behaviour except the defect fixes themselves.

Commits land here one Phase 0 item at a time. Each item starts with a failing unit test and gets two adversarial reviews before it is final.

In this PR so far

fix(logs): ActivityCronJob and LinesLogsCronJob kept only the first spooled row per node per minute and deleted the rest. They now import every row in batches of 1000, skip rows that don't decode, and claim the spool by renaming it so concurrent writers aren't lost.
Coming next on this branch

live.php: in Redis mode, disallow_2nd_ip_con throws a ValueError.
php_pids: it holds PHP-FPM master pids, so in Redis mode MAIN's cron:users kills live PHP-served LB viewers.
SystemInfo: bandwidth totals, rps, the stream-producer count, and two fatals that break the heartbeat.
OPENSSL_EXTRA: a mismatch between MAIN and LB. The fix adds a fingerprint check, provisioning, a repair command and a 10-minute dual-accept window.
MAIN-only gates for crons, the stale LB build manifest, and the proxy_api.php and SSH-credential stop-gaps.
Legacy-backed seams: SignalDispatcher, NodeRpc/NodeActions, StreamSource/StreamStateWriter/StreamRowMerge/StreamCacheBuilder, LogSink, lazy DB in the streaming bootstrap, and trace-only DB/Redis connect audit hooks.
Type of change
Bug fix
New feature
Refactor / cleanup
Documentation
Build / CI / tooling
Checklist
Code follows the project conventions (see .github/instructions/php-conventions.instructions.md).
Added/updated tests for the change where applicable.
Documentation updated where applicable (docs/, README).
Checked locally: php tests/phpunit.phar -c tests/phpunit.xml.dist passes (899 tests) and make gates passes. PHPStan comes from this PR's CI, because the dev tools can't be installed in this environment.
Merged
Phase 0: fix viewer kills, live.php fatal, log import, telemetry and OPENSSL_EXTRA drift
#9
obscuremind
merged 13 commits into
main
from
claude/main-lb-api-communication-r0bdpp
Conversation
@obscuremind
obscuremind
commented
6 hours ago
•
Summary
This PR fixes the five Phase 0 defects of the MAIN ↔ LB API communication plan (docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md). Each fix started from a failing test and went through two adversarial reviews.

fix(users), 2 commits. servers.php_pids held the 4 PHP-FPM master pids. In Redis mode, MAIN's cron:users never found a connection's worker pid in that list, so it dropped every live PHP-served viewer on an LB about a minute after connecting. That covers VOD, timeshift, and live TS when fanout is off. Changes:

The watchdog now publishes the worker pids (ProcessManager::phpFpmWorkerPIDs()).
A remote pid is dated by its last write.
An idle pool is no longer mistaken for an unknown one.
php_pids is kept out of the per-request servers cache and the admin API.
fix(stream), 2 commits. With disallow_2nd_ip_con on in Redis mode, live.php threw ValueError: Array sizes are inconsistent, and a TypeError for HMAC identities. ConnectionTracker::acceptedLineIP() now reads the connection rows behind the LINE# keys and accepts the oldest connection's IP, as MySQL mode already does.

fix(logs), follow-up to https://github.com/obscuremind/XC_VM/pull/8. The importer now updates only lines rows that exist, and it caps each batch by byte size as well as by row count.

fix(watchdog), 2 commits. Telemetry fixes:

The bandwidth totals are summed over the selected interfaces, and the received total reads rx_bytes.
requests_per_second now has a value, from a persistent CounterRateSampler.
total_running_streams counts ffmpeg processes and xc_fanout remux producers, read from /proc.
Two fatals that stopped the heartbeat are fixed.
The watchdog_data key set and order are unchanged.

OPENSSL_EXTRA drift between MAIN and LB, 5 commits. A MAIN installed with the current installer uses a random config/openssl_extra. LBs added with server:install fall back to the literal default. On such clusters, every token MAIN mints fails readToken on the LB. Changes:

feat(diagnose): each node publishes a one-way fingerprint of its value (server_hardware.openssl_extra_fp, never the value itself). server:diagnose reports a mismatch.
fix(install): LbInstallFlow::provisionOpensslExtra() gives new LBs MAIN's value.
fix(servers): a MAIN-only server:sync-openssl-extra repairs existing LBs through a root signal (set_openssl_extra). The command is stripped from the LB archive. The row is never handed to proxies by proxy_api.php. The command refuses to run when MAIN's FPM uses a different value from its CLI.
feat(stream): after a switch, Encryption::readToken also accepts the value the node replaced, for 10 minutes. It retries only after the current value fails. There is a documented ~1/256 miss for legacy (non-sealed) tokens.
Docs: server-diagnostics.md and cli-tools.md.
Type of change
Bug fix
New feature
Refactor / cleanup
Documentation
Build / CI / tooling
Checklist
Code follows the project conventions (see .github/instructions/php-conventions.instructions.md).
Added/updated tests for the change where applicable.
Documentation updated where applicable (docs/, README).
Validated locally on 6c391f25:

PHPUnit: 995 tests pass (php tests/phpunit.phar -c tests/phpunit.xml.dist).
make gates passes; the LB manifest has 705 files.
PHPStan level 5 reports no errors.
phpcs (PSR-12 + Generic) passes on the changed files.
GitHub Actions runners are not starting jobs on this fork (see https://github.com/obscuremind/XC_VM/pull/8 and https://github.com/obscuremind/XC_VM/pull/9 comments), so these local runs stand in for CI for now.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/Vateron-Media/XC_VM/pull/204 **Author:** [@obscuremind](https://github.com/obscuremind) **Created:** 9/25/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `main` --- ### 📝 Commits (10+) - [`12257af`](https://github.com/Vateron-Media/XC_VM/commit/12257af38246b76030cb353d8bac8da91350e8bd) docs(design): add the MAIN ↔ LB API communication design spec - [`44fda47`](https://github.com/Vateron-Media/XC_VM/commit/44fda47b284aa6cfcc8cac3d35461f465739d8ea) Merge pull request #7 from obscuremind/claude/main-lb-api-communication-r0bdpp - [`71108b2`](https://github.com/Vateron-Media/XC_VM/commit/71108b20eb0eaea9c5ae8badc1864984b91e7485) fix(logs): import every spooled activity and client-request row - [`091660f`](https://github.com/Vateron-Media/XC_VM/commit/091660fe338e68564fbc11c6a6e148f6fc962292) Merge pull request #8 from obscuremind/claude/main-lb-api-communication-r0bdpp - [`7464754`](https://github.com/Vateron-Media/XC_VM/commit/7464754b35b6b0b62b9de7b6c748cf20795b6e17) fix(logs): update only existing lines and bound import batches by size - [`8ef2440`](https://github.com/Vateron-Media/XC_VM/commit/8ef2440fea7a79a932d2f0ede0eab9a800833763) fix(stream): read connection rows for disallow_2nd_ip_con in Redis mode - [`a936d8f`](https://github.com/Vateron-Media/XC_VM/commit/a936d8ffff6a4275d92d24bade02b899b5a758d7) fix(stream): move the disallow_2nd_ip_con Redis decision into acceptedLineIP() - [`7ee9e71`](https://github.com/Vateron-Media/XC_VM/commit/7ee9e7153701aade0e767cb69708a03cc01520c6) fix(users): publish FPM worker pids so Redis reaping spares LB viewers - [`6bc29e8`](https://github.com/Vateron-Media/XC_VM/commit/6bc29e8ee756d0dd316b1872fff717dc1266c69f) fix(users): date a remote worker pid by its last write and tell idle pools from unknown - [`f8f3ca3`](https://github.com/Vateron-Media/XC_VM/commit/f8f3ca3a82a81945c4845bc6eba83224427e97cd) fix(watchdog): correct bandwidth totals, rps, producers and fatals ### 📊 Changes **227 files changed** (+14050 additions, -1048 deletions) <details> <summary>View changed files</summary> 📝 `.gitignore` (+1 -0) 📝 `Makefile` (+57 -29) ➕ `docs/adr/0004-cluster-api.md` (+126 -0) 📝 `docs/en/administration/server-diagnostics.md` (+27 -1) 📝 `docs/en/builds/build_system.md` (+56 -25) ➕ `docs/en/development/cluster-seams.md` (+54 -0) 📝 `docs/en/development/streaming-subsystem.md` (+45 -2) 📝 `docs/en/guides/cli-tools.md` (+25 -2) 📝 `docs/en/guides/dev-workflow.md` (+1 -1) 📝 `docs/en/guides/feature-flags.md` (+1 -0) ➕ `docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md` (+1131 -0) 📝 `lb_configs/nginx.conf` (+4 -6) 📝 `mkdocs.yml` (+2 -0) 📝 `src/Cli/Commands/CacheHandlerCommand.php` (+5 -3) ➕ `src/Cli/Commands/ClusterInitCommand.php` (+46 -0) 📝 `src/Cli/Commands/CreatedCommand.php` (+6 -4) 📝 `src/Cli/Commands/DelayCommand.php` (+5 -2) 📝 `src/Cli/Commands/FanoutSyncCommand.php` (+12 -4) 📝 `src/Cli/Commands/LbInstallFlow.php` (+32 -2) 📝 `src/Cli/Commands/MonitorCommand.php` (+8 -7) _...and 80 more files_ </details> ### 📄 Description This PR starts work on the MAIN ↔ LB API communication plan. Under the plan, LB nodes stop connecting to MAIN's MySQL and Redis, and every exchange moves to a signed, encrypted cluster API. Node tokens derive from the licence and rotate on an interval set in Settings. docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md adds the design as supplied: revision 3 of the condensed plan plus 28 consistency corrections. It is the source of truth for the phases (0–11) and decisions D1–D21. Phase 0 ("fix prerequisite defects, add legacy-backed seams and gates; no behaviour change") lands on this branch as separate commits, each with its own unit tests. It fixes five defects: Log-import crons keep only one spooled row per node per minute (ActivityCronJob, LinesLogsCronJob). In Redis mode, disallow_2nd_ip_con throws a ValueError in live.php (and a TypeError for HMAC identities). servers.php_pids stores PHP-FPM master pids, so in Redis mode MAIN's cron:users kills live PHP-served viewers on LBs. SystemInfo/watchdog telemetry: bandwidth totals, requests-per-second, the stream-producer count and two fatals that stop the heartbeat. OPENSSL_EXTRA can differ between MAIN and LBs. The fix adds verification, provisioning, a repair command and a 10-minute dual-accept window. The rest of Phase 0 follows on this branch: MAIN-only gates for crons, the LB build manifest, stop-gaps for proxy_api.php and the SSH credential file, and the legacy-backed seams (SignalDispatcher, NodeRpc/NodeActions, the stream seams, LogSink, lazy DB, audit hooks). Type of change Bug fix New feature Refactor / cleanup Documentation Build / CI / tooling Checklist Code follows the project conventions (see .github/instructions/php-conventions.instructions.md). Added/updated tests for the change where applicable. Documentation updated where applicable (docs/, README). Verification per commit: php tests/phpunit.phar -c tests/phpunit.xml.dist (baseline 892 tests green) and make gates. PHPStan and phpcs were not run: this environment could not install the dev tools. Phase 0 of the MAIN ↔ LB API communication plan (docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md, merged in https://github.com/obscuremind/XC_VM/pull/7): fix prerequisite defects, add legacy-backed seams and gates. Nothing changes behaviour except the defect fixes themselves. Commits land here one Phase 0 item at a time. Each item starts with a failing unit test and gets two adversarial reviews before it is final. In this PR so far fix(logs): ActivityCronJob and LinesLogsCronJob kept only the first spooled row per node per minute and deleted the rest. They now import every row in batches of 1000, skip rows that don't decode, and claim the spool by renaming it so concurrent writers aren't lost. Coming next on this branch live.php: in Redis mode, disallow_2nd_ip_con throws a ValueError. php_pids: it holds PHP-FPM master pids, so in Redis mode MAIN's cron:users kills live PHP-served LB viewers. SystemInfo: bandwidth totals, rps, the stream-producer count, and two fatals that break the heartbeat. OPENSSL_EXTRA: a mismatch between MAIN and LB. The fix adds a fingerprint check, provisioning, a repair command and a 10-minute dual-accept window. MAIN-only gates for crons, the stale LB build manifest, and the proxy_api.php and SSH-credential stop-gaps. Legacy-backed seams: SignalDispatcher, NodeRpc/NodeActions, StreamSource/StreamStateWriter/StreamRowMerge/StreamCacheBuilder, LogSink, lazy DB in the streaming bootstrap, and trace-only DB/Redis connect audit hooks. Type of change Bug fix New feature Refactor / cleanup Documentation Build / CI / tooling Checklist Code follows the project conventions (see .github/instructions/php-conventions.instructions.md). Added/updated tests for the change where applicable. Documentation updated where applicable (docs/, README). Checked locally: php tests/phpunit.phar -c tests/phpunit.xml.dist passes (899 tests) and make gates passes. PHPStan comes from this PR's CI, because the dev tools can't be installed in this environment. Merged [Phase 0: fix viewer kills, live.php fatal, log import, telemetry and OPENSSL_EXTRA drift](https://github.com/obscuremind/XC_VM/pull/9#top) #9 [obscuremind](https://github.com/obscuremind) merged 13 commits into [main](https://github.com/obscuremind/XC_VM/tree/main) from [claude/main-lb-api-communication-r0bdpp](https://github.com/obscuremind/XC_VM/tree/claude/main-lb-api-communication-r0bdpp) Conversation @[obscuremind](https://github.com/obscuremind) obscuremind commented [6 hours ago](https://github.com/obscuremind/XC_VM/pull/9#issue-5576275090) • Summary This PR fixes the five Phase 0 defects of the MAIN ↔ LB API communication plan (docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md). Each fix started from a failing test and went through two adversarial reviews. fix(users), 2 commits. servers.php_pids held the 4 PHP-FPM master pids. In Redis mode, MAIN's cron:users never found a connection's worker pid in that list, so it dropped every live PHP-served viewer on an LB about a minute after connecting. That covers VOD, timeshift, and live TS when fanout is off. Changes: The watchdog now publishes the worker pids (ProcessManager::phpFpmWorkerPIDs()). A remote pid is dated by its last write. An idle pool is no longer mistaken for an unknown one. php_pids is kept out of the per-request servers cache and the admin API. fix(stream), 2 commits. With disallow_2nd_ip_con on in Redis mode, live.php threw ValueError: Array sizes are inconsistent, and a TypeError for HMAC identities. ConnectionTracker::acceptedLineIP() now reads the connection rows behind the LINE# keys and accepts the oldest connection's IP, as MySQL mode already does. fix(logs), follow-up to https://github.com/obscuremind/XC_VM/pull/8. The importer now updates only lines rows that exist, and it caps each batch by byte size as well as by row count. fix(watchdog), 2 commits. Telemetry fixes: The bandwidth totals are summed over the selected interfaces, and the received total reads rx_bytes. requests_per_second now has a value, from a persistent CounterRateSampler. total_running_streams counts ffmpeg processes and xc_fanout remux producers, read from /proc. Two fatals that stopped the heartbeat are fixed. The watchdog_data key set and order are unchanged. OPENSSL_EXTRA drift between MAIN and LB, 5 commits. A MAIN installed with the current installer uses a random config/openssl_extra. LBs added with server:install fall back to the literal default. On such clusters, every token MAIN mints fails readToken on the LB. Changes: feat(diagnose): each node publishes a one-way fingerprint of its value (server_hardware.openssl_extra_fp, never the value itself). server:diagnose reports a mismatch. fix(install): LbInstallFlow::provisionOpensslExtra() gives new LBs MAIN's value. fix(servers): a MAIN-only server:sync-openssl-extra repairs existing LBs through a root signal (set_openssl_extra). The command is stripped from the LB archive. The row is never handed to proxies by proxy_api.php. The command refuses to run when MAIN's FPM uses a different value from its CLI. feat(stream): after a switch, Encryption::readToken also accepts the value the node replaced, for 10 minutes. It retries only after the current value fails. There is a documented ~1/256 miss for legacy (non-sealed) tokens. Docs: server-diagnostics.md and cli-tools.md. Type of change Bug fix New feature Refactor / cleanup Documentation Build / CI / tooling Checklist Code follows the project conventions (see .github/instructions/php-conventions.instructions.md). Added/updated tests for the change where applicable. Documentation updated where applicable (docs/, README). Validated locally on 6c391f25: PHPUnit: 995 tests pass (php tests/phpunit.phar -c tests/phpunit.xml.dist). make gates passes; the LB manifest has 705 files. PHPStan level 5 reports no errors. phpcs (PSR-12 + Generic) passes on the changed files. GitHub Actions runners are not starting jobs on this fork (see https://github.com/obscuremind/XC_VM/pull/8 and https://github.com/obscuremind/XC_VM/pull/9 comments), so these local runs stand in for CI for now. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
thegame_1980 added the pull-request label 2026-09-25 12:04:24 +02:00
thegame_1980 changed title from [PR #204] Phase 0 to [PR #204] [CLOSED] Phase 0 2026-09-25 20:04:22 +02:00
thegame_1980 changed title from [PR #204] [CLOSED] Phase 0 to [PR #204] Phase 0 2026-09-29 04:04:46 +02:00
thegame_1980 changed title from [PR #204] Phase 0 to [PR #204] [CLOSED] Phase 0 2026-09-29 12:04:38 +02:00
thegame_1980 changed title from [PR #204] [CLOSED] Phase 0 to [PR #204] Phase 0 2026-10-06 12:05:44 +02:00
thegame_1980 changed title from [PR #204] Phase 0 to [PR #204] [CLOSED] Phase 0 2026-10-06 20:05:47 +02:00
Sign in to join this conversation.
No labels pull-request
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Vateron-Media/XC_VM#116