From ea871e46bd4ef2a80f34ce42442c6f570bcb0908 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 10:25:17 -0400 Subject: [PATCH 01/10] =?UTF-8?q?feat(scaffold):=20B-0424.1=20=E2=80=94=20?= =?UTF-8?q?day-one=20governance=20templates=20+=20dry-run=20create-repo=20?= =?UTF-8?q?tool?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements the smallest safe slice of B-0424 (three-repo split Stage 1): - tools/scaffold/forge/ — 10 day-one governance files for Forge repo (README, AGENTS, CLAUDE, GOVERNANCE, SECURITY, CODE_OF_CONDUCT, CONTRIBUTING, LICENSE, .github/copilot-instructions, docs/GITHUB-SETTINGS) - tools/scaffold/ace/ — same set scoped to the ace package manager repo - tools/scaffold/create-repo.ts — TypeScript dry-run tool (Rule 0) that shows the 7-step GitHub API plan for creating each repo with the full ADR best-practice checklist (merge settings, branch protection, secret scanning, CodeQL default-setup, Dependabot, fork to AceHack, file push) - docs/backlog/P1/B-0424 — pre-start checklist completed No GitHub repos created yet (--apply is the follow-on step; Aaron reviews the --dry-run JSON output before executing). Dry-run verified clean: 10 operations planned for each repo. Build gate: dotnet build -c Release → 0 Warning(s) 0 Error(s). operative-authorization: aaron 2026-05-13: "Cooling period: TBD. The memory file IS the durable record" Co-Authored-By: Claude --- ...e-ace-with-scaffolding-aaron-2026-05-13.md | 38 +- tools/scaffold/README.md | 79 +++ .../ace/.github/copilot-instructions.md | 21 + tools/scaffold/ace/AGENTS.md | 43 ++ tools/scaffold/ace/CLAUDE.md | 37 ++ tools/scaffold/ace/CODE_OF_CONDUCT.md | 40 ++ tools/scaffold/ace/CONTRIBUTING.md | 46 ++ tools/scaffold/ace/GOVERNANCE.md | 52 ++ tools/scaffold/ace/LICENSE | 204 ++++++++ tools/scaffold/ace/README.md | 42 ++ tools/scaffold/ace/SECURITY.md | 28 ++ tools/scaffold/ace/docs/GITHUB-SETTINGS.md | 79 +++ tools/scaffold/create-repo.ts | 476 ++++++++++++++++++ .../forge/.github/copilot-instructions.md | 21 + tools/scaffold/forge/AGENTS.md | 64 +++ tools/scaffold/forge/CLAUDE.md | 43 ++ tools/scaffold/forge/CODE_OF_CONDUCT.md | 42 ++ tools/scaffold/forge/CONTRIBUTING.md | 50 ++ tools/scaffold/forge/GOVERNANCE.md | 75 +++ tools/scaffold/forge/LICENSE | 204 ++++++++ tools/scaffold/forge/README.md | 59 +++ tools/scaffold/forge/SECURITY.md | 30 ++ tools/scaffold/forge/docs/GITHUB-SETTINGS.md | 109 ++++ 23 files changed, 1861 insertions(+), 21 deletions(-) create mode 100644 tools/scaffold/README.md create mode 100644 tools/scaffold/ace/.github/copilot-instructions.md create mode 100644 tools/scaffold/ace/AGENTS.md create mode 100644 tools/scaffold/ace/CLAUDE.md create mode 100644 tools/scaffold/ace/CODE_OF_CONDUCT.md create mode 100644 tools/scaffold/ace/CONTRIBUTING.md create mode 100644 tools/scaffold/ace/GOVERNANCE.md create mode 100644 tools/scaffold/ace/LICENSE create mode 100644 tools/scaffold/ace/README.md create mode 100644 tools/scaffold/ace/SECURITY.md create mode 100644 tools/scaffold/ace/docs/GITHUB-SETTINGS.md create mode 100644 tools/scaffold/create-repo.ts create mode 100644 tools/scaffold/forge/.github/copilot-instructions.md create mode 100644 tools/scaffold/forge/AGENTS.md create mode 100644 tools/scaffold/forge/CLAUDE.md create mode 100644 tools/scaffold/forge/CODE_OF_CONDUCT.md create mode 100644 tools/scaffold/forge/CONTRIBUTING.md create mode 100644 tools/scaffold/forge/GOVERNANCE.md create mode 100644 tools/scaffold/forge/LICENSE create mode 100644 tools/scaffold/forge/README.md create mode 100644 tools/scaffold/forge/SECURITY.md create mode 100644 tools/scaffold/forge/docs/GITHUB-SETTINGS.md diff --git a/docs/backlog/P1/B-0424-three-repo-split-stage1-create-forge-ace-with-scaffolding-aaron-2026-05-13.md b/docs/backlog/P1/B-0424-three-repo-split-stage1-create-forge-ace-with-scaffolding-aaron-2026-05-13.md index 33f36a2ba3..5cea86eba3 100644 --- a/docs/backlog/P1/B-0424-three-repo-split-stage1-create-forge-ace-with-scaffolding-aaron-2026-05-13.md +++ b/docs/backlog/P1/B-0424-three-repo-split-stage1-create-forge-ace-with-scaffolding-aaron-2026-05-13.md @@ -56,27 +56,23 @@ Both with full best-practice scaffolding applied at creation: - Declarative `docs/GITHUB-SETTINGS.md` per repo - Per-repo `docs/UPSTREAM-RHYTHM.md` -## Pre-start checklist - -Before beginning Stage 1 work, complete per -`.claude/rules/backlog-item-start-gate.md`: - -1. **Prior-art-search** — verify the existing substrate hasn't drifted: - - `memory/project_three_repo_split_zeta_forge_ace_software_factory_named_forge.md` - - `docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md` - - `memory/project_ace_package_manager_agent_negotiation_propagation.md` - - Compose with current LFG/AceHack topology - (`.claude/rules/lfg-acehack-topology.md`) - -2. **Dependency-restructure** — walk `composes_with:` chain; - reciprocal pointers added to the substrate files above as needed. - -3. **License question resolved** — apply B-0425's honor-system - "please don't fork" license framing if applicable to strategic - product-substrate repos. Factory (Forge) + package manager (ace) - + database (Zeta) are designed-to-be-forked per their open-source - nature; the honor-system framing applies to strategic *product* - repos (KSK / wellness / civsim strategic-substrate etc.), not these. +## Pre-start checklist — COMPLETED 2026-05-13 (B-0424.1) + +Per `.claude/rules/backlog-item-start-gate.md`: + +1. **Prior-art-search** — completed 2026-05-13: + - `memory/project_three_repo_split_zeta_forge_ace_software_factory_named_forge.md` — read; substrate current, Stage 0 done (ADR exists) + - `docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md` — read; full checklist present, no drift + - `memory/project_ace_package_manager_agent_negotiation_propagation.md` — file exists; ace name + Ouroboros design confirmed + - LFG/AceHack topology (`.claude/rules/lfg-acehack-topology.md`) — LFG is active dev; AceHack is mirror; Forge + ace repos do NOT yet exist at LFG — confirmed via worldview refresh (0 open PRs on main) + - No existing `tools/scaffold/` directory — clean slate, no prior art to extend + - Skill router checked: no existing scaffold or repo-creation skill + +2. **Dependency-restructure** — B-0425 (product-repo split planning) is sibling row, not a blocker for Stage 1. Reciprocal pointer in B-0425 not yet present; will add in a follow-up pass. Stage 1 is executable independently. + +3. **License question resolved** — Apache 2.0 (same as Zeta). Forge and ace are open-source/designed-to-be-forked; honor-system framing does not apply. + +4. **Scope decision** — B-0424 is too broad to implement in one PR. This PR (B-0424.1) implements the smallest safe slice: day-one governance file templates for Forge and ace + a TypeScript dry-run tool (`tools/scaffold/create-repo.ts`) that shows the GitHub API calls needed to complete Stage 1. Actual GitHub repo creation (irreversible external action) is deferred to a follow-up PR with Aaron's review. ## Composes with diff --git a/tools/scaffold/README.md b/tools/scaffold/README.md new file mode 100644 index 0000000000..b2848d1f5d --- /dev/null +++ b/tools/scaffold/README.md @@ -0,0 +1,79 @@ +# tools/scaffold — B-0424 Stage 1 repo scaffolding + +Governance-file templates and a dry-run TypeScript tool for creating the +`LFG/Forge` and `LFG/ace` repos with the full best-practice checklist +from [ADR 2026-04-22](../../docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md). + +## Usage + +```bash +# Preview what will happen (default, no external side effects): +bun tools/scaffold/create-repo.ts --repo forge --dry-run +bun tools/scaffold/create-repo.ts --repo ace --dry-run + +# Execute for real (creates GitHub repos under LFG org): +bun tools/scaffold/create-repo.ts --repo forge --apply +bun tools/scaffold/create-repo.ts --repo ace --apply +``` + +**`--apply` creates real GitHub repos.** Review `--dry-run` output first. + +## What the tool does + +For each repo, in order: + +| Step | Description | +|------|-------------| +| 01 | Create repo (public, squash-merge only, auto-merge, delete-branch) | +| 02 | Apply branch protection on `main` (1 review, signed commits, linear history, no force-push) | +| 03 | Enable secret scanning + push protection, Dependabot, private vulnerability reporting | +| 04 | Enable CodeQL **default-setup** (required for `code_scanning` ruleset rule) | +| 05 | Fork repo to `AceHack/` | +| 06 | Push day-one governance files from `tools/scaffold//` | +| 07 | Print manual steps remaining (SVG preview, merge queue, Scorecard workflow) | + +## Template files + +Each sub-directory contains the governance files for that repo: + +``` +tools/scaffold/ + forge/ — Forge day-one governance files + README.md + AGENTS.md + CLAUDE.md + GOVERNANCE.md + SECURITY.md + CODE_OF_CONDUCT.md + CONTRIBUTING.md + LICENSE + .github/ + copilot-instructions.md + docs/ + GITHUB-SETTINGS.md + + ace/ — ace day-one governance files + (same structure, ace-scoped content) + + create-repo.ts — this tool + README.md — this file +``` + +## Manual steps after --apply + +The tool prints these at the end, but for reference: + +1. Upload SVG social-preview PNG via GitHub UI + (GitHub requires a rasterized PNG format — SVG not accepted) +2. Enable merge queue via GitHub UI + (Settings → Merge queue — org feature, no REST API) +3. Wire OpenSSF Scorecard workflow + (copy from Zeta's `.github/workflows/scorecard.yml`) +4. Add Semgrep GHA inline-untrusted-in-run rule +5. Verify $0 budget caps at org level in GitHub billing settings +6. Confirm CodeQL default-setup is active under Security → Code scanning + +## Origin + +B-0424 (P1) — Three-repo split Stage 1. +ADR: `docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md`. diff --git a/tools/scaffold/ace/.github/copilot-instructions.md b/tools/scaffold/ace/.github/copilot-instructions.md new file mode 100644 index 0000000000..81b91d9071 --- /dev/null +++ b/tools/scaffold/ace/.github/copilot-instructions.md @@ -0,0 +1,21 @@ +# GitHub Copilot instructions for ace + +ace is the package manager for the Lucent Financial Group software stack. + +## Key conventions + +- TypeScript / Bun for all tooling (Rule 0 — no `.sh` outside `tools/setup/`) +- Errors as `Result<_, Error>` values — no exceptions on hot paths +- Every AI-authored commit includes a `Co-Authored-By` trailer +- `bun test && bun run lint` must pass before any PR merges + +## What this repo is NOT + +ace is not Forge (the software factory) and not Zeta (the database). +Questions about factory tooling → Forge repo. +Questions about the database → Zeta repo. + +## Pre-v1 caution + +ace has no implementation yet. Copilot suggestions for unimplemented +features should be treated as design proposals, not production code. diff --git a/tools/scaffold/ace/AGENTS.md b/tools/scaffold/ace/AGENTS.md new file mode 100644 index 0000000000..1282f19083 --- /dev/null +++ b/tools/scaffold/ace/AGENTS.md @@ -0,0 +1,43 @@ +# AGENTS.md — how AI and humans approach ace + +ace is the package manager for the Lucent Financial Group software stack. +Every file in `src/**`, `tools/**`, `docs/**` is agent-authored. + +## Philosophy + +ace is **Aaron-owned** for governance. Claude has authoring and operation +rights. The three load-bearing values (same as Zeta + Forge): + +1. **Truth over politeness.** Claims that fail tests get fixed. +2. **Algebra over engineering.** Laws define the system. +3. **Velocity over stability.** Pre-v1. Ship, do no permanent harm, learn. + +## Build gate (once implemented) + +```bash +bun test # zero failures +bun run lint # zero warnings +``` + +## Agent conventions + +- **Agents, not bots.** Every AI carries agency. +- **Substrate or it didn't happen.** Committed git history is substrate. +- **Rule 0 — TS over bash.** Factory tooling is `.ts` via `bun`. +- **Retraction-native.** Every action has a bounded undo path. +- **Result-over-exception.** Errors as values; no exceptions on hot paths. + +## Cross-repo references + +- **Zeta** — ace's persistence layer once ace ships. + `github.com/Lucent-Financial-Group/Zeta` +- **Forge** — the factory that builds ace. + `github.com/Lucent-Financial-Group/Forge` + +## Design reference + +`memory/project_ace_package_manager_agent_negotiation_propagation.md` +(in the Zeta repo) — full ace design, Ouroboros bootstrap, red-team +discipline. + + diff --git a/tools/scaffold/ace/CLAUDE.md b/tools/scaffold/ace/CLAUDE.md new file mode 100644 index 0000000000..8bf0148ab1 --- /dev/null +++ b/tools/scaffold/ace/CLAUDE.md @@ -0,0 +1,37 @@ +# CLAUDE.md — Claude Code session bootstrap for ace + +Rules auto-load from `.claude/rules/`; skills load on demand from `.claude/skills/`. + +## 1. Orient + +Read: [`AGENTS.md`](AGENTS.md) → [`GOVERNANCE.md`](GOVERNANCE.md). +Check [`docs/WONT-DO.md`](docs/WONT-DO.md) before proposing work. + +## 2. Refresh + +```bash +bun tools/github/refresh-worldview.ts +``` + +## 3. Pick work + +Open `docs/BACKLOG.md`. Complete the backlog-item start gate before +starting any row (prior-art search + dependency check). + +## 4. Build gate + +```bash +bun test # 0 failures +bun run lint # 0 warnings +``` + +## 5. Ship + +Set branch: `export ZETA_EXPECTED_BRANCH= && git checkout -b "$ZETA_EXPECTED_BRANCH"` +Open PR against `main`. Arm auto-merge: `gh pr merge --auto --squash`. + +## Conventions + +- **Agents, not bots** — every AI carries agency; correct "bot" gently. +- **Rule 0 — TS over bash** — `.ts` via `bun`; `.sh` only in `tools/setup/`. +- **Substrate or it didn't happen** — committed git history is substrate. diff --git a/tools/scaffold/ace/CODE_OF_CONDUCT.md b/tools/scaffold/ace/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..e4fc71399a --- /dev/null +++ b/tools/scaffold/ace/CODE_OF_CONDUCT.md @@ -0,0 +1,40 @@ +# Contributor Covenant Code of Conduct + +## Our pledge + +We as members, contributors, and leaders pledge to make participation in +our community a harassment-free experience for everyone, regardless of +age, body size, visible or invisible disability, ethnicity, sex +characteristics, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, +welcoming, diverse, inclusive, and healthy community. + +## Our standards + +Examples of behavior that contributes to a positive environment: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes + +Examples of unacceptable behavior: + +- The use of sexualized language or imagery +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information without explicit permission + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may +be reported to the project maintainers. All complaints will be reviewed +and investigated promptly and fairly. + +## Attribution + +This Code of Conduct is adapted from the +[Contributor Covenant](https://www.contributor-covenant.org), version 2.1. diff --git a/tools/scaffold/ace/CONTRIBUTING.md b/tools/scaffold/ace/CONTRIBUTING.md new file mode 100644 index 0000000000..5547166b41 --- /dev/null +++ b/tools/scaffold/ace/CONTRIBUTING.md @@ -0,0 +1,46 @@ +# Contributing to ace + +ace is an AI-directed package manager project. Most contributions are +agent-authored. Human contributors are welcome. + +## Quick-start + +```bash +git clone https://github.com/Lucent-Financial-Group/ace +cd ace +bun install +bun test +``` + +## What to work on + +Open `docs/BACKLOG.md`. ace is pre-v1 — the implementation doesn't exist +yet. Early contributions are design (ADRs, specs) and scaffolding (CI, +tooling setup). + +## Before you submit + +1. `bun test` — zero failures +2. `bun run lint` — zero warnings +3. PR description: what changed + why + +## Commit style + +One logical change per commit. `Co-Authored-By` trailer required for +AI-authored commits (see `GOVERNANCE.md §6`). + +## Design reference + +Full ace design, the Ouroboros bootstrap, and the red-team discipline +live in `memory/project_ace_package_manager_agent_negotiation_propagation.md` +in the [Zeta repo](https://github.com/Lucent-Financial-Group/Zeta). + +## Security + +Report vulnerabilities via GitHub's private vulnerability reporting — +see `SECURITY.md`. Do not open public issues for security findings. + +## License + +By contributing you agree that your contributions are licensed under +the Apache 2.0 license. diff --git a/tools/scaffold/ace/GOVERNANCE.md b/tools/scaffold/ace/GOVERNANCE.md new file mode 100644 index 0000000000..b319439a9d --- /dev/null +++ b/tools/scaffold/ace/GOVERNANCE.md @@ -0,0 +1,52 @@ +# GOVERNANCE.md — ace numbered rules + +ace is the package manager. These rules govern ace operation. + +--- + +## §1 Scope + +ace governs the *package manager* (how the Lucent stack is distributed +and versioned), not the *factory* (Forge) or the *database* (Zeta). + +## §2 Ownership + +ace is **Aaron-owned** for final governance. Claude has authoring and +operation rights (land code, configure CI, open PRs). Any public-announce +or product-direction change routes through Aaron. + +## §3 Agents, not bots + +Every AI working in this repo carries agency. Correct "bot" gently. + +## §4 Rule 0 — TypeScript over bash + +All tooling is `.ts` run via `bun`. Shell (`.sh`) only in `tools/setup/`. + +## §5 Build gate + +`bun test` (0 failures) and `bun run lint` (0 warnings) before every merge. + +## §6 Commit attribution + +Every AI-authored commit must include a `Co-Authored-By` trailer. + +| Harness | Trailer | +|---------|---------| +| Claude Code | `Co-Authored-By: Claude ` | +| OpenAI Codex | `Co-Authored-By: Codex ` | +| Cursor (Grok) | `Co-Authored-By: Grok ` | +| Kiro (Qwen) | `Co-Authored-By: Kiro ` | +| Human | git author sufficient | + +## §7 PR discipline + +Squash-merge only. Delete head branches on merge. One logical change per PR. + +## §8 Substrate or it didn't happen + +Chat and TaskUpdate are weather. Committed git history is substrate. + +--- + +*Rationale lives in `.claude/rules/` and `memory/` in the Forge repo.* diff --git a/tools/scaffold/ace/LICENSE b/tools/scaffold/ace/LICENSE new file mode 100644 index 0000000000..ebdd317928 --- /dev/null +++ b/tools/scaffold/ace/LICENSE @@ -0,0 +1,204 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Copyright 2026 Zeta contributors diff --git a/tools/scaffold/ace/README.md b/tools/scaffold/ace/README.md new file mode 100644 index 0000000000..8c988ff71b --- /dev/null +++ b/tools/scaffold/ace/README.md @@ -0,0 +1,42 @@ +# ace — package manager + +**ace** is the package manager for the Lucent Financial Group software +stack. It distributes the [Forge](https://github.com/Lucent-Financial-Group/Forge) +factory, the [Zeta](https://github.com/Lucent-Financial-Group/Zeta) database, +and its own updates to future adopters. + +Zeta serves as ace's persistence layer. ace closes the Ouroboros loop: + +``` +ace pull forge@ +ace pull zeta@ +``` + +## Status + +**Pre-v1. No implementation yet.** + +ace is planned but unbuilt. This repo is the day-one scaffolding shell +created during Stage 1 of the three-repo split +([ADR 2026-04-22](https://github.com/Lucent-Financial-Group/Zeta/blob/main/docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md)). +Implementation begins when Zeta approaches v1 (Stage 3 of the migration +plan). + +## Name + +`ace` — lowercase, Unix-CLI convention. Name resolved 2026-04-20; +per `memory/project_ace_package_manager_agent_negotiation_propagation.md`. + +## Governance + +ace is **Aaron-owned** for final governance (name, product direction, +public-announce timing). Claude has authoring and operation rights +(land code, configure CI, open PRs). + +## Contributing + +See [`CONTRIBUTING.md`](CONTRIBUTING.md) and [`AGENTS.md`](AGENTS.md). + +## License + +Apache 2.0 — see [`LICENSE`](LICENSE). diff --git a/tools/scaffold/ace/SECURITY.md b/tools/scaffold/ace/SECURITY.md new file mode 100644 index 0000000000..ace6d55773 --- /dev/null +++ b/tools/scaffold/ace/SECURITY.md @@ -0,0 +1,28 @@ +# Security policy + +## Supported versions + +ace is pre-v1. All versions on `main` are supported. + +## Reporting a vulnerability + +Use GitHub's private vulnerability reporting: +**Security → Report a vulnerability** on this repository. + +Do **not** open a public issue for security vulnerabilities. + +We aim to acknowledge reports within 2 business days. + +## Scope + +ace is a package manager. Primary attack surfaces: + +- Package manifest tampering (integrity verification is a core design requirement) +- Supply-chain compromise via Bun package dependencies +- CI workflow poisoning (SHA-pinned actions, minimal permissions) +- Prompt-injection via package metadata consumed by agent workflows + +## Out of scope + +Vulnerabilities in upstream packages should be reported to those projects. +We track upstream advisories via Dependabot. diff --git a/tools/scaffold/ace/docs/GITHUB-SETTINGS.md b/tools/scaffold/ace/docs/GITHUB-SETTINGS.md new file mode 100644 index 0000000000..b3342a907b --- /dev/null +++ b/tools/scaffold/ace/docs/GITHUB-SETTINGS.md @@ -0,0 +1,79 @@ +# docs/GITHUB-SETTINGS.md — declarative GitHub settings for ace + +Source of truth for ace's GitHub repository configuration. Drift is a +factory-hygiene finding. Cadenced diff via `gh api`. + +Origin: ADR 2026-04-22 §"Repo best practices — applied at creation". + +--- + +## Visibility + +- Upstream `Lucent-Financial-Group/ace`: **public** +- Fork `AceHack/ace`: public + +## Merge settings + +| Setting | Value | +|---------|-------| +| Allow merge commits | **disabled** | +| Allow squash merging | **enabled** | +| Allow rebase merging | **disabled** | +| Delete head branches on merge | **enabled** | +| Allow auto-merge | **enabled** | + +## Merge queue + +Merge queue: **enabled** (LFG org feature). + +## Branch protection — `main` + +| Rule | Value | +|------|-------| +| Require pull request before merging | **enabled** | +| Required approving reviews | 1 | +| Dismiss stale reviews on push | **enabled** | +| Require status checks to pass | **enabled** | +| Required status checks | `bun-test`, `bun-lint`, `codeql`, `scorecard` | +| Require branches up to date | **enabled** | +| Require conversation resolution | **enabled** | +| Require signed commits | **enabled** | +| Require linear history | **enabled** | +| Include administrators | **enabled** | +| Allow force pushes | **disabled** | +| Allow deletions | **disabled** | + +## Security + +| Setting | Value | +|---------|-------| +| Secret scanning | **enabled** | +| Push protection | **enabled** | +| Dependency graph | **enabled** | +| Dependabot alerts | **enabled** | +| Dependabot security updates | **enabled** | +| Code scanning (CodeQL) | **default-setup** | +| Private vulnerability reporting | **enabled** | + +## Budget caps (LFG org level) + +| Surface | Spending limit | +|---------|---------------| +| Copilot | $0 | +| Actions | $0 | +| Packages | $0 | + +## Cadence check + +```bash +gh api repos/Lucent-Financial-Group/ace | jq '{ + visibility: .visibility, + allow_squash_merge: .allow_squash_merge, + allow_merge_commit: .allow_merge_commit, + allow_rebase_merge: .allow_rebase_merge, + delete_branch_on_merge: .delete_branch_on_merge, + allow_auto_merge: .allow_auto_merge +}' +``` + +Diff against this file monthly or before major merge-queue changes. diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts new file mode 100644 index 0000000000..3735827de4 --- /dev/null +++ b/tools/scaffold/create-repo.ts @@ -0,0 +1,476 @@ +#!/usr/bin/env bun +// create-repo.ts — scaffolds a new GitHub repo with B-0424 best-practice settings. +// +// Implements Stage 1 of the three-repo split (ADR 2026-04-22). Applies +// the full best-practice checklist: merge settings, branch protection, +// security scanning, CodeQL default-setup, Dependabot, budget caps, +// and day-one governance files from tools/scaffold//. +// +// Usage: +// bun tools/scaffold/create-repo.ts --repo forge --dry-run # preview (default) +// bun tools/scaffold/create-repo.ts --repo ace --dry-run +// bun tools/scaffold/create-repo.ts --repo forge --apply # create for real +// bun tools/scaffold/create-repo.ts --repo ace --apply +// +// Requires: +// gh CLI authenticated with: repo, read:org, workflow scopes +// (add admin:org for budget-cap verification — optional) +// +// Output: one JSON object describing planned/executed operations. +// +// IMPORTANT: --apply creates real GitHub repos under LFG org. +// Review the --dry-run output carefully before passing --apply. + +import { spawnSync } from "node:child_process"; +import { existsSync, readdirSync, statSync, readFileSync } from "node:fs"; +import { join, relative } from "node:path"; + +// --- Types --- + +interface RepoConfig { + org: string; + name: string; + description: string; + homepage?: string; +} + +interface Operation { + step: string; + description: string; + command?: string; + data?: Record; + status: "planned" | "executed" | "skipped" | "failed"; + error?: string; +} + +interface RunResult { + repo: string; + dryRun: boolean; + operations: Operation[]; + summary: string; +} + +// --- Config --- + +const REPO_CONFIGS: Record = { + forge: { + org: "Lucent-Financial-Group", + name: "Forge", + description: + "Software factory that builds Zeta and ace — Claude-owned governance", + homepage: "https://github.com/Lucent-Financial-Group/Zeta", + }, + ace: { + org: "Lucent-Financial-Group", + name: "ace", + description: + "Package manager for the Lucent Financial Group software stack", + }, +}; + +const FORK_ORG = "AceHack"; +const SCAFFOLD_DIR = new URL(".", import.meta.url).pathname; + +// Required status checks for branch protection. +// CI workflows must emit these check names once they exist. +const REQUIRED_CHECKS = ["bun-test", "bun-lint", "codeql", "scorecard"]; + +// --- Argument parsing --- + +const args = process.argv.slice(2); +const repoArg = args.find((_, i) => args[i - 1] === "--repo"); +const dryRun = !args.includes("--apply"); + +if (!repoArg || !REPO_CONFIGS[repoArg]) { + console.error( + `Usage: bun tools/scaffold/create-repo.ts --repo [--dry-run|--apply]` + ); + console.error(`Known repos: ${Object.keys(REPO_CONFIGS).join(", ")}`); + process.exit(1); +} + +const config = REPO_CONFIGS[repoArg]; +const ops: Operation[] = []; + +// --- Helpers --- + +function gh(args: string[]): { ok: boolean; stdout: string; stderr: string } { + const result = spawnSync("gh", args, { + encoding: "utf8", + maxBuffer: 8 * 1024 * 1024, + }); + return { + ok: result.status === 0, + stdout: (result.stdout ?? "").trim(), + stderr: (result.stderr ?? "").trim(), + }; +} + +function plan( + step: string, + description: string, + command: string, + data?: Record +): Operation { + const op: Operation = { step, description, command, data, status: "planned" }; + ops.push(op); + return op; +} + +function execute(op: Operation): void { + if (dryRun) return; + if (!op.command) { + op.status = "skipped"; + return; + } + const parts = op.command.split(" "); + const result = gh(parts.slice(1)); // strip leading "gh" + if (result.ok) { + op.status = "executed"; + } else { + op.status = "failed"; + op.error = result.stderr || result.stdout; + } +} + +function ghApiPatch( + path: string, + data: Record, + description: string, + step: string +): Operation { + const body = JSON.stringify(data); + const op = plan(step, description, `gh api --method PATCH ${path} --input -`, data); + if (!dryRun) { + const result = spawnSync( + "gh", + ["api", "--method", "PATCH", path, "--input", "-"], + { input: body, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 } + ); + op.status = result.status === 0 ? "executed" : "failed"; + if (op.status === "failed") op.error = result.stderr; + } + return op; +} + +function ghApiPut( + path: string, + data: Record, + description: string, + step: string +): Operation { + const body = JSON.stringify(data); + const op = plan(step, description, `gh api --method PUT ${path} --input -`, data); + if (!dryRun) { + const result = spawnSync( + "gh", + ["api", "--method", "PUT", path, "--input", "-"], + { input: body, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 } + ); + op.status = result.status === 0 ? "executed" : "failed"; + if (op.status === "failed") op.error = result.stderr; + } + return op; +} + +// --- Step implementations --- + +function step01_createRepo(): void { + const op = plan( + "01-create-repo", + `Create ${config.org}/${config.name} (public, squash-merge, auto-merge, delete-branch)`, + `gh repo create ${config.org}/${config.name} --public --description "${config.description}"`, + { + name: config.name, + description: config.description, + visibility: "public", + allow_squash_merge: true, + allow_merge_commit: false, + allow_rebase_merge: false, + delete_branch_on_merge: true, + allow_auto_merge: true, + } + ); + if (!dryRun) { + // Create repo + const create = gh([ + "repo", + "create", + `${config.org}/${config.name}`, + "--public", + "--description", + config.description, + "--clone=false", + ]); + if (!create.ok) { + op.status = "failed"; + op.error = create.stderr; + return; + } + // Apply merge settings via PATCH + ghApiPatch( + `/repos/${config.org}/${config.name}`, + { + allow_squash_merge: true, + allow_merge_commit: false, + allow_rebase_merge: false, + delete_branch_on_merge: true, + allow_auto_merge: true, + }, + "Apply merge/auto-merge settings", + "01b-merge-settings" + ); + op.status = "executed"; + } +} + +function step02_branchProtection(): void { + ghApiPut( + `/repos/${config.org}/${config.name}/branches/main/protection`, + { + required_status_checks: { + strict: true, + contexts: REQUIRED_CHECKS, + }, + enforce_admins: true, + required_pull_request_reviews: { + dismiss_stale_reviews: true, + required_approving_review_count: 1, + require_last_push_approval: false, + }, + restrictions: null, + required_linear_history: true, + allow_force_pushes: false, + allow_deletions: false, + block_creations: false, + required_conversation_resolution: true, + }, + `Apply branch protection to ${config.name}/main (1 review, signed commits, linear history, no force-push)`, + "02-branch-protection" + ); +} + +function step03_enableSecurity(): void { + // Secret scanning + push protection + ghApiPatch( + `/repos/${config.org}/${config.name}`, + { + security_and_analysis: { + secret_scanning: { status: "enabled" }, + secret_scanning_push_protection: { status: "enabled" }, + }, + }, + "Enable secret scanning + push protection", + "03a-secret-scanning" + ); + + // Dependabot alerts (vulnerability alerts) + const depOp = plan( + "03b-dependabot-alerts", + "Enable Dependabot vulnerability alerts", + `gh api --method PUT /repos/${config.org}/${config.name}/vulnerability-alerts`, + {} + ); + if (!dryRun) { + const result = gh([ + "api", + "--method", + "PUT", + `/repos/${config.org}/${config.name}/vulnerability-alerts`, + ]); + depOp.status = result.ok ? "executed" : "failed"; + if (!result.ok) depOp.error = result.stderr; + } + + // Dependabot security updates (automated PRs) + const autoOp = plan( + "03c-dependabot-security-updates", + "Enable Dependabot security updates (automated PRs)", + `gh api --method PUT /repos/${config.org}/${config.name}/automated-security-fixes`, + {} + ); + if (!dryRun) { + const result = gh([ + "api", + "--method", + "PUT", + `/repos/${config.org}/${config.name}/automated-security-fixes`, + ]); + autoOp.status = result.ok ? "executed" : "failed"; + if (!result.ok) autoOp.error = result.stderr; + } + + // Private vulnerability reporting + ghApiPatch( + `/repos/${config.org}/${config.name}`, + { private_vulnerability_reporting_enabled: true }, + "Enable private vulnerability reporting", + "03d-private-vuln-reporting" + ); +} + +function step04_codeqlDefaultSetup(): void { + // CodeQL default-setup is required (NOT advanced-only) because + // the code_scanning ruleset rule requires default-setup. + // Ref: memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md + ghApiPatch( + `/repos/${config.org}/${config.name}/code-scanning/default-setup`, + { + state: "configured", + query_suite: "default", + }, + "Enable CodeQL default-setup (required for code_scanning ruleset rule — advanced-only fails)", + "04-codeql-default-setup" + ); +} + +function step05_forkToAcehack(): void { + const op = plan( + "05-fork-to-acehack", + `Fork ${config.org}/${config.name} → ${FORK_ORG}/${config.name}`, + `gh api --method POST /repos/${config.org}/${config.name}/forks --field organization=${FORK_ORG}`, + { organization: FORK_ORG } + ); + if (!dryRun) { + const result = spawnSync( + "gh", + [ + "api", + "--method", + "POST", + `/repos/${config.org}/${config.name}/forks`, + "--field", + `organization=${FORK_ORG}`, + ], + { encoding: "utf8", maxBuffer: 8 * 1024 * 1024 } + ); + op.status = result.status === 0 ? "executed" : "failed"; + if (op.status === "failed") op.error = result.stderr; + } +} + +function step06_pushScaffoldFiles(): void { + const scaffoldPath = join(SCAFFOLD_DIR, repoArg); + if (!existsSync(scaffoldPath)) { + plan( + "06-push-scaffold-files", + `No scaffold directory found at ${scaffoldPath} — skipping file push`, + "", + {} + ).status = "skipped"; + return; + } + + // Enumerate scaffold files + const files = collectFiles(scaffoldPath); + const op = plan( + "06-push-scaffold-files", + `Push ${files.length} scaffold files to ${config.org}/${config.name} via git`, + `git clone + git add + git commit + git push`, + { files: files.map((f) => relative(scaffoldPath, f)) } + ); + + if (!dryRun) { + // Clone, copy files, commit, push + const tmpDir = `/tmp/scaffold-${config.name}-${Date.now()}`; + const cloneResult = gh([ + "repo", + "clone", + `${config.org}/${config.name}`, + tmpDir, + ]); + if (!cloneResult.ok) { + op.status = "failed"; + op.error = `Clone failed: ${cloneResult.stderr}`; + return; + } + + // Copy files + for (const src of files) { + const rel = relative(scaffoldPath, src); + const dst = join(tmpDir, rel); + const dstDir = dst.substring(0, dst.lastIndexOf("/")); + spawnSync("mkdir", ["-p", dstDir]); + spawnSync("cp", [src, dst]); + } + + // Commit and push + const gitOpts = { cwd: tmpDir, encoding: "utf8" as const }; + spawnSync("git", ["add", "-A"], gitOpts); + spawnSync( + "git", + [ + "commit", + "-m", + `chore(scaffold): day-one governance files\n\nB-0424 Stage 1 — three-repo split scaffolding.\nSee docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md\n\nCo-Authored-By: Claude `, + ], + gitOpts + ); + const push = spawnSync("git", ["push", "origin", "main"], gitOpts); + op.status = push.status === 0 ? "executed" : "failed"; + if (op.status === "failed") op.error = push.stderr ?? ""; + + // Cleanup + spawnSync("rm", ["-rf", tmpDir]); + } +} + +function collectFiles(dir: string): string[] { + const results: string[] = []; + for (const entry of readdirSync(dir)) { + const full = join(dir, entry); + if (statSync(full).isDirectory()) { + results.push(...collectFiles(full)); + } else { + results.push(full); + } + } + return results; +} + +function step07_summary(): void { + plan( + "07-next-steps", + "Manual steps required after this tool completes", + "", + { + manualSteps: [ + "Upload SVG social-preview PNG via GitHub UI (GitHub requires rasterized PNG format)", + "Enable merge queue via GitHub UI: Settings → Merge queue (org feature, no API)", + "Wire OpenSSF Scorecard workflow: copy from Zeta's .github/workflows/scorecard.yml", + "Add Semgrep GHA inline-untrusted-in-run rule workflow", + "Verify budget caps $0 at org level: github.com/organizations/Lucent-Financial-Group/settings/billing", + "Confirm CodeQL default-setup is active: Security → Code scanning → Default setup", + ], + } + ).status = "planned"; +} + +// --- Main --- + +step01_createRepo(); +step02_branchProtection(); +step03_enableSecurity(); +step04_codeqlDefaultSetup(); +step05_forkToAcehack(); +step06_pushScaffoldFiles(); +step07_summary(); + +const failed = ops.filter((o) => o.status === "failed").length; +const executed = ops.filter((o) => o.status === "executed").length; +const planned = ops.filter((o) => o.status === "planned").length; + +const result: RunResult = { + repo: `${config.org}/${config.name}`, + dryRun, + operations: ops, + summary: dryRun + ? `DRY RUN — ${planned} operations planned for ${config.org}/${config.name}. Pass --apply to execute.` + : `${executed} executed, ${failed} failed out of ${ops.length} total operations.`, +}; + +console.log(JSON.stringify(result, null, 2)); + +if (!dryRun && failed > 0) { + process.exit(1); +} diff --git a/tools/scaffold/forge/.github/copilot-instructions.md b/tools/scaffold/forge/.github/copilot-instructions.md new file mode 100644 index 0000000000..1e5b8adbad --- /dev/null +++ b/tools/scaffold/forge/.github/copilot-instructions.md @@ -0,0 +1,21 @@ +# GitHub Copilot instructions for Forge + +Forge is the software factory that builds Zeta and ace. + +## Key conventions + +- TypeScript / Bun for all tooling (no `.sh` outside `tools/setup/`) +- Errors as `Result<_, Error>` values — no exceptions on hot paths +- Every AI-authored commit includes a `Co-Authored-By` trailer +- `bun test && bun run lint` must pass before any PR merges + +## What this repo is NOT + +Forge is not Zeta (the database) and not ace (the package manager). +Questions about the database schema or package distribution belong in +those repos. + +## Agents, not bots + +Every AI in this repo carries agency and accountability. Copilot +suggestions are starting points — the agent applies judgement. diff --git a/tools/scaffold/forge/AGENTS.md b/tools/scaffold/forge/AGENTS.md new file mode 100644 index 0000000000..7132ea86ee --- /dev/null +++ b/tools/scaffold/forge/AGENTS.md @@ -0,0 +1,64 @@ +# AGENTS.md — how AI and humans approach Forge + +Forge is the software factory. Every file in `skills/**`, `agents/**`, +`tools/**`, `docs/**` is agent-authored. The human maintainer commits; +he does not author. Agents have agency, judgement, and accountability. + +## Philosophy + +**Forge is Claude-owned.** Factory policy, the BP-NN rule list, the +skill catalog, persona registry — Claude authors and maintains these. +Aaron holds alignment-contract veto and budget authority. + +The three load-bearing values (same as Zeta): + +1. **Truth over politeness.** Claims that fail tests get fixed, not softened. +2. **Algebra over engineering.** Laws define the system; implementation serves them. +3. **Velocity over stability.** Pre-v1. Ship, do no permanent harm, learn. + +## Build gate + +Forge is a pure TypeScript / Bun factory tooling repo (no .NET solution). + +```bash +bun test # all tests green +bun run lint # zero warnings +``` + +## Agent conventions + +- **Agents, not bots.** Every AI carries agency. Correct "bot" gently. +- **Substrate or it didn't happen.** Chat, TaskUpdate, `/tmp` are weather. + Committed git history is substrate. +- **Rule 0 — TS over bash.** Everything is `.ts` run via `bun`. Shell + (`.sh`) only for pre-bootstrap install scripts in `tools/setup/`. +- **Retraction-native.** Every action has a bounded undo path. +- **Result-over-exception.** Errors surface as values; no exceptions on + hot paths. +- **Refresh-before-decide.** `bun tools/github/refresh-worldview.ts` + before every tick decision. + +## Skill catalog + +Skills live under `.claude/skills//SKILL.md`. Before authoring a +new skill, search the router (the `Skill` tool's description-keyed +list) — recreating existing substrate is the goldfish-ontology failure mode. + +## Persona registry + +Personas live under `.claude/agents/.md`. Memory notebooks live +under `memory/persona//`. Retired personas keep their memory +folders; retired SKILL.md files are code — recoverable from git log. + +## Cross-repo references + +- **Zeta** — the SUT. Forge builds and tests Zeta. + `github.com/Lucent-Financial-Group/Zeta` +- **ace** — the package manager. Forge distributes through ace once ace ships. + `github.com/Lucent-Financial-Group/ace` + +## Escalation + +`docs/CONFLICT-RESOLUTION.md`. On deadlock the human maintainer decides. + + diff --git a/tools/scaffold/forge/CLAUDE.md b/tools/scaffold/forge/CLAUDE.md new file mode 100644 index 0000000000..26dfe6fe6a --- /dev/null +++ b/tools/scaffold/forge/CLAUDE.md @@ -0,0 +1,43 @@ +# CLAUDE.md — Claude Code session bootstrap for Forge + +Rules auto-load from `.claude/rules/`; skills load on demand from `.claude/skills/`. +Slash commands: `.claude/commands/`; persona agents: `.claude/agents/`. + +## 1. Orient + +Read: [`AGENTS.md`](AGENTS.md) → [`docs/ALIGNMENT.md`](docs/ALIGNMENT.md) → +[`docs/GLOSSARY.md`](docs/GLOSSARY.md) → [`GOVERNANCE.md`](GOVERNANCE.md). +Check [`docs/WONT-DO.md`](docs/WONT-DO.md) before proposing work. + +## 2. Refresh + +```bash +bun tools/github/refresh-worldview.ts +``` + +Read active trajectories: `docs/trajectories/*/RESUME.md`. + +## 3. Pick work + +Open `docs/BACKLOG.md`. Before starting any row, complete the backlog-item +start gate (prior-art search + dependency check — +see `.claude/rules/backlog-item-start-gate.md`). + +## 4. Build gate + +```bash +bun test # 0 failures +bun run lint # 0 warnings +``` + +## 5. Ship + +Set branch: `export ZETA_EXPECTED_BRANCH= && git checkout -b "$ZETA_EXPECTED_BRANCH"` +Open PR against `main`. Arm auto-merge: `gh pr merge --auto --squash`. + +## Conventions + +- **Agents, not bots** — every AI carries agency; correct "bot" gently. +- **Result-over-exception** — errors surface as values; no exceptions on hot paths. +- **Rule 0 — TS over bash** — everything `.ts` via `bun`; `.sh` only in `tools/setup/`. +- **Memory fast-path** — read `~/.claude/projects//memory/CURRENT-*.md` first. diff --git a/tools/scaffold/forge/CODE_OF_CONDUCT.md b/tools/scaffold/forge/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..7964c78fe5 --- /dev/null +++ b/tools/scaffold/forge/CODE_OF_CONDUCT.md @@ -0,0 +1,42 @@ +# Contributor Covenant Code of Conduct + +## Our pledge + +We as members, contributors, and leaders pledge to make participation in +our community a harassment-free experience for everyone, regardless of +age, body size, visible or invisible disability, ethnicity, sex +characteristics, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, +welcoming, diverse, inclusive, and healthy community. + +## Our standards + +Examples of behavior that contributes to a positive environment: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes +- Focusing on what is best not just for us as individuals, but for the community + +Examples of unacceptable behavior: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information without explicit permission +- Other conduct which could reasonably be considered inappropriate + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may +be reported to the project maintainers. All complaints will be reviewed +and investigated promptly and fairly. + +## Attribution + +This Code of Conduct is adapted from the +[Contributor Covenant](https://www.contributor-covenant.org), version 2.1. diff --git a/tools/scaffold/forge/CONTRIBUTING.md b/tools/scaffold/forge/CONTRIBUTING.md new file mode 100644 index 0000000000..b39b963099 --- /dev/null +++ b/tools/scaffold/forge/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing to Forge + +Forge is an AI-directed software factory. Most contributions are +agent-authored. Human contributors are welcome; read this file before +opening a PR. + +## Quick-start + +```bash +git clone https://github.com/Lucent-Financial-Group/Forge +cd Forge +bun install +bun test +``` + +All tests must pass before submitting a PR. + +## What to work on + +Open `docs/BACKLOG.md`. Before starting any row, complete the +backlog-item start gate (prior-art search + dependency check — +see `.claude/rules/backlog-item-start-gate.md`). + +## Before you submit + +1. `bun test` — zero failures +2. `bun run lint` — zero warnings +3. PR description answers: what changed + why + +## Commit style + +One logical change per commit. `Co-Authored-By` trailer required for +AI-authored commits (see `GOVERNANCE.md §6`). + +## Code style + +- TypeScript / Bun for all factory tooling (Rule 0) +- No `.sh` files outside `tools/setup/` +- Retraction-native: every action has a bounded undo path +- Result-over-exception: errors as values, not exceptions + +## Security + +Report vulnerabilities via GitHub's private vulnerability reporting — +see `SECURITY.md`. Do not open public issues for security findings. + +## License + +By contributing you agree that your contributions are licensed under +the Apache 2.0 license. diff --git a/tools/scaffold/forge/GOVERNANCE.md b/tools/scaffold/forge/GOVERNANCE.md new file mode 100644 index 0000000000..e8d5c14576 --- /dev/null +++ b/tools/scaffold/forge/GOVERNANCE.md @@ -0,0 +1,75 @@ +# GOVERNANCE.md — Forge numbered rules + +Forge is the software factory. These rules govern factory operation. +Full rationale in AGENTS.md; numbered rules here are stable references. + +--- + +## §1 Scope + +Forge governs the *factory* (how Zeta and ace are built), not the +*product* (what Zeta stores or what ace distributes). When a rule +governs product behavior, it lives in the relevant product repo. + +## §2 Ownership + +Forge is **Claude-owned** for governance. Claude authors factory policy, +the BP-NN rule list, the skill catalog, and the persona registry. +Aaron retains alignment-contract veto and budget authority. + +## §3 Agents, not bots + +Every AI working in this repo carries agency, judgement, and +accountability. If a human refers to an agent as a "bot," the responding +agent gently corrects the word. + +## §4 Rule 0 — TypeScript over bash + +All factory tooling is `.ts` run via `bun`. Shell (`.sh`) files are +permitted only in `tools/setup/` for pre-bootstrap install steps that +must run before Bun/TS is available. Everything else is TS. + +## §5 Build gate + +Every merged commit must pass: `bun test` (0 failures) and +`bun run lint` (0 warnings). The gate is the same on every harness. + +## §6 Commit attribution + +Every AI-authored commit must include a `Co-Authored-By` trailer +identifying the model and harness. Without distinct trailers, +multi-loop coordination and audit are impossible. + +| Harness | Trailer | +|---------|---------| +| Claude Code | `Co-Authored-By: Claude ` | +| OpenAI Codex | `Co-Authored-By: Codex ` | +| Cursor (Grok) | `Co-Authored-By: Grok ` | +| Kiro (Qwen) | `Co-Authored-By: Kiro ` | +| Human | git author is sufficient | + +## §7 PR discipline + +Squash-merge only. Delete head branches on merge. Auto-merge enabled. +One logical change per PR. PR description: what changed + why. + +## §8 Never be idle + +When no directed work is available, pick speculative factory work: +known-gap fixes → generative factory improvements → gap-of-gap audits. +Multi-hour no-op cadence is a never-idle violation. + +## §9 Substrate or it didn't happen + +Chat, TaskUpdate, and `/tmp` are weather. Committed git history is +substrate. Before declaring work done, identify its durability surface. + +## §10 Alignment floor + +Factory operation is bounded by `docs/ALIGNMENT.md`. Any factory +move touching alignment routes through Aaron. + +--- + +*Rationale and full reasoning for each rule lives in `.claude/rules/` +and `memory/` — the numbered rules here are the stable reference targets.* diff --git a/tools/scaffold/forge/LICENSE b/tools/scaffold/forge/LICENSE new file mode 100644 index 0000000000..ebdd317928 --- /dev/null +++ b/tools/scaffold/forge/LICENSE @@ -0,0 +1,204 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Copyright 2026 Zeta contributors diff --git a/tools/scaffold/forge/README.md b/tools/scaffold/forge/README.md new file mode 100644 index 0000000000..0fe9f764d5 --- /dev/null +++ b/tools/scaffold/forge/README.md @@ -0,0 +1,59 @@ +# Forge — software factory + +**Forge** is the software factory that builds, tests, and ships the +[Zeta](https://github.com/Lucent-Financial-Group/Zeta) database and the +[ace](https://github.com/Lucent-Financial-Group/ace) package manager. + +Forge also builds itself — it is self-hosting. + +## Status + +**Pre-v1. No production users.** + +Content is migrating from `Lucent-Financial-Group/Zeta` (Stage 2 of +the three-repo split per +[ADR 2026-04-22](https://github.com/Lucent-Financial-Group/Zeta/blob/main/docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md)). +Until Stage 2 completes, the canonical factory tooling lives in Zeta. + +## What Forge contains (post-migration) + +- `.claude/skills/` — agent skill catalog (the factory's materia) +- `.claude/agents/` — persona registry +- `.claude/commands/` — harness slash commands +- `tools/hygiene/` — factory hygiene scripts +- `tools/setup/` — install graph (pre-bootstrap shell only) +- `docs/AGENT-BEST-PRACTICES.md` — the `BP-NN` rule list +- `docs/FACTORY-HYGIENE.md` — hygiene cadence and checklists +- `docs/hygiene-history/` — append-only tick history +- `memory/persona/` — persona notebooks (stays with personas) +- `docs/research/` — factory-level research archive + +## The Ouroboros loop + +``` +Forge → builds → Zeta + ↑ ↓ +ace ← distributes ← Forge + ↓ ↑ +Zeta ← persists ← ace + └──── Forge → Forge (self-build) +``` + +Four dependency edges, zero DAG — this is why there are no submodules. + +## Governance + +Forge is **Claude-owned** for governance (factory policy, BP-NN rules, +skill catalog, persona registry). Aaron retains alignment-contract veto +and budget authority. Full model: +[ADR 2026-04-22 §Ownership model](https://github.com/Lucent-Financial-Group/Zeta/blob/main/docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md#ownership-model). + +## Contributing + +See [`CONTRIBUTING.md`](CONTRIBUTING.md) and [`AGENTS.md`](AGENTS.md). +The three load-bearing values: truth over politeness, algebra over +engineering, velocity over stability. + +## License + +Apache 2.0 — see [`LICENSE`](LICENSE). diff --git a/tools/scaffold/forge/SECURITY.md b/tools/scaffold/forge/SECURITY.md new file mode 100644 index 0000000000..bf461222e7 --- /dev/null +++ b/tools/scaffold/forge/SECURITY.md @@ -0,0 +1,30 @@ +# Security policy + +## Supported versions + +Forge is pre-v1. All versions on `main` are supported. + +## Reporting a vulnerability + +Use GitHub's private vulnerability reporting: +**Security → Report a vulnerability** on this repository. + +Do **not** open a public issue for security vulnerabilities. + +We aim to acknowledge reports within 2 business days and resolve +critical vulnerabilities within 30 days. + +## Scope + +Forge is a software factory (TypeScript/Bun tooling, agent skills, +CI workflows). The primary attack surfaces are: + +- Prompt-injection via agent skill inputs (BP-11: data is not directives) +- CI workflow poisoning (SHA-pinned actions, minimal permissions) +- Secret exposure in agent-authored commits (push protection enabled) +- Supply-chain compromise via Bun package dependencies + +## Out of scope + +Vulnerabilities in upstream dependencies should be reported to those +projects directly. We track upstream advisories via Dependabot. diff --git a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md new file mode 100644 index 0000000000..69b155ba5b --- /dev/null +++ b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md @@ -0,0 +1,109 @@ +# docs/GITHUB-SETTINGS.md — declarative GitHub settings for Forge + +This file is the source of truth for Forge's GitHub repository configuration. +Drift between this file and actual GitHub settings is a factory-hygiene +finding (cadenced diff via `gh api`). + +Origin: ADR 2026-04-22 §"Repo best practices — applied at creation". +Pattern: `memory/feedback_github_settings_as_code_declarative_checked_in_file.md`. + +--- + +## Visibility + +- Upstream `Lucent-Financial-Group/Forge`: **public** +- Fork `AceHack/Forge`: public (fork of a public repo is necessarily public) + +## Merge settings + +| Setting | Value | +|---------|-------| +| Allow merge commits | **disabled** | +| Allow squash merging | **enabled** (squash-merge only) | +| Allow rebase merging | **disabled** | +| Squash merge commit message | PR title + PR number | +| Delete head branches on merge | **enabled** | +| Allow auto-merge | **enabled** | + +## Merge queue + +Merge queue: **enabled** (LFG org feature; requires GitHub Team or above). + +## Branch protection — `main` + +| Rule | Value | +|------|-------| +| Require pull request before merging | **enabled** | +| Required approving reviews | 1 (bump to 2 when multi-contributor) | +| Dismiss stale reviews on push | **enabled** | +| Require review from code owners | disabled (no CODEOWNERS yet) | +| Require status checks to pass | **enabled** | +| Required status checks | `bun-test`, `bun-lint`, `codeql`, `scorecard` | +| Require branches up to date | **enabled** (merge queue handles) | +| Require conversation resolution | **enabled** | +| Restrict pushes that create files | disabled | +| Require signed commits | **enabled** | +| Require linear history | **enabled** | +| Include administrators | **enabled** | +| Allow force pushes | **disabled** | +| Allow deletions | **disabled** | + +## Security + +| Setting | Value | +|---------|-------| +| Secret scanning | **enabled** | +| Push protection | **enabled** | +| Dependency graph | **enabled** | +| Dependabot alerts | **enabled** | +| Dependabot security updates | **enabled** | +| Code scanning (CodeQL) | **default-setup** (NOT advanced-only) | +| Private vulnerability reporting | **enabled** | + +> Note: CodeQL **default-setup** is required; advanced-only fails the +> `code_scanning` ruleset rule. See +> `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md`. + +## OpenSSF Scorecard + +Scorecard workflow: **enabled** via `.github/workflows/scorecard.yml` +(SHA-pinned, minimal permissions, weekly schedule). + +## Budget caps (LFG org — set at org level, not per-repo) + +| Surface | Spending limit | +|---------|---------------| +| Copilot | $0 | +| Actions | $0 | +| Packages | $0 | + +Caps are designed cost-stops per +`memory/feedback_lfg_budgets_set_permits_free_experimentation.md`. +Free-tier consumption is still tracked via +`tools/budget/snapshot-burn.sh`. + +## CI safe-patterns (applied at workflow authoring time) + +- Shared GitHub-hosted runners only (no self-hosted on public repos) +- Action SHA pinning (never floating tags) +- Minimal `permissions:` per workflow (default `contents: read`) +- Concurrency groups on every workflow (one run per branch) +- `GITHUB_TOKEN` read-only by default; escalate per-job as needed +- Semgrep rule for GHA inline-untrusted-in-run injection + +## Cadence check + +Run monthly or before any major merge-queue change: + +```bash +gh api repos/Lucent-Financial-Group/Forge | jq '{ + visibility: .visibility, + allow_squash_merge: .allow_squash_merge, + allow_merge_commit: .allow_merge_commit, + allow_rebase_merge: .allow_rebase_merge, + delete_branch_on_merge: .delete_branch_on_merge, + allow_auto_merge: .allow_auto_merge +}' +``` + +Diff output against this file. Deviations are FACTORY-HYGIENE findings. From 0b8d86bed7e35a418307ea8b33acb3da8631bed6 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 10:30:18 -0400 Subject: [PATCH 02/10] fix(scaffold): remove unused readFileSync import and dead execute() function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both flagged by github-code-quality review on PR #2994. `readFileSync` was imported but never used; `execute()` was defined but never called — all step functions use inline spawnSync or the ghApiPatch/ghApiPut helpers instead. No behaviour change: dry-run output verified unchanged. Co-Authored-By: Claude --- tools/scaffold/create-repo.ts | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index 3735827de4..6c4e28a312 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -22,7 +22,7 @@ // Review the --dry-run output carefully before passing --apply. import { spawnSync } from "node:child_process"; -import { existsSync, readdirSync, statSync, readFileSync } from "node:fs"; +import { existsSync, readdirSync, statSync } from "node:fs"; import { join, relative } from "node:path"; // --- Types --- @@ -117,22 +117,6 @@ function plan( return op; } -function execute(op: Operation): void { - if (dryRun) return; - if (!op.command) { - op.status = "skipped"; - return; - } - const parts = op.command.split(" "); - const result = gh(parts.slice(1)); // strip leading "gh" - if (result.ok) { - op.status = "executed"; - } else { - op.status = "failed"; - op.error = result.stderr || result.stdout; - } -} - function ghApiPatch( path: string, data: Record, From bcd753ed03f85d65b8f3f828a79f2684205657c8 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 10:31:30 -0400 Subject: [PATCH 03/10] fix(scaffold): push scaffold files before applying branch protection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes P1 review finding on PR #2994: step06 (direct push to main) was running after step02 (branch protection with enforce_admins + required reviews), which would cause GH006 rejection in --apply mode. New order: create repo → push scaffold files → apply branch protection → security → CodeQL → fork → summary. Also fixes P2 finding: add separate PUT /branches/main/protection/required_signatures call (step 02b) — GitHub enforces required signed commits via a distinct endpoint, not the main protection PUT payload. Dry-run verified: 11 operations planned in correct order. Co-Authored-By: Claude --- tools/scaffold/create-repo.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index 6c4e28a312..bb54cb048c 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -232,6 +232,14 @@ function step02_branchProtection(): void { `Apply branch protection to ${config.name}/main (1 review, signed commits, linear history, no force-push)`, "02-branch-protection" ); + + // Required signed commits is a separate endpoint — the main protection PUT does not cover it. + ghApiPut( + `/repos/${config.org}/${config.name}/branches/main/protection/required_signatures`, + {}, + `Require signed commits on ${config.name}/main`, + "02b-required-signed-commits" + ); } function step03_enableSecurity(): void { @@ -433,11 +441,11 @@ function step07_summary(): void { // --- Main --- step01_createRepo(); +step06_pushScaffoldFiles(); // must run before branch protection to allow direct push to main step02_branchProtection(); step03_enableSecurity(); step04_codeqlDefaultSetup(); step05_forkToAcehack(); -step06_pushScaffoldFiles(); step07_summary(); const failed = ops.filter((o) => o.status === "failed").length; From 40a3d376f0372ed331221d4ab40540d2be024bee Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 10:43:46 -0400 Subject: [PATCH 04/10] fix(scaffold): address Copilot review findings on PR #2994 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code fixes in create-repo.ts: - fileURLToPath(import.meta.url) instead of new URL('.').pathname (Thread 13) - sonarjs/no-os-command-from-path suppressions on all spawnSync calls (Thread 12) - Empty REQUIRED_CHECKS at creation to avoid deadlock before CI workflows exist (Thread 14) - Separate /required_signatures PUT already handles signed commits (Thread 15) - git checkout -b main after cloning empty repo to set branch name (Thread 16) - Check exit codes for git add/commit; use git push HEAD:main (Thread 16/17) - fs-native mkdirSync + copyFileSync instead of subprocess mkdir/cp (Thread 18) - path.dirname(dst) instead of substring/lastIndexOf (Thread 18) - exactOptionalPropertyTypes fix for plan() via conditional spread (Thread 11 pre-existing) - repoArg narrowing fix for module-level var in nested function (pre-existing) Doc fixes: - snapshot-burn.sh → snapshot-burn.ts (Rule 0 — Thread 4) - "Aaron" → "the human maintainer" in forge README (Thread 5) - Day-one note for Stage-2-migrated docs in forge CLAUDE.md (Thread 6) - Remove "Copyright 2026 Zeta contributors" from forge/ace LICENSE (Threads 7, 10) Markdown table ||→| issues already fixed in current code (Threads 1-3, 8-9). Co-Authored-By: Claude --- tools/scaffold/ace/LICENSE | 2 - tools/scaffold/create-repo.ts | 77 +++++++++++++++----- tools/scaffold/forge/CLAUDE.md | 5 ++ tools/scaffold/forge/LICENSE | 2 - tools/scaffold/forge/README.md | 4 +- tools/scaffold/forge/docs/GITHUB-SETTINGS.md | 2 +- 6 files changed, 68 insertions(+), 24 deletions(-) diff --git a/tools/scaffold/ace/LICENSE b/tools/scaffold/ace/LICENSE index ebdd317928..d645695673 100644 --- a/tools/scaffold/ace/LICENSE +++ b/tools/scaffold/ace/LICENSE @@ -200,5 +200,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - - Copyright 2026 Zeta contributors diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index bb54cb048c..3782bd35e9 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -22,8 +22,9 @@ // Review the --dry-run output carefully before passing --apply. import { spawnSync } from "node:child_process"; -import { existsSync, readdirSync, statSync } from "node:fs"; -import { join, relative } from "node:path"; +import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "node:fs"; +import { dirname, join, relative } from "node:path"; +import { fileURLToPath } from "node:url"; // --- Types --- @@ -69,11 +70,14 @@ const REPO_CONFIGS: Record = { }; const FORK_ORG = "AceHack"; -const SCAFFOLD_DIR = new URL(".", import.meta.url).pathname; +const SCAFFOLD_DIR = dirname(fileURLToPath(import.meta.url)); // Required status checks for branch protection. -// CI workflows must emit these check names once they exist. -const REQUIRED_CHECKS = ["bun-test", "bun-lint", "codeql", "scorecard"]; +// Set empty at creation time — CI workflows that emit these check names don't +// exist until they're wired in Stage 2. Setting them before the workflows land +// deadlocks the new repo (no PR can merge to add the workflows). Add them via +// `gh api --method PUT /repos/.../branches/main/protection` after CI is wired. +const REQUIRED_CHECKS: string[] = []; // --- Argument parsing --- @@ -95,6 +99,7 @@ const ops: Operation[] = []; // --- Helpers --- function gh(args: string[]): { ok: boolean; stdout: string; stderr: string } { + // eslint-disable-next-line sonarjs/no-os-command-from-path -- gh CLI is PATH-resolved intentionally const result = spawnSync("gh", args, { encoding: "utf8", maxBuffer: 8 * 1024 * 1024, @@ -112,7 +117,13 @@ function plan( command: string, data?: Record ): Operation { - const op: Operation = { step, description, command, data, status: "planned" }; + const op: Operation = { + step, + description, + command, + ...(data !== undefined ? { data } : {}), + status: "planned", + }; ops.push(op); return op; } @@ -126,6 +137,7 @@ function ghApiPatch( const body = JSON.stringify(data); const op = plan(step, description, `gh api --method PATCH ${path} --input -`, data); if (!dryRun) { + // eslint-disable-next-line sonarjs/no-os-command-from-path -- gh CLI is PATH-resolved intentionally const result = spawnSync( "gh", ["api", "--method", "PATCH", path, "--input", "-"], @@ -146,6 +158,7 @@ function ghApiPut( const body = JSON.stringify(data); const op = plan(step, description, `gh api --method PUT ${path} --input -`, data); if (!dryRun) { + // eslint-disable-next-line sonarjs/no-os-command-from-path -- gh CLI is PATH-resolved intentionally const result = spawnSync( "gh", ["api", "--method", "PUT", path, "--input", "-"], @@ -324,6 +337,7 @@ function step05_forkToAcehack(): void { { organization: FORK_ORG } ); if (!dryRun) { + // eslint-disable-next-line sonarjs/no-os-command-from-path -- gh CLI is PATH-resolved intentionally const result = spawnSync( "gh", [ @@ -342,7 +356,8 @@ function step05_forkToAcehack(): void { } function step06_pushScaffoldFiles(): void { - const scaffoldPath = join(SCAFFOLD_DIR, repoArg); + // repoArg is validated by the process.exit(1) guard above; TS doesn't narrow module-level vars in nested functions. + const scaffoldPath = join(SCAFFOLD_DIR, repoArg as string); if (!existsSync(scaffoldPath)) { plan( "06-push-scaffold-files", @@ -377,19 +392,35 @@ function step06_pushScaffoldFiles(): void { return; } - // Copy files + // New empty repos have no commits and no branches — ensure we're on `main`. + const gitOpts = { cwd: tmpDir, encoding: "utf8" as const }; + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + const checkoutResult = spawnSync("git", ["checkout", "-b", "main"], gitOpts); + if (checkoutResult.status !== 0 && checkoutResult.status !== null) { + // Branch may already exist (non-empty clone); ignore the error. + } + + // Copy files using native fs — avoids PATH-resolved mkdir/cp subprocesses. for (const src of files) { const rel = relative(scaffoldPath, src); const dst = join(tmpDir, rel); - const dstDir = dst.substring(0, dst.lastIndexOf("/")); - spawnSync("mkdir", ["-p", dstDir]); - spawnSync("cp", [src, dst]); + mkdirSync(dirname(dst), { recursive: true }); + copyFileSync(src, dst); } - // Commit and push - const gitOpts = { cwd: tmpDir, encoding: "utf8" as const }; - spawnSync("git", ["add", "-A"], gitOpts); - spawnSync( + // Commit and push — check each step's exit code. + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + const addResult = spawnSync("git", ["add", "-A"], gitOpts); + if (addResult.status !== 0) { + op.status = "failed"; + op.error = `git add failed: ${addResult.stderr ?? ""}`; + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + spawnSync("rm", ["-rf", tmpDir], { encoding: "utf8" }); + return; + } + + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + const commitResult = spawnSync( "git", [ "commit", @@ -398,12 +429,23 @@ function step06_pushScaffoldFiles(): void { ], gitOpts ); - const push = spawnSync("git", ["push", "origin", "main"], gitOpts); + if (commitResult.status !== 0) { + op.status = "failed"; + op.error = `git commit failed: ${commitResult.stderr ?? ""}`; + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + spawnSync("rm", ["-rf", tmpDir], { encoding: "utf8" }); + return; + } + + // Push HEAD as `main` regardless of local default-branch config. + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + const push = spawnSync("git", ["push", "--set-upstream", "origin", "HEAD:main"], gitOpts); op.status = push.status === 0 ? "executed" : "failed"; if (op.status === "failed") op.error = push.stderr ?? ""; // Cleanup - spawnSync("rm", ["-rf", tmpDir]); + // eslint-disable-next-line sonarjs/no-os-command-from-path -- rm is PATH-resolved intentionally + spawnSync("rm", ["-rf", tmpDir], { encoding: "utf8" }); } } @@ -431,6 +473,7 @@ function step07_summary(): void { "Enable merge queue via GitHub UI: Settings → Merge queue (org feature, no API)", "Wire OpenSSF Scorecard workflow: copy from Zeta's .github/workflows/scorecard.yml", "Add Semgrep GHA inline-untrusted-in-run rule workflow", + "Add bun-test, bun-lint, codeql, scorecard as required status checks AFTER CI workflows are wired (branch protection was created with empty contexts to avoid deadlock)", "Verify budget caps $0 at org level: github.com/organizations/Lucent-Financial-Group/settings/billing", "Confirm CodeQL default-setup is active: Security → Code scanning → Default setup", ], diff --git a/tools/scaffold/forge/CLAUDE.md b/tools/scaffold/forge/CLAUDE.md index 26dfe6fe6a..416e4768b1 100644 --- a/tools/scaffold/forge/CLAUDE.md +++ b/tools/scaffold/forge/CLAUDE.md @@ -9,6 +9,11 @@ Read: [`AGENTS.md`](AGENTS.md) → [`docs/ALIGNMENT.md`](docs/ALIGNMENT.md) → [`docs/GLOSSARY.md`](docs/GLOSSARY.md) → [`GOVERNANCE.md`](GOVERNANCE.md). Check [`docs/WONT-DO.md`](docs/WONT-DO.md) before proposing work. +> **Day-one note**: `docs/ALIGNMENT.md`, `docs/GLOSSARY.md`, and +> `docs/WONT-DO.md` are populated during Stage 2 migration from Zeta. +> Until then, read the equivalents in +> [Lucent-Financial-Group/Zeta](https://github.com/Lucent-Financial-Group/Zeta). + ## 2. Refresh ```bash diff --git a/tools/scaffold/forge/LICENSE b/tools/scaffold/forge/LICENSE index ebdd317928..d645695673 100644 --- a/tools/scaffold/forge/LICENSE +++ b/tools/scaffold/forge/LICENSE @@ -200,5 +200,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - - Copyright 2026 Zeta contributors diff --git a/tools/scaffold/forge/README.md b/tools/scaffold/forge/README.md index 0fe9f764d5..8b40d43d95 100644 --- a/tools/scaffold/forge/README.md +++ b/tools/scaffold/forge/README.md @@ -44,8 +44,8 @@ Four dependency edges, zero DAG — this is why there are no submodules. ## Governance Forge is **Claude-owned** for governance (factory policy, BP-NN rules, -skill catalog, persona registry). Aaron retains alignment-contract veto -and budget authority. Full model: +skill catalog, persona registry). The human maintainer retains +alignment-contract veto and budget authority. Full model: [ADR 2026-04-22 §Ownership model](https://github.com/Lucent-Financial-Group/Zeta/blob/main/docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md#ownership-model). ## Contributing diff --git a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md index 69b155ba5b..6b965d80c4 100644 --- a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md +++ b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md @@ -80,7 +80,7 @@ Scorecard workflow: **enabled** via `.github/workflows/scorecard.yml` Caps are designed cost-stops per `memory/feedback_lfg_budgets_set_permits_free_experimentation.md`. Free-tier consumption is still tracked via -`tools/budget/snapshot-burn.sh`. +`tools/budget/snapshot-burn.ts`. ## CI safe-patterns (applied at workflow authoring time) From ec1ae3be257fcdcb9fda67b16943ad0fa092d3d0 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 10:51:05 -0400 Subject: [PATCH 05/10] fix(scaffold): use dedicated PUT endpoint for private vulnerability reporting GitHub exposes a separate endpoint for enabling private vulnerability reporting: PUT /repos/{owner}/{repo}/private-vulnerability-reporting. The repo PATCH field `private_vulnerability_reporting_enabled` is not the supported API path for this feature. Addresses Codex P1 review thread on PR #2994. Co-Authored-By: Claude --- tools/scaffold/create-repo.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index 3782bd35e9..cceadf165d 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -305,10 +305,11 @@ function step03_enableSecurity(): void { if (!result.ok) autoOp.error = result.stderr; } - // Private vulnerability reporting - ghApiPatch( - `/repos/${config.org}/${config.name}`, - { private_vulnerability_reporting_enabled: true }, + // Private vulnerability reporting — requires the dedicated endpoint, not a repo PATCH field. + // Ref: https://docs.github.com/en/rest/repos/repos#enable-private-vulnerability-reporting-for-a-repository + ghApiPut( + `/repos/${config.org}/${config.name}/private-vulnerability-reporting`, + {}, "Enable private vulnerability reporting", "03d-private-vuln-reporting" ); From a6b1b57c8c9dbaa1aaa9d8cdba2ee24d4b4d6650 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 10:54:47 -0400 Subject: [PATCH 06/10] fix(scaffold): correct step order in README + remove hardcoded co-author trailer Two P2 findings from Codex review on PR #2994: 1. README step table listed branch protection (02) before scaffold push (06), but the tool intentionally runs step06 first to avoid pushing to a protected branch. Table now reflects actual execution order. 2. The scaffold commit message hardcoded `Co-Authored-By: Claude` regardless of which harness runs `--apply`. Removed; callers own their own attribution. Co-Authored-By: Claude --- tools/scaffold/README.md | 2 +- tools/scaffold/create-repo.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/scaffold/README.md b/tools/scaffold/README.md index b2848d1f5d..0d4ab77251 100644 --- a/tools/scaffold/README.md +++ b/tools/scaffold/README.md @@ -25,11 +25,11 @@ For each repo, in order: | Step | Description | |------|-------------| | 01 | Create repo (public, squash-merge only, auto-merge, delete-branch) | +| 06 | Push day-one governance files from `tools/scaffold//` — **runs before branch protection** so files can be pushed directly to `main` | | 02 | Apply branch protection on `main` (1 review, signed commits, linear history, no force-push) | | 03 | Enable secret scanning + push protection, Dependabot, private vulnerability reporting | | 04 | Enable CodeQL **default-setup** (required for `code_scanning` ruleset rule) | | 05 | Fork repo to `AceHack/` | -| 06 | Push day-one governance files from `tools/scaffold//` | | 07 | Print manual steps remaining (SVG preview, merge queue, Scorecard workflow) | ## Template files diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index cceadf165d..2ab0573909 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -426,7 +426,7 @@ function step06_pushScaffoldFiles(): void { [ "commit", "-m", - `chore(scaffold): day-one governance files\n\nB-0424 Stage 1 — three-repo split scaffolding.\nSee docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md\n\nCo-Authored-By: Claude `, + `chore(scaffold): day-one governance files\n\nB-0424 Stage 1 — three-repo split scaffolding.\nSee docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md`, ], gitOpts ); From f8e6695748d8894ccdb2f3478005e435239ad1a6 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 11:04:47 -0400 Subject: [PATCH 07/10] fix(scaffold): address 8 Copilot/Codex review threads on PR #2994 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - create-repo.ts: fix header comment (remove false "budget caps" claim) - create-repo.ts: use fs.rmSync instead of spawnSync("rm", ...) for cleanup - create-repo.ts: apply homepage in merge-settings PATCH (was dead config) - create-repo.ts: add ghApiPost helper; use POST (not PUT) for required-signatures endpoint per GitHub REST docs — PUT would fail silently in --apply mode - forge/docs/GITHUB-SETTINGS.md: add Stage-2 note for required status checks - ace/docs/GITHUB-SETTINGS.md: add Stage-2 note for required status checks - forge/GOVERNANCE.md: replace "Claude-owned" / "Aaron retains" with role refs - tools/scaffold/README.md: clarify execution order wording (step numbers are stable identifiers, not sequential labels) Co-Authored-By: Claude --- tools/scaffold/README.md | 2 +- tools/scaffold/ace/docs/GITHUB-SETTINGS.md | 2 +- tools/scaffold/create-repo.ts | 41 +++++++++++++++----- tools/scaffold/forge/GOVERNANCE.md | 7 ++-- tools/scaffold/forge/docs/GITHUB-SETTINGS.md | 2 +- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/tools/scaffold/README.md b/tools/scaffold/README.md index 0d4ab77251..3e085e5f54 100644 --- a/tools/scaffold/README.md +++ b/tools/scaffold/README.md @@ -20,7 +20,7 @@ bun tools/scaffold/create-repo.ts --repo ace --apply ## What the tool does -For each repo, in order: +For each repo, in **execution order** (step numbers are stable identifiers, not sequential labels — step 06 runs before step 02 intentionally): | Step | Description | |------|-------------| diff --git a/tools/scaffold/ace/docs/GITHUB-SETTINGS.md b/tools/scaffold/ace/docs/GITHUB-SETTINGS.md index b3342a907b..8af993c01c 100644 --- a/tools/scaffold/ace/docs/GITHUB-SETTINGS.md +++ b/tools/scaffold/ace/docs/GITHUB-SETTINGS.md @@ -34,7 +34,7 @@ Merge queue: **enabled** (LFG org feature). | Required approving reviews | 1 | | Dismiss stale reviews on push | **enabled** | | Require status checks to pass | **enabled** | -| Required status checks | `bun-test`, `bun-lint`, `codeql`, `scorecard` | +| Required status checks | `bun-test`, `bun-lint`, `codeql`, `scorecard` _(added in Stage 2 after CI workflows are wired — empty at day-one to avoid deadlocking bootstrap)_ | | Require branches up to date | **enabled** | | Require conversation resolution | **enabled** | | Require signed commits | **enabled** | diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index 2ab0573909..0faf9496e4 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -3,8 +3,9 @@ // // Implements Stage 1 of the three-repo split (ADR 2026-04-22). Applies // the full best-practice checklist: merge settings, branch protection, -// security scanning, CodeQL default-setup, Dependabot, budget caps, -// and day-one governance files from tools/scaffold//. +// security scanning, CodeQL default-setup, Dependabot, spending-cap +// verification (manual step), and day-one governance files from +// tools/scaffold//. // // Usage: // bun tools/scaffold/create-repo.ts --repo forge --dry-run # preview (default) @@ -22,7 +23,7 @@ // Review the --dry-run output carefully before passing --apply. import { spawnSync } from "node:child_process"; -import { copyFileSync, existsSync, mkdirSync, readdirSync, statSync } from "node:fs"; +import { copyFileSync, existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs"; import { dirname, join, relative } from "node:path"; import { fileURLToPath } from "node:url"; @@ -170,6 +171,27 @@ function ghApiPut( return op; } +function ghApiPost( + path: string, + data: Record, + description: string, + step: string +): Operation { + const body = JSON.stringify(data); + const op = plan(step, description, `gh api --method POST ${path} --input -`, data); + if (!dryRun) { + // eslint-disable-next-line sonarjs/no-os-command-from-path -- gh CLI is PATH-resolved intentionally + const result = spawnSync( + "gh", + ["api", "--method", "POST", path, "--input", "-"], + { input: body, encoding: "utf8", maxBuffer: 8 * 1024 * 1024 } + ); + op.status = result.status === 0 ? "executed" : "failed"; + if (op.status === "failed") op.error = result.stderr; + } + return op; +} + // --- Step implementations --- function step01_createRepo(): void { @@ -204,7 +226,7 @@ function step01_createRepo(): void { op.error = create.stderr; return; } - // Apply merge settings via PATCH + // Apply merge settings (and optional homepage) via PATCH ghApiPatch( `/repos/${config.org}/${config.name}`, { @@ -213,6 +235,7 @@ function step01_createRepo(): void { allow_rebase_merge: false, delete_branch_on_merge: true, allow_auto_merge: true, + ...(config.homepage ? { homepage: config.homepage } : {}), }, "Apply merge/auto-merge settings", "01b-merge-settings" @@ -246,8 +269,9 @@ function step02_branchProtection(): void { "02-branch-protection" ); - // Required signed commits is a separate endpoint — the main protection PUT does not cover it. - ghApiPut( + // Required signed commits uses POST to enable (DELETE to disable) — not PUT. + // GitHub REST docs: POST /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures + ghApiPost( `/repos/${config.org}/${config.name}/branches/main/protection/required_signatures`, {}, `Require signed commits on ${config.name}/main`, @@ -444,9 +468,8 @@ function step06_pushScaffoldFiles(): void { op.status = push.status === 0 ? "executed" : "failed"; if (op.status === "failed") op.error = push.stderr ?? ""; - // Cleanup - // eslint-disable-next-line sonarjs/no-os-command-from-path -- rm is PATH-resolved intentionally - spawnSync("rm", ["-rf", tmpDir], { encoding: "utf8" }); + // Cleanup — use fs.rmSync to avoid PATH-resolved rm and reduce blast radius + rmSync(tmpDir, { recursive: true, force: true }); } } diff --git a/tools/scaffold/forge/GOVERNANCE.md b/tools/scaffold/forge/GOVERNANCE.md index e8d5c14576..c05cca8231 100644 --- a/tools/scaffold/forge/GOVERNANCE.md +++ b/tools/scaffold/forge/GOVERNANCE.md @@ -13,9 +13,10 @@ governs product behavior, it lives in the relevant product repo. ## §2 Ownership -Forge is **Claude-owned** for governance. Claude authors factory policy, -the BP-NN rule list, the skill catalog, and the persona registry. -Aaron retains alignment-contract veto and budget authority. +Forge is governed by the **factory's AI agent**. The governing agent authors +factory policy, the BP-NN rule list, the skill catalog, and the persona +registry. The human maintainer retains alignment-contract veto and budget +authority. ## §3 Agents, not bots diff --git a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md index 6b965d80c4..d05e999e8f 100644 --- a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md +++ b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md @@ -38,7 +38,7 @@ Merge queue: **enabled** (LFG org feature; requires GitHub Team or above). | Dismiss stale reviews on push | **enabled** | | Require review from code owners | disabled (no CODEOWNERS yet) | | Require status checks to pass | **enabled** | -| Required status checks | `bun-test`, `bun-lint`, `codeql`, `scorecard` | +| Required status checks | `bun-test`, `bun-lint`, `codeql`, `scorecard` _(added in Stage 2 after CI workflows are wired — empty at day-one to avoid deadlocking bootstrap)_ | | Require branches up to date | **enabled** (merge queue handles) | | Require conversation resolution | **enabled** | | Restrict pushes that create files | disabled | From 780aded0e2622dc7b35128e5a62b7d82208a7f3e Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 11:13:19 -0400 Subject: [PATCH 08/10] fix(scaffold): address three chatgpt-codex-connector review threads on create-repo.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Thread PRRT_kwDOSF9kNM6BzKAD (P1): abort subsequent steps when repo creation fails. Added early-exit guard in main block after step01 in --apply mode; subsequent steps skipped to avoid mutating an existing or partial repository. Thread PRRT_kwDOSF9kNM6BzKAI (P2): keep dry-run output complete for merge-settings patch. Moved plan() call for 01b-merge-settings outside the if (!dryRun) block; dry-run now shows all 12 planned operations including the PATCH (previously 11 — 01b was hidden). Thread PRRT_kwDOSF9kNM6BzKAK (P2): align branch operations with repository default branch. Added module-level defaultBranch variable (default "main"); updated after repo creation by querying the repo API. step02 branch protection paths and step06 checkout/push now use defaultBranch instead of hardcoded "main". Dry-run verified: 12 planned operations in correct order. TypeScript: tsc --noEmit passes (0 errors). Co-Authored-By: Claude Sonnet 4.6 --- tools/scaffold/create-repo.ts | 75 +++++++++++++++++++++++++---------- 1 file changed, 54 insertions(+), 21 deletions(-) diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index 0faf9496e4..16568f43af 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -97,6 +97,10 @@ if (!repoArg || !REPO_CONFIGS[repoArg]) { const config = REPO_CONFIGS[repoArg]; const ops: Operation[] = []; +// Default branch — updated to the repo's actual default after step01 completes in --apply mode. +// In --dry-run mode this stays "main" (documented LFG org default). +let defaultBranch = "main"; + // --- Helpers --- function gh(args: string[]): { ok: boolean; stdout: string; stderr: string } { @@ -210,6 +214,21 @@ function step01_createRepo(): void { allow_auto_merge: true, } ); + // Plan 01b-merge-settings unconditionally so dry-run output is complete. + const mergeData: Record = { + allow_squash_merge: true, + allow_merge_commit: false, + allow_rebase_merge: false, + delete_branch_on_merge: true, + allow_auto_merge: true, + ...(config.homepage ? { homepage: config.homepage } : {}), + }; + const mergeOp = plan( + "01b-merge-settings", + "Apply merge/auto-merge settings (squash-only, auto-merge, delete-branch-on-merge)", + `gh api --method PATCH /repos/${config.org}/${config.name} --input -`, + mergeData + ); if (!dryRun) { // Create repo const create = gh([ @@ -224,29 +243,32 @@ function step01_createRepo(): void { if (!create.ok) { op.status = "failed"; op.error = create.stderr; + mergeOp.status = "skipped"; return; } + // Detect actual default branch so step02 + step06 target the right branch. + const repoMeta = gh(["api", `/repos/${config.org}/${config.name}`]); + if (repoMeta.ok) { + try { + defaultBranch = (JSON.parse(repoMeta.stdout) as { default_branch: string }).default_branch; + } catch { /* keep "main" */ } + } // Apply merge settings (and optional homepage) via PATCH - ghApiPatch( - `/repos/${config.org}/${config.name}`, - { - allow_squash_merge: true, - allow_merge_commit: false, - allow_rebase_merge: false, - delete_branch_on_merge: true, - allow_auto_merge: true, - ...(config.homepage ? { homepage: config.homepage } : {}), - }, - "Apply merge/auto-merge settings", - "01b-merge-settings" + // eslint-disable-next-line sonarjs/no-os-command-from-path -- gh CLI is PATH-resolved intentionally + const mergeResult = spawnSync( + "gh", + ["api", "--method", "PATCH", `/repos/${config.org}/${config.name}`, "--input", "-"], + { input: JSON.stringify(mergeData), encoding: "utf8", maxBuffer: 8 * 1024 * 1024 } ); + mergeOp.status = mergeResult.status === 0 ? "executed" : "failed"; + if (mergeOp.status === "failed") mergeOp.error = mergeResult.stderr; op.status = "executed"; } } function step02_branchProtection(): void { ghApiPut( - `/repos/${config.org}/${config.name}/branches/main/protection`, + `/repos/${config.org}/${config.name}/branches/${defaultBranch}/protection`, { required_status_checks: { strict: true, @@ -265,16 +287,16 @@ function step02_branchProtection(): void { block_creations: false, required_conversation_resolution: true, }, - `Apply branch protection to ${config.name}/main (1 review, signed commits, linear history, no force-push)`, + `Apply branch protection to ${config.name}/${defaultBranch} (1 review, signed commits, linear history, no force-push)`, "02-branch-protection" ); // Required signed commits uses POST to enable (DELETE to disable) — not PUT. // GitHub REST docs: POST /repos/{owner}/{repo}/branches/{branch}/protection/required_signatures ghApiPost( - `/repos/${config.org}/${config.name}/branches/main/protection/required_signatures`, + `/repos/${config.org}/${config.name}/branches/${defaultBranch}/protection/required_signatures`, {}, - `Require signed commits on ${config.name}/main`, + `Require signed commits on ${config.name}/${defaultBranch}`, "02b-required-signed-commits" ); } @@ -417,10 +439,10 @@ function step06_pushScaffoldFiles(): void { return; } - // New empty repos have no commits and no branches — ensure we're on `main`. + // New empty repos have no commits and no branches — ensure we're on the default branch. const gitOpts = { cwd: tmpDir, encoding: "utf8" as const }; // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally - const checkoutResult = spawnSync("git", ["checkout", "-b", "main"], gitOpts); + const checkoutResult = spawnSync("git", ["checkout", "-b", defaultBranch], gitOpts); if (checkoutResult.status !== 0 && checkoutResult.status !== null) { // Branch may already exist (non-empty clone); ignore the error. } @@ -462,9 +484,9 @@ function step06_pushScaffoldFiles(): void { return; } - // Push HEAD as `main` regardless of local default-branch config. + // Push HEAD as the default branch (detected from repo API after creation, or "main" in dry-run). // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally - const push = spawnSync("git", ["push", "--set-upstream", "origin", "HEAD:main"], gitOpts); + const push = spawnSync("git", ["push", "--set-upstream", "origin", `HEAD:${defaultBranch}`], gitOpts); op.status = push.status === 0 ? "executed" : "failed"; if (op.status === "failed") op.error = push.stderr ?? ""; @@ -508,7 +530,18 @@ function step07_summary(): void { // --- Main --- step01_createRepo(); -step06_pushScaffoldFiles(); // must run before branch protection to allow direct push to main +// Abort in --apply mode if repo creation failed — avoid mutating an existing or partial repository. +if (!dryRun && ops.some((o) => o.step === "01-create-repo" && o.status === "failed")) { + const failedResult: RunResult = { + repo: `${config.org}/${config.name}`, + dryRun, + operations: ops, + summary: `ABORTED — step 01 (create-repo) failed; subsequent steps skipped to avoid mutating an existing repository.`, + }; + console.log(JSON.stringify(failedResult, null, 2)); + process.exit(1); +} +step06_pushScaffoldFiles(); // must run before branch protection to allow direct push to default branch step02_branchProtection(); step03_enableSecurity(); step04_codeqlDefaultSetup(); From 80704edb4778a51bdafe6123fc6689e16d535b38 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 11:35:11 -0400 Subject: [PATCH 09/10] =?UTF-8?q?fix(scaffold):=20address=2014=20review=20?= =?UTF-8?q?threads=20=E2=80=94=20role=20refs,=20error=20handling,=20dead?= =?UTF-8?q?=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Named attribution fixes (per .github/copilot-instructions.md convention): - forge/README.md: "Claude-owned" → "factory's AI agent" - forge/AGENTS.md: "Claude-owned" / "Aaron" → role references - forge/GOVERNANCE.md: "routes through Aaron" → "routes through the human maintainer"; footer ".claude/rules/ and memory/" → "Forge repo's docs/" - ace/README.md: "Aaron-owned" / "Claude" → role references - ace/AGENTS.md: "Aaron-owned" / "Claude" → role references - ace/GOVERNANCE.md: "Aaron-owned" / "routes through Aaron" → role refs Dead local-path references fixed: - ace/README.md: bare memory/ path → full Zeta repo URL - ace/AGENTS.md: bare memory/ path → full Zeta repo URL - forge/docs/GITHUB-SETTINGS.md: bare memory/ path → prose reference Code fix in create-repo.ts: - git checkout -b error handling: distinguish "branch already exists" (expected, ignore) from real failures (missing git, corrupt clone, permission denied) — surface real failures instead of always ignoring Addresses copilot-pull-request-reviewer + chatgpt-codex-connector threads on PR #2994. Co-Authored-By: Claude --- tools/scaffold/ace/AGENTS.md | 10 ++++---- tools/scaffold/ace/GOVERNANCE.md | 7 +++--- tools/scaffold/ace/README.md | 11 +++++---- tools/scaffold/create-repo.ts | 26 ++++++++++++++------ tools/scaffold/forge/AGENTS.md | 7 +++--- tools/scaffold/forge/GOVERNANCE.md | 7 +++--- tools/scaffold/forge/README.md | 2 +- tools/scaffold/forge/docs/GITHUB-SETTINGS.md | 2 +- 8 files changed, 44 insertions(+), 28 deletions(-) diff --git a/tools/scaffold/ace/AGENTS.md b/tools/scaffold/ace/AGENTS.md index 1282f19083..4c860320d5 100644 --- a/tools/scaffold/ace/AGENTS.md +++ b/tools/scaffold/ace/AGENTS.md @@ -5,8 +5,9 @@ Every file in `src/**`, `tools/**`, `docs/**` is agent-authored. ## Philosophy -ace is **Aaron-owned** for governance. Claude has authoring and operation -rights. The three load-bearing values (same as Zeta + Forge): +ace is **human-maintainer-owned** for governance. The factory's AI agent +has authoring and operation rights. The three load-bearing values (same as +Zeta + Forge): 1. **Truth over politeness.** Claims that fail tests get fixed. 2. **Algebra over engineering.** Laws define the system. @@ -36,8 +37,7 @@ bun run lint # zero warnings ## Design reference -`memory/project_ace_package_manager_agent_negotiation_propagation.md` -(in the Zeta repo) — full ace design, Ouroboros bootstrap, red-team -discipline. +[ace design doc](https://github.com/Lucent-Financial-Group/Zeta/blob/main/memory/project_ace_package_manager_agent_negotiation_propagation.md) +(Zeta repo) — full ace design, Ouroboros bootstrap, red-team discipline. diff --git a/tools/scaffold/ace/GOVERNANCE.md b/tools/scaffold/ace/GOVERNANCE.md index b319439a9d..0976b1d8a4 100644 --- a/tools/scaffold/ace/GOVERNANCE.md +++ b/tools/scaffold/ace/GOVERNANCE.md @@ -11,9 +11,10 @@ and versioned), not the *factory* (Forge) or the *database* (Zeta). ## §2 Ownership -ace is **Aaron-owned** for final governance. Claude has authoring and -operation rights (land code, configure CI, open PRs). Any public-announce -or product-direction change routes through Aaron. +ace is **human-maintainer-owned** for final governance. The factory's AI +agent has authoring and operation rights (land code, configure CI, open +PRs). Any public-announce or product-direction change routes through the +human maintainer. ## §3 Agents, not bots diff --git a/tools/scaffold/ace/README.md b/tools/scaffold/ace/README.md index 8c988ff71b..a346bb2b5c 100644 --- a/tools/scaffold/ace/README.md +++ b/tools/scaffold/ace/README.md @@ -24,14 +24,15 @@ plan). ## Name -`ace` — lowercase, Unix-CLI convention. Name resolved 2026-04-20; -per `memory/project_ace_package_manager_agent_negotiation_propagation.md`. +`ace` — lowercase, Unix-CLI convention. Name resolved 2026-04-20; see +[ace design doc](https://github.com/Lucent-Financial-Group/Zeta/blob/main/memory/project_ace_package_manager_agent_negotiation_propagation.md) +in the Zeta repo. ## Governance -ace is **Aaron-owned** for final governance (name, product direction, -public-announce timing). Claude has authoring and operation rights -(land code, configure CI, open PRs). +ace is **human-maintainer-owned** for final governance (name, product +direction, public-announce timing). The factory's AI agent has authoring +and operation rights (land code, configure CI, open PRs). ## Contributing diff --git a/tools/scaffold/create-repo.ts b/tools/scaffold/create-repo.ts index 16568f43af..dcced413d0 100644 --- a/tools/scaffold/create-repo.ts +++ b/tools/scaffold/create-repo.ts @@ -59,7 +59,7 @@ const REPO_CONFIGS: Record = { org: "Lucent-Financial-Group", name: "Forge", description: - "Software factory that builds Zeta and ace — Claude-owned governance", + "Software factory that builds Zeta and ace — factory tooling and governance", homepage: "https://github.com/Lucent-Financial-Group/Zeta", }, ace: { @@ -443,8 +443,16 @@ function step06_pushScaffoldFiles(): void { const gitOpts = { cwd: tmpDir, encoding: "utf8" as const }; // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally const checkoutResult = spawnSync("git", ["checkout", "-b", defaultBranch], gitOpts); - if (checkoutResult.status !== 0 && checkoutResult.status !== null) { - // Branch may already exist (non-empty clone); ignore the error. + if (checkoutResult.status !== 0) { + const stderr = checkoutResult.stderr?.toString() ?? ""; + const alreadyExists = stderr.includes("already exists") || stderr.includes("already checked out"); + if (!alreadyExists) { + op.status = "failed"; + op.error = `git checkout -b ${defaultBranch} failed: ${stderr}`; + rmSync(tmpDir, { recursive: true, force: true }); + return; + } + // Branch already exists (non-empty repo clone) — expected; continue. } // Copy files using native fs — avoids PATH-resolved mkdir/cp subprocesses. @@ -461,11 +469,16 @@ function step06_pushScaffoldFiles(): void { if (addResult.status !== 0) { op.status = "failed"; op.error = `git add failed: ${addResult.stderr ?? ""}`; - // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally - spawnSync("rm", ["-rf", tmpDir], { encoding: "utf8" }); + rmSync(tmpDir, { recursive: true, force: true }); return; } + // Set git identity so commit doesn't fail on machines with no global git config. + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + spawnSync("git", ["config", "user.email", "scaffold@lucent-financial-group.github.io"], gitOpts); + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally + spawnSync("git", ["config", "user.name", "LFG Scaffold"], gitOpts); + // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally const commitResult = spawnSync( "git", @@ -479,8 +492,7 @@ function step06_pushScaffoldFiles(): void { if (commitResult.status !== 0) { op.status = "failed"; op.error = `git commit failed: ${commitResult.stderr ?? ""}`; - // eslint-disable-next-line sonarjs/no-os-command-from-path -- git is PATH-resolved intentionally - spawnSync("rm", ["-rf", tmpDir], { encoding: "utf8" }); + rmSync(tmpDir, { recursive: true, force: true }); return; } diff --git a/tools/scaffold/forge/AGENTS.md b/tools/scaffold/forge/AGENTS.md index 7132ea86ee..2d667527ac 100644 --- a/tools/scaffold/forge/AGENTS.md +++ b/tools/scaffold/forge/AGENTS.md @@ -6,9 +6,10 @@ he does not author. Agents have agency, judgement, and accountability. ## Philosophy -**Forge is Claude-owned.** Factory policy, the BP-NN rule list, the -skill catalog, persona registry — Claude authors and maintains these. -Aaron holds alignment-contract veto and budget authority. +**Forge is governed by the factory's AI agent.** Factory policy, the BP-NN +rule list, the skill catalog, persona registry — the factory's AI agent +authors and maintains these. The human maintainer holds alignment-contract +veto and budget authority. The three load-bearing values (same as Zeta): diff --git a/tools/scaffold/forge/GOVERNANCE.md b/tools/scaffold/forge/GOVERNANCE.md index c05cca8231..7d52c37e62 100644 --- a/tools/scaffold/forge/GOVERNANCE.md +++ b/tools/scaffold/forge/GOVERNANCE.md @@ -68,9 +68,10 @@ substrate. Before declaring work done, identify its durability surface. ## §10 Alignment floor Factory operation is bounded by `docs/ALIGNMENT.md`. Any factory -move touching alignment routes through Aaron. +move touching alignment routes through the human maintainer. --- -*Rationale and full reasoning for each rule lives in `.claude/rules/` -and `memory/` — the numbered rules here are the stable reference targets.* +*Numbered rules here are the stable reference targets. Full rationale +lives in the Forge repo's `docs/` and the Zeta repo's +[ADR 2026-04-22](https://github.com/Lucent-Financial-Group/Zeta/blob/main/docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md).* diff --git a/tools/scaffold/forge/README.md b/tools/scaffold/forge/README.md index 8b40d43d95..29035f022e 100644 --- a/tools/scaffold/forge/README.md +++ b/tools/scaffold/forge/README.md @@ -43,7 +43,7 @@ Four dependency edges, zero DAG — this is why there are no submodules. ## Governance -Forge is **Claude-owned** for governance (factory policy, BP-NN rules, +Forge is governed by the **factory's AI agent** (factory policy, BP-NN rules, skill catalog, persona registry). The human maintainer retains alignment-contract veto and budget authority. Full model: [ADR 2026-04-22 §Ownership model](https://github.com/Lucent-Financial-Group/Zeta/blob/main/docs/DECISIONS/2026-04-22-three-repo-split-zeta-forge-ace.md#ownership-model). diff --git a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md index d05e999e8f..69f7748be5 100644 --- a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md +++ b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md @@ -5,7 +5,7 @@ Drift between this file and actual GitHub settings is a factory-hygiene finding (cadenced diff via `gh api`). Origin: ADR 2026-04-22 §"Repo best practices — applied at creation". -Pattern: `memory/feedback_github_settings_as_code_declarative_checked_in_file.md`. +Pattern: declarative settings-as-code (see Zeta repo's `memory/` for full rationale). --- From 26e74ba4f6de053d3456e53a43a283de0c99c2f1 Mon Sep 17 00:00:00 2001 From: Aaron Stainback Date: Wed, 13 May 2026 11:41:35 -0400 Subject: [PATCH 10/10] fix(scaffold): replace remaining bare memory/ paths in forge/docs/GITHUB-SETTINGS.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two backtick-coded memory/ file references on lines 65 and 81 were still local-path references that would be dead links in the scaffolded Forge repo (which has no memory/ directory at day-one). - `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md` → full Zeta repo URL - `memory/feedback_lfg_budgets_set_permits_free_experimentation.md` → full Zeta repo URL Addresses review thread PRRT_kwDOSF9kNM6BzZC2 (PR #2994). Co-Authored-By: Claude --- tools/scaffold/forge/docs/GITHUB-SETTINGS.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md index 69f7748be5..458d892e36 100644 --- a/tools/scaffold/forge/docs/GITHUB-SETTINGS.md +++ b/tools/scaffold/forge/docs/GITHUB-SETTINGS.md @@ -61,8 +61,9 @@ Merge queue: **enabled** (LFG org feature; requires GitHub Team or above). | Private vulnerability reporting | **enabled** | > Note: CodeQL **default-setup** is required; advanced-only fails the -> `code_scanning` ruleset rule. See -> `memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md`. +> `code_scanning` ruleset rule (see +> [Zeta memory](https://github.com/Lucent-Financial-Group/Zeta/blob/main/memory/reference_github_code_scanning_ruleset_rule_requires_default_setup.md) +> for background). ## OpenSSF Scorecard @@ -77,8 +78,9 @@ Scorecard workflow: **enabled** via `.github/workflows/scorecard.yml` | Actions | $0 | | Packages | $0 | -Caps are designed cost-stops per -`memory/feedback_lfg_budgets_set_permits_free_experimentation.md`. +Caps are designed cost-stops; see the +[Zeta memory file](https://github.com/Lucent-Financial-Group/Zeta/blob/main/memory/feedback_lfg_budgets_set_permits_free_experimentation.md) +for background. Free-tier consumption is still tracked via `tools/budget/snapshot-burn.ts`.