Rebounder Tech Blog

Written by the people who actually run these systems in production.

signed_terms_source_version Unchecked, Terms Shown as Agreed

Published About 5 min readBy the Rebounder engineering team — the people who operate these systems

This article may contain affiliate links. Its content is not affected by advertising.

In short

A signed contract's confirmation page always rendered the current terms as what the customer agreed to, so after a revision a customer could see clauses they'd never read, shown as already agreed.

Conclusion

The confirmation page for an e-signed contract always rendered the “current” terms text, and labeled it as the thing the customer had agreed to — never the version they had actually signed. Any time the terms got revised, a customer who had signed an older version and then opened their own contract page could be shown brand-new clauses they had never read, presented as “what you agreed to.”

The fix was to freeze the terms version number into the database at the moment the signature became final, then only render the body text inline when that frozen version matches the current version. When it doesn’t match, the body is hidden and replaced with a notice saying “the terms you agreed to (version N) differ from the current version.”

Symptom

The contract flow with advertisers presents the terms text on an application page (/p/[token]), and the signature is finalized through a web-based agreement action. Even for an already-signed contract, opening this page would render the “current” terms text, every time:

// Before the fix (excerpt)
{advTerms && (
  <details className="mb-3 rounded-md border border-gray-200 bg-gray-50">
    <summary className="cursor-pointer px-3 py-2 text-xs font-medium text-gray-700 hover:text-brand">
      Show full text of "{advTerms.title}" (what you agreed to)
    </summary>
    ...
  </details>
)}

advTerms is the current terms body returned by getContractTemplate(). The only condition gating it is advTerms && — nothing here checks whether the contract was signed, or which version was current at the time of signing. The heading read “what you agreed to” regardless of whether the contract was signed or still pending.

Terms wording can change version to version — the comments in src/lib/contract-doc.ts are explicit that “bump the version by 1 whenever the body text changes” and “never delete a past version’s entry.” Which means the instant the terms got revised, every customer opening the application page — including those who had signed under an older version — would see the new wording presented as “what you agreed to.”

Cause

At the time this code was written, there was nowhere recording “which terms version was current the moment the signature was finalized.” The contracts table had a signing timestamp (agreed_at) and a signer name (agreed_name), but nothing capturing which clauses they agreed to, so the display layer had no option other than “show the current terms.”

The review flagged this through the following chain of reasoning. The terms text carries structured metadata per version:

// src/lib/contract-doc.ts
const META_HISTORY: Record<string, Record<number, ContractMeta>> = {
  "ad-terms": {
    1: { version: 1, effective_date: "2026-07-24", has_auto_renew_clause: true },
    2: { version: 2, effective_date: "2026-08-30", has_auto_renew_clause: true },
  },
  ...
};

A flag like has_auto_renew_clause is designed as a structured signal that can differ version to version. If a future version ever flipped that flag, the “always show the current version” implementation would present a clause the customer had never actually read as something they’d “agreed to.” The review flagged this as a legal-misrepresentation risk and marked it top priority (P0).

The fix

The terms version number current at the moment the signature was finalized now gets frozen into contracts.signed_terms_source_version, and the display layer compares that frozen version against the current one before deciding what to show.

// src/app/p/[token]/page.tsx (after the fix, excerpt)
const signedTermsVersion = contract.signed_terms_source_version;
// Only safe to show the body inline when it's provably the same text the customer actually saw:
//  - Unsigned: the current version they're about to agree to
//  - Signed: only when the frozen version (signed_terms_source_version) matches the current version
const showTermsBody =
  !!advTerms &&
  (!isSigned ||
    (signedTermsVersion != null && signedTermsVersion === advTermsMeta?.version));
// Signed, but the frozen version differs from the current one — hide the body, show a notice instead.
const signedOnOlderTerms =
  isSigned &&
  signedTermsVersion != null &&
  signedTermsVersion !== advTermsMeta?.version;

The display side got a dedicated notice for the mismatched-version case too:

{signedOnOlderTerms && (
  <p className="mb-3 rounded-md border border-gray-200 bg-gray-50 px-3 py-2 text-xs leading-relaxed text-gray-600">
    The terms you agreed to (version {signedTermsVersion}) differ from the current version.
    If you need a copy of what you agreed to at the time, please contact your representative.
  </p>
)}

The heading copy was also split by signature state: unsigned contracts still read “what you agree to,” while signed contracts now read “what you agreed to at the time” — past tense, describing a historical fact rather than an ongoing offer. Rather than swapping the body text live, the fix is built around preserving the integrity of a signed record against the version it was signed under.

Why this wasn’t caught

The code was correctly typed and threw no runtime errors. advTerms is always a retrievable object, and rendering it straight into JSX is syntactically fine, so none of typecheck, lint, or the build ever flagged it.

The actual defect was that the business requirement — “a signed customer should see the version they signed” — was simply never implemented, and no test existed to verify it before this fix. Since the terms had never actually gone through multiple real revisions, the behavioral gap between “always show current” and “show the version that was signed” had never surfaced in practice, so the feature looked like it worked. This fix added a new unit test that verifies the version match against signed_terms_source_version, so the same defect won’t silently reappear the next time the terms get revised.

Frequently asked questions

Q1Did this actually mislead a real customer in production?

No. This was caught as a logical defect during a code review by a separate agent, not an incident report. Whether any signed contract actually hit this path after a real revision was not checked.

Q2How is the signed version recorded?

The terms text is managed in code with a version number incremented on every edit. The moment a signature is finalized, that version gets frozen into contracts.signed_terms_source_version and compared against the current version on display.

Q3Why didn't typecheck or tests catch this?

advTerms was correctly typed and rendered without a runtime error. No test verified that a signed customer should see the version they signed, because that requirement was never implemented. A new unit test was added with the fix.

Environment verified

  • kimiteras-portal (Next.js, Supabase). The e-signature contract flow with advertisers (the /p/[token] application confirmation page)
  • Terms text is managed in code with version numbers in src/lib/contract-doc.ts's META_HISTORY. The signed version gets frozen into contracts.signed_terms_source_version at the moment of signing (as of 2026-07-24)

What this article is based on

  • TypeScript file lines 491-501commit 82fbbf7
  • TypeScript file lines 174-188commit 00d6d04
  • TypeScript file lines 514-533commit 00d6d04
  • TypeScript file lines 51-74commit 00d6d04

Every claim in this article comes from the records above. The repositories we operate are private so we cannot link to them, but which file, which lines, and at which commit we read them is recorded for every article. Nothing here is written from guesswork.