Skip to content

sync never reports that owners LOST access — the artifact a fleet collects cannot distinguish co-owning from displacing #32

Description

@jordonpeterson

Severity: high. Independently named the single highest-value improvement by two user tests (a platform engineer running a 100-repo rollout, and a reorg manager). Pre-existing.

sync --format json / --summary-out is what docs/FLEET.md loops over. For a displacing change it carries no before-state at all.

Repro

The README's own advice for a displacing baseline is "run set_owners(*, …) on its own first". Run it against a repo with hand-curated ownership:

cot sync --repo danger --op 'set_owners(*, [@acme/everyone])'
applied: 1 op(s) applied, 0 skipped; 1 line change(s), 5 path(s) change owners
  ops[0]  applied (proven: tree)                                            # exit 0

@acme/appsec and @acme/security-leads just lost the scanners directory. The change record:

{ "action": "insert", "line": 18, "pattern": "*",
  "new_owners": ["@acme/everyone"],
  "reason": "inserted after the last rule whose match set intersects the scope ... (R-3)" }

No old_owners (the record is line-level; an insert has no previous line), warnings: null, and the PR body a reviewer sees says only:

- status: `applied`
- paths whose owners change: 5

Five paths changed. Not "three teams stop owning things". Nothing in the sync path distinguishes co-owning 5 files from displacing 5 files' owners.

The information already exists

plan --out on the identical op emits full ownership_rows with owners_before: ["@acme/appsec","@acme/security-leads"] → owners_after: ["@acme/everyone"]. But plan is the deliberate two-step path and FLEET.md is explicit that a rollout loops over sync, so at fleet scale the artifact that would catch this is the one you do not have.

Suggested fix

Put owners_removed (or the whole ownership_rows) into the sync record, and give --summary-out an Owners losing access section whenever any path's owner set shrinks. The tool already computes it; this is surfacing, not new analysis.

Related: the R-8 refusal hands the operator a copy-pasteable instruction into exactly this unguarded operation — tracked separately in #35.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions