Fixing Payment Terms Inconsistencies Across Multi-Environment Proposal Generation
Overview
This session involved identifying and correcting payment term discrepancies across two related proposal documents stored in S3, then synchronizing changes back to both local development and production environments. The work demonstrates the complexity of maintaining document consistency when the same logical content exists in multiple formats (HTML templates, local git repos, and cloud storage) with asynchronous deployment pipelines.
What Was Done
- Identified conflicting payment terms in
/Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/jada-charter-proposal-sue.html - Retrieved and corrected the corresponding S3-hosted proposal at
s3://queenofsandiego.com/proposals/jada-charter-proposal-ewing.html - Resolved contradictory language around deposit requirements and weather-related refund policies
- Deployed corrected versions back to S3 for production access
- Updated the progress dashboard with task completion notes
Technical Details: The Payment Terms Problem
The initial issue surfaced when reviewing proposal content across two related documents. The "Sue Ewing" charter proposal variant contained contradictory language:
Line 525 (original conflicting state):
"Deposit held in all cases"
vs.
Weather refund terms that implied conditional deposit handling
Meanwhile, the S3-hosted production version of the same proposal (jada-charter-proposal-ewing.html) contained incorrect payment language:
Original S3 content:
"50% deposit required at booking"
This was inconsistent with the corrected business logic that should state deposit handling conditionally based on cancellation scenarios.
Resolution: Multi-Location Synchronization
The fix required a three-step process:
Step 1: Retrieve from S3
aws s3 cp s3://queenofsandiego.com/proposals/jada-charter-proposal-ewing.html /tmp/ewing-proposal.html --region us-east-1
This brought the production version locally for inspection and editing.
Step 2: Validate and Correct Local Repository Version
The local git repository version at /Users/cb/Documents/repos/sites/queenofsandiego.com/proposals/jada-charter-proposal-sue.html was the source of truth. The payment terms were corrected from the contradictory state to a single, consistent statement regarding deposit and refund handling.
Step 3: Deploy Back to S3
aws s3 cp /tmp/ewing-proposal.html s3://queenofsandiego.com/proposals/jada-charter-proposal-ewing.html --content-type text/html
The corrected file was uploaded back to S3 with proper content-type headers to ensure CloudFront caching and browser rendering worked correctly.
Infrastructure & Deployment Pipeline
The proposal system uses a distributed architecture:
- Source of Truth: Git repository at
/Users/cb/Documents/repos/sites/queenofsandiego.com/ - Production Storage: S3 bucket
queenofsandiego.comunder/proposals/prefix - Content Distribution: CloudFront CDN (distribution ID not exposed) caches objects from S3
- Access Pattern: Direct S3 access via AWS CLI for document management; browser clients fetch from CloudFront
Files are not automatically synced from git to S3—changes require explicit deployment via AWS CLI commands. This manual step ensures controlled releases and prevents accidental production overwrites from development branches.
Dashboard Integration
After correcting both proposals, the progress tracking system was updated using a Python tool:
python3 /Users/cb/Documents/repos/tools/update_dashboard.py add-note t-f20bc5a4 \
--text "Payment terms fixed on both proposals. Ewing variant corrected in S3."
This command creates a timestamped note on task t-f20bc5a4, making the fix visible to the team and establishing an audit trail of changes. The dashboard pulls from a JSON state file served at https://progress.queenofsandiego.com/state.json.
Key Technical Decisions
Why Validate Before Deploying: The proposal documents contain business-critical information (payment terms, cancellation policies). A regex-based search for keywords like "deposit", "payment", "refund", and "50%" allowed us to verify the exact location of inconsistencies before any changes were made.
Why Use S3 + CloudFront: This architecture separates storage (S3) from content delivery (CloudFront). S3 provides versioning and access controls; CloudFront provides edge caching and fast delivery to clients. HTML proposals are static assets, making this pattern ideal.
Why Explicit S3 Deployment: Rather than automated git-to-S3 syncing (which could propagate errors), the team uses manual AWS CLI deployment. This allows for validation, testing, and selective deployment of only corrected documents.
Why Timestamp Notes in Dashboard: The progress tracking system creates an immutable log of all changes. This is especially important for proposals—there's a permanent record of when payment terms were corrected, aiding compliance and dispute resolution.
Content-Type Headers Matter
When uploading HTML documents to S3, explicitly setting --content-type text/html ensures:
- Browsers render the file as HTML, not force a download
- CloudFront caches with the correct MIME type, serving proper
Content-Typeheaders to clients - SEO and link preview tools (e.g., Slack unfurls, meta tag readers) parse the document correctly
Omitting this flag can result in S3 defaulting to application/octet-stream, breaking browser rendering.
Lessons Learned
This work surfaced the need for a stronger proposal validation workflow. Currently, inconsistencies are caught during manual review. A future improvement would be automated linting that checks for contradictory language patterns in payment terms (e.g., flagging both "deposit held in all cases" and conditional refund language in the same document).
What's Next
Future improvements to this process:
- Proposal Template System: Move from static HTML to a templated system (Jinja2 or similar) to generate variants programmatically, reducing copy-paste inconsistencies
- Automated Testing: Linters that validate payment term consistency across proposal variants
- CloudFront Invalidation: Implement automatic cache invalidation on proposal updates to reduce TTL cache-staleness issues
- Versioning: Add semantic versioning to proposal filenames to track which version was sent to which client