Skip to content

feat(settings): default settings.enablePluginPadOptions to true#7841

Merged
JohnMcLear merged 1 commit into
developfrom
fix/enable-plugin-pad-options-default-true
May 25, 2026
Merged

feat(settings): default settings.enablePluginPadOptions to true#7841
JohnMcLear merged 1 commit into
developfrom
fix/enable-plugin-pad-options-default-true

Conversation

@JohnMcLear
Copy link
Copy Markdown
Member

@JohnMcLear JohnMcLear commented May 25, 2026

Note to Sam: This is more of a fix than a feat, it's the pad wide setting for plugins enabled by default as I intended but messed it up :)

Summary

  • Flip settings.enablePluginPadOptions default from falsetrue. Matches the original intent of shipping the ep_* passthrough in 3.0.0 (PR feat(padOptions): pass plugin-namespaced ep_* keys through applyPadSettings #7698): let plugins like ep_plugin_helpers' padToggle / padSelect ride the existing padoptions broadcast/persist rail out of the box.
  • Updates Settings.ts, settings.json.template (env-var default), PluginCapabilities.ts comment, and doc/plugins.md (now describes the flag as opt-out instead of opt-in).
  • Backend test describe-blocks relabeled — true is now (default), false is now (operator opt-out). Same matrix; both branches still pass.

Why now

  • "pad-wide settings unavailable" message on console ep_comments_page#422 (and sibling per-plugin reports discussed on Discord) — stock 3.x deployments console.warn on every pad load because ep_plugin_helpers detects clientVars.enablePluginPadOptions === false and tells the admin to flip it. With the flag default-true, the warning stops firing on fresh installs while still surfacing for operators who have explicitly opted out.
  • Plugins on ep_plugin_helpers >= 0.6 already expect pad-wide options to work; default-false silently no-op'd pad.changePadOption('ep_*', …) and made the helper UI inert.

Compat

  • Deployments with an explicit "enablePluginPadOptions": false in settings.json keep that value — no migration.
  • clientVars shape is unchanged; older clients only read enablePluginPadOptions and keep working.

Follow-up

  • ether/ep_plugin_helpers: README and warning comments still describe the flag as opt-in. Separate PR queued.

Closes ether/ep_comments_page#422 (warning suppression for stock deployments).

Test plan

  • mocha tests/backend/specs/Pad.ts — 31 passing, both (default) and (operator opt-out) branches green
  • Full backend suite via CI
  • Smoke a fresh settings.json (env-var path) to confirm clientVars.enablePluginPadOptions === true on default deploy

🤖 Generated with Claude Code

@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

Review Summary by Qodo

Default enablePluginPadOptions to true for plugin compatibility

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Default settings.enablePluginPadOptions from false to true
• Aligns with original 3.0.0 intent for plugin pad-wide options
• Suppresses console warnings on fresh deployments
• Updates documentation and test labels to reflect opt-out model
Diagram
flowchart LR
  A["enablePluginPadOptions: false<br/>(old default)"] -->|"flip to true"| B["enablePluginPadOptions: true<br/>(new default)"]
  B -->|"plugins like ep_plugin_helpers"| C["Pad-wide options work<br/>out of the box"]
  B -->|"operators can opt-out"| D["Set to false in<br/>settings.json"]
  A -->|"caused warnings"| E["console.warn on pad load"]
  C -->|"eliminates"| E

Loading

File Changes

1. src/node/utils/Settings.ts ⚙️ Configuration changes +5/-5

Flip enablePluginPadOptions default to true

• Changed enablePluginPadOptions default value from false to true
• Updated comment to describe new opt-out model instead of opt-in
• Clarifies that operators can disable by setting to false in settings.json

src/node/utils/Settings.ts


2. src/node/utils/PluginCapabilities.ts 📝 Documentation +1/-1

Update PluginCapabilities comment for new default

• Updated comment to reflect new default value of true
• Maintains documentation of the capability flag for plugins

src/node/utils/PluginCapabilities.ts


3. settings.json.template ⚙️ Configuration changes +4/-4

Update template default and documentation

• Changed environment variable default from false to true
• Updated comment to describe feature as enabled by default
• Clarifies opt-out behavior for operators

settings.json.template


View more (2)
4. doc/plugins.md 📝 Documentation +4/-3

Update plugin documentation for new default

• Changed documented default from false to true
• Reframed as opt-out instead of opt-in
• Updated example to show disabling the feature
• Clarified that enabled state is now the default

doc/plugins.md


5. src/tests/backend/specs/Pad.ts 🧪 Tests +3/-3

Relabel test blocks to reflect new default

• Relabeled test describe-block for true case to "(default)"
• Relabeled test describe-block for false case to "(operator opt-out)"
• Updated test description to reflect opt-out terminology
• Both test branches remain unchanged in logic

src/tests/backend/specs/Pad.ts


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects
Copy link
Copy Markdown

qodo-free-for-open-source-projects Bot commented May 25, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (2)

Grey Divider


Remediation recommended

1. Default flip breaks upgrades 📘 Rule violation ☼ Reliability
Description
Changing the default for enablePluginPadOptions from false to true will change behavior for
existing deployments that upgrade without explicitly setting the key, creating a
backward-compatibility risk. It also violates the requirement that new features remain behind a
feature flag and be disabled by default so the default/absent-config path matches prior behavior.
Code

src/node/utils/Settings.ts[R437-441]

Evidence
PR Compliance ID 3 is implicated because enabling the feature when the config key is absent
introduces unmitigated breaking behavior for older config versions that previously relied on absence
implying false via the prior default. PR Compliance ID 5 is implicated because the PR sets
enablePluginPadOptions: true in runtime defaults and also changes the settings.json.template
(including the env-var default) to true, meaning the feature is effectively enabled by default
rather than remaining opt-in behind a disabled-by-default feature flag.

src/node/utils/Settings.ts[434-441]
settings.json.template[851-860]
doc/plugins.md[267-281]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The default for `enablePluginPadOptions` has been changed to `true`, which can alter behavior for existing installs that upgrade with older configurations that omit this setting. This both creates a backward-compatibility risk (since absence previously implied `false`) and violates the policy that new features must be feature-flagged and disabled by default so the default path preserves prior behavior.

## Issue Context
Older configs may not include an explicit `enablePluginPadOptions` entry in `settings.json` and therefore rely on the core default; flipping the default changes runtime behavior after upgrade without an explicit opt-in. The PR also updates the runtime defaults and the `settings.json.template` (including the env-var default) to `true`, making the feature on by default rather than keeping the disabled path equivalent to previous versions.

## Fix Focus Areas
- src/node/utils/Settings.ts[437-441]
- settings.json.template[851-860]
- doc/plugins.md[267-281]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Missing default regression test 📘 Rule violation ☼ Reliability
Description
No automated test verifies that the default value of settings.enablePluginPadOptions is now
true; existing tests explicitly override the flag, so they would still pass if the default change
were reverted. This weakens regression coverage for the behavior change.
Code

src/node/utils/Settings.ts[R437-441]

Evidence
PR Compliance ID 1 requires a regression test that would fail if the fix were reverted. The default
is changed in Settings.ts, but the test suite saves the original value and then sets the flag
explicitly, meaning there is no assertion that the default itself is true.

src/node/utils/Settings.ts[434-441]
src/tests/backend/specs/Pad.ts[203-220]
Best Practice: Repository guidelines

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Add a regression test that fails if `enablePluginPadOptions` default is not `true`.

## Issue Context
Current tests set `settings.enablePluginPadOptions` in `before()` hooks, so they do not validate the default value coming from `Settings.ts`.

## Fix Focus Areas
- src/node/utils/Settings.ts[437-441]
- src/tests/backend/specs/Pad.ts[203-220]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

3. Docs miss padwide gate 🐞 Bug ⚙ Maintainability
Description
doc/plugins.md describes the ep_* padoptions passthrough as gated only by
settings.enablePluginPadOptions, but the server ignores all padoptions mutations unless
settings.enablePadWideSettings is enabled and the sender is the pad creator. Operators/plugins
with enablePadWideSettings:false will see ep_* changes silently not persist even if
enablePluginPadOptions:true.
Code

doc/plugins.md[R269-271]

Evidence
The documentation states runtime gating is via enablePluginPadOptions, but server-side
padoptions messages are ignored unless pad-wide settings are enabled and the sender is the pad
creator, making the runtime gate effectively broader than documented.

doc/plugins.md[269-281]
src/node/handler/PadMessageHandler.ts[338-366]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`doc/plugins.md`'s "Runtime flag" section for plugin-namespaced pad-wide options states the passthrough is gated by `settings.enablePluginPadOptions`, but in practice persistence/broadcast of `padoptions` changes is also gated by `settings.enablePadWideSettings` and restricted to the pad creator.

This can confuse operators or plugin authors when `enablePadWideSettings` is disabled: ep_* options will not be accepted/persisted even if `enablePluginPadOptions` is true.

## Issue Context
Server-side padoptions handling returns early when `settings.enablePadWideSettings` is false and rejects non-creator updates.

## Fix Focus Areas
- doc/plugins.md[269-281]

Add a short note in the runtime gating section explaining that plugin pad-wide options ride the same rail as native pad-wide settings and therefore require `enablePadWideSettings` to be enabled (and are subject to the same creator-only restriction).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

JohnMcLear added a commit to ether/ep_plugin_helpers that referenced this pull request May 25, 2026
ether/etherpad#7841 flips settings.enablePluginPadOptions default to
true, turning the runtime gate from opt-in into opt-out. Update the
helper's README + source comments so the framing matches:

- README PadToggle section: requires the patch (3.0.0+) AND the flag
  not be explicitly false; calls out that older 3.x cores shipped it
  default false so operators on those versions still need the explicit
  opt-in.
- pad-toggle-server.js / pad-toggle.js / pad-select-server.js comment
  blocks: remove the "default false per AGENTS.MD §52" framing; describe
  the post-flip default and explicit operator opt-out as the case
  where the warning fires.

Behavior unchanged — runtime flag detection still reads
clientVars.runtimeEnabled and warns when it's false; the warning copy
itself ("settings.enablePluginPadOptions is false — set to true …")
stays correct for operators who've explicitly disabled.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JohnMcLear
Copy link
Copy Markdown
Member Author

CI note: the two Windows backend test failures (`Windows with Plugins (24)` and `Windows without plugins (24)`) are the pre-existing silent-ELIFECYCLE flake on Windows runners — each run dies at a different test file (this one died inside `messages.ts USER_CHANGES` and `socketio.ts Pad-wide settings creator gate`, neither of which touches `enablePluginPadOptions`). The develop tip itself (sha `d9dabe35`) fails `Windows without plugins (24)` the same way 30 min before this PR was opened.

Every Linux variant (with + without plugins, plus 24-only matrix), Playwright Chrome ×2, Playwright Chrome with plugins, Playwright Firefox, Wrapper unit, perform type check, build, build-test, build-test-local-plugin, test, Analyze, CodeQL, Build snap (destructive-mode), and dependency-review all pass.

Heartbeat instrumentation to surface the silent Windows failure root cause is queued in #7838.

@JohnMcLear JohnMcLear requested a review from SamTV12345 May 25, 2026 13:35
JohnMcLear added a commit that referenced this pull request May 25, 2026
…7842)

* test(ci): schedule a mid-test snapshot 150ms after every beforeEach

Run 26401801404 (PR #7841 after merging develop) captured the dying
test's beforeEach node-report — be-0258, written 75ms after
socketio.ts > "Pad-wide settings creator gate different browsers"
entered — but no further state. The kill landed 321ms into the test
body, between 1 Hz heartbeat ticks, and the 100ms boundary throttle
prevented further beforeEach writes inside the same test. The report
we have shows only the listening server socket; the connections that
the test body creates (and that presumably precede the kill) never
get snapshotted.

Schedule an unref'd setTimeout from beforeEach that fires 150ms after
the test entered. If it's still the running test at fire time (i.e.
slow enough that the death window applies), capture a node-report
from INSIDE the test body — the moment when the real TCP / socket.io
activity is in flight. Fast tests (<150ms) skip the write because
afterEach has already cleared currentTest by the time the timer
fires.

Result on the next reproduction of the death pattern:
  - be-NNNN report at +75ms (beforeEach, body not yet started)
  - mt-MMMM report at +150ms (mid-test, body in flight, before kill
    at +320ms)
  - kill, no further reports

Cost: only slow tests (>150ms) generate an mt report, so the
artifact size growth is bounded by the count of tests that take
longer than 150ms — typically a small minority. Locally verified
against a 3-test probe: 2 fast tests skipped, 1 300ms test produced
the expected mt-NNNN snapshot.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(ci): bump heartbeat from 1Hz to 5Hz

Run 26402211271 produced be-0207 (the dying test's beforeEach
snapshot) but no mid-test snapshot, even though setTimeout(150ms)
was scheduled and the test body lived another 280 ms after that
deadline. setTimeout under Windows-runner load is being starved
past the deadline — we already saw the previous test's mt fire at
+252 ms (102 ms late) when the deadline was 150 ms, so the dying
test's timer was likely scheduled to fire well after the kill at
+425 ms.

setInterval has fired reliably throughout the investigation
(every heartbeat in every run lands within ~1 s of schedule, even
when setTimeout misses). Bump heartbeat to 200 ms (5 Hz) so any
death window ≥200 ms is sampled inside the test body, independent
of how starved setTimeout is.

Cost on the Windows runner: the existing log shows writeReport
completes in <1 ms (from "Writing Node.js report" to "Node.js
report completed" timestamps), so 5 Hz adds ~5 ms/s of overhead.
Artifact growth: ~500 reports for a 100 s test phase (~25 MB raw,
~5 MB compressed). The setTimeout mid-test snapshot stays — it's
belt-and-suspenders cheap and fires for slow tests where the
heartbeat alone might not align with the death window.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: isolate mt/hb writes from `be` throttle + gate timer on canWriteReport

Qodo flagged two real issues on #7842:

1. The single shared `lastReportT` made `mt` writes poison the `be`
   throttle window. Slow tests trigger an `mt` write at +150 ms, then
   the test ends a few ms later, and the NEXT test's `beforeEach`
   landed within the 100 ms throttle from the `mt` write — so its
   own `be` snapshot was suppressed. That's the exact boundary
   coverage the throttle is supposed to PROTECT. Local repro with a
   180 ms slow test followed by a fast one confirmed: the fast
   test's `be-0004` is now captured instead of swallowed.

   Fix: split into `lastBoundaryT` used and updated only by `be`
   writes. `hb` and `mt` pass `updateThrottle=false` and never
   advance the boundary timestamp.

2. `setTimeout` was being scheduled in `beforeEach` for every test
   even when `canWriteReport` is false (Linux backend matrix, local
   dev). That's a wasted timer per test for no possible diagnostic
   output. Gate the schedule itself on `canWriteReport`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This flag gates the ep_* passthrough on padoptions that shipped in 3.0.0
(PR #7698). It was introduced as opt-in, but the intent in shipping it
was to let plugins like ep_plugin_helpers' padToggle / padSelect ride
the existing broadcast/persist rail out of the box — flipping the
default closes the gap.

Why now
- ep_comments_page#422 (and sibling per-plugin reports discussed on
  Discord): stock 3.x deployments console.warn on every pad load because
  the helper detects clientVars.enablePluginPadOptions === false and
  tells the admin to flip it. With the flag default-true, the warning
  stops firing on fresh installs while still surfacing for operators
  who have explicitly opted out.
- Plugins that already depend on ep_plugin_helpers >= 0.6 expect the
  pad-wide path to work; the default-false gate silently no-op'd
  pad.changePadOption('ep_*', …) and made the helper UI inert.

Scope
- Settings.ts default flipped to true; comment rewritten to describe
  the new "operator opt-out" model rather than the old AGENTS.MD §52
  opt-in framing (that policy still applies to *new* features; this
  one has shipped and proven safe).
- settings.json.template env-var substitution default flipped to true
  so docker / supervisor configs without an explicit value get the
  new behavior.
- doc/plugins.md updated to match (default true, opt-out via
  settings.json) and the PluginCapabilities source comment.
- Backend test describe-blocks relabeled — "true" is now "(default)",
  "false" is now "(operator opt-out)". Both branches still cover the
  same matrix so the size-cap / namespace-validation paths stay
  exercised.

Compat
- Existing deployments with an explicit `"enablePluginPadOptions":
  false` in settings.json keep that value — no migration needed.
- Older clients only read clientVars.enablePluginPadOptions; the
  protocol shape is unchanged.

Closes ep_comments_page#422 (helper warning suppression for stock
deployments).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@JohnMcLear JohnMcLear force-pushed the fix/enable-plugin-pad-options-default-true branch from 9d0c739 to 438fc43 Compare May 25, 2026 13:39
@JohnMcLear JohnMcLear merged commit 79e3d46 into develop May 25, 2026
32 of 33 checks passed
@JohnMcLear JohnMcLear deleted the fix/enable-plugin-pad-options-default-true branch May 25, 2026 13:43
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.

"pad-wide settings unavailable" message on console

2 participants