#190 turned DEMO_MODE from a hardcoded compose value into a Portainer stack variable with no default, and updated the compose header. The runbook that actually creates the stack was not updated with it, so the document and the file it deploys have been disagreeing since — in the three places most likely to be read under pressure.
Step 2's list of stack variables to record did not include DEMO_MODE, and step 6 says to add the variables from steps 2 and 3. An operator following this literally creates a stack that cannot boot. It is now in the list, with a paragraph of its own: it is the only one of the nine that is not a secret, which is exactly why it is the easy one to skip past.
The troubleshooting section said DEMO_MODE was hardcoded and therefore could not be missing, so its absence from the error list proved nothing. That was the most dangerous sentence in the file — an unset DEMO_MODE is now the first thing to check rather than something to rule out. The line now says it moved and why.
The crash-loop example was the PayPal triple, which cannot occur while DEMO_MODE is true. The message an operator will actually see during the demo interim — DEMO_MODE is required and must be exactly 'true' or 'false' — appeared nowhere in the runbook. Both forms are shown now, in the order they are likely to be hit.
Added what neither document said: Compose only warns about an unset variable and deploys anyway. In Portainer's stack UI that warning is easy to miss, and the container then crash-loops under restart: unless-stopped — loud in the log, invisible in a glance at the stack list. The container log is the signal, not the deploy output.
The compose header carried two claims that #190 falsified and did not correct: that the PayPal secrets are required "because DEMO_MODE is false below", and that only secrets are interpolated. Both now describe the file as it is.
This is the drift composeEnvironment.test.ts exists to prevent, surfacing in the one place no test can reach — the guard keeps the compose file honest about its own intent and cannot see the runbook beside it.
Verified: 278 backend unit tests pass, including the compose guard that parses this file, and a sweep for the stale claims finds none left.
#190 turned `DEMO_MODE` from a hardcoded compose value into a Portainer stack variable with no default, and updated the compose header. The runbook that actually creates the stack was not updated with it, so the document and the file it deploys have been disagreeing since — in the three places most likely to be read under pressure.
Step 2's list of stack variables to record did not include `DEMO_MODE`, and step 6 says to add the variables from steps 2 and 3. An operator following this literally creates a stack that cannot boot. It is now in the list, with a paragraph of its own: it is the only one of the nine that is not a secret, which is exactly why it is the easy one to skip past.
The troubleshooting section said `DEMO_MODE` was hardcoded and therefore could not be missing, so its absence from the error list proved nothing. That was the most dangerous sentence in the file — an unset `DEMO_MODE` is now the *first* thing to check rather than something to rule out. The line now says it moved and why.
The crash-loop example was the PayPal triple, which cannot occur while `DEMO_MODE` is `true`. The message an operator will actually see during the demo interim — `DEMO_MODE is required and must be exactly 'true' or 'false'` — appeared nowhere in the runbook. Both forms are shown now, in the order they are likely to be hit.
Added what neither document said: Compose only *warns* about an unset variable and deploys anyway. In Portainer's stack UI that warning is easy to miss, and the container then crash-loops under `restart: unless-stopped` — loud in the log, invisible in a glance at the stack list. The container log is the signal, not the deploy output.
The compose header carried two claims that #190 falsified and did not correct: that the PayPal secrets are required "because DEMO_MODE is false below", and that only secrets are interpolated. Both now describe the file as it is.
This is the drift `composeEnvironment.test.ts` exists to prevent, surfacing in the one place no test can reach — the guard keeps the compose file honest about its own intent and cannot see the runbook beside it.
Verified: 278 backend unit tests pass, including the compose guard that parses this file, and a sweep for the stale claims finds none left.
Closes #196
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
#190 turned `DEMO_MODE` from a hardcoded compose value into a Portainer stack variable with no default, and updated the compose header. The runbook that actually creates the stack was not updated with it, so the document and the file it deploys have been disagreeing since — in the three places most likely to be read under pressure.
Step 2's list of stack variables to record did not include `DEMO_MODE`, and step 6 says to add the variables from steps 2 and 3. An operator following this literally creates a stack that cannot boot. It is now in the list, with a paragraph of its own: it is the only one of the nine that is not a secret, which is exactly why it is the easy one to skip past.
The troubleshooting section said `DEMO_MODE` was hardcoded and therefore could not be missing, so its absence from the error list proved nothing. That was the most dangerous sentence in the file — an unset `DEMO_MODE` is now the *first* thing to check rather than something to rule out. The line now says it moved and why.
The crash-loop example was the PayPal triple, which cannot occur while `DEMO_MODE` is `true`. The message an operator will actually see during the demo interim — `DEMO_MODE is required and must be exactly 'true' or 'false'` — appeared nowhere in the runbook. Both forms are shown now, in the order they are likely to be hit.
Added what neither document said: Compose only *warns* about an unset variable and deploys anyway. In Portainer's stack UI that warning is easy to miss, and the container then crash-loops under `restart: unless-stopped` — loud in the log, invisible in a glance at the stack list. The container log is the signal, not the deploy output.
The compose header carried two claims that #190 falsified and did not correct: that the PayPal secrets are required "because DEMO_MODE is false below", and that only secrets are interpolated. Both now describe the file as it is.
This is the drift `composeEnvironment.test.ts` exists to prevent, surfacing in the one place no test can reach — the guard keeps the compose file honest about its own intent and cannot see the runbook beside it.
Verified: 278 backend unit tests pass, including the compose guard that parses this file, and a sweep for the stale claims finds none left.
Closes#196
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
#190 turned
DEMO_MODEfrom a hardcoded compose value into a Portainer stack variable with no default, and updated the compose header. The runbook that actually creates the stack was not updated with it, so the document and the file it deploys have been disagreeing since — in the three places most likely to be read under pressure.Step 2's list of stack variables to record did not include
DEMO_MODE, and step 6 says to add the variables from steps 2 and 3. An operator following this literally creates a stack that cannot boot. It is now in the list, with a paragraph of its own: it is the only one of the nine that is not a secret, which is exactly why it is the easy one to skip past.The troubleshooting section said
DEMO_MODEwas hardcoded and therefore could not be missing, so its absence from the error list proved nothing. That was the most dangerous sentence in the file — an unsetDEMO_MODEis now the first thing to check rather than something to rule out. The line now says it moved and why.The crash-loop example was the PayPal triple, which cannot occur while
DEMO_MODEistrue. The message an operator will actually see during the demo interim —DEMO_MODE is required and must be exactly 'true' or 'false'— appeared nowhere in the runbook. Both forms are shown now, in the order they are likely to be hit.Added what neither document said: Compose only warns about an unset variable and deploys anyway. In Portainer's stack UI that warning is easy to miss, and the container then crash-loops under
restart: unless-stopped— loud in the log, invisible in a glance at the stack list. The container log is the signal, not the deploy output.The compose header carried two claims that #190 falsified and did not correct: that the PayPal secrets are required "because DEMO_MODE is false below", and that only secrets are interpolated. Both now describe the file as it is.
This is the drift
composeEnvironment.test.tsexists to prevent, surfacing in the one place no test can reach — the guard keeps the compose file honest about its own intent and cannot see the runbook beside it.Verified: 278 backend unit tests pass, including the compose guard that parses this file, and a sweep for the stale claims finds none left.
Closes #196
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com