Phase 2 of the merge-hardening effort (Phase 1 added bin/fork-check + the
fork-invariants manifest).
- config/brand_assets.sha256: checksum baseline of the WaboSign 'W' mark assets
(the 6 logos + both apple-touch icons, which the old hardcoded 6-file restore
list missed). bin/fork-check now verifies each asset's sha256 (catching a
silent upstream overwrite that bypasses the text sweep) and warns about
public/ brand-looking files not in the baseline. Single source of truth.
- bin/sync-upstream: restore brand assets by reading the baseline (not a
hardcoded list, so new brand files are covered automatically); run BOTH
rebrand-check and fork-check after the post-merge sweep, aborting with a
remediation message and leaving the tree in place if either fails; optional
RUN_TESTS=1 to run rspec; print a status summary + the human-judgment residue.
- .gitattributes: add the two apple-touch icons to the -merge brand list,
kept in sync with the baseline.
- REBRANDING.md: replace the 21-item manual post-merge checklist (which was not
run reliably) with an automated tier delegated to fork-check + the manifest,
plus a slim human-judgment residue; add an agent sync runbook and an
'Adding a new fork invariant' guide; correct the stale based_on attribution note.
- rebrand-check/rebrand-sync: allowlist/deny the new baseline file (its comment
legitimately references DocuSeal's logo).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ -20,9 +20,9 @@ Scope: ~183 files modified. Decisions were made in a planning conversation befor
## AGPL §7(b) attribution
- `Wabosign::UPSTREAM_NAME = 'DocuSeal'` and `Wabosign::UPSTREAM_URL` constants added
- [app/views/shared/_powered_by.html.erb](app/views/shared/_powered_by.html.erb) and [app/views/shared/_email_attribution.html.erb](app/views/shared/_email_attribution.html.erb) now render a "based on DocuSeal (AGPLv3)" credit alongside the WaboSign brand
- [app/views/shared/_powered_by.html.erb](app/views/shared/_powered_by.html.erb) renders "WaboSign, a fork of DocuSeal" in the footer; [app/views/shared/_email_attribution.html.erb](app/views/shared/_email_attribution.html.erb) states the fork relationship in the email footer
- [app/javascript/submission_form/completed.vue](app/javascript/submission_form/completed.vue) carries the same credit on the post-signing completion screen
- New `based_on` i18n key added to all 14 language sections
- i18n keys `fork_of` and `product_name_is_a_fork_of_upstream_html` carry the credit text (English; other locales fall back via `config.i18n.fallbacks`). `bin/fork-check` asserts these surfaces keep the credit
- [README.md](README.md) and [LICENSE_ADDITIONAL_TERMS](LICENSE_ADDITIONAL_TERMS) rewritten
- New [NOTICE](NOTICE) file added crediting DocuSeal LLC and listing modifications
@ -73,103 +73,81 @@ Upstream lives at `docusealco/docuseal`. Each upstream release is brought in by
### Tooling
- [bin/rebrand-sync](bin/rebrand-sync) — Ruby script that performs the DocuSeal → WaboSign rename sweep across the working tree. Idempotent. Honors a deny-list (see §"Intentionally preserved upstream references" above) and sentinel-protects AGPL §7(b) attribution phrases, SDK custom-element names (`docuseal-form`, `docuseal-builder`), `@docuseal/*` npm packages, and the `github.com/docusealco/{fields-detection,pdfium-binaries,turbo}` binary URLs.
- [bin/rebrand-check](bin/rebrand-check) — fails (exit 1) if any unintended DocuSeal reference survives. Wired into [.github/workflows/ci.yml](.github/workflows/ci.yml) as the `Rebrand check` job.
- [bin/rebrand-check](bin/rebrand-check) — fails (exit 1) if any unintended DocuSeal *text* reference survives. Wired into CI as the `Rebrand check` job.
- [bin/fork-check](bin/fork-check) — fails (exit 1) if any **fork invariant** is broken: re-introduced Pro gate, deleted fork code, overwritten brand asset, lost attribution, dangling partial render, or PRESERVE↔ALLOW_PATTERNS drift. Driven by the declarative manifest [config/fork_invariants.yml](config/fork_invariants.yml). Wired into CI as the `Fork invariants` job. This is the executable form of the old manual post-merge checklist.
- [config/fork_invariants.yml](config/fork_invariants.yml) — the data behind `bin/fork-check`. Extend **this file** (not the script) when upstream adds a new gate; every entry carries a `why:`.
- [config/brand_assets.sha256](config/brand_assets.sha256) — checksum baseline of the WaboSign "W" mark assets. The single source of truth for "what is a brand asset": `bin/fork-check` verifies it, `bin/sync-upstream` restores from it, and [.gitattributes](.gitattributes) `-merge` should mirror it.
- `git config rerere.enabled true && git config rerere.autoupdate true` — once-per-checkout setup; remembers semantic conflict resolutions so the same call is not re-made each release.
- [.gitattributes](.gitattributes) marks `Gemfile.lock` and `yarn.lock` as `-merge` (regenerate after merge rather than diffing).
- [.gitattributes](.gitattributes) marks the brand binary assets as `-merge` (always keep ours; never blend an upstream version during a merge).
### Per-sync steps
### Runbook (for a human or AI agent)
The whole sync — fetch, branch from the tag, sweep, merge, restore brand assets,
re-sweep, and run both gates — is automated:
```sh
git fetch upstream --tags
git checkout -b sync/upstream-<tag><tag> # e.g. 3.0.0
bin/rebrand-sync
git add -A && git commit -m "Apply WaboSign rebrand sweep to upstream <tag>"
bin/sync-upstream <tag> # e.g. bin/sync-upstream 3.0.2
# RUN_TESTS=1 bin/sync-upstream <tag> # also run rspec before declaring done
When upstream introduces a new SDK identifier, binary URL, or attribution surface that must survive the sweep, edit `PRESERVE` in [bin/rebrand-sync](bin/rebrand-sync) and `ALLOW_PATTERNS` in [bin/rebrand-check](bin/rebrand-check) together. The two must stay in sync — `rebrand-sync` decides what the sweep ignores, `rebrand-check` decides what CI tolerates. **This pairing is now CI-enforced:**`bin/fork-check` fails if a `PRESERVE` token containing "docuseal" has no matching `ALLOW_PATTERN`.
bundle install
yarn install
### Adding a new fork invariant
# Verify (see "Verification" in the plan), then:
git tag wabosign-synced-with-<tag>
```
When upstream re-introduces a gate, deletes fork code, or adds a brand asset, encode the rule in [config/fork_invariants.yml](config/fork_invariants.yml) — not in `bin/fork-check`. Use a path-scoped `must_not_contain` for re-added gates (never ban a token tree-wide unless it is genuinely unique to the gate — `Wabosign.multitenant?` is legitimate in ~19 views), `must_exist`/`must_not_exist` for files, and add new brand files to `config/brand_assets.sha256` (and the `.gitattributes``-merge` list). Always include a `why:` — it is the institutional memory the next sync will need.
Or use the automated script:
```sh
bin/sync-upstream <tag>
```
## Post-Merge Verification
### Adding new preserved tokens
Most of what used to be a 21-item manual checklist is now executed by CI. After a
sync, the gates below must be green; only a short residue needs a human eye.
### Automated (CI — must pass)
- **`bin/rebrand-check`** — no unintended DocuSeal *text* survived the sweep.
- **`bin/fork-check`** — every fork invariant holds. The assertions (and the
rationale for each) live in [config/fork_invariants.yml](config/fork_invariants.yml):
`lib/docuseal.rb` absent; SMS stack + `lib/ability.rb` present; no dead paywall
i18n keys; no dangling partial renders; PRESERVE↔ALLOW_PATTERNS in sync.
- **`rspec`** — suite passes (also catches Zeitwerk module conflicts at boot).
When upstream changes something the manifest does not yet know about, **extend
the manifest** (see "Adding a new fork invariant" above) rather than re-checking
by hand. That way the next sync inherits the protection.
### Human-judgment residue (not automatable)
When upstream introduces a new SDK identifier, binary URL, or attribution surface that must survive the sweep, edit `PRESERVE` in [bin/rebrand-sync](bin/rebrand-sync) and `ALLOW_PATTERNS` in [bin/rebrand-check](bin/rebrand-check) together. The two must stay in sync — `rebrand-sync` decides what the sweep ignores, `rebrand-check` decides what CI tolerates.
## Post-Merge Verification Checklist
Run through these checks after every upstream merge. The earlier failures are caught by `bin/rebrand-check`; the later ones require manual inspection or `rspec`.
### Automatic (`bin/rebrand-check`)
- Rebrand check passes (no unintended DocuSeal references)