[object Object]

← back to Cli Printing Press

fix(cli): exempt vendor OpenAPI/Swagger source under .manuscripts from PII scan (#1496)

dc0651ab8bf2cb1f9060b14a31de836df7f91ef3 · 2026-05-16 00:15:27 -0700 · Trevin Chow

* fix(cli): exempt vendor-published OpenAPI/Swagger source under .manuscripts from PII scan

The PII gate already exempts root-level spec.{json,yaml,yml} on the
premise that vendor `example:` blocks are documentation, not customer
PII. The exemption was depth-1 only, so a generation that archived the
vendor's published per-resource spec files (`apps/calendars.json`,
`pushpress-v3.yaml`, etc.) under .manuscripts/.../research/ false-failed
publish on the documentation-shape values inside.

Adds a content-detected variant of the same exemption: when a file
anywhere inside a .manuscripts/ subtree begins with an OpenAPI 2.x/3.x
or Swagger 2.0 root-document marker, scanPIIFile skips it. Content
detection beats filename heuristics because vendors ship spec source
under arbitrary basenames that no glob would reliably cover.

The exemption is scoped to .manuscripts/ so non-archive paths
(committed docs/, generated internal/, testdata/ fixtures) still scan.
HARs, session-state captures, and hand-edited proofs under
.manuscripts/ also keep scanning because they carry no version marker.
A complementary regression test pins both directions.

Closes #1356

* fix(cli): anchor JSON vendor-spec markers to document root

Greptile flagged that the JSON markers (`"openapi"\s*:\s*"[23]\.`) had
no document-root anchor, so a non-spec JSON file under .manuscripts/
with a nested `"openapi": "3.0.0"` field deep in its payload (response
envelope, captured config blob, metadata wrapper) would silently bypass
PII scanning. The YAML markers were already anchored via `(?m)^` to
column 0, which in valid YAML means a root-level key.

Tighten the JSON regexes to `\A\s*\{\s*"openapi"\s*:\s*"[23]\.`,
requiring `openapi` (or `swagger`) as the first key after the opening
brace. JSON specs put the version key at root by convention; the strict
anchor matches the YAML behavior and forecloses the nested-key bypass.

Adds three regex-level cases (nested openapi inside `user_data`, info
before openapi, nested swagger) and an end-to-end FindPII regression
test that builds a captured.json with a nested openapi field plus real
PII and asserts the file still scans.

* fix(cli): anchor YAML vendor-spec markers to document start

Greptile's second pass flagged the symmetric YAML gap. The previous
`(?m)^openapi\s*:` regex fired on any column-0 occurrence within the
8 KB head probe — so a research-notes YAML under .manuscripts/ that
listed real PII in earlier root-level keys and a later `openapi: 3.0.0`
key would silently bypass scanning. The JSON anchor (`\A\s*\{\s*"openapi"`)
forecloses the same shape; YAML needed parallel treatment.

Anchor both YAML markers to document start with an explicit allowed
lead-in (optional YAML directives `%...`, document marker `---`,
comment lines, blank lines). Any other content before `openapi`/`swagger`
at column 0 rejects the exemption.

Adds:
- four regex-level cases: yaml-pii-before-openapi (negative), yaml-with-
  document-marker (positive), yaml-with-comment-prefix (positive),
  yaml-with-directive-and-marker (positive), yaml-with-blank-lead
  (positive), yaml-swagger-after-meta (negative).
- a YAMLPIIBeforeOpenAPI FindPII regression that mirrors the JSON one.

---------

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>

Files touched

Diff

commit dc0651ab8bf2cb1f9060b14a31de836df7f91ef3
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Sat May 16 00:15:27 2026 -0700

    fix(cli): exempt vendor OpenAPI/Swagger source under .manuscripts from PII scan (#1496)
    
    * fix(cli): exempt vendor-published OpenAPI/Swagger source under .manuscripts from PII scan
    
    The PII gate already exempts root-level spec.{json,yaml,yml} on the
    premise that vendor `example:` blocks are documentation, not customer
    PII. The exemption was depth-1 only, so a generation that archived the
    vendor's published per-resource spec files (`apps/calendars.json`,
    `pushpress-v3.yaml`, etc.) under .manuscripts/.../research/ false-failed
    publish on the documentation-shape values inside.
    
    Adds a content-detected variant of the same exemption: when a file
    anywhere inside a .manuscripts/ subtree begins with an OpenAPI 2.x/3.x
    or Swagger 2.0 root-document marker, scanPIIFile skips it. Content
    detection beats filename heuristics because vendors ship spec source
    under arbitrary basenames that no glob would reliably cover.
    
    The exemption is scoped to .manuscripts/ so non-archive paths
    (committed docs/, generated internal/, testdata/ fixtures) still scan.
    HARs, session-state captures, and hand-edited proofs under
    .manuscripts/ also keep scanning because they carry no version marker.
    A complementary regression test pins both directions.
    
    Closes #1356
    
    * fix(cli): anchor JSON vendor-spec markers to document root
    
    Greptile flagged that the JSON markers (`"openapi"\s*:\s*"[23]\.`) had
    no document-root anchor, so a non-spec JSON file under .manuscripts/
    with a nested `"openapi": "3.0.0"` field deep in its payload (response
    envelope, captured config blob, metadata wrapper) would silently bypass
    PII scanning. The YAML markers were already anchored via `(?m)^` to
    column 0, which in valid YAML means a root-level key.
    
    Tighten the JSON regexes to `\A\s*\{\s*"openapi"\s*:\s*"[23]\.`,
    requiring `openapi` (or `swagger`) as the first key after the opening
    brace. JSON specs put the version key at root by convention; the strict
    anchor matches the YAML behavior and forecloses the nested-key bypass.
    
    Adds three regex-level cases (nested openapi inside `user_data`, info
    before openapi, nested swagger) and an end-to-end FindPII regression
    test that builds a captured.json with a nested openapi field plus real
    PII and asserts the file still scans.
    
    * fix(cli): anchor YAML vendor-spec markers to document start
    
    Greptile's second pass flagged the symmetric YAML gap. The previous
    `(?m)^openapi\s*:` regex fired on any column-0 occurrence within the
    8 KB head probe — so a research-notes YAML under .manuscripts/ that
    listed real PII in earlier root-level keys and a later `openapi: 3.0.0`
    key would silently bypass scanning. The JSON anchor (`\A\s*\{\s*"openapi"`)
    forecloses the same shape; YAML needed parallel treatment.
    
    Anchor both YAML markers to document start with an explicit allowed
    lead-in (optional YAML directives `%...`, document marker `---`,
    comment lines, blank lines). Any other content before `openapi`/`swagger`
    at column 0 rejects the exemption.
    
    Adds:
    - four regex-level cases: yaml-pii-before-openapi (negative), yaml-with-
      document-marker (positive), yaml-with-comment-prefix (positive),
      yaml-with-directive-and-marker (positive), yaml-with-blank-lead
      (positive), yaml-swagger-after-meta (negative).
    - a YAMLPIIBeforeOpenAPI FindPII regression that mirrors the JSON one.
    
    ---------
    
    Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
---
 internal/artifacts/pii.go                          |  70 ++++++-
 internal/artifacts/pii_test.go                     | 229 +++++++++++++++++++++
 .../printing-press-polish/references/pii-polish.md |   4 +-
 3 files changed, 300 insertions(+), 3 deletions(-)

diff --git a/internal/artifacts/pii.go b/internal/artifacts/pii.go
index 57acfc53..b3aa3478 100644
--- a/internal/artifacts/pii.go
+++ b/internal/artifacts/pii.go
@@ -173,14 +173,71 @@ var excludedFiles = map[string]bool{
 // addresses) are documentation, not customer PII, so a Stripe/Zendesk/
 // GitHub spec doesn't false-fail every promote. Exemption is depth-1
 // only; a spec.yaml nested under .manuscripts/ or testdata/ is captured
-// content and stays in scope. Mirrors findArchivedSpec()'s candidate
-// set in internal/pipeline/climanifest.go.
+// content and stays in scope unless content-detection identifies it as
+// an archived vendor spec (see manuscriptsDir + looksLikeVendorAPISpec).
+// Mirrors findArchivedSpec()'s candidate set in
+// internal/pipeline/climanifest.go.
 var rootVendorSpecFiles = map[string]bool{
 	"spec.json": true,
 	"spec.yaml": true,
 	"spec.yml":  true,
 }
 
+// manuscriptsDir is the path component that scopes the content-detected
+// vendor-spec exemption. Vendor specs archived under any depth inside
+// .manuscripts/ — research/, discovery/, or freeform subdirs — are
+// reproducible from the upstream URL and contain documentation `example:`
+// values, not customer PII. Limiting the content exemption to manuscripts
+// keeps the bypass off non-archive paths (committed docs/, generated
+// internal/, etc.) so a hand-edited file at docs/api.yaml still scans.
+const manuscriptsDir = ".manuscripts"
+
+// vendorSpecMarkers are the OpenAPI/Swagger version-marker patterns
+// looksLikeVendorAPISpec probes for in a file's head bytes. The two-form
+// shape (JSON quoted-key vs YAML unquoted-key) is required because vendor
+// docs ship both formats. Both forms anchor the key to the document
+// start: JSON requires `openapi`/`swagger` as the first key after the
+// opening brace; YAML requires it as the first content line after any
+// allowed lead-in (YAML directive `%...`, document marker `---`,
+// comments, blank lines). Without these anchors, a non-spec file with
+// PII in earlier keys could bypass scanning when it happened to also
+// contain an `openapi`/`swagger` marker deeper in the payload — a
+// response envelope, captured config blob, or research-notes YAML that
+// listed real values before the version field. Version constraints
+// (2.x or 3.x) avoid matching freeform mentions like "openapi: future".
+var vendorSpecMarkers = []*regexp.Regexp{
+	// JSON: {"openapi": "3.x.x" — openapi must be the first key.
+	regexp.MustCompile(`\A\s*\{\s*"openapi"\s*:\s*"[23]\.`),
+	regexp.MustCompile(`\A\s*\{\s*"swagger"\s*:\s*"2\.`),
+	// YAML: optional %directives, `---` document marker, comments, and
+	// blank lines may precede the marker, but no other content key can
+	// appear before `openapi`/`swagger` at column 0.
+	regexp.MustCompile(`\A(?:(?:%[^\n]*|---[ \t]*|[ \t]*#[^\n]*|[ \t]*)\n)*openapi\s*:\s*['"]?[23]\.`),
+	regexp.MustCompile(`\A(?:(?:%[^\n]*|---[ \t]*|[ \t]*#[^\n]*|[ \t]*)\n)*swagger\s*:\s*['"]?2\.`),
+}
+
+// looksLikeVendorAPISpec reports whether the first few KB of a file
+// match an OpenAPI 2.x/3.x or Swagger 2.0 root-document marker. Content
+// detection beats filename heuristics because vendors ship spec source
+// under arbitrary basenames (`apps/calendars.json`, `pushpress-v3.yaml`)
+// that no glob would reliably cover. Restricted at the call site to
+// files under .manuscripts/ so non-archive paths cannot bypass scanning
+// by embedding a stray version marker.
+func looksLikeVendorAPISpec(probe []byte) bool {
+	for _, re := range vendorSpecMarkers {
+		if re.Match(probe) {
+			return true
+		}
+	}
+	return false
+}
+
+// isUnderManuscripts reports whether the slash-separated relative path
+// lives anywhere inside a .manuscripts/ subtree.
+func isUnderManuscripts(relSlash string) bool {
+	return slices.Contains(strings.Split(relSlash, "/"), manuscriptsDir)
+}
+
 // skippedDirs are subtree names the walker never descends into at the
 // top level. Scoping to depth-1 is deliberate — `.git` and friends as
 // direct children of the cli-dir are infrastructure; the same names
@@ -307,6 +364,15 @@ func scanPIIFile(root, path string) ([]PIIFinding, error) {
 	}
 	relSlash := filepath.ToSlash(rel)
 
+	// Vendor-published OpenAPI/Swagger source archived under .manuscripts/
+	// carries documentation `example:` values, not customer PII. Mirrors
+	// the depth-1 rootVendorSpecFiles exemption for the case where the
+	// spec source lives nested in research/, discovery/, or freeform
+	// archive subdirs and the basename isn't `spec.{json,yaml,yml}`.
+	if isUnderManuscripts(relSlash) && looksLikeVendorAPISpec(probe) {
+		return nil, nil
+	}
+
 	var findings []PIIFinding
 	lineNumber := 0
 	for {
diff --git a/internal/artifacts/pii_test.go b/internal/artifacts/pii_test.go
index d6a3f82a..17de3d41 100644
--- a/internal/artifacts/pii_test.go
+++ b/internal/artifacts/pii_test.go
@@ -233,6 +233,10 @@ func TestFindPII_RootVendorSpecExempt(t *testing.T) {
 //   - arbitrary subdirs (output/) match via the *.yaml entry in
 //     highRiskFileGlobs; pinned here as a regression guard against a
 //     future tweak that broadens the exemption from depth-1 to all paths
+//
+// The companion exemption added in #1356 only triggers when the file
+// looks like an OpenAPI/Swagger root document. Files without that
+// marker still scan even when nested under .manuscripts/.
 func TestFindPII_NestedSpecYamlStillScans(t *testing.T) {
 	root := t.TempDir()
 	pii := `"email": "captured@victim.com"`
@@ -252,6 +256,231 @@ func TestFindPII_NestedSpecYamlStillScans(t *testing.T) {
 	assert.Contains(t, files, "output/spec.yaml")
 }
 
+// #1356: Vendor-published OpenAPI/Swagger specs archived under
+// .manuscripts/ are documentation source — `example:` values look like
+// PII but are public. The content-based exemption triggers off the
+// version-marker shape so basenames like apps/calendars.json or
+// pushpress-v3.yaml (which no filename glob would reliably cover) are
+// also exempted.
+func TestFindPII_ManuscriptsVendorSpecExempt(t *testing.T) {
+	root := t.TempDir()
+	require.NoError(t, os.MkdirAll(filepath.Join(root, ".manuscripts", "run1", "research", "apps"), 0755))
+	require.NoError(t, os.MkdirAll(filepath.Join(root, ".manuscripts", "run1", "research"), 0755))
+
+	// OpenAPI 3.x JSON with documentation-shape PII.
+	openapiJSON := `{
+  "openapi": "3.0.3",
+  "info": {"title": "Calendars"},
+  "paths": {
+    "/users": {
+      "post": {
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "example": {"email": "user1@testemail.com", "phone": "(415) 555-0123"}
+            }
+          }
+        }
+      }
+    }
+  }
+}`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "research", "apps", "calendars.json"), openapiJSON)
+
+	// OpenAPI 3.x YAML with documentation-shape PII.
+	openapiYAML := `openapi: 3.0.0
+info:
+  title: PushPress v3
+paths:
+  /bookings:
+    post:
+      requestBody:
+        content:
+          application/json:
+            example:
+              email: info@acme.com
+              phone: 1-800-555-1234
+              address: 123 Main Street
+`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "research", "pushpress-v3.yaml"), openapiYAML)
+
+	// Swagger 2.0 JSON with documentation-shape PII.
+	swaggerJSON := `{
+  "swagger": "2.0",
+  "info": {"title": "Legacy"},
+  "paths": {"/u": {"get": {"responses": {"200": {"examples": {"application/json": {"email": "x@y.com"}}}}}}}
+}`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "research", "legacy.json"), swaggerJSON)
+
+	findings, err := FindPII(root)
+	require.NoError(t, err)
+
+	files := uniqueFiles(findings)
+	assert.NotContains(t, files, ".manuscripts/run1/research/apps/calendars.json",
+		"OpenAPI 3.x JSON in manuscripts must be exempt")
+	assert.NotContains(t, files, ".manuscripts/run1/research/pushpress-v3.yaml",
+		"OpenAPI 3.x YAML in manuscripts must be exempt")
+	assert.NotContains(t, files, ".manuscripts/run1/research/legacy.json",
+		"Swagger 2.0 JSON in manuscripts must be exempt")
+}
+
+// Negative regression: vendor-spec content detection only applies inside
+// .manuscripts/. A file at docs/api.yaml or testdata/openapi.json with
+// OpenAPI markers still scans — those are committed, hand-curated
+// artifacts that could legitimately accumulate real PII.
+func TestFindPII_VendorSpecOutsideManuscriptsStillScans(t *testing.T) {
+	root := t.TempDir()
+	openapiYAML := `openapi: 3.0.0
+info:
+  title: Public API
+paths:
+  /u:
+    post:
+      requestBody:
+        content:
+          application/json:
+            example:
+              email: leaked@victim.com
+`
+	require.NoError(t, os.MkdirAll(filepath.Join(root, "docs"), 0755))
+	require.NoError(t, os.MkdirAll(filepath.Join(root, "testdata"), 0755))
+	write(t, filepath.Join(root, "docs", "api.yaml"), openapiYAML)
+	write(t, filepath.Join(root, "testdata", "openapi.json"), `{"openapi":"3.0.0","info":{"title":"x"},"paths":{"/u":{"post":{"requestBody":{"content":{"application/json":{"example":{"email":"leaked@victim.com"}}}}}}}}`)
+
+	findings, err := FindPII(root)
+	require.NoError(t, err)
+
+	files := uniqueFiles(findings)
+	assert.Contains(t, files, "docs/api.yaml",
+		"vendor-spec exemption must not bypass docs/ committed artifacts")
+	assert.Contains(t, files, "testdata/openapi.json",
+		"vendor-spec exemption must not bypass testdata fixtures")
+}
+
+// Negative regression: HARs and session-state captures under
+// .manuscripts/ keep scanning. They have no OpenAPI marker, so
+// looksLikeVendorAPISpec returns false and the exemption never fires.
+func TestFindPII_NonSpecManuscriptCapturesStillScan(t *testing.T) {
+	root := t.TempDir()
+	require.NoError(t, os.MkdirAll(filepath.Join(root, ".manuscripts", "run1", "discovery"), 0755))
+
+	har := `{
+  "log": {
+    "version": "1.2",
+    "entries": [
+      {"request": {"url": "https://api.example.com"}, "response": {"content": {"text": "{\"email\":\"real@user.com\",\"phone\":\"(415) 555-0123\"}"}}}
+    ]
+  }
+}`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "discovery", "session.har"), har)
+
+	sessionState := `{
+  "cookies": [{"name": "auth_token", "value": "secret"}],
+  "user": {"email": "real@user.com", "address": "1234 Main Street"}
+}`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "discovery", "session-state.json"), sessionState)
+
+	findings, err := FindPII(root)
+	require.NoError(t, err)
+
+	files := uniqueFiles(findings)
+	assert.Contains(t, files, ".manuscripts/run1/discovery/session.har")
+	assert.Contains(t, files, ".manuscripts/run1/discovery/session-state.json")
+}
+
+// The exemption probes a head window for the marker. A file that buries
+// `openapi: 3.0` deep past the probe window does not bypass scanning —
+// the head-window bound is intentional so an attacker (or large
+// hand-edited proof) cannot smuggle PII past the gate by prepending
+// arbitrary unrelated content.
+func TestLooksLikeVendorAPISpec(t *testing.T) {
+	tests := []struct {
+		name  string
+		probe string
+		want  bool
+	}{
+		{"openapi-3.0-json", `{"openapi": "3.0.3"}`, true},
+		{"openapi-3.1-json", `{"openapi":"3.1.0"}`, true},
+		{"openapi-2.0-json", `{"openapi": "2.0"}`, true},
+		{"swagger-2.0-json", `{"swagger": "2.0"}`, true},
+		{"openapi-3.0-json-pretty", "{\n  \"openapi\": \"3.0.3\",\n  \"info\": {}\n}", true},
+		{"openapi-yaml", "openapi: 3.0.0\ninfo:\n  title: x", true},
+		{"openapi-yaml-quoted", `openapi: "3.0.0"`, true},
+		{"swagger-yaml", "swagger: '2.0'\ninfo:\n  title: x", true},
+		{"plain-json", `{"users": [{"email": "x@y.com"}]}`, false},
+		{"plain-yaml", "users:\n  - email: x@y.com\n", false},
+		{"prose-mentioning-openapi", "This file describes the openapi: 3.0 schema we built.", false},
+		{"openapi-mid-line-yaml", "  openapi: 3.0", false},
+		{"openapi-future-version-string", `{"openapi": "4.0"}`, false},
+		// Anchor regressions: only root-level keys may signal a vendor
+		// spec. A non-spec JSON file whose nested payload contains an
+		// `openapi`/`swagger` field must not trip the exemption.
+		{"json-nested-openapi-field", `{"user_data": {"extras": {"openapi": "3.0.0", "email": "real@user.com"}}}`, false},
+		{"json-info-before-openapi", `{"info": {"title": "x"}, "openapi": "3.0.0"}`, false},
+		{"json-swagger-nested", `{"meta": {"swagger": "2.0"}}`, false},
+		// YAML anchor regressions: PII-shaped values in earlier root
+		// keys must not be exempted just because a later root key looks
+		// like an OpenAPI/Swagger version marker.
+		{"yaml-pii-before-openapi", "captured_at: 2026-05-15\nuser_email: real@user.com\nopenapi: 3.0.0", false},
+		{"yaml-swagger-after-meta", "tenant: acme\nswagger: '2.0'", false},
+		// YAML lead-in allowed: optional document marker, directives,
+		// comment lines, and blank lines before the version marker.
+		{"yaml-with-document-marker", "---\nopenapi: 3.0.0", true},
+		{"yaml-with-comment-prefix", "# Vendor-published OpenAPI spec\nopenapi: 3.0.0", true},
+		{"yaml-with-directive-and-marker", "%YAML 1.2\n---\nopenapi: 3.0.0", true},
+		{"yaml-with-blank-lead", "\nopenapi: 3.0.0", true},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert.Equal(t, tt.want, looksLikeVendorAPISpec([]byte(tt.probe)))
+		})
+	}
+}
+
+// Anchor regression at the file walk level: a JSON file under
+// .manuscripts/ whose first 8 KB contains a nested "openapi": "3.0.0"
+// (but no root-level marker) must still scan. Pins the JSON anchor's
+// intent so a future weakening of the regex surfaces here as a real
+// PII gate regression instead of a silent bypass.
+func TestFindPII_NestedOpenAPIFieldStillScans(t *testing.T) {
+	root := t.TempDir()
+	require.NoError(t, os.MkdirAll(filepath.Join(root, ".manuscripts", "run1", "research"), 0755))
+	nestedJSON := `{
+  "captured_at": "2026-05-15",
+  "payload": {
+    "request": {"openapi": "3.0.0"},
+    "response": {"email": "real@user.com", "phone": "(415) 555-0123"}
+  }
+}`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "research", "captured.json"), nestedJSON)
+
+	findings, err := FindPII(root)
+	require.NoError(t, err)
+	assert.Contains(t, uniqueFiles(findings), ".manuscripts/run1/research/captured.json",
+		"nested openapi field must not bypass PII scanning")
+}
+
+// YAML parallel: a research-notes YAML under .manuscripts/ that lists
+// real captured PII in earlier root keys and a later `openapi: 3.0.0`
+// root key must still scan. Without the document-start anchor on the
+// YAML marker, the column-0 `openapi:` line would trip the exemption
+// and silently exempt the PII above it.
+func TestFindPII_YAMLPIIBeforeOpenAPIStillScans(t *testing.T) {
+	root := t.TempDir()
+	require.NoError(t, os.MkdirAll(filepath.Join(root, ".manuscripts", "run1", "research"), 0755))
+	notes := `captured_at: 2026-05-15
+user_email: real@user.com
+phone: (415) 555-0123
+openapi: 3.0.0
+`
+	write(t, filepath.Join(root, ".manuscripts", "run1", "research", "notes.yaml"), notes)
+
+	findings, err := FindPII(root)
+	require.NoError(t, err)
+	assert.Contains(t, uniqueFiles(findings), ".manuscripts/run1/research/notes.yaml",
+		"YAML with PII before a root-level openapi marker must not bypass PII scanning")
+}
+
 func TestFindPII_BinaryFileSkip(t *testing.T) {
 	root := t.TempDir()
 	// Planted PII in a "json" file with embedded nulls (mimics binary)
diff --git a/skills/printing-press-polish/references/pii-polish.md b/skills/printing-press-polish/references/pii-polish.md
index 66f6a96e..7d77422f 100644
--- a/skills/printing-press-polish/references/pii-polish.md
+++ b/skills/printing-press-polish/references/pii-polish.md
@@ -70,7 +70,9 @@ When a downstream consumer (parser, schema validator) needs a valid-shape value,
 
 **Manuscripts (`.manuscripts/<runID>/`).** Highest-risk source — captured browser-sniff content is by construction where customer values entered. Acceptance for manuscript findings requires the explicit `evidence_context`-cited justification; "captured data" alone is not sufficient. When in doubt, replace the value in the manuscript file directly (it's local working state) and use a hand-authored fixture with synthetic values for any downstream tests.
 
-**Vendor spec files at the CLI root (`spec.yaml`, `spec.yml`, `spec.json`).** Exempt from the audit by design — these are the OpenAPI/internal source the operator passed to `--spec`, and vendor `example:` blocks (Stripe `jenny@example.com`, GitHub user-schema example phones) are documentation, not customer PII. The exemption is depth-1 only; the same basename nested under `.manuscripts/` or `testdata/` is captured content and stays in scope.
+**Vendor spec files at the CLI root (`spec.yaml`, `spec.yml`, `spec.json`).** Exempt from the audit by design — these are the OpenAPI/internal source the operator passed to `--spec`, and vendor `example:` blocks (Stripe `jenny@example.com`, GitHub user-schema example phones) are documentation, not customer PII. The exemption is depth-1 only; the same basename nested under `testdata/` is captured content and stays in scope.
+
+**Vendor spec source archived under `.manuscripts/`.** Files anywhere inside a `.manuscripts/` subtree whose head bytes match an OpenAPI 2.x/3.x or Swagger 2.0 root-document marker are exempt — the operator archived the vendor's published spec source alongside research, and its `example:` blocks are documentation. The exemption is content-based, not glob-based, so per-resource subdir basenames like `apps/calendars.json` or vendor-named files like `pushpress-v3.yaml` are covered without an allowlist. HARs, `session-state.json`, hand-edited proofs, and any other non-spec content under `.manuscripts/` stays in scope because the marker check fails on them.
 
 ## Forbidden accept patterns
 

← 9d3050b5 fix(cli): always emit boolean body fields, no zero-guard (#1  ·  back to Cli Printing Press  ·  fix(cli): refresh auth on redirects via CheckRedirect (#1497 f3f70435 →