From 760dd55ac18da8e9ea5300b1b299b723ebe2c7b8 Mon Sep 17 00:00:00 2001 From: KimBeomJin Date: Thu, 27 Aug 2026 22:37:47 +0900 Subject: [PATCH] Add public CSV CI case study --- csv-ci-case-study.html | 58 ++++++++++++++++++++++++++++++++ index.html | 2 +- offer.test.mjs | 15 +++++++++ sitemap.xml | 4 +++ validate-csv-github-actions.html | 2 +- 5 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 csv-ci-case-study.html diff --git a/csv-ci-case-study.html b/csv-ci-case-study.html new file mode 100644 index 0000000..0f2345b --- /dev/null +++ b/csv-ci-case-study.html @@ -0,0 +1,58 @@ + + + + + + + + Finding Duplicate CSV Rows Before Publication — CSV Preflight + + + + + +
+ +
+ PUBLIC REPRODUCTION · 2026-08-27 +

Ten duplicate rows caught before publication

+

A generated open-source parts database provided a real test of the free Action: inspect the output, report exact duplicates, and block publication without guessing which records to rewrite.

+ +
+
1.1 MBpublic CSV snapshot
+
1,583data rows checked
+
10exact duplicates reported
+
0issues after exact-row dedupe
+
+ +

What was checked

+

The public CDFER/jlcpcb-parts-database project generates a CSV and publishes it through GitHub Pages. Running the released CSV Preflight implementation against the live snapshot found 10 data rows that were byte-for-byte equivalent after CSV parsing. The report identified their row numbers; it did not delete or merge them.

+ +

The narrow proposed fix

+

Public pull request #11 adds a full-row drop_duplicates() call after the generator merges its data, then runs the Action before the Pages artifact is uploaded. On the reproduced snapshot, this reduced 1,583 rows to 1,573 and the validator reported no remaining structural issue.

+ +
Status boundary: the pull request is an open contribution, not a customer result or an accepted upstream change. The repository's full multi-gigabyte generation process was not run locally, and the PR says so.
+ +

Why exact duplicates are the safe first boundary

+

Rows that merely share a part number or description may still represent distinct records. Automatically merging near-duplicates would introduce a business rule that a structural validator cannot justify. This check reports exact repeated rows; the owning project decides whether and where deduplication belongs.

+ +

Reusable workflow pattern

+
    +
  1. Generate or update the CSV.
  2. +
  3. Run the Action using an immutable commit SHA.
  4. +
  5. Keep the issue report as an artifact even when validation fails.
  6. +
  7. Upload or publish data only after the check passes.
  8. +
+ +

The complete copy-ready workflow is in the GitHub Actions guide. It validates one generic UTF-8 CSV up to 10 MiB on the runner, requires no API key, and does not upload the input. Passing checks CSV structure only; it does not guarantee an importer accepts the file.

+ +
+
FIXED SCOPE · USD 99

Want this wired into one repository?

One public repository or sanitized minimal reproduction, one CSV path, one workflow, diagnostic artifacts, a usage note, and one revision. Scope is confirmed in writing before payment.

+ Check setup fit ↗ +
+
+
+ + diff --git a/index.html b/index.html index 90930ad..e256ec8 100644 --- a/index.html +++ b/index.html @@ -1,5 +1,5 @@ CSV Preflight — local CSV and Shopify product import checker -

Read: CSV Is a State Machine · Checkable example · 한국어 서비스

LOCAL-ONLY CSV CHECK

Catch import failures
before your importer does.

Drop or paste CSV. Nothing leaves your browser.

+

Read: CSV Is a State Machine · Checkable example · Public CI case study · 한국어 서비스

LOCAL-ONLY CSV CHECK

Catch import failures
before your importer does.

Drop or paste CSV. Nothing leaves your browser.

OR PASTE
Shopify preset reviewed against the official product CSV guide on 2026-08-27. It checks a bounded set of documented rules and does not guarantee import success.
diff --git a/offer.test.mjs b/offer.test.mjs index ab2f047..4431601 100644 --- a/offer.test.mjs +++ b/offer.test.mjs @@ -15,6 +15,7 @@ const koreanTemplate = readFileSync( const robots = readFileSync(new URL("./robots.txt", import.meta.url), "utf8"); const sitemap = readFileSync(new URL("./sitemap.xml", import.meta.url), "utf8"); const caseStudy = readFileSync(new URL("./case-study.html", import.meta.url), "utf8"); +const csvCiCaseStudy = readFileSync(new URL("./csv-ci-case-study.html", import.meta.url), "utf8"); const caseInput = readFileSync(new URL("./examples/messy-contacts.csv", import.meta.url), "utf8"); const caseOutput = readFileSync(new URL("./examples/normalized-contacts.csv", import.meta.url), "utf8"); const caseReport = readFileSync(new URL("./examples/preflight-errors.csv", import.meta.url), "utf8"); @@ -206,6 +207,7 @@ test("publishes truthful search metadata for every public page", () => { "https://softpeanut.github.io/csv-preflight/ko.html", "https://softpeanut.github.io/csv-preflight/article.html", "https://softpeanut.github.io/csv-preflight/case-study.html", + "https://softpeanut.github.io/csv-preflight/csv-ci-case-study.html", "https://softpeanut.github.io/csv-preflight/pro-terms.html", "https://softpeanut.github.io/csv-preflight/pro-terms-ko.html", "https://softpeanut.github.io/csv-preflight/shopify-csv-guide-ko.html", @@ -230,3 +232,16 @@ test("case study downloads are exact outputs of the public analyzer", () => { assert.match(caseStudy, /agreed before work starts/); assert.doesNotMatch(caseStudy, /customer|client result|guaranteed/i); }); + +test("public CI case study preserves evidence and sales boundaries", () => { + assert.match(page, /csv-ci-case-study\.html/); + assert.match(githubActionGuide, /csv-ci-case-study\.html/); + assert.match(csvCiCaseStudy, /1,583/); + assert.match(csvCiCaseStudy, /10<\/strong>exact duplicates reported/); + assert.match(csvCiCaseStudy, /1,573/); + assert.match(csvCiCaseStudy, /CDFER\/jlcpcb-parts-database\/pull\/11/); + assert.match(csvCiCaseStudy, /open contribution, not a customer result or an accepted upstream change/); + assert.match(csvCiCaseStudy, /full multi-gigabyte generation process was not run locally/); + assert.match(csvCiCaseStudy, /template=ci-setup\.yml/); + assert.doesNotMatch(csvCiCaseStudy, /customer success|production-proven|guaranteed|adopted upstream/i); +}); diff --git a/sitemap.xml b/sitemap.xml index 3322821..0a09aef 100644 --- a/sitemap.xml +++ b/sitemap.xml @@ -16,6 +16,10 @@ https://softpeanut.github.io/csv-preflight/case-study.html 2026-08-27 + + https://softpeanut.github.io/csv-preflight/csv-ci-case-study.html + 2026-08-27 + https://softpeanut.github.io/csv-preflight/pro-terms.html 2026-08-27 diff --git a/validate-csv-github-actions.html b/validate-csv-github-actions.html index 1f71404..f7dc936 100644 --- a/validate-csv-github-actions.html +++ b/validate-csv-github-actions.html @@ -113,7 +113,7 @@

Use schema checks separately

Structural validation cannot decide whether a price is negative, a customer ID exists, or a date belongs to the required timezone. Add importer-specific schema and business-rule checks after structural parsing. Keep their reports separate so reviewers can distinguish malformed CSV from valid CSV containing invalid domain values.

-

Start with the browser checker, inspect the standalone Action source and tests, or use the public v1.0.0 Action release. For offline batch and team use, the published Pro terms describe the completed product. If you want this exact one-file workflow configured against a public or sanitized repository, the separate $99 fixed-scope setup terms define every deliverable and exclusion before payment.

+

Start with the browser checker, inspect the standalone Action source and tests, review the public 1,583-row reproduction, or use the public v1.0.0 Action release. For offline batch and team use, the published Pro terms describe the completed product. If you want this exact one-file workflow configured against a public or sanitized repository, the separate $99 fixed-scope setup terms define every deliverable and exclusion before payment.