Skip to content

fix(settings): guard /settings dialog to project-scoped keys#106

Merged
shoom1 merged 1 commit into
developfrom
fix/settings-ui-project-scope-guard
Jul 16, 2026
Merged

fix(settings): guard /settings dialog to project-scoped keys#106
shoom1 merged 1 commit into
developfrom
fix/settings-ui-project-scope-guard

Conversation

@shoom1

@shoom1 shoom1 commented Jul 16, 2026

Copy link
Copy Markdown
Owner

Policy

Follow-up to #105, per review discussion: settings that persist at user level must not be editable via /settings. A dialog edit to a non-allowlisted key would land in the user ~/.{app}/settings.json and silently apply across all projects of the app.

Change

_build_ui_items() — the single funnel every dialog item passes through — now excludes any key whose target field is not in PROJECT_SETTABLE_KEYS, logging user_scoped_setting_excluded_from_ui per key so app developers discover the policy at dev time instead of debugging a missing item. Since the dialog result dict can only contain keys of rendered items, this one check covers the whole /settings path.

Details:

  • The synthetic model key passes via a _UI_KEY_TARGET_FIELDS alias (set_model() writes default_model, which is allowlisted). Any future synthetic key must declare its target field or it is excluded — deny-by-default, same posture as P0-1.
  • Dangling keys for removed fields (e.g. airesearcher's log_activity) now warn instead of being silently skipped.
  • No escape hatch by design; if a domain app ever needs a user-scoped toggle in its dialog, that should be a deliberate, reviewed framework change.
  • Programmatic update_setting()/save_settings() with user-scoped keys stays legitimate — the trust-split save from fix(settings): trust-split save so /settings changes survive the P0-1 allowlist #105 remains their writer; the dialog just can't produce them.

Current exposure audit (why this is safe to enforce now): base dialog shows model + thinking_effort; research_demo adds verbose_thinking — all project-scoped, so nothing visible changes for existing apps.

Tests

TDD: 4 tests in tests/cli/test_settings_ui_scope.py written first and watched fail — user-scoped key excluded with warning, allowlisted keys render warning-free, model passes the guard, dangling key warns. Full offline suite: 1981 passed.

https://claude.ai/code/session_01SwkKXQpy3JLEqrPkQA8QRv

Policy follow-up to #105: settings that persist at user level must not be
editable via /settings — a dialog edit to a non-allowlisted key would land
in ~/.{app}/settings.json and silently apply across all projects of the
app.

_build_ui_items() now excludes (with a per-key warning) any key whose
target field is not in PROJECT_SETTABLE_KEYS, regardless of what a domain
app returns from get_ui_setting_keys(). The synthetic "model" key passes
via the _UI_KEY_TARGET_FIELDS alias (set_model() writes default_model,
which is allowlisted). Dangling keys for removed fields (e.g.
airesearcher's log_activity) now warn instead of being silently skipped.

Programmatic update_setting()/save_settings() with user-scoped keys stays
legitimate — the split-save from #105 remains their writer; the dialog
just can't produce them.

Claude-Session: https://claude.ai/code/session_01SwkKXQpy3JLEqrPkQA8QRv
@shoom1
shoom1 merged commit 151d31e into develop Jul 16, 2026
2 checks passed
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