Skip to content

feat(permissions): setup autonomy: detect + warn + offer-to-remove overlay attributes that override the intended posture#401

Merged
aleskalfas merged 1 commit into
mainfrom
feat/399-setup-autonomy-detect-warn-offer
Jun 30, 2026
Merged

feat(permissions): setup autonomy: detect + warn + offer-to-remove overlay attributes that override the intended posture#401
aleskalfas merged 1 commit into
mainfrom
feat/399-setup-autonomy-detect-warn-offer

Conversation

@aleskalfas

Copy link
Copy Markdown
Owner

What

pkit permissions setup autonomy now detects per-machine settings.local.json attributes that override the intended autonomy posture, warns loudly, and offers consent-gated removal. Generalizes #313 (the autoAllowBashIfSandboxed split-brain) from one override to the whole class.

  • Detection is platform-aware: _intended_sandbox_on returns False on macOS (intended posture is sandbox-OFF per [Feature] setup autonomy must not enable a macOS-incompatible sandbox (detect platform; warn or skip) #336), True elsewhere. Judges enabled against the platform-correct intent (on macOS enabled:false agrees with intent and is not flagged; enabled:true is) and allowUnsandboxedCommands:true (un-seals ADR-028) on any platform. Reads only the gitignored overlay — the committed floor is the intended posture, never a finding.
  • Override vs cruft: genuine overrides (defeat the posture) render with + a "how it defeats" line, labelled remove-to-restore-autonomy; inert cruft (e.g. dead excludedCommands with the box off) renders with ·, labelled remove-to-tidy.
  • Consent-gated removal via --remove-overrides (auto-confirm) or interactive click.confirm; deliberately not wired to any blanket --yes (the trust-gesture exemption). Declined / non-interactive → warn-only, file untouched.
  • Whole-file vs attributes-only: unlink the whole settings.local.json only when nothing of value remains after stripping findings (decided on a deep copy); else strip only the finding keys, leaving every other key byte-faithful.
  • Committed baseline never touched — detector + remover only ever read/write settings.local.json; a dedicated test asserts the committed settings.json is byte-identical before/after.

Composition with #313's seal (architect-confirmed)

Order is detect → confinement step (sandbox_enable(strict) re-asserts #313's seal) → report/remove. Removal re-detects post-seal and removes only what is still a finding — so a required-attr override the seal already reconciled is reported "already reconciled" rather than double-handled. The seal stays the single writer of allowUnsandboxedCommands (ADR-028 dp-2); #399 defers to it and removes only the slice no primitive owns (cruft everywhere + the macOS enabled inversion). Warn is wide (honesty, all platforms); removal is narrow (only where this feature owns the key). Architect review: no escalation, no reorder needed.

Verification

  • 16 new tests; full permissions suite 242 pass; full suite 4122 pass.
  • pkit schemas validate (13 pass); migrations check-diff --include-working-tree --base main clean (pure addition).
  • Live .claude/settings.local.json untouched (tests use tmp_path trees).

Version / migration

Backbone (src/project_kit/permissions.py) — .pkit/VERSION 1.130.2 → 1.131.0 (new flag + new principle = surface change per PRJ-002); package.yaml requires_backbone auto-broadened. No migration (additive).

Doc impact

  • .pkit/cli/README.md — detection/removal behavior + --remove-overrides on the setup autonomy row.

Follow-up (non-blocking, architect-flagged)

On macOS a settings.local.json containing only sandbox.enabled:true is whole-file-unlinked rather than routed through sandbox_disable (the key's owning primitive). Consent-gated, macOS-only, reversible — correct today, but routing the macOS enabled override through sandbox_disable would keep the "remove via the owning primitive" discipline the seal path follows. Worth a later tidy, not a blocker.

Closes #399

🤖 Generated with Claude Code

…rlay attributes

setup autonomy now detects per-machine settings.local.json attributes that
override the intended autonomy posture (platform-aware: macOS intended =
sandbox-OFF per #336, else ON), warns loudly naming each override and how it
defeats the posture, and offers consent-gated removal via --remove-overrides
(whole-file when purely overriding, else attributes-only preserving other keys).

Detection reads only the gitignored per-machine overlay; the committed baseline
is never opened for write. Removal flows through a consent gate and is
deliberately not wired to any blanket --yes (the trust-gesture exemption).
Composes with #313's seal: detect runs pre-confinement, removal re-detects
post-seal and reports already-reconciled required-attrs rather than double-handling.
Distinguishes genuine overrides (remove-to-restore-autonomy) from inert cruft
(remove-to-tidy).

Surface change (new flag + new principle) -> backbone 1.130.2 -> 1.131.0.

Closes #399

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@aleskalfas

Copy link
Copy Markdown
Owner Author

Reviewer agent (local, reviewer): APPROVED

  • Branch shape ✓ pass — feat/399-setup-autonomy-detect-warn-offer matches <type>/<issue-number>-<slug> ([project-management:DEC-013-branch-and-pr-conventions], git-conventions.yaml branch-name).
  • Branch-type / issue-type alignment ✓ pass — issue [Feature] setup autonomy: detect + warn + offer-to-remove overlay attributes that override the intended posture #399 is type:feature; pr_type_mapping maps feature → feat; branch type is feat (classification.yaml pr_type_mapping).
  • PR title Conventional Commits + type match ✓ pass — title parses as feat(permissions): … with an accepted type, and feat matches the issue's type:feature (COR-008 + [project-management:DEC-013-branch-and-pr-conventions]).
  • Issue classification complete ✓ pass — [Feature] setup autonomy: detect + warn + offer-to-remove overlay attributes that override the intended posture #399 carries type:feature, priority:Medium, and workstream:permissions — all three mandated axes present ([project-management:DEC-012-classification-axes]).
  • PR body links closing issue ✓ pass — Closes #399 in the body and closingIssuesReferences populated with [Feature] setup autonomy: detect + warn + offer-to-remove overlay attributes that override the intended posture #399 ([project-management:DEC-013-branch-and-pr-conventions], git-conventions.yaml pr-body).
  • ## Doc impact section ✓ pass — present, mirroring the .pkit/cli/README.md edit (git-conventions.yaml pr-body, hard-reject rule).
  • Surface-change discipline ✓ pass — backbone surface change (new --remove-overrides flag + new principle); .pkit/VERSION bumped 1.130.2 → 1.131.0 (minor, correct for an additive surface change per PRJ-002), package.yaml requires_backbone auto-broadened to <1.132.0. No renames/removals, no schema_version bumps, no capability subtree restructure — pure addition; migrations check-diff reported clean, so no migration is owed (COR-010).
  • No-shared-files invariant ✓ pass — touched paths are project-kit's own source (src/project_kit/*, tests/*, .pkit/cli/README.md, .pkit/VERSION, the adapter package.yaml). project-kit self-hosts; these are project-owned source files, not installed core-owned files in an adopter tree (COR-001).
  • warning — verification checkboxes live under a ## Verification heading rather than the schema's recommended ## Test plan (git-conventions.yaml pr-body, body.placeholder.empty-checkbox-section keys on an empty required section; here the section carries authored items — 4122-pass suite, schemas validate, check-diff clean — so it is informational only, not gate-blocking).

@aleskalfas aleskalfas merged commit 0fc9454 into main Jun 30, 2026
1 check passed
@aleskalfas aleskalfas deleted the feat/399-setup-autonomy-detect-warn-offer branch June 30, 2026 19:36
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.

[Feature] setup autonomy: detect + warn + offer-to-remove overlay attributes that override the intended posture

1 participant