# Resync `prole` as a Customer Deploy of `knoe-db` **Status:** **Dormant.** The plan was written when `~/dev/prole` and `~/dev/knoe-db` were two separate working trees diverging on GitHub vs the knoe Gitea. As of 2026-04, the prole→knoe rebrand has merged into `knoe-db/main` directly, there is no separate `~/dev/prole` working tree under active development, and both `origin` and `knoe` remotes in this repo point at upstream `git@git-ssh.knoe.dev:knoe.dev/knoe-db.git`. The customer-branch workflow described below is the **target shape** for any future per-customer separation; it has not been executed and has no current customer driving it. Sections below are preserved as the design reference if the workflow is reactivated. **Owner:** chrisfu **Audience:** Jr/mid engineer joining the project. No prior knowledge of the prole↔knoe-db split assumed. --- ## 1. Context This working tree (`~/dev/prole`) and `~/dev/knoe-db` started life as the same project. Over time `knoe-db` has become the canonical upstream — the "Knoe" infrastructure platform, hosted at `git@git-ssh.knoe.dev:knoe.dev/knoe-db.git` — while `prole` has continued as a separate fork on GitHub with its own diverging history. The strategic decision the team has made is: **stop forking, start branching.** `knoe-db` is the platform's source of truth. Customer deployments — currently `prole.org`, eventually others — live as **branches in `knoe-db`**, not as separate repositories. A customer branch carries only the customer-specific divergence (config files, branding, on-prem manifests, kubeconfig handling). Platform changes always land on `knoe-db/main` and customer branches rebase or merge from main on a regular cadence. This plan describes how to bring `~/dev/prole` into that shape. ### Why a branch and not a fork - **One pull-request review surface for platform changes.** A change that affects all deployments goes through MR review on `knoe-db/main` once. In a fork model the same change has to be re-reviewed (or, more often, silently re-implemented) per fork. - **Customer-specific divergence is observable.** A `git diff main..prole` is the complete answer to "what's special about the prole.org deploy?" In a fork model that question requires a manual cross-repo diff that quickly goes stale. - **Resync is mechanical.** `git rebase main` or `git merge main` updates the deploy branch. In a fork model resync is a recurring tax that engineers underinvest in until the forks have drifted past easy reconciliation — which is roughly where prole is today. - **Customer-specific platform changes get attention.** If a customer needs a platform-level change to support their deploy, it lands on `main` (and is therefore available to all customers) instead of being hidden in a fork that never makes it back. ### What's already done - prole has `knoe-db` configured as a git remote named `knoe`: ``` knoe git@git-ssh.knoe.dev:knoe.dev/knoe-db.git (fetch) knoe git@git-ssh.knoe.dev:knoe.dev/knoe-db.git (push) origin git@github.com:dredx/prole.git (fetch) origin git@github.com:dredx/prole.git (push) ``` So the network plumbing for `git fetch knoe` is in place. `origin` is the legacy GitHub fork. - `knoe-db` already has `docs/plans/` with the architectural references for `knoe-auth Round 1` and the four-mode installer — see [`knoe-db/docs/plans/`](../../../knoe-db/docs/plans/) (path relative to your `~/dev/` root). ### What's not yet done - Most of `prole/main` has not seen `knoe-db/main`'s recent work (the prole→knoe rebrand, the welcome-mode-selector Phase 0, the fully implemented `authority/` module, the 1Password CLI cutover, etc.). - Prole still tracks `infrastructure/` (the prole.org-specific Ansible tree) which `knoe-db` excised in commit `5a769f2`. - Prole still tracks the old `prole-*` directory names that knoe-db has renamed (`prole-app/`, `prole-tools-app/`, `prole.sh`, `prole.spec`, `prole_requirements.txt`). - Prole's working tree carries credentials and runtime artifacts that should never have been near git in the first place — `postgres-password.txt`, `prole-k3s.kubeconfig*`, `secrets/`, `ssh-keys/`. None are committed (verified with `git ls-files`), but they exist in the working copy and are a data-leak risk. --- ## 2. Target shape When this plan is done: - The `prole` working directory tracks a branch in `knoe-db` — name to be confirmed, proposed `customer/prole.org` or simply `prole`. - `git remote` looks like: ``` origin git@git-ssh.knoe.dev:knoe.dev/knoe-db.git ``` The legacy GitHub `origin` is either retired entirely or kept as `archive` for historical reference. - `git diff origin/main` (i.e. `knoe-db/main`) shows **only** prole-specific divergence: - Customer-branded config (`conf/prole.cfg`, host names, realm `PROLE.LOCAL`, etc.) - On-prem manifests scoped to `prole.org` infrastructure (`deploy/opentofu/k3s/manifests/prole/*`) - Customer-specific docs (`docs/plans/customer-deploy-resync.md` — this file — and any future prole-only plans) - All tracked platform code (`authority/`, `knoe/`, `etc/init_*.sh`, `deploy/gcp/gke/*`, the test pipeline) is **byte-identical** to `knoe-db/main`. Changes to those files happen on `knoe-db/main` first and reach prole via merge/rebase. - Working-tree credentials and runtime files are removed, gitignored, and replaced with the 1Password-driven equivalents already used in `knoe-db`. ### What "customer-specific" actually means here It's a short list, and the discipline is to keep it short: | Type | Example | Where it lives on the branch | | --- | --- | --- | | Customer config | `conf/prole.cfg` (cluster contexts, realm, hostnames) | `conf/` | | Customer realm | `PROLE.LOCAL` Kerberos manifests | `deploy/opentofu/k3s/manifests/prole/prole-kdc-*.yaml` | | Customer cluster glue | k3s `prole.org` host inventory, anything host-pinned to `merlin/myrddin/pi.prole.org` | `deploy/opentofu/k3s/manifests/prole/` | | Customer docs | `docs/plans/customer-deploy-resync.md`, any future prole-only specs | `docs/plans/` | Anything that doesn't fit one of those four lines is probably platform code that should land on `main`. --- ## 3. Migration plan The migration is in four phases. Each phase is reviewable on its own; do not collapse them. > **All git work in this plan should run in Claude Code, not in Cowork.** Cowork's bash sandbox has no network access and cannot reach `git-ssh.knoe.dev`. Open a Code session in `~/dev/prole` and drive the commands from there. ### Phase 1 — Snapshot and inventory The goal of this phase is to produce a complete account of what's currently special about prole, *before* anyone starts deleting things. Output is a file checked into the working tree (`docs/plans/resync-inventory.md`, net-new) listing every file that differs from `knoe-db/main`, classified as one of: - **PLATFORM-DRIFT** — file should match `knoe-db/main`. Discrepancy is just stale prole. Action: take knoe-db's version. - **CUSTOMER-SPECIFIC** — file is genuinely prole-only. Action: keep, plan to land on the customer branch. - **WORKING-TREE-NOISE** — credentials, build artifacts, kubeconfigs. Action: gitignore upstream if not already; remove from working tree; never commit. - **AMBIGUOUS** — needs human review. Action: discuss before acting. Concrete commands (run in Code in `~/dev/prole`): ```bash # fetch knoe-db git fetch knoe # list all files that exist in prole but not in knoe-db/main git diff --name-only --diff-filter=D knoe/main..HEAD > /tmp/prole-only.txt # list all files that exist in both but differ git diff --name-only knoe/main..HEAD | grep -v '^docs/plans/customer-deploy-resync.md$' > /tmp/prole-modified.txt # list all files that exist in knoe-db/main but not in prole git diff --name-only --diff-filter=A knoe/main..HEAD > /tmp/knoe-db-new.txt ``` Walk through each list and classify. Expected hot spots based on the current state: - `infrastructure/` — entirely PLATFORM-DRIFT (excised upstream by commit `5a769f2`). - `prole-app/`, `prole-auth/`, `prole-mssql-db/`, `prole-net/`, `prole-tools-app/`, `prole.sh`, `prole.spec`, `prole_requirements.txt` — PLATFORM-DRIFT (renamed upstream during the prole→knoe rebrand). - `authority/src/main/java/org/prole/authority/HealthController.java` etc. — PLATFORM-DRIFT (stale Spring Boot skeleton; upstream has the full module). - `deploy/opentofu/k3s/manifests/prole/*` — likely CUSTOMER-SPECIFIC (the `prole.org` realm and host pinning belongs on the customer branch). - `conf/prole.cfg`, `conf/prole.silent.all.cfg` — CUSTOMER-SPECIFIC. - `postgres-password.txt`, `prole-k3s.kubeconfig*`, `secrets/`, `ssh-keys/` — WORKING-TREE-NOISE. These should not be tracked anywhere. Output of phase 1 is the inventory file plus a short summary commit on a fresh branch (proposed name `resync/phase-1-inventory`). ### Phase 2 — Bring `prole/main` to `knoe-db/main` > ⚠️ **Read this whole phase before running any of it.** This is where the divergence collapses; recovery from a botched merge is much harder than waiting an hour to do it right. Approach: do **not** try to merge upstream into prole's diverged main. Instead: 1. Create a backup tag at the current state: `git tag prole-pre-resync-$(date +%Y%m%d)`. Push it to `origin` (the GitHub fork) for safety. 2. Create a fresh customer-deploy branch off `knoe-db/main`: ```bash git checkout -b customer/prole.org knoe/main ``` 3. Cherry-pick **only** the CUSTOMER-SPECIFIC commits/files from the inventory. The cleanest way is a one-pass apply: ```bash # for each file in the customer-specific list, copy from old prole main git checkout prole-pre-resync- -- git add ``` Commit in coherent groups (e.g. one commit per logical scope: "config", "k3s manifests", "customer docs"). 4. Push the new branch to the `knoe` remote: ```bash git push knoe customer/prole.org ``` 5. Open an MR in `knoe-db` for the customer branch (it doesn't merge to main — it's a long-lived branch — but the MR makes it visible and reviewable). After this phase, `customer/prole.org` is byte-identical to `main` except for the (small) customer-specific delta. ### Phase 3 — Retire the GitHub fork and clean the working tree 1. Update the local working tree's `origin` remote to point at `knoe`: ```bash git remote rename origin archive git remote rename knoe origin git fetch origin ``` Or, if you want to delete the GitHub fork outright, drop the `archive` remote. Either is fine; the GitHub copy is no longer authoritative. 2. Switch the working tree to the new branch: ```bash git checkout customer/prole.org ``` 3. Delete working-tree noise (the WORKING-TREE-NOISE bucket from phase 1). For each file: - Confirm it's not tracked: `git ls-files --error-unmatch `. - Confirm it's covered by `.gitignore` (or add it). - Delete it: `rm -rf `. - Special case: `postgres-password.txt`. Treat the contents as compromised because it was sitting in a working tree synced to who-knows-where. **Rotate the password through the standard process**, do not just delete the file. 4. Replicate `knoe-db`'s 1Password CLI workflow: `etc/` already has the 1Password integration after `knoe-db` commit `b421f49`. Set up the 1Password CLI and verify `op signin` works before relying on the new flow. ### Phase 4 — Establish the resync cadence Going forward, prole resyncs from `knoe-db/main` on a deliberate cadence (proposal: weekly, or after any commit on `main` that touches a file the customer branch carries a divergent copy of). Mechanism — pick one: - **Rebase** `customer/prole.org` onto `knoe-db/main`. Linear history, clean diff against main, but rewrites the customer-branch SHAs on every resync. Choose this if no other tooling has hardcoded references to customer-branch commits. - **Merge** `knoe-db/main` into `customer/prole.org`. Preserves history, no SHA rewriting, but the `git log --oneline` gets messy and `git diff main..customer/prole.org` includes merge artifacts. Recommendation: **rebase**. Customer divergence is small enough to keep clean, and the simpler diff is worth more than the merge-commit history. Set up CI on `knoe-db` to run the customer-deploy smoke test against the rebased branch nightly. Failure of that smoke test is an early signal that platform changes have broken the customer deploy and need a customer-side fix. --- ## 4. Out of scope These are real items but they are **not** part of the resync. Each becomes its own plan when its time comes. - Migrating the *running* prole.org cluster to the new branch's deployment shape. Resync is a code-level operation; the live cluster is a separate migration governed by `etc/init_*.sh` and the installer. - Bringing prole's existing Supabase work back into knoe-db/main. Recent prole commits include Supabase fixes (`fix(supabase): ...`) that aren't in upstream. Some of that may be platform code that should land on `main`; some may be prole-specific. Sort that out as a follow-up MR. - The active "knoe-db Init:0/1 on myrddin" debug. That's a runtime-state problem on the prole.org cluster, unrelated to the source-code resync. Track in its own ticket. - Onboarding additional customer deploys. Once one customer branch is healthy, the second is mostly mechanical, but not part of this plan's scope. --- ## 5. Verification The resync is done when all of these are true. 1. `git remote -v` in `~/dev/prole` shows `origin` pointing at `knoe-db`. The legacy GitHub remote is either gone or named `archive`. 2. `git status` is clean on branch `customer/prole.org`. 3. `git diff knoe/main` (or `git diff origin/main` post-rename) shows **only** files in the four categories listed in §2 ("What 'customer-specific' actually means"). No `infrastructure/`, no `prole-app/`, no stale Java skeletons. 4. `git ls-files` does not list `postgres-password.txt`, `prole-k3s.kubeconfig*`, or any file under `secrets/` or `ssh-keys/`. 5. The Postgres password that was previously sitting in `postgres-password.txt` has been rotated. 6. `./install.sh` or `./knoe.sh install` runs end-to-end on the customer branch in `min` and `k3d` modes (the cheap modes to verify locally). 7. `customer/prole.org` is pushed to `knoe-db` and visible in the upstream repo's branch list. 8. `docs/plans/customer-deploy-resync.md` (this file) and `docs/plans/resync-inventory.md` (created in phase 1) are committed on the customer branch. --- ## 6. Risks and call-outs - **Don't run any of this with the prole.org cluster in a degraded state if the cluster recovery depends on a script that the resync deletes.** The current `knoe-db` Init:0/1 debug is a live ops problem; finish that first, or be very careful that the scripts you're about to delete from prole are not the ones the cluster needs to come back. - **The Postgres password file is a real incident.** A credential file in a working tree synced via Dropbox / iCloud / network home directory has a non-trivial blast radius. Treat as compromised, rotate, do not just delete. - **The GitHub `origin` may have copies of secrets in its history.** Before retiring the fork, audit its commit history for committed credentials (`git log -p | grep -iE 'password|secret|token|key'` is a starting point). If anything is in there, rotate before retiring. GitHub's "delete repository" does not retroactively un-disclose anything that was scraped while the repo was up. --- ## 7. Glossary **Upstream / downstream** — Upstream is the canonical project (`knoe-db`); downstream is a deployment of it (`prole.org` customer branch). Changes flow from upstream to downstream, never the other way without an MR back. **Customer deploy** — A specific deployment of the knoe.dev platform for one organization. Carries customer-specific config (hostnames, realm, branding) on top of the platform's main branch. Lives as a long-lived branch in the platform repo, not a fork. **Long-lived branch** — A branch that's not intended to merge back to main. It's continuously rebased onto main as platform work lands, but its own divergence stays as a divergence forever. **Resync** — The act of bringing a customer branch up to a newer `main`. A periodic, deliberate operation; not a continuous one. **Phase 0** — The most recent platform-side rebrand and test-pipeline foundation work (commit `0052a4d` in `knoe-db`). Context here only because it's what `customer/prole.org` is rebasing onto.