service-fee-write-path-removalrun.md03_define/output/spec.mdEvery quote adds a 10% platform service fee to the expert's price, and every milestone invoice
pro-rates that fee onto itself: serviceFee = amount × SERVICE_FEE_PERCENTAGE, total = amount + serviceFee. No such fee exists as a system-side commercial term — anything Sustentus negotiates is
agreed and settled outside the platform. So the customer-facing total on every quote and invoice is
inflated by a number the business does not charge, and two finance screens show a "Service fee" line
for money nobody collects. This advances Refine the bridge / Q2-2026 Objective 3 — Validate
Technical Infrastructure & Payout Flow: the payout flow can only be validated against numbers that
mean what they say, and today the recorded total does not.
New quotes and invoices record only the work value — the money the platform stores becomes the money the expert quoted.
total = amount, with no fee written.total = amount and clears any fee the document
already carried.amount = quote.amount × milestone percentage and total = amount.
The fee limb of that calculation is deleted, not zeroed.SERVICE_FEE_PERCENTAGE configuration point is retired: the constant that reads it, its
docs/ENV.md row, and the value in the Vercel dashboard. getMaxMilestones in the same file is
unrelated and survives untouched.business/platform-overview
describes it as a revenue stream — that section is rewritten so the page still explains how the
platform earns, not deleted.The serviceFee schema field stays in place this round, still readable, so documents already written
keep validating and every existing read path keeps working. Stub 2 removes it.
total === amount and no serviceFee written.total === amount and clears any serviceFee the
document already carried.amount === quote.amount × percentage / 100 and
total === amount, with no serviceFee written.getServiceFeePercentage no longer exists, and no unused helper is left behind in
proposal-constants.ts; getMaxMilestones is untouched and still works.SERVICE_FEE_PERCENTAGE appears nowhere in the repo outside apps/docs/archive/.total === amount.business/service-journey/{quote,invoicing,proposals,user-interaction-overview},
business/platform-overview (revenue section rewritten, not dropped), business/roles,
business/initiatives/build-the-bridge, and docs/ENV.md.expert-workbench/earnings.ts no longer explains earnings as excluding a
platform service fee (the code there is already correct and does not change).pnpm format:check, pnpm lint, and the per-app builds pass.serviceFee from the Mongoose schemas, and the totalAmount virtual on the quote model
— stub 2. (The virtual coalesces with ?? 0 and has no callers, so it is inert here.)total ?? (amount + serviceFee) read fallbacks in vendor, sdm-market-signals,
csm-blocker-queue and customer-project — stub 2. They are harmless now: new documents carry no fee,
so the fallback adds zero.total = amount reset on historic records —
stub 2, and gated on an owner decision recorded in the scope breakdown.total field itself, now redundant — a follow-on leanness chore.apps/docs/archive/pipeline-runs/**.SERVICE_FEE_PERCENTAGE also
needs the value unset in the Vercel dashboard — env drift is a known failure surface here, so it
belongs in the release notes.04_build/output/notes.mdfeat: service-fee-write-path-removal — stop computing and showing the service feepackages/services/src/shared/proposal-constants.ts: deleted getServiceFeePercentage and the
parseEnvFloat helper it was the sole caller of — leaving the helper would have been an unused
binding and a lint failure. parseEnvInt / getMaxMilestones untouched. The barrel is a
wildcard export *, so no barrel line needed removing.packages/services/src/db/services/quote/index.ts: createDraftForProposal writes
total: params.amount and no serviceFee; updateFinancialsForProposal sets
{ amount, total: amount } and $unsets serviceFee, so re-pricing a quote written before this
change clears the fee rather than leaving it stale. Dropped the now-unused import.packages/services/src/db/services/invoice/index.ts: createFromMilestone pro-rates
quote.amount only — the fee limb, the serviceFee projection field, and the stale doc comment
are gone; the invoice is written with total: amount.packages/services/src/db/services/demo-data/index.ts: seeded quotes and invoices carry
total: amount with no fee.packages/services/src/db/services/expert-workbench/earnings.ts: comment only — it explained
amount as "ex platform serviceFee", which no longer describes anything. Code unchanged.apps/web/app/(app)/finances/{quotes,invoices}/[id]/page.tsx: removed the "Service fee" cell and
changed the money grid from sm:grid-cols-3 to sm:grid-cols-2, so there is no empty column.docs/ENV.md: removed the SERVICE_FEE_PERCENTAGE row.apps/docs/app/business/**: corrected service-journey/{quote,invoicing,proposals,user-interaction-overview},
roles, initiatives/build-the-bridge. On platform-overview the Service Fee section was
rewritten as Transaction Terms (not deleted) — it now states the platform charges no
system-side fee and that subscription tiers are the revenue the product models, so the page still
explains how the platform earns.total === amount, no serviceFee — createDraftForProposal writes total: params.amount and omits the field.total === amount and clears any carried fee — $set + $unset in one update.amount === quote.amount × percentage / 100 and total === amount.getServiceFeePercentage gone, no unused helper left; getMaxMilestones untouched (still consumed by validate-proposal-milestones.ts and apps/web/lib/proposals/proposal-form-schema.ts).SERVICE_FEE_PERCENTAGE gone from code and docs — see the caveat below.total === amount.docs/ENV.md.earnings.ts comment no longer describes earnings as excluding a platform fee.pnpm format:check, pnpm lint, per-app builds pass — owned by CI, not asserted locally
(Build contract §Verify). Husky formatted the staged files on commit.SERVICE_FEE_PERCENTAGE criterion is satisfied for code, config and docs, but the string
still appears under pipeline/ — in this run's own spec.md and the intake/ breakdown that
specified the removal. Those are the durable record of the work and must not be rewritten; read
the criterion as production surfaces only. apps/docs/archive/ is untouched as specified.service-fee-schema-and-data-removal: the
serviceFee path on the quote and invoice schemas, the totalAmount virtual on the quote model,
and the total ?? (amount + serviceFee) read fallbacks in vendor, sdm-market-signals,
csm-blocker-queue and customer-project. They are inert for new documents — the fallback adds
zero when no fee was written. A repo sweep for serviceFee will hit these; that is expected.totalAmount virtual ((amount ?? 0) + (serviceFee ?? 0)) has no callers anywhere in the
monorepo, so it cannot produce a wrong number here; the ?? 0 coalescing also means no NaN.serviceFee and inflated total until stub 2's migration.
That is intended for this run, and the historic-total reset is still the owner decision flagged
in the scope breakdown.SERVICE_FEE_PERCENTAGE must also be unset in the Vercel
dashboard. Nothing reads it after this PR, so a stale value is inert rather than dangerous, but
leaving it invites the next person to think the fee is still configurable.05_verify/output/verify.mdSERVICE_FEE_PERCENTAGE in
Vercel) and one accepted interim data inconsistency (below). Triggered by the DB write paths and
the retired env var.complexity: standard), run inline — the /code-review command
is user-invocation-only and cannot be model-invoked, so the review was performed directly against
the branch diff. No blocking findings; 2 observations recorded below. The CI Claude review is
not enabled (vars.ENABLE_CLAUDE_REVIEW unset — its check run reports skipped), so there
were no posted comments to triage.CI on dca41ad: all green — Quality Project (format/lint/typecheck/build), Audit database,
Migrate preview database, Spec structure, Project run labels, Vercel Preview Comments. Production
migration and the CONVENTIONS review skipped. No failures at any point.
Agent-verified (reachable without signing in):
web-git-claude-service-fee-write-path-removal-njperx-sustentus.vercel.app
serves the app, no deployment-protection wall, no error page (agent)getServiceFeePercentage no longer exists and no unused helper remains in
proposal-constants.ts — repo sweep returns zero hits; CI typecheck+lint green, which is
what would catch the orphaned parseEnvFloat. getMaxMilestones retained with both
consumers intact (agent)SERVICE_FEE_PERCENTAGE gone from code, config and docs — sweep clean outside
apps/docs/archive/. Caveat: the string still appears under pipeline/ in this run's own
spec.md and the intake breakdown that specified the removal; those are the durable record
and must not be rewritten. Read the criterion as production surfaces only (agent)platform-overview's revenue section
rewritten as "Transaction Terms" rather than deleted, so the page still explains how the
platform earns — verified in the diff. Note the docs Vercel preview was marked Ignored,
so there is no preview URL for these this round (agent)expert-workbench/earnings.ts comment no longer describes earnings as excluding a platform
fee; its code is unchanged (agent)pnpm format:check, pnpm lint, per-app builds — Quality Project check run green (agent, CI)Code paths traced in the diff but not demonstrated on the preview — these need a signed-in session and real records, so they are the operator's:
total === amount and no serviceFee
(operator — pending)total === amount and clears any serviceFee the
document already carried (operator — pending)amount === quote.amount × percentage / 100 and
total === amount, no serviceFee (operator — pending)total === amount (operator — pending, needs a demo
seed run)serviceFee (sweep clean) and
none changed shape; confirm notifyInvoiceRaised still fires on an invoice raise, since
notifications fail silently by design (operator — pending)total; re-pricing an old quote silently repairs it, so the state clears
unevenly. No code breaks: nothing sums invoices against a quote total or cross-validates the
two — verified by sweep — so this is a display/reporting artifact only. This is the concrete shape
of the "leave history alone vs reset total" decision the scope breakdown reserved for the owner
and deferred to service-fee-schema-and-data-removal. Argues for running stub 2 close behind.SERVICE_FEE_PERCENTAGE must be unset in the Vercel dashboard. Nothing
reads it after this PR, so a stale value is inert rather than dangerous — the risk is a future
reader assuming the fee is still configurable.(quote.amount ?? 0) * pct is unchanged by this diff
and is now marginally better — total mirrors amount exactly instead of compounding two float
limbs. No action.VendorEnvelopeInvoice.serviceFee is still populated but read nowhere,
and the quote model's totalAmount virtual still has zero callers monorepo-wide. Both are
deliberately deferred to stub 2; both are inert (the virtual coalesces with ?? 0, so no NaN).getMaxMilestones reads MAX_MILESTONES, which is absent from
turbo.json globalEnv. Worth an intake item; out of scope for this run.Agent-side passes are complete and clean. The operator-demonstrated lines above are outstanding; this record does not claim them. The Verify gate is Jamie's to confirm in conversation.
06_ship/output/changelog.mdThe platform no longer adds a 10% service fee on top of the expert's price. A new quote records the amount the expert quoted and nothing more, so its total is that same figure. Milestone invoices follow the quote — each one bills its share of the expert's price, with no fee added on top.
The "Service fee" line has gone from the quote and invoice detail screens, which now show the amount and the total side by side. Customers see one number to approve and pay; experts see the figure they quoted carried through to every invoice raised against it.
Quotes and invoices issued before this change keep the totals they were issued with, so a customer may still see an older quote whose total sits above its amount. Re-pricing a proposal brings its quote in line.
06_ship/output/investor-update.mdWho it's for: Customers, experts, vendors and CSMs What shipped: The platform no longer adds a 10% service fee to quotes or milestone invoices. Why it matters: Refine the Bridge / Objective 3: Validate Technical Infrastructure & Payout Flow. Payouts can only be validated against figures that mean what they say.
Every new quote and invoice satisfies total equals amount.
Dig deeper: https://github.com/sustentus/sustentus/pull/744 · https://help.sustentus.com/changelog/2026-08-03-service-fee-write-path-removal
06_ship/output/release.md4d11774017fce1 — Quality Project, Audit database, Migrate preview
database, Spec structure, Project run labels, Vercel Preview Comments all passed; production
migration and the CONVENTIONS review skipped. No failures at any point in the run.apps/docs/app/technical/** for the fee and the
env var, zero hits.service-journey/{quote,invoicing,proposals,user-interaction-overview},
platform-overview (Service Fee section rewritten as Transaction Terms, not deleted, so the page
still explains how the platform earns), roles, initiatives/build-the-bridge, plus docs/ENV.md.total === amount, no serviceFee — verified in Verify (code trace)total === amount and clears any carried fee — verified in Verify (code trace)amount === quote.amount × percentage / 100, total === amount — verified in Verify (code trace)getServiceFeePercentage gone, no unused helper left; getMaxMilestones untouched — verified in Verify (sweep + CI lint/typecheck)SERVICE_FEE_PERCENTAGE absent outside apps/docs/archive/ — verified in Verify (sweep; see caveat below)total === amount — verified in Verify (code trace)earnings.ts comment corrected — verified in Verify (diff)pnpm format:check, pnpm lint, per-app builds pass — Quality Project greenSERVICE_FEE_PERCENTAGE in the Vercel dashboard. Nothing reads it now, so a stale value
is inert rather than dangerous — the risk is a future reader assuming the fee is still
configurable. This is the one manual action this run leaves behind.serviceFee and inflated total, so their Amount and Total now disagree on screen
with no line explaining the gap. New invoices raised against an old quote correctly carry no fee,
so they won't reconcile to that quote's total; re-pricing an old quote repairs it. No code breaks
— nothing sums invoices against a quote total or cross-validates them. Resolved by
service-fee-schema-and-data-removal, which still needs the owner's decision on whether to reset
total on historic records.05_verify/output/verify.md.SERVICE_FEE_PERCENTAGE criterion is satisfied for production surfaces. The string still
appears under pipeline/ in this run's own spec and the intake breakdown that specified the
removal — those are the durable record and were deliberately not rewritten.service-fee-schema-and-data-removal: the serviceFee schema field on
both models, the quote totalAmount virtual (zero callers monorepo-wide), the four
total ?? (amount + serviceFee) read fallbacks, and the migration of existing documents.getMaxMilestones reads MAX_MILESTONES, which is absent
from turbo.json globalEnv.