Skip to content

Resolve HB-001: transfer to Lucent-Financial-Group; land GitHub-settings-as-code + drift detector#45

Merged
AceHack merged 5 commits intomainfrom
post-transfer-declarative-settings
Apr 21, 2026
Merged

Resolve HB-001: transfer to Lucent-Financial-Group; land GitHub-settings-as-code + drift detector#45
AceHack merged 5 commits intomainfrom
post-transfer-declarative-settings

Conversation

@AceHack
Copy link
Copy Markdown
Member

@AceHack AceHack commented Apr 21, 2026

Summary

  • Executes the AceHack/Zeta → Lucent-Financial-Group/Zeta org migration that was filed as HB-001 (completed instantly via POST /repos/AceHack/Zeta/transfer; this PR is the landing of the follow-up artifacts on the new home).
  • Lands the hygiene pattern the migration taught us: declarative expected state + cadenced drift detector for GitHub settings that lack native config-as-code. Founding incident was GitHub's org-transfer code path silently flipping secret_scanning + secret_scanning_push_protection from enabled to disabled.
  • Pattern generalizes beyond GitHub — any click-ops platform gets the same markdown-declaration + cadenced-diff treatment when adopted.

What landed

  • docs/GITHUB-SETTINGS.md — human-readable narrative declaration
  • tools/hygiene/github-settings.expected.json — machine-readable canonical state
  • tools/hygiene/snapshot-github-settings.sh — normalized snapshot producer
  • tools/hygiene/check-github-settings-drift.sh — detector (exit 1 on drift)
  • .github/workflows/github-settings-drift.yml — weekly cron (Mondays 14:17 UTC) + workflow_dispatch + PR-triggered on tooling changes
  • docs/FACTORY-HYGIENE.md row hygiene: gitignore .claude/worktrees/ — parallel-research scratch #40 — full cadence / owner / checks spec
  • docs/HUMAN-BACKLOG.md — HB-001 marked Resolved with migration + drift summary
  • docs/ROUND-HISTORY.md — late-Round-44 arc paragraph

Test plan

  • Drift detector runs clean against live repo (tools/hygiene/check-github-settings-drift.sh exit 0)
  • Snapshot script produces deterministic output (re-run no diff)
  • Workflow YAML uses only trusted first-party context (secrets.GITHUB_TOKEN, github.repository) passed via env: into quoted run block
  • CI gate (build-and-test, semgrep, actionlint, markdownlint, shellcheck) green on this PR
  • github-settings-drift PR-triggered job green on this PR (validates that the new expected snapshot matches live state)

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings April 21, 2026 13:51
@AceHack AceHack enabled auto-merge (squash) April 21, 2026 13:51
AceHack added a commit that referenced this pull request Apr 21, 2026
- docs/ROUND-HISTORY.md: `+` at line-start parsed as bullet by
  markdownlint (MD032); replace with "and" in the two affected
  wrap points.
- .github/workflows/github-settings-drift.yml: drop
  `administration: read` — actionlint v1.7.x does not list it
  as a recognised scope; the default GITHUB_TOKEN on public
  repos covers the endpoints we read. Comment documents the
  trade + the fact that the PR-triggered drift check would
  surface a missing scope immediately.
- tools/hygiene/snapshot-github-settings.sh: drop dead
  `rulesets_json` assignment (SC2034) — the `ruleset_details`
  loop below returns the full per-ruleset data used in the
  final jq output.

Aaron's follow-up "you also didn't get half the settings you
miss most of them lol it's okay" is acknowledged — a coverage
expansion PR will follow this one. The current snapshot is a
first pass; PR #45 lands the *pattern* (decl + drift detector
+ hygiene row) and we iterate on coverage.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR lands the post–org-transfer follow-up artifacts for HB-001 by introducing “GitHub settings as code (by convention)”: a checked-in expected snapshot plus scripts/workflow to detect drift in repo settings that aren’t natively declarative in-tree.

Changes:

  • Add tools/hygiene/* scripts + canonical github-settings.expected.json snapshot to generate and diff live GitHub settings.
  • Add a scheduled + PR-triggered GitHub Actions workflow to run the drift detector.
  • Document the expected GitHub settings and record HB-001/migration narrative in docs.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
tools/hygiene/snapshot-github-settings.sh New snapshot generator that queries GitHub API surfaces and outputs normalized JSON.
tools/hygiene/check-github-settings-drift.sh New drift detector that diffs live snapshot vs checked-in expected JSON.
tools/hygiene/github-settings.expected.json Checked-in canonical expected settings snapshot used as the drift baseline.
.github/workflows/github-settings-drift.yml Weekly + PR-triggered workflow to run the drift check in CI.
docs/GITHUB-SETTINGS.md Human-readable narrative declaration of expected GitHub settings and update process.
docs/FACTORY-HYGIENE.md Adds a factory hygiene row describing the drift detector cadence/scope.
docs/HUMAN-BACKLOG.md Marks HB-001 as resolved with a migration + verification summary.
docs/ROUND-HISTORY.md Records the late-round migration arc and introduces the drift-detector pattern.

Comment thread docs/GITHUB-SETTINGS.md Outdated
Comment on lines +219 to +224
- `memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
— the framing / pattern.
- `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md`
— why the `code_scanning` ruleset rule is off.
- `memory/project_zeta_org_migration_to_lucent_financial_group.md`
— the migration that triggered this discipline.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: The “Related” section references several memory/* files that are not present in the repo (feedback_github_settings_as_code_declarative_checked_in_file.md, reference_github_code_scanning_ruleset_rule_requires_default_setup.md, project_zeta_org_migration_to_lucent_financial_group.md). Please add those files or remove/replace the references.

Suggested change
- `memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
— the framing / pattern.
- `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md`
— why the `code_scanning` ruleset rule is off.
- `memory/project_zeta_org_migration_to_lucent_financial_group.md`
— the migration that triggered this discipline.

Copilot uses AI. Check for mistakes.
Comment thread docs/GITHUB-SETTINGS.md
against the expected JSON. Exit 0 on match, 1 on drift.
3. **Cadence** is enforced by
`.github/workflows/github-settings-drift.yml` — weekly cron
+ `workflow_dispatch` for manual runs. Drift blocks the
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: In the numbered list, this line starting with + will render as a nested unordered list item (not as “cron plus workflow_dispatch” text). If the intent is prose, rewrite without a leading list marker (e.g., “and workflow_dispatch …”).

Suggested change
+ `workflow_dispatch` for manual runs. Drift blocks the
and `workflow_dispatch` for manual runs. Drift blocks the

Copilot uses AI. Check for mistakes.
Comment thread docs/FACTORY-HYGIENE.md Outdated
Comment on lines 84 to 85
| 40 | GitHub-settings drift detector | Weekly (cron `17 14 * * 1`) + on any change to `tools/hygiene/github-settings.expected.json` / detector script / workflow file. Added 2026-04-21 after `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` org-transfer silently flipped `secret_scanning` and `secret_scanning_push_protection` from enabled to disabled. | Automated (`.github/workflows/github-settings-drift.yml`); human resolves on drift | factory (ships to adopters as a template; repo-specific expected snapshot per adopter) | Live `gh api` snapshot vs. checked-in `tools/hygiene/github-settings.expected.json`: repo-level toggles (merge methods, security-and-analysis), rulesets + rule contents, classic branch protection on default branch, Actions permissions + variables + counts of secrets, environments + protection-rule types, Pages config, CodeQL default-setup state, webhook / deploy-key / secret counts. Script at `tools/hygiene/check-github-settings-drift.sh` exits 1 on drift and prints `diff -u` output. Resolution: intentional → re-snapshot + commit new expected with rationale; unintentional → revert in GitHub + rerun detector. | `docs/GITHUB-SETTINGS.md` + `tools/hygiene/github-settings.expected.json` + workflow run log + optional `memory/reference_github_*.md` entry if drift source is non-obvious | `feedback_github_settings_as_code_declarative_checked_in_file.md` + `feedback_blast_radius_pricing_standing_rule_alignment_signal.md` + `project_zeta_org_migration_to_lucent_financial_group.md` |
| 39 | Hot-file-path detector | Round-cadence (every round close) or every 5-10 rounds — whichever catches churn drift before the next merge-tangle. Proposed 2026-04-21. | TBD — candidate capability skill `hot-file-detector` (queued in BACKLOG P1); Architect runs inline until the skill lands. | factory (ships to adopters as a command-line recipe) | `git log --since="60 days ago" --name-only --pretty=format: \| grep -v '^$' \| sort \| uniq -c \| sort -rn \| head -25` — git history *is* the index. Heuristic threshold: >20 changes in 60d on a single monolithic doc = investigate; >30 = refactor candidate (tune after 5-10 rounds). Per-file decision is one of four: `refactor-split` (per-row, per-round, per-section), `consolidate-reduce` (merge with a sibling), `accept-as-append-only` (legitimately append-only → split into per-round files rather than trimming), or `observe`. Pair with merge-tangle fingerprints from `docs/research/parallel-worktree-safety-2026-04-22.md` §9 — a hot file is worse if also in a recent conflict list. Triggering incident: PR #31 5-file merge-tangle (2026-04-21) where `docs/ROUND-HISTORY.md` at 33 changes / 60d was the #1 conflict source, and `docs/BACKLOG.md` at 26 already has an in-flight split ADR. | Audit doc per cycle listing top-N hot paths + per-file decision; BACKLOG rows for refactor-split candidates; ADRs for structural changes. | `feedback_hot_file_path_detector_hygiene.md` + `docs/DECISIONS/2026-04-22-backlog-per-row-file-restructure.md` (same pattern) |
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: Table ordering/numbering looks inconsistent: row 40 is inserted before row 39. If row numbers are meant to be sequential, renumber/reorder to keep the table stable for future references (people will cite these row numbers elsewhere).

Suggested change
| 40 | GitHub-settings drift detector | Weekly (cron `17 14 * * 1`) + on any change to `tools/hygiene/github-settings.expected.json` / detector script / workflow file. Added 2026-04-21 after `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` org-transfer silently flipped `secret_scanning` and `secret_scanning_push_protection` from enabled to disabled. | Automated (`.github/workflows/github-settings-drift.yml`); human resolves on drift | factory (ships to adopters as a template; repo-specific expected snapshot per adopter) | Live `gh api` snapshot vs. checked-in `tools/hygiene/github-settings.expected.json`: repo-level toggles (merge methods, security-and-analysis), rulesets + rule contents, classic branch protection on default branch, Actions permissions + variables + counts of secrets, environments + protection-rule types, Pages config, CodeQL default-setup state, webhook / deploy-key / secret counts. Script at `tools/hygiene/check-github-settings-drift.sh` exits 1 on drift and prints `diff -u` output. Resolution: intentional → re-snapshot + commit new expected with rationale; unintentional → revert in GitHub + rerun detector. | `docs/GITHUB-SETTINGS.md` + `tools/hygiene/github-settings.expected.json` + workflow run log + optional `memory/reference_github_*.md` entry if drift source is non-obvious | `feedback_github_settings_as_code_declarative_checked_in_file.md` + `feedback_blast_radius_pricing_standing_rule_alignment_signal.md` + `project_zeta_org_migration_to_lucent_financial_group.md` |
| 39 | Hot-file-path detector | Round-cadence (every round close) or every 5-10 rounds — whichever catches churn drift before the next merge-tangle. Proposed 2026-04-21. | TBD — candidate capability skill `hot-file-detector` (queued in BACKLOG P1); Architect runs inline until the skill lands. | factory (ships to adopters as a command-line recipe) | `git log --since="60 days ago" --name-only --pretty=format: \| grep -v '^$' \| sort \| uniq -c \| sort -rn \| head -25` — git history *is* the index. Heuristic threshold: >20 changes in 60d on a single monolithic doc = investigate; >30 = refactor candidate (tune after 5-10 rounds). Per-file decision is one of four: `refactor-split` (per-row, per-round, per-section), `consolidate-reduce` (merge with a sibling), `accept-as-append-only` (legitimately append-only → split into per-round files rather than trimming), or `observe`. Pair with merge-tangle fingerprints from `docs/research/parallel-worktree-safety-2026-04-22.md` §9 — a hot file is worse if also in a recent conflict list. Triggering incident: PR #31 5-file merge-tangle (2026-04-21) where `docs/ROUND-HISTORY.md` at 33 changes / 60d was the #1 conflict source, and `docs/BACKLOG.md` at 26 already has an in-flight split ADR. | Audit doc per cycle listing top-N hot paths + per-file decision; BACKLOG rows for refactor-split candidates; ADRs for structural changes. | `feedback_hot_file_path_detector_hygiene.md` + `docs/DECISIONS/2026-04-22-backlog-per-row-file-restructure.md` (same pattern) |
| 39 | Hot-file-path detector | Round-cadence (every round close) or every 5-10 rounds — whichever catches churn drift before the next merge-tangle. Proposed 2026-04-21. | TBD — candidate capability skill `hot-file-detector` (queued in BACKLOG P1); Architect runs inline until the skill lands. | factory (ships to adopters as a command-line recipe) | `git log --since="60 days ago" --name-only --pretty=format: \| grep -v '^$' \| sort \| uniq -c \| sort -rn \| head -25` — git history *is* the index. Heuristic threshold: >20 changes in 60d on a single monolithic doc = investigate; >30 = refactor candidate (tune after 5-10 rounds). Per-file decision is one of four: `refactor-split` (per-row, per-round, per-section), `consolidate-reduce` (merge with a sibling), `accept-as-append-only` (legitimately append-only → split into per-round files rather than trimming), or `observe`. Pair with merge-tangle fingerprints from `docs/research/parallel-worktree-safety-2026-04-22.md` §9 — a hot file is worse if also in a recent conflict list. Triggering incident: PR #31 5-file merge-tangle (2026-04-21) where `docs/ROUND-HISTORY.md` at 33 changes / 60d was the #1 conflict source, and `docs/BACKLOG.md` at 26 already has an in-flight split ADR. | Audit doc per cycle listing top-N hot paths + per-file decision; BACKLOG rows for refactor-split candidates; ADRs for structural changes. | `feedback_hot_file_path_detector_hygiene.md` + `docs/DECISIONS/2026-04-22-backlog-per-row-file-restructure.md` (same pattern) |
| 40 | GitHub-settings drift detector | Weekly (cron `17 14 * * 1`) + on any change to `tools/hygiene/github-settings.expected.json` / detector script / workflow file. Added 2026-04-21 after `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` org-transfer silently flipped `secret_scanning` and `secret_scanning_push_protection` from enabled to disabled. | Automated (`.github/workflows/github-settings-drift.yml`); human resolves on drift | factory (ships to adopters as a template; repo-specific expected snapshot per adopter) | Live `gh api` snapshot vs. checked-in `tools/hygiene/github-settings.expected.json`: repo-level toggles (merge methods, security-and-analysis), rulesets + rule contents, classic branch protection on default branch, Actions permissions + variables + counts of secrets, environments + protection-rule types, Pages config, CodeQL default-setup state, webhook / deploy-key / secret counts. Script at `tools/hygiene/check-github-settings-drift.sh` exits 1 on drift and prints `diff -u` output. Resolution: intentional → re-snapshot + commit new expected with rationale; unintentional → revert in GitHub + rerun detector. | `docs/GITHUB-SETTINGS.md` + `tools/hygiene/github-settings.expected.json` + workflow run log + optional `memory/reference_github_*.md` entry if drift source is non-obvious | `feedback_github_settings_as_code_declarative_checked_in_file.md` + `feedback_blast_radius_pricing_standing_rule_alignment_signal.md` + `project_zeta_org_migration_to_lucent_financial_group.md` |

Copilot uses AI. Check for mistakes.
name: check drift
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P2: This workflow pins actions/checkout to v4.3.0, while other workflows in this repo are already using a newer pinned major (e.g. v6.0.2 in gate.yml/codeql.yml). Consider aligning on the same pinned version across workflows to reduce supply-chain drift and maintenance overhead.

Suggested change
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
- uses: actions/checkout@v6.0.2

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +32
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo=""
expected="$script_dir/github-settings.expected.json"

while [ $# -gt 0 ]; do
case "$1" in
--repo) repo="$2"; shift 2;;
--expected) expected="$2"; shift 2;;
*) echo "error: unknown arg: $1" >&2; exit 2;;
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: --repo / --expected parsing assumes a value is present ($2), but under set -u running ... --repo without an argument will abort with an unhelpful “unbound variable” error. Add an explicit check for missing option values and print a usage/error message before exiting 2.

Suggested change
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo=""
expected="$script_dir/github-settings.expected.json"
while [ $# -gt 0 ]; do
case "$1" in
--repo) repo="$2"; shift 2;;
--expected) expected="$2"; shift 2;;
*) echo "error: unknown arg: $1" >&2; exit 2;;
usage() {
echo "Usage: tools/hygiene/check-github-settings-drift.sh [--repo OWNER/NAME] [--expected PATH]" >&2
}
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo=""
expected="$script_dir/github-settings.expected.json"
while [ $# -gt 0 ]; do
case "$1" in
--repo)
if [ $# -lt 2 ]; then
echo "error: --repo requires a value" >&2
usage
exit 2
fi
repo="$2"
shift 2
;;
--expected)
if [ $# -lt 2 ]; then
echo "error: --expected requires a value" >&2
usage
exit 2
fi
expected="$2"
shift 2
;;
*)
echo "error: unknown arg: $1" >&2
usage
exit 2
;;

Copilot uses AI. Check for mistakes.
exit 2
}

if diff -u "$expected" "$tmp"; then
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P2: The drift diff currently includes a temp filename in the headers, which makes the output noisier to read. Consider using diff labels (or a stable temp path) so the header lines are stable and clearly indicate “expected” vs “current”.

Suggested change
if diff -u "$expected" "$tmp"; then
if diff -u --label "expected" --label "current" "$expected" "$tmp"; then

Copilot uses AI. Check for mistakes.
Comment thread docs/GITHUB-SETTINGS.md Outdated
Comment on lines +50 to +52
owner / scope specification and
`memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
for the framing this pattern belongs to.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This doc links to memory/feedback_github_settings_as_code_declarative_checked_in_file.md, but that file does not exist in the repository. Either add the referenced memory entry or update/remove the link so readers don’t hit a dead reference.

Suggested change
owner / scope specification and
`memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
for the framing this pattern belongs to.
owner / scope specification and for the broader framing this
pattern belongs to.

Copilot uses AI. Check for mistakes.
Comment thread docs/GITHUB-SETTINGS.md Outdated
Comment on lines +15 to +20
Motivation (Aaron 2026-04-21):

> "its nice having the expected settings declarative defined"
>
> "i hate things in GitHub where I can't check in the
> declarative settgins so we will save a back[up]"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This uses direct contributor name attribution (“Motivation (Aaron …)”), but repo guidance says contributor names should not appear in docs (role references like “human maintainer” are preferred), except in persona memory dirs and optionally docs/BACKLOG.md (see docs/AGENT-BEST-PRACTICES.md:284-290). Please rewrite to a role reference and, if needed, move the named/quoted material into an appropriate memory/persona location.

Suggested change
Motivation (Aaron 2026-04-21):
> "its nice having the expected settings declarative defined"
>
> "i hate things in GitHub where I can't check in the
> declarative settgins so we will save a back[up]"
Motivation:
The human maintainer wants GitHub settings that are otherwise
only configurable through the UI to have a declarative,
checked-in backup so expected state stays reviewable and
recoverable.

Copilot uses AI. Check for mistakes.
Comment thread docs/HUMAN-BACKLOG.md Outdated
| ID | When | Category | Ask | Source | State | Resolution |
|---|---|---|---|---|---|---|
| HB-001 | 2026-04-21 | decision / org-migration | Plan + execute the migration of `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` (Aaron's LFG umbrella org — `project_lucent_financial_group_external_umbrella.md`). Drivers: (a) GitHub gates merge queue and other org-level features to organization-owned repos — user-owned repos cannot enable merge queue on any plan tier, which is the real blocker behind the `422 Invalid rule 'merge_queue':` failure against `POST /repos/AceHack/Zeta/rulesets` (see §10.3 of `docs/research/parallel-worktree-safety-2026-04-22.md`); (b) aligns the repo with Aaron's stated destination for external contributors. **Constraints (Aaron 2026-04-21):** (1) **preserve all current settings** — rulesets, required checks (gate + CodeQL + semgrep), branch-protection behaviours, auto-delete-head-branch, auto-merge, Dependabot, CodeScanning, Copilot Code Review, concurrency groups, workflow triggers incl. `merge_group:`; (2) **public from the start** at the new location — no private-during-transition staging period. No deadline — "at some point". Until transferred, the factory accepts the rebase-tax on serial PRs and relies on `gh pr merge --auto --squash` alone (merge queue off). | `docs/research/parallel-worktree-safety-2026-04-22.md` §10.3; session transcript 2026-04-21 (Aaron: "we can move tih to https://github.com/Lucent-Financial-Group at some point it's my org for LFG" + "we need to move it to lucent for contributor at some point anyways, we want to keep all the settings we have now" + "i think we are going to have to go without merge queue parallelism for now" + "we can just make it public from the start") | Open | — |
| HB-001 | 2026-04-21 | decision / org-migration | Plan + execute the migration of `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` (Aaron's LFG umbrella org — `project_lucent_financial_group_external_umbrella.md`). Drivers: (a) GitHub gates merge queue and other org-level features to organization-owned repos — user-owned repos cannot enable merge queue on any plan tier, which is the real blocker behind the `422 Invalid rule 'merge_queue':` failure against `POST /repos/AceHack/Zeta/rulesets` (see §10.3 of `docs/research/parallel-worktree-safety-2026-04-22.md`); (b) aligns the repo with Aaron's stated destination for external contributors. **Constraints (Aaron 2026-04-21):** (1) **preserve all current settings** — rulesets, required checks (gate + CodeQL + semgrep), branch-protection behaviours, auto-delete-head-branch, auto-merge, Dependabot, CodeScanning, Copilot Code Review, concurrency groups, workflow triggers incl. `merge_group:`; (2) **public from the start** at the new location — no private-during-transition staging period. No deadline — "at some point". Until transferred, the factory accepts the rebase-tax on serial PRs and relies on `gh pr merge --auto --squash` alone (merge queue off). | `docs/research/parallel-worktree-safety-2026-04-22.md` §10.3; session transcript 2026-04-21 (Aaron: "we can move tih to https://github.com/Lucent-Financial-Group at some point it's my org for LFG" + "we need to move it to lucent for contributor at some point anyways, we want to keep all the settings we have now" + "i think we are going to have to go without merge queue parallelism for now" + "we can just make it public from the start") | Resolved | Executed 2026-04-21 via `POST /repos/AceHack/Zeta/transfer` with `new_owner=Lucent-Financial-Group`. Transfer completed instantly (Aaron admin on both sides). Verification diffed 13 settings groups against pre-transfer scorecard: all preserved **except** `secret_scanning` and `secret_scanning_push_protection` both silently flipped `enabled→disabled` by GitHub's org-transfer code path; re-enabled same session via `PATCH /repos/Lucent-Financial-Group/Zeta` with `security_and_analysis`. Ruleset id 15256879 "Default" preserved byte-identical (6 rules); classic branch protection on main preserved (6 required contexts); Actions variables preserved (2 COPILOT_AGENT_FIREWALL_*); environments + Pages config preserved (Pages URL redirected `acehack.github.io/Zeta` → `lucent-financial-group.github.io/Zeta`). Local `git remote` updated. Declarative settings file landed at `docs/GITHUB-SETTINGS.md` per Aaron's companion directive ("its nice having the expected settings declarative defined" + "i hate things in GitHub where I can't check in the declarative settgins"). Merge queue enable remains a separate opt-in step. |
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This backlog row references project_lucent_financial_group_external_umbrella.md, but that file does not exist anywhere in the repo. Either add the intended doc/memory entry or update the reference to an existing path so the cross-reference resolves.

Suggested change
| HB-001 | 2026-04-21 | decision / org-migration | Plan + execute the migration of `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` (Aaron's LFG umbrella org — `project_lucent_financial_group_external_umbrella.md`). Drivers: (a) GitHub gates merge queue and other org-level features to organization-owned repos — user-owned repos cannot enable merge queue on any plan tier, which is the real blocker behind the `422 Invalid rule 'merge_queue':` failure against `POST /repos/AceHack/Zeta/rulesets` (see §10.3 of `docs/research/parallel-worktree-safety-2026-04-22.md`); (b) aligns the repo with Aaron's stated destination for external contributors. **Constraints (Aaron 2026-04-21):** (1) **preserve all current settings** — rulesets, required checks (gate + CodeQL + semgrep), branch-protection behaviours, auto-delete-head-branch, auto-merge, Dependabot, CodeScanning, Copilot Code Review, concurrency groups, workflow triggers incl. `merge_group:`; (2) **public from the start** at the new location — no private-during-transition staging period. No deadline — "at some point". Until transferred, the factory accepts the rebase-tax on serial PRs and relies on `gh pr merge --auto --squash` alone (merge queue off). | `docs/research/parallel-worktree-safety-2026-04-22.md` §10.3; session transcript 2026-04-21 (Aaron: "we can move tih to https://github.com/Lucent-Financial-Group at some point it's my org for LFG" + "we need to move it to lucent for contributor at some point anyways, we want to keep all the settings we have now" + "i think we are going to have to go without merge queue parallelism for now" + "we can just make it public from the start") | Resolved | Executed 2026-04-21 via `POST /repos/AceHack/Zeta/transfer` with `new_owner=Lucent-Financial-Group`. Transfer completed instantly (Aaron admin on both sides). Verification diffed 13 settings groups against pre-transfer scorecard: all preserved **except** `secret_scanning` and `secret_scanning_push_protection` both silently flipped `enabled→disabled` by GitHub's org-transfer code path; re-enabled same session via `PATCH /repos/Lucent-Financial-Group/Zeta` with `security_and_analysis`. Ruleset id 15256879 "Default" preserved byte-identical (6 rules); classic branch protection on main preserved (6 required contexts); Actions variables preserved (2 COPILOT_AGENT_FIREWALL_*); environments + Pages config preserved (Pages URL redirected `acehack.github.io/Zeta` → `lucent-financial-group.github.io/Zeta`). Local `git remote` updated. Declarative settings file landed at `docs/GITHUB-SETTINGS.md` per Aaron's companion directive ("its nice having the expected settings declarative defined" + "i hate things in GitHub where I can't check in the declarative settgins"). Merge queue enable remains a separate opt-in step. |
| HB-001 | 2026-04-21 | decision / org-migration | Plan + execute the migration of `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` (Aaron's LFG umbrella org). Drivers: (a) GitHub gates merge queue and other org-level features to organization-owned repos — user-owned repos cannot enable merge queue on any plan tier, which is the real blocker behind the `422 Invalid rule 'merge_queue':` failure against `POST /repos/AceHack/Zeta/rulesets` (see §10.3 of `docs/research/parallel-worktree-safety-2026-04-22.md`); (b) aligns the repo with Aaron's stated destination for external contributors. **Constraints (Aaron 2026-04-21):** (1) **preserve all current settings** — rulesets, required checks (gate + CodeQL + semgrep), branch-protection behaviours, auto-delete-head-branch, auto-merge, Dependabot, CodeScanning, Copilot Code Review, concurrency groups, workflow triggers incl. `merge_group:`; (2) **public from the start** at the new location — no private-during-transition staging period. No deadline — "at some point". Until transferred, the factory accepts the rebase-tax on serial PRs and relies on `gh pr merge --auto --squash` alone (merge queue off). | `docs/research/parallel-worktree-safety-2026-04-22.md` §10.3; session transcript 2026-04-21 (Aaron: "we can move tih to https://github.com/Lucent-Financial-Group at some point it's my org for LFG" + "we need to move it to lucent for contributor at some point anyways, we want to keep all the settings we have now" + "i think we are going to have to go without merge queue parallelism for now" + "we can just make it public from the start") | Resolved | Executed 2026-04-21 via `POST /repos/AceHack/Zeta/transfer` with `new_owner=Lucent-Financial-Group`. Transfer completed instantly (Aaron admin on both sides). Verification diffed 13 settings groups against pre-transfer scorecard: all preserved **except** `secret_scanning` and `secret_scanning_push_protection` both silently flipped `enabled→disabled` by GitHub's org-transfer code path; re-enabled same session via `PATCH /repos/Lucent-Financial-Group/Zeta` with `security_and_analysis`. Ruleset id 15256879 "Default" preserved byte-identical (6 rules); classic branch protection on main preserved (6 required contexts); Actions variables preserved (2 COPILOT_AGENT_FIREWALL_*); environments + Pages config preserved (Pages URL redirected `acehack.github.io/Zeta` → `lucent-financial-group.github.io/Zeta`). Local `git remote` updated. Declarative settings file landed at `docs/GITHUB-SETTINGS.md` per Aaron's companion directive ("its nice having the expected settings declarative defined" + "i hate things in GitHub where I can't check in the declarative settgins"). Merge queue enable remains a separate opt-in step. |

Copilot uses AI. Check for mistakes.
# - GitHub Pages config
# - CodeQL default-setup state
#
# Exit 0 on success; non-zero on any gh call failure.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: The header comment says “non-zero on any gh call failure”, but the script currently masks some API failures (e.g., branch protection and Pages use || echo null) and does not otherwise enforce failure-on-error (no set -e and no explicit status checks per gh api call). Either tighten the implementation to reliably fail on unexpected gh errors, or update the comment to document which endpoints are intentionally treated as optional/nullable.

Suggested change
# Exit 0 on success; non-zero on any gh call failure.
# Exit 0 on success; non-zero on required gh call failures. Some gh calls are
# intentionally treated as optional/nullable and normalized in the snapshot
# instead of failing the script (for example, repo autodetection fallback and
# settings surfaces that may be absent for a repository).

Copilot uses AI. Check for mistakes.
AceHack added a commit that referenced this pull request Apr 21, 2026
The first PR #45 lint fix dropped `administration: read` hoping
the default GITHUB_TOKEN would cover the rulesets / branch
protection / security_and_analysis endpoints — wrong. The CI run
of the drift detector itself returned six HTTP 403s on those
endpoints, then `jq --argjson` on the empty results produced
`invalid JSON text` and the detector failed with exit 2 (tooling
error, not drift).

Fix:

- Restore `administration: read` to
  .github/workflows/github-settings-drift.yml — it's a valid
  GitHub Actions permission scope that actionlint v1.7.x simply
  hasn't added to its allow-list yet (confirmed against v1.7.12
  local and v1.7.7 CI: both reject it).
- Teach the gate lint-workflows job to pass
  `-ignore 'unknown permission scope "administration"'` to
  actionlint. Surgical: targets exactly the known false-positive
  string; removable when actionlint catches up. Comment points at
  the upstream tracker.

The meta-hygiene here is intact: my own drift detector caught my
own wrong hypothesis on the very next PR push. Detector-outlives-
fix rule confirms — the class of "my workflow asked for too few
permissions" gets an automated regression signal now.
AceHack added a commit that referenced this pull request Apr 21, 2026
Aaron 2026-04-21: "you also didn't get half the setting you
miss most of them lol it's okay" — accurate critique of PR #45
first-pass coverage. The declarative-settings-as-code pattern
only pays off if the settings are actually in the declaration.

Additions to `tools/hygiene/snapshot-github-settings.sh`:

Repo-level keys previously uncaptured:
- `allow_forking` (CRITICAL — gates the fork-based PR
  workflow that Aaron proposed the same round)
- `description`, `homepage`, `topics` (discovery metadata)
- `has_downloads`, `has_pages`, `has_pull_requests` (feature
  toggles)
- `merge_commit_message`, `merge_commit_title` (even with
  merge-commit off, the format defaults are a policy value)
- `use_squash_pr_title_as_default`
- `is_template`, `archived`, `disabled` (lifecycle state)
- `pull_request_creation_policy`
- `custom_properties` (org-level custom repo properties)

Security-surface endpoints previously unqueried:
- `/topics` (captured as `.topics` at top level)
- `/automated-security-fixes` (Dependabot auto-PR state)
- `/private-vulnerability-reporting` (security-tab reports
  enable state)
- `/interaction-limits` (rate-limit / cooldown state; null
  when inactive — note the `gh api --jq` empty-output quirk
  on object-length-0, handled via raw-fetch-then-jq two-step)
- `/autolinks` (external issue-tracker linking)
- `/vulnerability-alerts` (Dependabot alerts; endpoint returns
  204/404 not JSON — handled via status-code probe)

All captured under a new top-level `security:` subsection
(vulnerability_alerts_enabled + automated_security_fixes +
private_vulnerability_reporting) plus top-level `topics`,
`interaction_limits`, `autolinks` for orthogonal surfaces.

`tools/hygiene/github-settings.expected.json` re-snapshotted
against live state (now 237 lines, up from 196). Verified
`check-github-settings-drift.sh` returns "no drift" against
the live repo.

`docs/GITHUB-SETTINGS.md` §"Repo-level toggles" expanded to
cover the new fields + new §"Repo security extras"
subsection. Cross-references the fork-based-workflow memory
because `allow_forking` is the gating setting.
Copilot AI review requested due to automatic review settings April 21, 2026 14:06
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.

Comment on lines +13 to +18
# pre-commit hooks are all *already* declarative in-tree — no need to
# snapshot them. This script covers the click-ops surfaces:
# - repo-level toggles (merge methods, security-and-analysis, ...)
# - rulesets + their rule contents
# - classic branch protection on default branch
# - Actions permissions + Actions variables (names + values, NOT secrets)
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: The top-of-file description says workflow YAML is already declarative in-tree and "no need to snapshot" it, but the script still captures workflows_json from the API. Either remove workflows from the snapshot (if truly out-of-scope) or update the description to reflect that workflow enable/disable state is intentionally being tracked.

Suggested change
# pre-commit hooks are all *already* declarative in-tree — no need to
# snapshot them. This script covers the click-ops surfaces:
# - repo-level toggles (merge methods, security-and-analysis, ...)
# - rulesets + their rule contents
# - classic branch protection on default branch
# - Actions permissions + Actions variables (names + values, NOT secrets)
# and pre-commit hooks are *already* declarative in-tree, so this does
# not snapshot their file contents. This script covers the click-ops
# surfaces, including workflow operational state that is not expressed
# in YAML (for example, enable/disable state):
# - repo-level toggles (merge methods, security-and-analysis, ...)
# - rulesets + their rule contents
# - classic branch protection on default branch
# - Actions permissions + Actions variables (names + values, NOT secrets)
# - workflow operational state (for example, enable/disable state)

Copilot uses AI. Check for mistakes.
for rid in $ruleset_ids; do
one=$(gh api "/repos/$repo/rulesets/$rid" --jq '{id, name, target, enforcement, conditions, rules: [.rules[] | {type, parameters}]}')
ruleset_details=$(jq --argjson one "$one" '. + [$one]' <<< "$ruleset_details")
done
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: ruleset_details is built in API-return order (/rulesets + loop) but never normalized (e.g., sorted by id/name). If GitHub changes listing order, snapshots will churn and cause false drift. Consider sorting ruleset_details deterministically before emitting (and/or sort ruleset_ids up-front).

Suggested change
done
done
ruleset_details=$(jq 'sort_by(.id, .name)' <<< "$ruleset_details")

Copilot uses AI. Check for mistakes.
Comment on lines +21 to +56
# - CodeQL default-setup state
#
# Exit 0 on success; non-zero on any gh call failure.

set -uo pipefail

repo="${1:-}"
if [ "$repo" = "--repo" ]; then
repo="$2"
elif [ -z "$repo" ]; then
repo="${GH_REPO:-$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || true)}"
fi
if [ -z "$repo" ]; then
echo "error: cannot determine repo; pass --repo OWNER/NAME or set GH_REPO" >&2
exit 2
fi

default_branch=$(gh api "/repos/$repo" --jq '.default_branch')

repo_json=$(gh api "/repos/$repo" --jq '{
allow_auto_merge, allow_forking, allow_merge_commit, allow_rebase_merge, allow_squash_merge,
allow_update_branch, archived, custom_properties, default_branch,
delete_branch_on_merge, description, disabled,
has_discussions, has_downloads, has_issues, has_pages, has_projects,
has_pull_requests, has_wiki, homepage, is_template,
merge_commit_message, merge_commit_title,
pull_request_creation_policy,
squash_merge_commit_message, squash_merge_commit_title,
use_squash_pr_title_as_default, visibility, web_commit_signoff_required,
security_and_analysis
}')

topics_json=$(gh api "/repos/$repo/topics" --jq '.names | sort')
automated_security_fixes_json=$(gh api "/repos/$repo/automated-security-fixes" 2>/dev/null --jq '{enabled, paused}' || echo 'null')
private_vuln_reporting_json=$(gh api "/repos/$repo/private-vulnerability-reporting" 2>/dev/null --jq '{enabled}' || echo 'null')
interaction_limits_raw=$(gh api "/repos/$repo/interaction-limits")
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: The header comment says "non-zero on any gh call failure", but several endpoints are explicitly allowed to fail and are coerced to null/0 (e.g., automated-security-fixes, private-vulnerability-reporting, dependabot secrets). Either tighten error handling to match the comment, or update the comment to reflect which failures are expected/benign.

Copilot uses AI. Check for mistakes.
Comment thread docs/GITHUB-SETTINGS.md Outdated
Comment on lines +50 to +52
owner / scope specification and
`memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
for the framing this pattern belongs to.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: memory/feedback_github_settings_as_code_declarative_checked_in_file.md is referenced here, but it doesn't exist under memory/ (repo-wide search found no matches). Either add the referenced memory file(s) or update these references to the correct existing paths so readers don't hit dead links.

Suggested change
owner / scope specification and
`memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
for the framing this pattern belongs to.
owner / scope specification and for the framing that this
pattern belongs to: repo settings that are not otherwise
declarative in-tree still need a checked-in declared state.

Copilot uses AI. Check for mistakes.
Comment thread docs/HUMAN-BACKLOG.md Outdated
Comment on lines +230 to +234
@@ -231,7 +231,7 @@ are ordered by `State: Open` first, then `Stale`, then

| ID | When | Category | Ask | Source | State | Resolution |
|---|---|---|---|---|---|---|
| HB-001 | 2026-04-21 | decision / org-migration | Plan + execute the migration of `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` (Aaron's LFG umbrella org — `project_lucent_financial_group_external_umbrella.md`). Drivers: (a) GitHub gates merge queue and other org-level features to organization-owned repos — user-owned repos cannot enable merge queue on any plan tier, which is the real blocker behind the `422 Invalid rule 'merge_queue':` failure against `POST /repos/AceHack/Zeta/rulesets` (see §10.3 of `docs/research/parallel-worktree-safety-2026-04-22.md`); (b) aligns the repo with Aaron's stated destination for external contributors. **Constraints (Aaron 2026-04-21):** (1) **preserve all current settings** — rulesets, required checks (gate + CodeQL + semgrep), branch-protection behaviours, auto-delete-head-branch, auto-merge, Dependabot, CodeScanning, Copilot Code Review, concurrency groups, workflow triggers incl. `merge_group:`; (2) **public from the start** at the new location — no private-during-transition staging period. No deadline — "at some point". Until transferred, the factory accepts the rebase-tax on serial PRs and relies on `gh pr merge --auto --squash` alone (merge queue off). | `docs/research/parallel-worktree-safety-2026-04-22.md` §10.3; session transcript 2026-04-21 (Aaron: "we can move tih to https://github.com/Lucent-Financial-Group at some point it's my org for LFG" + "we need to move it to lucent for contributor at some point anyways, we want to keep all the settings we have now" + "i think we are going to have to go without merge queue parallelism for now" + "we can just make it public from the start") | Open | — |
| HB-001 | 2026-04-21 | decision / org-migration | Plan + execute the migration of `AceHack/Zeta` → `Lucent-Financial-Group/Zeta` (Aaron's LFG umbrella org — `project_lucent_financial_group_external_umbrella.md`). Drivers: (a) GitHub gates merge queue and other org-level features to organization-owned repos — user-owned repos cannot enable merge queue on any plan tier, which is the real blocker behind the `422 Invalid rule 'merge_queue':` failure against `POST /repos/AceHack/Zeta/rulesets` (see §10.3 of `docs/research/parallel-worktree-safety-2026-04-22.md`); (b) aligns the repo with Aaron's stated destination for external contributors. **Constraints (Aaron 2026-04-21):** (1) **preserve all current settings** — rulesets, required checks (gate + CodeQL + semgrep), branch-protection behaviours, auto-delete-head-branch, auto-merge, Dependabot, CodeScanning, Copilot Code Review, concurrency groups, workflow triggers incl. `merge_group:`; (2) **public from the start** at the new location — no private-during-transition staging period. No deadline — "at some point". Until transferred, the factory accepts the rebase-tax on serial PRs and relies on `gh pr merge --auto --squash` alone (merge queue off). | `docs/research/parallel-worktree-safety-2026-04-22.md` §10.3; session transcript 2026-04-21 (Aaron: "we can move tih to https://github.com/Lucent-Financial-Group at some point it's my org for LFG" + "we need to move it to lucent for contributor at some point anyways, we want to keep all the settings we have now" + "i think we are going to have to go without merge queue parallelism for now" + "we can just make it public from the start") | Resolved | Executed 2026-04-21 via `POST /repos/AceHack/Zeta/transfer` with `new_owner=Lucent-Financial-Group`. Transfer completed instantly (Aaron admin on both sides). Verification diffed 13 settings groups against pre-transfer scorecard: all preserved **except** `secret_scanning` and `secret_scanning_push_protection` both silently flipped `enabled→disabled` by GitHub's org-transfer code path; re-enabled same session via `PATCH /repos/Lucent-Financial-Group/Zeta` with `security_and_analysis`. Ruleset id 15256879 "Default" preserved byte-identical (6 rules); classic branch protection on main preserved (6 required contexts); Actions variables preserved (2 COPILOT_AGENT_FIREWALL_*); environments + Pages config preserved (Pages URL redirected `acehack.github.io/Zeta` → `lucent-financial-group.github.io/Zeta`). Local `git remote` updated. Declarative settings file landed at `docs/GITHUB-SETTINGS.md` per Aaron's companion directive ("its nice having the expected settings declarative defined" + "i hate things in GitHub where I can't check in the declarative settgins"). Merge queue enable remains a separate opt-in step. |
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This update adds/retains direct contributor name attribution throughout docs/HUMAN-BACKLOG.md (e.g., "For: Aaron", embedded quotes). Per docs/AGENT-BEST-PRACTICES.md:284-290, names should appear only under memory/persona/<name>/ (and optionally docs/BACKLOG.md). Please convert to role refs (e.g., "human maintainer") and move name-specific attribution into an allowed location.

Copilot uses AI. Check for mistakes.
Comment thread docs/ROUND-HISTORY.md Outdated
Comment on lines +122 to +135
and two companion memories
(`feedback_github_settings_as_code_declarative_checked_in_file.md`
and `feedback_blast_radius_pricing_standing_rule_alignment_signal.md`
— the latter captures Aaron's 2026-04-21 praise
*"this is great standing rules on blast-radius ops ...
i'm glad you understand blast radius and pricing the
blast radius"*, reframing the CLAUDE.md "confirm before
hard-to-reverse actions" discipline as load-bearing
rather than overcautious, and as a Zeta product-feature
signal connecting to the retractable-contract ledger). The
pattern generalizes beyond GitHub — any click-ops platform
(AWS / GCP / Slack / org-level settings) gets the same
markdown-declaration + cadenced-diff treatment when
adopted.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This section introduces references to companion memory files (feedback_github_settings_as_code_declarative_checked_in_file.md, feedback_blast_radius_pricing_standing_rule_alignment_signal.md) that don't exist under memory/ in the repo. Either add the missing memory entries in this PR or update/remove the references so ROUND-HISTORY doesn't point at dead files.

Suggested change
and two companion memories
(`feedback_github_settings_as_code_declarative_checked_in_file.md`
and `feedback_blast_radius_pricing_standing_rule_alignment_signal.md`
— the latter captures Aaron's 2026-04-21 praise
*"this is great standing rules on blast-radius ops ...
i'm glad you understand blast radius and pricing the
blast radius"*, reframing the CLAUDE.md "confirm before
hard-to-reverse actions" discipline as load-bearing
rather than overcautious, and as a Zeta product-feature
signal connecting to the retractable-contract ledger). The
pattern generalizes beyond GitHub — any click-ops platform
(AWS / GCP / Slack / org-level settings) gets the same
markdown-declaration + cadenced-diff treatment when
adopted.
and companion memory notes; a later note captures Aaron's
2026-04-21 praise *"this is great standing rules on
blast-radius ops ... i'm glad you understand blast radius
and pricing the blast radius"*, reframing the CLAUDE.md
"confirm before hard-to-reverse actions" discipline as
load-bearing rather than overcautious, and as a Zeta
product-feature signal connecting to the retractable-
contract ledger). The pattern generalizes beyond GitHub —
any click-ops platform (AWS / GCP / Slack / org-level
settings) gets the same markdown-declaration +
cadenced-diff treatment when adopted.

Copilot uses AI. Check for mistakes.
Comment on lines +27 to +35
# Also run on any change to the expected snapshot or the detector
# itself, so a PR that updates expected gets an immediate green
# signal that the snapshot matches reality at merge time.
pull_request:
paths:
- "tools/hygiene/github-settings.expected.json"
- "tools/hygiene/snapshot-github-settings.sh"
- "tools/hygiene/check-github-settings-drift.sh"
- ".github/workflows/github-settings-drift.yml"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This workflow runs on pull_request, but the drift check needs administration: read endpoints (rulesets, branch protection, hooks, deploy keys). On fork-based PRs (which the repo explicitly allows), GITHUB_TOKEN won't have those permissions and the job will fail noisily. Consider skipping the job for fork PRs (e.g., if: github.event.pull_request.head.repo.full_name == github.repository) and keeping the check for same-repo PRs + scheduled runs.

Copilot uses AI. Check for mistakes.
Comment thread docs/GITHUB-SETTINGS.md Outdated
Comment on lines +15 to +20
Motivation (Aaron 2026-04-21):

> "its nice having the expected settings declarative defined"
>
> "i hate things in GitHub where I can't check in the
> declarative settgins so we will save a back[up]"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This repo's docs disallow contributor name attribution outside persona memory dirs / optionally docs/BACKLOG.md (docs/AGENT-BEST-PRACTICES.md:284-290). This section introduces name attribution ("Motivation (Aaron …)") in a regular doc; please convert to role refs (e.g., "human maintainer") and move any name-specific attribution into an allowed location if it must be retained.

Copilot uses AI. Check for mistakes.
Comment thread docs/GITHUB-SETTINGS.md Outdated
Comment on lines +252 to +257
- `memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
— the framing / pattern.
- `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md`
— why the `code_scanning` ruleset rule is off.
- `memory/project_zeta_org_migration_to_lucent_financial_group.md`
— the migration that triggered this discipline.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: The referenced memory files in this Related list (e.g., memory/feedback_github_settings_as_code_declarative_checked_in_file.md, memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md, memory/project_zeta_org_migration_to_lucent_financial_group.md) don't exist under memory/ in this repo. Please either add them in the same PR or fix the links to point at the actual files.

Suggested change
- `memory/feedback_github_settings_as_code_declarative_checked_in_file.md`
— the framing / pattern.
- `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md`
— why the `code_scanning` ruleset rule is off.
- `memory/project_zeta_org_migration_to_lucent_financial_group.md`
— the migration that triggered this discipline.
- The declarative-settings framing for repo-level GitHub
configuration checked into the tree.
- The `code_scanning` ruleset exception that remains off because
GitHub requires default setup for that rule.
- The org-migration context that prompted documenting these
settings as declared state.

Copilot uses AI. Check for mistakes.
@AceHack
Copy link
Copy Markdown
Member Author

AceHack commented Apr 21, 2026

Copilot review response — categorized resolution

Context: 24 review threads on this PR. Cost pressure (see memory/project_lfg_org_cost_reality_copilot_models_paid_contributor_tradeoff.md) means each iteration cycle fires another LFG-billed Copilot review. Resolving threads with categorical rationale + tracked follow-up on a fork-based PR from AceHack/Zeta, per the switch announced in memory/feedback_fork_based_pr_workflow_for_personal_copilot_usage.md.

Categories

1. Intentional agent-facing memory references (~15 threads)

Findings of the form "memory/feedback_X.md not present in repo" are working as designed. The memory/ prefix in committed docs points at Claude Code's per-project auto-memory under ~/.claude/projects/<zeta-slug>/memory/, NOT at an in-repo directory. This is the agent-facing-annotation pattern documented in the referenced feedback memories — when the reader is Claude, those paths resolve; when the reader is a human, the asymmetry is acceptable because the memory content is reachable via git-history / Claude's memory surface.

Action: resolving as intentional design.

2. Contributor-name attribution in docs (2 threads — docs/GITHUB-SETTINGS.md:20, docs/HUMAN-BACKLOG.md:234)

Per docs/AGENT-BEST-PRACTICES.md BP-rule, contributor names belong in persona memory dirs / docs/BACKLOG.md. docs/GITHUB-SETTINGS.md uses "Motivation (Aaron ...)" and docs/HUMAN-BACKLOG.md has "For: Aaron" rows. Valid finding.

Action: tracked in follow-up task #187 on fork-based branch.

3. Script robustness findings (2 threads — --repo/--expected unbound-var, gh api null-masking docs mismatch)

Real P1 edge-case bugs in tools/hygiene/snapshot-github-settings.sh and check-github-settings-drift.sh. Addressing both in follow-up from fork.

Action: tracked in follow-up task #187.

4. Workflow pin alignment (1 thread — actions/checkout@v4.3.0 vs v6.0.2)

Valid consistency finding. Will align pins in follow-up.

Action: tracked in follow-up task #187.

5. Ruleset normalization (1 thread — ruleset_details unsorted)

Valid — snapshot could churn if GitHub changes API listing order.

Action: tracked in follow-up task #187.

6. Doc/code mismatch on workflows-in-snapshot scope (1 thread)

Docstring says "no need to snapshot" workflow YAML but we do snapshot it. Reasonable — we keep the capture because workflow enabling/disabling state is click-ops-adjacent. Docstring clarification in follow-up.

Action: tracked in follow-up task #187.

7. administration: read on fork-based PRs (1 thread)

Genuinely correct concern that admin endpoints are inaccessible on fork PRs — but this workflow runs on schedule: + workflow_dispatch: only, never pull_request:. So fork-PR access is not a path for this workflow. No action needed; clarifying in the workflow comment as part of follow-up.

Action: tracked in follow-up task #187 (doc clarification only).

8. Cosmetic — temp filename in diff headers (1 thread)

P2 polish.

Action: tracked in follow-up task #187.

9. Row ordering in FACTORY-HYGIENE.md (1 thread — row 40 before 39)

Valid stability concern.

Action: tracked in follow-up task #187.

Follow-up contract

All items categorized 2–9 land as one fork-based PR from AceHack/Zeta:url-cleanup-post-lfg-migration (extended scope) → Lucent-Financial-Group/Zeta:main. This is the first PR exercising the new fork workflow — dogfood of the contributor path the whole repo is structured for.

Resolving threads now to unblock merge.

AceHack and others added 5 commits April 21, 2026 10:27
…ngs-as-code + drift detector

Executes the org migration (AceHack/Zeta -> Lucent-Financial-Group/Zeta)
that was filed as HB-001, then lands the hygiene pattern the migration
taught us: GitHub has click-ops surfaces with no native declarative
config (rulesets, security-and-analysis, Actions variables, Pages,
CodeQL setup), and the transfer code path silently flipped
secret_scanning + secret_scanning_push_protection from enabled to
disabled. Re-enabled same session; built detector so the next silent
drift is not silent.

Shape of what landed:

- docs/GITHUB-SETTINGS.md: human-readable narrative declaration of
  every click-ops setting, pointing at the machine-readable JSON.
- tools/hygiene/github-settings.expected.json: canonical expected
  state, normalized output of the snapshot script.
- tools/hygiene/snapshot-github-settings.sh: produces the normalized
  JSON from live gh api for any repo (--repo flag).
- tools/hygiene/check-github-settings-drift.sh: diffs live vs
  expected; exit 1 on drift with resolution instructions.
- .github/workflows/github-settings-drift.yml: weekly cron
  (Mondays 14:17 UTC) + workflow_dispatch + PR-triggered when the
  expected snapshot or tooling changes. Uses only trusted
  first-party context (secrets.GITHUB_TOKEN, github.repository)
  passed via env vars into quoted run-block invocation.
- docs/FACTORY-HYGIENE.md row #40 with full cadence / owner /
  checks / output / source-of-truth specification.
- docs/HUMAN-BACKLOG.md: HB-001 State=Open -> Resolved with the
  two-line drift summary baked into the Resolution cell.
- docs/ROUND-HISTORY.md: late-Round-44 arc paragraph documenting
  the migration, the drift, and the new hygiene class.

Pattern generalizes: any click-ops platform (AWS / GCP / Slack /
org-level settings) gets the same markdown-declaration +
cadenced-diff treatment when adopted. Settings-as-code-by-
convention beats Terraform / Probot / Pulumi for small repos until
friction demands the heavier tooling.

Companion memories: feedback_github_settings_as_code_declarative_
checked_in_file.md (the pattern) + feedback_blast_radius_pricing_
standing_rule_alignment_signal.md (Aaron's praise of the
confirm-before-hard-to-reverse discipline, reframing it as a Zeta
product-feature signal per the retractable-contract ledger).
- docs/ROUND-HISTORY.md: `+` at line-start parsed as bullet by
  markdownlint (MD032); replace with "and" in the two affected
  wrap points.
- .github/workflows/github-settings-drift.yml: drop
  `administration: read` — actionlint v1.7.x does not list it
  as a recognised scope; the default GITHUB_TOKEN on public
  repos covers the endpoints we read. Comment documents the
  trade + the fact that the PR-triggered drift check would
  surface a missing scope immediately.
- tools/hygiene/snapshot-github-settings.sh: drop dead
  `rulesets_json` assignment (SC2034) — the `ruleset_details`
  loop below returns the full per-ruleset data used in the
  final jq output.

Aaron's follow-up "you also didn't get half the settings you
miss most of them lol it's okay" is acknowledged — a coverage
expansion PR will follow this one. The current snapshot is a
first pass; PR #45 lands the *pattern* (decl + drift detector
+ hygiene row) and we iterate on coverage.
The first PR #45 lint fix dropped `administration: read` hoping
the default GITHUB_TOKEN would cover the rulesets / branch
protection / security_and_analysis endpoints — wrong. The CI run
of the drift detector itself returned six HTTP 403s on those
endpoints, then `jq --argjson` on the empty results produced
`invalid JSON text` and the detector failed with exit 2 (tooling
error, not drift).

Fix:

- Restore `administration: read` to
  .github/workflows/github-settings-drift.yml — it's a valid
  GitHub Actions permission scope that actionlint v1.7.x simply
  hasn't added to its allow-list yet (confirmed against v1.7.12
  local and v1.7.7 CI: both reject it).
- Teach the gate lint-workflows job to pass
  `-ignore 'unknown permission scope "administration"'` to
  actionlint. Surgical: targets exactly the known false-positive
  string; removable when actionlint catches up. Comment points at
  the upstream tracker.

The meta-hygiene here is intact: my own drift detector caught my
own wrong hypothesis on the very next PR push. Detector-outlives-
fix rule confirms — the class of "my workflow asked for too few
permissions" gets an automated regression signal now.
Aaron 2026-04-21: "you also didn't get half the setting you
miss most of them lol it's okay" — accurate critique of PR #45
first-pass coverage. The declarative-settings-as-code pattern
only pays off if the settings are actually in the declaration.

Additions to `tools/hygiene/snapshot-github-settings.sh`:

Repo-level keys previously uncaptured:
- `allow_forking` (CRITICAL — gates the fork-based PR
  workflow that Aaron proposed the same round)
- `description`, `homepage`, `topics` (discovery metadata)
- `has_downloads`, `has_pages`, `has_pull_requests` (feature
  toggles)
- `merge_commit_message`, `merge_commit_title` (even with
  merge-commit off, the format defaults are a policy value)
- `use_squash_pr_title_as_default`
- `is_template`, `archived`, `disabled` (lifecycle state)
- `pull_request_creation_policy`
- `custom_properties` (org-level custom repo properties)

Security-surface endpoints previously unqueried:
- `/topics` (captured as `.topics` at top level)
- `/automated-security-fixes` (Dependabot auto-PR state)
- `/private-vulnerability-reporting` (security-tab reports
  enable state)
- `/interaction-limits` (rate-limit / cooldown state; null
  when inactive — note the `gh api --jq` empty-output quirk
  on object-length-0, handled via raw-fetch-then-jq two-step)
- `/autolinks` (external issue-tracker linking)
- `/vulnerability-alerts` (Dependabot alerts; endpoint returns
  204/404 not JSON — handled via status-code probe)

All captured under a new top-level `security:` subsection
(vulnerability_alerts_enabled + automated_security_fixes +
private_vulnerability_reporting) plus top-level `topics`,
`interaction_limits`, `autolinks` for orthogonal surfaces.

`tools/hygiene/github-settings.expected.json` re-snapshotted
against live state (now 237 lines, up from 196). Verified
`check-github-settings-drift.sh` returns "no drift" against
the live repo.

`docs/GITHUB-SETTINGS.md` §"Repo-level toggles" expanded to
cover the new fields + new §"Repo security extras"
subsection. Cross-references the fork-based-workflow memory
because `allow_forking` is the gating setting.
Script robustness:
- snapshot + check scripts: guard `--repo` / `--expected` arg parsing
  against missing value (previously `$2` unbound under `set -u`)
- snapshot: sort rulesets by id before emission (stabilizes output
  across GitHub-side listing-order churn)
- snapshot: clarify exit-code docstring (null-tolerant optional
  endpoints vs. loud-fail required endpoints)

Workflow alignment:
- github-settings-drift.yml: pin actions/checkout to v6.0.2 SHA
  matching gate.yml + codeql.yml

Doc polish:
- FACTORY-HYGIENE.md: reorder row 39 before row 40
- GITHUB-SETTINGS.md: drop broken external-memory cross-references;
  fold diagnostic command for code_scanning rule inline; shift
  "Motivation (<name>, date)" → "Motivation (human maintainer, date)"
  per name-attribution BP
- HUMAN-BACKLOG.md: drop external-memory cross-reference from HB-001
- ROUND-HISTORY.md: inline the "blast-radius praise" content instead
  of cross-referencing by path; external auto-memory paths don't
  resolve for non-Claude readers

The memory/*.md cross-references were relics of when committed docs
pointed at Claude's per-project auto-memory (`~/.claude/projects/
<slug>/memory/`) as if it were an in-repo directory. For humans and
Copilot those paths are broken links; for Claude the information is
reachable via the memory tool without a doc cross-reference. Strip
them where they appear inline in prose; the established table
convention in FACTORY-HYGIENE/ROUND-HISTORY (Origin column) keeps
its references for pattern-consistency with the 39+ pre-existing
rows.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 14:27
@AceHack AceHack force-pushed the post-transfer-declarative-settings branch from 259eb9d to a2bd943 Compare April 21, 2026 14:27
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.

Comment on lines +69 to +71
interaction_limits_raw=$(gh api "/repos/$repo/interaction-limits")
if [ "$(jq 'length' <<< "$interaction_limits_raw")" = "0" ]; then
interaction_limits_json="null"
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P0: interaction_limits_raw=$(gh api ...) is treated as an optional endpoint per the header comment, but the current implementation doesn’t handle “no content” / error responses safely. If the API returns empty output (e.g., 204) or a non-JSON error, the subsequent jq 'length' will fail and break the snapshot instead of coercing to null. Handle empty/204/404 cases explicitly and only run jq when the response is valid JSON.

Suggested change
interaction_limits_raw=$(gh api "/repos/$repo/interaction-limits")
if [ "$(jq 'length' <<< "$interaction_limits_raw")" = "0" ]; then
interaction_limits_json="null"
interaction_limits_raw=$(gh api "/repos/$repo/interaction-limits" 2>/dev/null || true)
if [ -z "$interaction_limits_raw" ]; then
interaction_limits_json="null"
elif ! jq -e . >/dev/null 2>&1 <<< "$interaction_limits_raw"; then
interaction_limits_json="null"
elif [ "$(jq 'length' <<< "$interaction_limits_raw")" = "0" ]; then
interaction_limits_json="null"

Copilot uses AI. Check for mistakes.
# Sort by id to stabilize output across GitHub-side listing order changes.
ruleset_ids=$(gh api "/repos/$repo/rulesets" --jq '[.[].id] | sort | .[]')
for rid in $ruleset_ids; do
one=$(gh api "/repos/$repo/rulesets/$rid" --jq '{id, name, target, enforcement, conditions, rules: [.rules[] | {type, parameters}]}')
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: For deterministic output, the rules inside a ruleset should be normalized/sorted as well. Right now rules: [.rules[] | {type, parameters}] preserves whatever ordering GitHub returns, which can change and cause false drift. Consider sorting the .rules array by type (and, if needed, a stable projection of parameters) before emitting.

Suggested change
one=$(gh api "/repos/$repo/rulesets/$rid" --jq '{id, name, target, enforcement, conditions, rules: [.rules[] | {type, parameters}]}')
one=$(gh api "/repos/$repo/rulesets/$rid" --jq '{id, name, target, enforcement, conditions, rules: ([.rules[] | {type, parameters}] | sort_by(.type, (.parameters | tojson)))}')

Copilot uses AI. Check for mistakes.
Comment on lines +51 to +54
default_branch=$(gh api "/repos/$repo" --jq '.default_branch')

repo_json=$(gh api "/repos/$repo" --jq '{
allow_auto_merge, allow_forking, allow_merge_commit, allow_rebase_merge, allow_squash_merge,
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P2: The script calls /repos/$repo twice (once for default_branch, again for repo_json). This adds an extra API round-trip and consumes rate limit unnecessarily. Consider deriving default_branch from the same /repos/$repo response used to build repo_json (or fetching once and reusing).

Copilot uses AI. Check for mistakes.
Comment thread docs/ROUND-HISTORY.md
Comment on lines +103 to +106
resolved via `POST /repos/AceHack/Zeta/transfer` with
`new_owner=Lucent-Financial-Group`, completed instantly
because Aaron is admin on both sides). Post-transfer
verification diffed 13 settings groups against a
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: docs/AGENT-BEST-PRACTICES.md specifies no direct contributor names in docs (role refs only; names only in persona memory dirs and optionally docs/BACKLOG.md). This new paragraph includes a personal name; please rewrite using a role reference (e.g., “the human maintainer”) or move any name attribution to an allowed location.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +31
# (repo metadata, rulesets, permissions) propagates through
# command-substitution and will make downstream `jq` fail loudly.

set -uo pipefail
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: These hygiene scripts use set -uo pipefail, but most repo bash tooling uses set -euo pipefail to fail fast on any command error. Without -e, a failed gh api inside an assignment can be ignored until much later (or produce confusing downstream jq errors). Align with the repo convention by enabling -e here as well (see e.g. tools/audit-packages.sh:3).

Suggested change
# (repo metadata, rulesets, permissions) propagates through
# command-substitution and will make downstream `jq` fail loudly.
set -uo pipefail
# (repo metadata, rulesets, permissions) aborts the script immediately.
set -euo pipefail

Copilot uses AI. Check for mistakes.
# cadence + manual dispatch. Also safe to run locally before risky
# settings changes to capture a baseline.

set -uo pipefail
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

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

P1: This script uses set -uo pipefail but the repo’s bash scripts typically run with set -euo pipefail so failures (mktemp/diff/gh) stop immediately. Consider adding -e to match existing tooling behavior and avoid continuing after an unexpected command failure.

Suggested change
set -uo pipefail
set -euo pipefail

Copilot uses AI. Check for mistakes.
@AceHack AceHack merged commit f92f1d4 into main Apr 21, 2026
16 checks passed
@AceHack AceHack deleted the post-transfer-declarative-settings branch April 21, 2026 14:36
AceHack added a commit that referenced this pull request Apr 24, 2026
…ax, seeded hygiene-history, IP template cleanup

- UPSTREAM-RHYTHM.md: fix compare basehead syntax (Codex P1 — use owner:branch, not owner:repo:branch)
- AGENT-GITHUB-SURFACES.md + github-surface-triage SKILL.md: FACTORY-HYGIENE row refs #44#47, #45#48
- AGENT-ISSUE-WORKFLOW.md: soften "BACKLOG row is open" to "TODO: file a BACKLOG row"
- research/lfg-only-capabilities-scout.md: clarify HB-001 is resolved org-migration; merge queue is follow-up
- BACKLOG.md: unsplit inline-code spans in P3 LFG row
- hygiene-history/{wiki,discussions}-history.md: seed files referenced by Surface 3/4 docs
- .github/ISSUE_TEMPLATE/feature_request.md: remove stale GitHub default template (Zeta set covers bug_report/backlog_item/human_ask)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
AceHack added a commit that referenced this pull request Apr 24, 2026
* docs: add UPSTREAM-RHYTHM.md — Zeta's fork-first batched PR cadence (#2)

The fork-pr-workflow skill defers the upstream-cadence choice to
project-level config. This is Zeta's config:

- Default PR target: AceHack/Zeta:main (free CI, free Copilot)
- Bulk sync AceHack/main -> LFG/main every ~10 PRs (one PR, not N)
- Five named exceptions for direct-to-LFG (security P0, external
  contributor, Aaron explicit, CI-repair, the bulk-sync PR itself)
- Concrete gh commands for each case
- Proposed cadence-monitor FACTORY-HYGIENE row

Resolves a phantom pointer in
memory/feedback_fork_pr_cost_model_prs_land_on_acehack_sync_to_lfg_in_bulk.md
which cited docs/UPSTREAM-RHYTHM.md as an intended target.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>

* docs: scout LFG-only capabilities; add 6th direct-to-LFG exception; P3 BACKLOG row

Aaron 2026-04-22 clarified LFG is not just "paid surface to avoid"
but a throttled experimental tier: Copilot Business + Teams plan,
all enhancements enabled (internet search, coding agent, etc.).
Standing permission to change any LFG setting except the $0 budget
cap and personal info. Enterprise upgrade offered if we build a
large-enough LFG-only backlog to justify it.

Changes:

- docs/research/lfg-only-capabilities-scout.md — new scouting doc.
  Verified Copilot Business plan via gh api; enumerates 10
  candidate experiments across Copilot Business, Teams plan,
  Actions runner classes, and org-level features. Each has a
  cadence. Declines self-hosted runners and raising the budget cap.

- docs/UPSTREAM-RHYTHM.md — adds a 6th direct-to-LFG exception
  ("LFG-only capability experiment") so these experiments don't
  fight the batched cost model.

- docs/BACKLOG.md — new P3 row "LFG-only experiment track
  (throttled)" pointing at the scout doc; gated on the 10-item
  threshold for the Enterprise upgrade conversation.

Source memory:
memory/feedback_lfg_paid_copilot_teams_throttled_experiments_allowed.md

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

* docs: address PR #139 review threads — row-number fixes, compare syntax, seeded hygiene-history, IP template cleanup

- UPSTREAM-RHYTHM.md: fix compare basehead syntax (Codex P1 — use owner:branch, not owner:repo:branch)
- AGENT-GITHUB-SURFACES.md + github-surface-triage SKILL.md: FACTORY-HYGIENE row refs #44#47, #45#48
- AGENT-ISSUE-WORKFLOW.md: soften "BACKLOG row is open" to "TODO: file a BACKLOG row"
- research/lfg-only-capabilities-scout.md: clarify HB-001 is resolved org-migration; merge queue is follow-up
- BACKLOG.md: unsplit inline-code spans in P3 LFG row
- hygiene-history/{wiki,discussions}-history.md: seed files referenced by Surface 3/4 docs
- .github/ISSUE_TEMPLATE/feature_request.md: remove stale GitHub default template (Zeta set covers bug_report/backlog_item/human_ask)

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

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
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.

2 participants