Skip to content

refactor(sections)!: one helper per repeated concept; the snapshot notes teams and collaborators leave out use the shared template - #212

Merged
Vivswan merged 6 commits into
mainfrom
refactor/sections-shared-helpers
Sep 13, 2026
Merged

Vivswan merged 6 commits into
mainfrom
refactor/sections-shared-helpers

Conversation

@Vivswan

@Vivswan Vivswan commented Sep 13, 2026 •

Copy link
Copy Markdown
Owner

Before / after

before   collaborators/index.ts   `${label}: the live role "${role}" has no declaration that plans as itself (...), so it cannot be read back`   (throw)
         teams/index.ts           `${label}: the live role "${role}" has no declaration that plans as itself (...); not declared`              (note)
         teams/index.ts           `teams: owner "o" is a personal account, not an organization, so team access does not apply`
         custom_properties/       `custom_properties: owner "o" is a personal account, and custom properties require an organization-owned repository`
         nine spellings of `<label>: missing - declared in the settings file but not on ...; apply will create it`
         three spellings of `<label>: value of X is not readable; export it into the environment as VAR before apply`

after    shared/roles.ts          readBackPermission(section, label, role, notes)   throws where the default deletes, notes elsewhere
         shared/org-owner.ts      ORG_PROBE + personalAccountNote(section, owner, probe, phase)   one wording for both sections
         contract/module.ts       missingDrift(label, { where, action })
         shared/snapshot-helpers  unreadableSecretNote(label, what, variable)
         + cannotVerifyNote, leftOutOfSnapshot, valueDrift on the sites #202 left: interaction_limits, repository, teams, collaborators, custom_properties, secret_scanning, the engines

What changed

Every repeated line in src/sections renders through one helper: the missing-drift line, the unreadable-secret note, the role no declaration plans as, the personal-account probe, and the cannot-verify, left-out, and field-drift templates on the sites #202 had not reached (three field-drift lines whose suffixes do not fit the four-argument valueDrift stay bespoke: the OIDC claim-key order note in actions/index.ts, the subsetDiff delta with recreate remedies in list-section.ts, and the workflow state line with its raw annotation in workflows/index.ts; the contract-tightening task decides their shape); the four bespoke sections say in their header why they are not on listSection.

Behavior changes

Each has a row in docs/upgrading/v2-to-v3.md section 13 (the section number may shift if another break lands first):

  • Snapshot notes on teams (four kinds), collaborators (owner, expired invitation, email invitation), and an inherited interaction limit use <label>: left out of the snapshot - <reason>; the email invitation is labelled collaborators[invitation <id>].
  • interaction_limits.expiry and the repository toggles GitHub cannot read back use the cannot-verify template.
  • A personal account under teams or custom_properties reads <section>: owner "o" is a personal account, not an organization, so this section does not apply (the plan adds the skip suffix).
  • Nothing else moves: every missing-drift, unreadable-secret, and field-drift line renders byte for byte as before.

Proof

  • Tests and gates: 3468 unit tests green (bun run check clean), bun run test:e2e 260/260 after bun .github/scripts/trim-openapi.ts; the harness below classifies every main-vs-head difference (0 unclassified).
  • Line accounting: production src +248 -139 = +109, tests +15, docs +4. Not net negative; per helper block, adds against the lines it retired:
    • missingDrift +12 (module.ts) retires 7 one-line literals, but its 8 call sites format over 2-3 lines each: about +6 net. Kept for one spelling of a line nine sites render.
    • unreadableSecretNote +8 retires 3 literals of 1-2 lines each: about +3 net. Same reason.
    • readBackPermission +27 (roles.ts) retires the two copies of the role rule (collaborators 9 lines, teams 6): about +12 net, 12 of the added lines its doc comment. The one place the throw-versus-note decision lives.
    • ORG_PROBE + personalAccountNote +33 (org-owner.ts) retire two 6-line probe decls, two personal-account templates, and four probe branches: about -2 in the two sections, +33 in the new file. The one wording for the owner probe both sections declare.
    • the cannotVerifyNote, leftOutOfSnapshot, valueDrift conversions (existing helpers): +40 across interaction_limits, repository, teams, collaborators, secret_scanning, environments, and the engines, every one a literal becoming a formatted call.
    • the four bespoke header sentences: +8.
      The count measures formatting, not text. Three sources make the whole of the growth: the two new files (+60 outside their doc comments), 29 lines of doc comments, and the import-block reflow (+42 -11 = +31, one name per line once a block passes the formatter's width); the section bodies themselves are -13. The owner keeps every helper shared and the headers; the remaining candidate is doc-comment lines that restate the code, folded as a new commit if the gate names any.
Technical details

Base: main at 5dfc10a (#207).

Helpers and their callers

helper callers
missingDrift (contract/module.ts) environments index, branch-policies, protection-rules (where: "enabled on the environment", own action), secret_scanning, list-section, the secrets and variables engines
unreadableSecretNote (shared/snapshot-helpers.ts) environments/snapshot.ts, list-section.ts, repo-secrets.ts
readBackPermission (shared/roles.ts) collaborators (default "delete": throws), teams (default "keep": note)
ORG_PROBE, personalAccountNote (shared/org-owner.ts) teams, custom_properties (which adds primaryRead: { notFound: "absent" }; teams' list is its primary read)
cannotVerifyNote (existing) + interaction_limits.expiry, repository toggles
leftOutOfSnapshot (existing) + teams (4), collaborators (3), interaction_limits inherited
valueDrift (existing) + custom_properties, secret_scanning, repository (toggle, routed), variables engine, environments nested. Out of scope, their suffixes not fitting the template: actions/index.ts (OIDC claim keys, order note), shared/list-section.ts (subsetDiff delta with recreate remedies), workflows/index.ts (state with raw annotation)

Harness (main at 5dfc10a vs this head, same inputs, same matrix as #202): 9268 leaves compared, 24 differing, 0 unclassified; all 24 are the left-out phrase on teams and collaborators snapshot notes. interaction_limits and repository sit outside the harness matrix; their unit tests pin the two cannot-verify lines and the drift lines.

Line accounting (production src = src/** minus *.test.ts, mock.ts, scenarios, docs.yml; against main at 5dfc10a):

file net
src/sections/collaborators/index.ts -8 (the email note inlined, the role rule moved out)
src/sections/teams/index.ts -3
src/sections/environments/snapshot.ts -2
src/sections/shared/repo-secrets.ts, shared/secrets-engine.ts, shared/variables-engine.ts -1 each
src/sections/custom_properties/index.ts 0
src/sections/secret_scanning_custom_patterns/index.ts +2
src/sections/environments/index.ts +3
src/sections/environments/branch-policies.ts +5
src/sections/shared/list-section.ts +6
src/sections/environments/protection-rules.ts, interaction_limits/index.ts, shared/snapshot-helpers.ts +8 each
src/sections/contract/module.ts +12 (missingDrift)
src/sections/repository/index.ts +13 (two valueDrift calls and one cannotVerifyNote, each over several lines)
src/sections/shared/roles.ts +27 (readBackPermission)
src/sections/shared/org-owner.ts +33 (new: ORG_PROBE, personalAccountNote)
total +248 -139 = +109

The conversions replace one-line template literals (many over 150 characters) with formatted calls, so the line count rises; the two new files carry the two concepts that had no home (the role rule, the owner probe), and 34 of the added lines are their doc comments. The owner refused the trims that would un-share a helper (keeping only ORG_PROBE shared, two local copies of the role rule) and keeps the header sentences; doc-comment lines that restate the code are the one remaining candidate, folded as a new commit if the gate names any.

Small fixes on the way: cd8b835 style(scenarios): fold descriptions over the 256 cap folds every scenario line over 256 columns into a >- block (30 lines: 27 descriptions, the three named in the #202 integration review among them, and three long stdout_contains items in the branches and multi-contents-denied scenarios); no yml width gate exists, and none is added here. The four repo-family check-drift scenarios pin GET .../secrets/public-key under never:, so check-mode purity is pinned at the e2e level too; the four secrets docs.yml cells and coverage notes say the key is read at apply, and docs/reference/secrets-and-vaults.md says so in one sentence. custom-properties-personal-account pins the new note text. Three docs.yml phrasings ("noted, not declared") read "left out with a note".

Codex rubber-duck review: round 1 (the fold and helpers commits): 0 blocking, 2 non-blocking (personalAccountNote took probe: object; collaborators kept a one-caller emailInvitationNote), both folded as faa7fad. Round 2 (the secrets docs commit and the fold): 0/1 (three docs.yml lines over 100 columns), wrapped as a fourth commit. Round 3 (the wrap): 0/0. Lead gate review at 58d36de: 0 blocking, 5 non-blocking, folded as the sixth commit (org-owner.ts keeps one doc comment) and these body edits (the three bespoke valueDrift survivors named, the import reflow named as a growth source).

Out-of-territory edits: test/scripts/changed-sections.test.ts pins the new shared file's fan-out (org-owner.ts -> custom_properties, teams), the same one-line pin #202 was granted for list-section.ts.

Recorded, not built: a yml width gate for the scenario corpus.

BEGIN_COMMIT_OVERRIDE
refactor(sections)!: one helper per repeated concept; the snapshot notes teams and collaborators leave out use the shared template

BREAKING CHANGE: the teams, collaborators, and inherited interaction-limit snapshot notes read <label>: left out of the snapshot - <reason>; the interaction_limits.expiry and repository toggle notes use the cannot-verify template; a personal account under teams or custom_properties reads one note (docs/upgrading/v2-to-v3.md section 13).
END_COMMIT_OVERRIDE

Copilot AI balanced review requested due to automatic review settings September 13, 2026 12:06
@github-actions

Copy link
Copy Markdown
Contributor

File size check

0 over a hard cap (fails), 8 warning(s).

File Size Tier Cap
.github/scripts/release-pipeline.ts 1755 lines warn 1600
.github/scripts/release-pipeline.ts:339 168 chars warn 150
.github/scripts/release-pipeline.ts:1 26 comment lines (header) warn 25
.github/scripts/release-pipeline.ts:1572 13 comment lines warn 10
.github/workflows/post-green.yml:139 11 comment lines warn 10
test/action/run.test.ts:759 151 chars warn 150
test/action/run.test.ts:780 155 chars warn 150
test/docs/guides.test.ts:468 155 chars warn 150

Split the file, wrap the line, shorten or exempt the comment, or list the path in .file-size-allow.local with a # reason.

4 managed file(s) skipped; repo-platform owns them.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The shared rendering changes preserve intended behavior and are covered by updated unit, snapshot, and e2e expectations.

Pull request overview

Centralizes repeated section diagnostics while documenting the resulting breaking message changes.

Changes:

  • Adds shared helpers for missing resources, unreadable secrets, role snapshots, and organization-owner probes.
  • Standardizes snapshot and drift messages across affected sections.
  • Updates unit tests, e2e scenarios, and generated documentation.
File summaries
File Description
test/sections/snapshot-rows/teams.ts Updates team snapshot note.
test/sections/snapshot-rows/collaborators.ts Updates collaborator snapshot notes.
test/scripts/changed-sections.test.ts Adds org-owner fan-out coverage.
test/engine/snapshot.test.ts Updates personal-account expectation.
test/e2e/scenarios/snapshot-unsupported-and-denied.yml Wraps scenario description.
test/e2e/scenarios/snapshot-dir-multi-repo.yml Wraps scenario description.
test/e2e/scenarios/multi-contents-denied.yml Wraps expected output.
src/sections/workflows/scenarios/workflows-snapshot-roundtrip.yml Wraps scenario description.
src/sections/webhooks/scenarios/webhooks-snapshot-roundtrip.yml Wraps scenario description.
src/sections/teams/teams.test.ts Updates standardized note assertions.
src/sections/teams/teams.docs.yml Updates snapshot terminology.
src/sections/teams/scenarios/teams-snapshot-roundtrip.yml Updates scenario prose and output.
src/sections/teams/index.ts Uses shared owner, role, and snapshot helpers.
src/sections/shared/variables-engine.ts Uses shared missing-drift rendering.
src/sections/shared/snapshot-helpers.ts Adds unreadable-secret note helper.
src/sections/shared/secrets-engine.ts Uses shared missing-drift rendering.
src/sections/shared/roles.ts Adds shared role snapshot handling.
src/sections/shared/repo-secrets.ts Uses unreadable-secret note helper.
src/sections/shared/org-owner.ts Adds shared organization-owner probe handling.
src/sections/shared/list-section.ts Uses shared drift and secret-note helpers.
src/sections/secret_scanning_custom_patterns/scenarios/secret-scanning-custom-patterns-snapshot-roundtrip.yml Wraps scenario description.
src/sections/secret_scanning_custom_patterns/index.ts Uses shared value and missing drift helpers.
src/sections/rulesets/scenarios/rulesets-snapshot-roundtrip.yml Wraps scenario description.
src/sections/rulesets/scenarios/rulesets-snapshot-bypass-hidden.yml Wraps scenario description.
src/sections/repository/scenarios/repository-snapshot-roundtrip.yml Wraps scenario description.
src/sections/repository/index.ts Uses shared value and verification notes.
src/sections/pages/scenarios/pages-snapshot-roundtrip.yml Wraps scenario description.
src/sections/milestones/scenarios/milestones-snapshot-roundtrip.yml Wraps scenario description.
src/sections/labels/scenarios/labels-snapshot-roundtrip.yml Wraps scenario description.
src/sections/interaction_limits/scenarios/interaction-limits-snapshot-roundtrip.yml Wraps scenario description.
src/sections/interaction_limits/interaction_limits.test.ts Updates verification-note assertion.
src/sections/interaction_limits/interaction_limits.docs.yml Updates snapshot terminology.
src/sections/interaction_limits/index.ts Uses shared verification and omission helpers.
src/sections/environments/snapshot.ts Uses unreadable-secret note helper.
src/sections/environments/protection-rules.ts Uses shared missing-drift rendering.
src/sections/environments/index.ts Uses shared missing-drift rendering.
src/sections/environments/branch-policies.ts Uses shared missing-drift rendering.
src/sections/deploy_keys/scenarios/deploy-keys-snapshot-roundtrip.yml Wraps scenario description.
src/sections/dependabot_secrets/scenarios/dependabot-secrets-snapshot-roundtrip.yml Wraps scenario description.
src/sections/dependabot_secrets/scenarios/dependabot-secrets-check-drift.yml Verifies check mode skips key reads.
src/sections/dependabot_secrets/dependabot_secrets.docs.yml Documents apply-time key reads.
src/sections/custom_properties/scenarios/custom-properties-snapshot-roundtrip.yml Wraps scenario description.
src/sections/custom_properties/scenarios/custom-properties-personal-account.yml Updates personal-account output.
src/sections/custom_properties/index.ts Uses shared owner and value helpers.
src/sections/custom_properties/custom_properties.test.ts Updates personal-account assertion.
src/sections/contract/module.ts Adds shared missing-drift helper.
src/sections/collaborators/scenarios/collaborators-snapshot-roundtrip.yml Updates snapshot-note outputs.
src/sections/collaborators/scenarios/collaborators-snapshot-expired-invitation.yml Updates expired-invitation note.
src/sections/collaborators/index.ts Uses shared role and omission helpers.
src/sections/collaborators/collaborators.test.ts Updates standardized note assertions.
src/sections/collaborators/collaborators.docs.yml Updates snapshot terminology.
src/sections/codespaces_secrets/scenarios/codespaces-secrets-snapshot-roundtrip.yml Wraps scenario description.
src/sections/codespaces_secrets/scenarios/codespaces-secrets-check-drift.yml Verifies check mode skips key reads.
src/sections/codespaces_secrets/codespaces_secrets.docs.yml Documents apply-time key reads.
src/sections/code_scanning_default_setup/scenarios/code-scanning-default-setup-snapshot-roundtrip.yml Wraps scenario description.
src/sections/code_quality_setup/scenarios/code-quality-setup-snapshot-roundtrip.yml Wraps scenario description.
src/sections/branches/scenarios/branches-missing-branch-no-contents-apply-warn-fails.yml Wraps expected error output.
src/sections/branches/scenarios/branches-missing-branch-no-contents-apply-fails.yml Wraps expected error output.
src/sections/autolinks/scenarios/autolinks-snapshot-roundtrip.yml Wraps scenario description.
src/sections/agents_variables/scenarios/agents-variables-snapshot-roundtrip.yml Wraps scenario description.
src/sections/agents_secrets/scenarios/agents-secrets-snapshot-roundtrip.yml Wraps scenario description.
src/sections/agents_secrets/scenarios/agents-secrets-check-drift.yml Verifies check mode skips key reads.
src/sections/agents_secrets/agents_secrets.docs.yml Documents apply-time key reads.
src/sections/actions/scenarios/actions-snapshot-roundtrip.yml Wraps scenario description.
src/sections/actions_variables/scenarios/actions-variables-snapshot-roundtrip.yml Wraps scenario description.
src/sections/actions_secrets/scenarios/actions-secrets-snapshot-roundtrip.yml Wraps scenario description.
src/sections/actions_secrets/scenarios/actions-secrets-check-drift.yml Verifies check mode skips key reads.
src/sections/actions_secrets/actions_secrets.docs.yml Documents apply-time key reads.
docs/upgrading/v2-to-v3.md Documents breaking wording changes.
docs/reference/sections.md Updates generated section reference.
docs/reference/secrets-and-vaults.md Documents apply-time sealing-key reads.
COVERAGE.md Updates coverage and behavior documentation.
Review details
  • Files reviewed: 72/72 changed files
  • Comments generated: 0
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Copilot AI review requested due to automatic review settings September 13, 2026 12:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The shared helpers preserve existing behavior where required, and intentional output changes are comprehensively tested and documented.

Review details
  • Files reviewed: 72/72 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced (auto)

Note

Copilot is running an experiment and ran this review at Balanced.

@Vivswan
Vivswan marked this pull request as ready for review September 13, 2026 12:27
@Vivswan Vivswan added the merge-when-green Owner approved: merge once every gate is green label Sep 13, 2026
@Vivswan
Vivswan merged commit aa1f86f into main Sep 13, 2026
39 checks passed
@Vivswan
Vivswan deleted the refactor/sections-shared-helpers branch September 13, 2026 19:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-when-green Owner approved: merge once every gate is green

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants