You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: CHANGELOG.md
+8Lines changed: 8 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,6 +2,14 @@
2
2
3
3
All notable project changes are recorded here. The README shows only the most recent entry.
4
4
5
+
## 2026-07-14 - OAuth-Blocked Recovery
6
+
7
+
- Classified refresh-token `invalid_grant` responses and unusable token files as explicit OAuth authorization blocks instead of ambiguous retry failures.
8
+
- Added bounded local credential fingerprinting and signal-interruptible waiting that makes no API calls until token content changes, then resumes automatically.
9
+
- Preserved already-public FFmpeg ingest under its local watchdog during an OAuth block and revalidated the exact cached lifecycle state after reauthorization.
10
+
- Limited custom child-stopping signal handlers to visible test-pattern runs so device authorization terminates normally.
11
+
- Added regression coverage and operator documentation for revoked, missing, malformed, unreadable, and oversized token states.
- Stopped setting `liveBroadcast` and `liveStream` descriptions; new insert payloads omit the description field entirely and privacy updates remain status-only.
Copy file name to clipboardExpand all lines: README.md
+8-3Lines changed: 8 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -132,6 +132,7 @@ See the [recovery state machine](docs/architecture-and-flows.md#recovery-state-m
132
132
| Lifecycle state is missing or corrupt | Legacy markers may be read once for migration; otherwise conflicting same-stream or same-title resources block creation until an operator reconciles ownership. |
133
133
| Ambiguous or unknown remote state | Reconciliation fails closed and creates nothing until the ambiguity is resolved. |
134
134
| OAuth access token expires | API helper refreshes from the stored refresh token. |
135
+
| OAuth refresh token is missing, invalid, expired, revoked, unreadable, or malformed | API mutation pauses without entering ambiguous backoff. The service waits for the token file to change and resumes automatically after `youtube-autoencoder-api authorize` saves a replacement. If a verified public stream is already running, FFmpeg remains under its local progress watchdog while the control plane is blocked. |
135
136
| Previous broadcast is `complete`, `revoked`, or confirmed missing | One new unlisted generation may be staged after the source probe passes. |
136
137
137
138
Recovery deadlines survive service and host restarts. Exponential backoff uses these class floors and caps:
@@ -143,6 +144,8 @@ Recovery deadlines survive service and host restarts. Exponential backoff uses t
OAuth authorization failures are blocked conditions, not retry classes. They do not consume API quota while the token file is unchanged.
148
+
146
149
The project never sets or updates YouTube `liveBroadcast` or `liveStream` descriptions. Normal recovery validates the exact broadcast ID in the private schema-v3 state file. Before a new insert, the helper persists the required title, scheduled start, privacy, creation window, and stream relationship; if the insert outcome is ambiguous, those fields may identify exactly one remote candidate, but they can never authorize another automatic insert. Legacy description markers are read only during one-way migration from schema v2.
|`invalid_client`| OAuth client type does not support the device-code flow. | Create a client for TVs and Limited Input devices, then replace `google-oauth-client.json`. |
400
403
|`authorization_pending`| The browser approval has not completed yet. | Finish the device-code flow; the CLI will keep polling until the code expires. |
401
404
|`slow_down`| Polling is too frequent. | The helper backs off automatically. |
405
+
|`invalid_grant`| The refresh token expired, was revoked, or no longer belongs to the OAuth client. Testing-mode authorizations commonly expire after seven days. | Move the OAuth app to In production for unattended use, rerun `youtube-autoencoder-api authorize`, and select the account that owns or manages the intended channel. The running service detects the saved token and resumes automatically. |
402
406
| Token works briefly then expires | App is still in Testing mode. | Add the correct test user for setup, then move the app to In production for unattended use and complete required verification. |
403
407
| API calls fail despite valid OAuth | The account does not own/manage the YouTube channel, live streaming is not enabled, or quota/policy blocks the operation. | Reauthorize with the right channel account, enable live streaming, and check project quota and YouTube Studio restrictions. |
404
408
@@ -521,10 +525,11 @@ Each eligible collection performs one [`videos.list`](https://developers.google.
521
525
522
526
Only the most recent changelog entry is shown here. See `CHANGELOG.md` for full history.
- New YouTube stream and broadcast inserts omit the description field, and normal lifecycle recovery never updates descriptions.
527
-
- Schema-v3 exact-ID state and a durable create fingerprint retain duplicate-safe recovery; legacy markers are read only for one-way migration.
530
+
- Refresh-token rejection and unusable token files now enter an explicit OAuth-blocked state instead of ambiguous retry backoff.
531
+
- The supervisor waits without API calls until token content changes, preserves an already-public FFmpeg stream under its watchdog, and revalidates exact lifecycle state after reauthorization.
532
+
- Device authorization keeps normal termination semantics; child-specific signal handling is limited to the visible test-pattern command.
RecoveryCreate --> RecoveryBackoff : insert outcome uncertain, never reinsert
104
110
```
105
111
106
-
The helper never sets or updates YouTube descriptions. Schema-v3 state stores the exact broadcast ID and a write-ahead create fingerprint. A lost insert response enters `verify_create`; recovery may adopt exactly one normalized remote match, but zero or multiple matches stay blocked under durable ambiguous backoff. Legacy description markers are read only for one-way schema-v2 migration.
112
+
The helper never sets or updates YouTube descriptions. Schema-v3 state stores the exact broadcast ID and a write-ahead create fingerprint. A lost insert response enters `verify_create`; recovery may adopt exactly one normalized remote match, but zero or multiple matches stay blocked under durable ambiguous backoff. OAuth rejection does not enter that backoff: the service makes no further API calls until the private token file changes. Legacy description markers are read only for one-way schema-v2 migration.
107
113
108
114
Return to [Recovery Behavior](../README.md#recovery-behavior).
Approve the device code in a browser for the Google account that owns the YouTube channel.
68
69
70
+
If a refresh token later expires or is revoked, the service enters an OAuth-blocked state without creating or mutating broadcasts. Run the same authorization command again. The service detects the atomically saved replacement token and resumes automatically; no service restart is required.
71
+
69
72
For a fresh deployment without an existing reusable stream, provision and validate it before enabling the production service:
0 commit comments