[object Object]

← back to Carnegie Identity Audit

Verify and stage exact Carnegie identity restoration for approval

fb6a436ce56a9842b6f22deb55039e9f86a8b12d · 2026-09-11 06:52:12 -0700 · Steve Abrams

Files touched

Diff

commit fb6a436ce56a9842b6f22deb55039e9f86a8b12d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Fri Sep 11 06:52:12 2026 -0700

    Verify and stage exact Carnegie identity restoration for approval
---
 approval-request.md               |  90 +++++++++++++++++++++++++++++
 collect.py                        |  87 ++++++++++++++++++++++++++++
 prepare.py                        | 118 ++++++++++++++++++++++++++++++++++++++
 verification/dtd-verdict.md       |  30 ++++++++++
 verification/dtd/codex-debate.txt |  10 +++-
 verification/e2e-proof.json       |   7 ++-
 verification/sha256-manifest.json |  27 +++++++++
 7 files changed, 367 insertions(+), 2 deletions(-)

diff --git a/approval-request.md b/approval-request.md
new file mode 100644
index 0000000..bbf2f52
--- /dev/null
+++ b/approval-request.md
@@ -0,0 +1,90 @@
+# TK-11246 — Restore Carnegie category identities
+
+Status: PREPARED, NOT EXECUTED. Execution confirmation pending. Owner: codex-run-11246.
+
+## Concrete request
+
+Approve this bounded repair, in this order:
+
+1. Apply the three-line suffix-preservation patch to `rollout.mjs`, `rollout2.mjs`,
+   and `build-siltech-grain-v2-archived.mjs` in `~/Projects/carnegie-split/`.
+2. Restore exactly 26 local `dw_unified.carnegie_catalog.mfr_sku` values for
+   DWAG-379296 through DWAG-379321 from the exact canonical mapping.
+3. Restore `custom.manufacturer_sku` and `dwc.manufacturer_sku` on exactly 52
+   Shopify products: 26 ACTIVE v2 replacements and 26 ARCHIVED pilot products,
+   totaling 104 existing metafields. Do not publish or unarchive anything.
+
+Kamatera already has the correct values: ZERO canonical writes. No Shopify
+variant SKU, price, title, handle, status, tags, or unrelated metafields change.
+No stripping of category suffixes, pattern/color recomputation, or bulk vendor
+rewrite is permitted by this proposal.
+
+## Evidence and why the old plan was insufficient
+
+Fresh read-only Shopify API collection on September 10 local time found three
+generations per exact SKU: the old grouped ARCHIVED parent (no manufacturer_sku
+in either namespace), the ARCHIVED pilot, and the ACTIVE v2 replacement.
+The 26 IDs from the still-earlier split-run artifact no longer resolve.
+All 26 archived pilot metafield timestamps are 2026-08-18T22:14:36Z through
+22:14:57Z, immediately before the original cleanup ledger entry at 22:15:39Z.
+This corroborates membership; the original standalone mutation-ID log was not
+recovered and is not claimed as recovered.
+
+Both the pilot and replacement carry the exact stripped staging code in both
+namespaces. Today's replacement generation inherited the defect. Restoring only
+the archived pilots would leave all 26 active replacements wrong.
+
+Canonical Kamatera read-only SELECT at 2026-09-11T00:58:48.94186Z (exact timestamp in
+canonical-catalog.json) confirms all 26 suffixed targets. Local staging still
+has the stripped values. Proposed restoration preserves 5,928 unique identities.
+
+Three creation scripts independently strip suffixes via cleanMfr(). The proposed
+patch preserves input identities byte-for-byte. Without this prerequisite,
+data-only repair would be lost on the next creation run.
+
+## Exact artifacts
+
+- Repo: `/Users/macstudio3/Projects/carnegie-identity-audit/`
+- `verification/repair-plan.json`: all 26 row IDs, exact old/new values, all 52
+  product IDs, exact variant IDs/SKUs/statuses, and 104 metafield IDs/types/prestate.
+- `preserve-manufacturer-identity.patch`: three source edits, not applied.
+- `verification/current-by-sku.json` and `historical-products.json`: Shopify reads.
+- `verification/current-catalog.json` and `canonical-catalog.json`: database reads.
+- `verification/e2e-proof.json`: proof boundaries, negative tests, and skipped writes.
+- `verification/dtd-verdict.md`: 2/2 available voters chose scoped preparation;
+  mandatory adversarial debate KEEP, contingent on row-level proof and approval.
+
+## Verification completed
+
+- Exact26 source-to-canonical mapping, current product/variant identity, both
+  namespaces, and unchanged grouped-product exclusion: PASS.
+- Full-table projected uniqueness: 5,928 distinct before and after: PASS.
+- Five negative fixtures (wrong vendor, wrong prestate, extra active membership,
+  wrong canonical target, grouped product mistaken for a scalar): rejected.
+- Each patched helper tested on 5,928 current codes plus 26 restoration targets:
+  5,954/5,954 preserved; current helper alters 5,763 of those inputs.
+- Patched full modules pass syntax checks; `git apply --check` passes.
+- No source, database, or Shopify business changes executed.
+
+## Execution and rollback requirements
+
+Before execution, refresh every source/prestate and reject any identity/value/
+status/canonical mismatch. Review current source diffs and preserve concurrent
+pricing changes. Capture durable rollback data. Apply source patch before local
+staging transaction, then one ACTIVE product canary and independent API readback
+before the remaining bounded Shopify batches. Use compare-and-set for metafields
+or equivalent drift rejection; never blindly overwrite a changed value.
+
+After execution, independently read DB and API to verify the exact target values,
+full-table uniqueness, unchanged product properties and grouped exclusions.
+Record partial completion durably so retries skip verified work.
+
+Rollback is conditional restoration of captured before-values only where the
+current value still equals this repair's after-value. Reverse source patch only
+after checking no later edits overlap. No remote push, new service, or schedule.
+
+## Remaining limits
+
+This does not quantify the broader storefront impact of the three stripping
+helpers; a separate read-only inventory is needed for other Carnegie rows.
+Ticket remains blocked until approved execution and post-write proof are complete.
diff --git a/collect.py b/collect.py
new file mode 100644
index 0000000..bf7bf34
--- /dev/null
+++ b/collect.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python3
+"""Bounded read-only queries; no API or database mutation path."""
+import datetime, hashlib, json, os, pathlib, subprocess, time, urllib.request
+
+BASE = pathlib.Path(__file__).resolve().parent
+PRIOR = pathlib.Path.home() / 'Projects/ticket-system/data/codex-yoloforever/evidence/cycle-20260905T0721Z.n3ijiG/11246'
+OUT = BASE / 'verification'
+OUT.mkdir(exist_ok=True)
+
+def save(name, value):
+    (OUT / name).write_text(json.dumps(value, indent=2) + '\n')
+
+def token():
+    env = {}
+    for line in (pathlib.Path.home() / 'Projects/secrets-manager/.env').read_text().splitlines():
+        if '=' in line and not line.startswith('#'):
+            k, v = line.split('=', 1)
+            env[k] = v.strip().strip('\"\'')
+    return env.get('SHOPIFY_ADMIN_TOKEN') or env['SHOPIFY_ADMIN_API_TOKEN']
+
+TOKEN = token()
+def gql(query, variables=None):
+    assert query.lstrip().startswith('query '), 'Only explicit read queries allowed'
+    for attempt in range(4):
+        req = urllib.request.Request(
+            'https://designer-laboratory-sandbox.myshopify.com/admin/api/2026-07/graphql.json',
+            data=json.dumps({'query': query, 'variables': variables or {}}).encode(),
+            headers={'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json'})
+        with urllib.request.urlopen(req, timeout=35) as response:
+            result = json.load(response)
+        if result.get('errors'):
+            if all(e.get('extensions', {}).get('code') == 'THROTTLED' for e in result['errors']):
+                time.sleep(2 + attempt * 2)
+                continue
+            raise RuntimeError(json.dumps(result['errors']))
+        assert result.get('data') is not None
+        return result['data']
+    raise RuntimeError('Read query throttle exhausted')
+
+FIELDS = '''id title handle vendor status tags updatedAt
+custom:metafield(namespace:"custom",key:"manufacturer_sku"){id value type updatedAt}
+dwc:metafield(namespace:"dwc",key:"manufacturer_sku"){id value type updatedAt}
+variants(first:100){pageInfo{hasNextPage} nodes{id sku title}}'''
+
+def main():
+    prior = json.loads((PRIOR / 'identity-report.json').read_text())
+    save('prior-identity-report.json', prior)
+    skus = [r['dw_sku'] for r in prior['rows']]
+    assert len(skus) == len(set(skus)) == 26
+    ids = list(dict.fromkeys('gid://shopify/Product/' + r[k] for r in prior['rows']
+        for k in ['candidate_shopify_product_id', 'earlier_generation_product_id']))
+    historical = []
+    for offset in range(0, len(ids), 10):
+        chunk = ids[offset:offset+10]
+        data = gql('query History($ids:[ID!]!){nodes(ids:$ids){... on Product{' + FIELDS + '}}}', {'ids':chunk})
+        historical.extend(dict(requested_id=i, product=p) for i,p in zip(chunk,data['nodes']))
+        time.sleep(0.5)
+    save('historical-products.json', historical)
+    searches = {}
+    for n, sku in enumerate(skus):
+        data = gql('query Current($q:String!){productVariants(first:100,query:$q){pageInfo{hasNextPage} nodes{id sku product{' + FIELDS + '}}}}', {'q':'sku:' + sku})
+        result = data['productVariants']
+        assert not result['pageInfo']['hasNextPage'], 'Truncated SKU search'
+        exact = [v for v in result['nodes'] if v['sku'] == sku]
+        assert exact, 'No exact match for ' + sku
+        for v in exact:
+            assert v['product']['vendor'] == 'Carnegie'
+            assert not v['product']['variants']['pageInfo']['hasNextPage']
+        searches[sku] = exact
+        print(f'{n+1}/26 {sku}: {len(exact)} exact variants', flush=True)
+        save('current-by-sku.json', searches)
+        time.sleep(0.5)
+    missing = gql('query Missing{node(id:"gid://shopify/Product/1"){id}}')
+    assert missing['node'] is None
+    save('negative-missing-product.json', missing)
+    sql = "SELECT json_build_object('observed_at',now(),'read_only',current_setting('default_transaction_read_only'),'catalog',(SELECT json_agg(t) FROM (SELECT id,dw_sku,mfr_sku,pattern_number,color_number,parent_sku,product_type,product_url,updated_at FROM carnegie_catalog ORDER BY id) t));"
+    (OUT/'current-readonly.sql').write_text(sql+'\n')
+    env = dict(os.environ, PGOPTIONS='-c default_transaction_read_only=on -c statement_timeout=5000', PGCONNECT_TIMEOUT='3')
+    db = subprocess.run(['psql','-X','-d','dw_unified','-At','-v','ON_ERROR_STOP=1','-f',str(OUT/'current-readonly.sql')],env=env,text=True,capture_output=True,check=True)
+    save('current-catalog.json',json.loads(db.stdout))
+    save('collection.json', {'observed_at':datetime.datetime.now(datetime.timezone.utc).isoformat(),
+        'ticket':'TK-11246','shop':'designer-laboratory-sandbox.myshopify.com','api':'2026-07',
+        'historical_ids':len(ids),'sku_searches':len(searches),'business_writes':0,
+        'source_sha256':hashlib.sha256((PRIOR/'identity-report.json').read_bytes()).hexdigest()})
+
+if __name__ == '__main__':
+    main()
diff --git a/prepare.py b/prepare.py
new file mode 100644
index 0000000..5c5d116
--- /dev/null
+++ b/prepare.py
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+"""Validate captured reads and prepare a non-executing, approval-gated plan."""
+import collections, copy, datetime, difflib, hashlib, json, pathlib, subprocess
+
+BASE=pathlib.Path(__file__).resolve().parent
+V=BASE/'verification'
+def read(name): return json.loads((V/name).read_text())
+def save(name,data): (V/name).write_text(json.dumps(data,indent=2)+'\n')
+
+def derive(prior,local,canonical,current,historical):
+    expected={r['dw_sku']:r for r in prior['rows']}
+    assert len(expected)==len(prior['rows'])==26
+    assert local['read_only']==canonical['read_only']=='on'
+    catalog=local['catalog']
+    assert len(catalog)==5928
+    assert len({r['mfr_sku'] for r in catalog})==5928
+    local_by={r['dw_sku']:r for r in catalog}
+    remote={r['dw_sku']:r for r in canonical['rows']}
+    assert set(remote)==set(current)==set(expected)
+    history={r['requested_id']:r['product'] for r in historical}
+    assert len(history)==len(historical)==52
+    rows=[]
+    proposed={r['dw_sku']:r['mfr_sku'] for r in catalog}
+    for sku,r in expected.items():
+        old=r['snapshot_mac2_mfr_sku']; target=r['snapshot_kamatera_mfr_sku']
+        assert remote[sku]['id']==local_by[sku]['id']==r['catalog_id']
+        assert remote[sku]['mfr_sku']==target and local_by[sku]['mfr_sku']==old
+        assert target!=old
+        proposed[sku]=target
+        variants=current[sku]
+        assert len(variants)==3 and all(v['sku']==sku for v in variants)
+        products=[v['product'] for v in variants]
+        assert all(p['vendor']=='Carnegie' for p in products)
+        assert all(not p['variants']['pageInfo']['hasNextPage'] for p in products)
+        active=[p for p in products if p['status']=='ACTIVE']
+        assert len(active)==1 and 'split-batch:carnegie-v2' in active[0]['tags']
+        pilot_id='gid://shopify/Product/'+r['candidate_shopify_product_id']
+        pilot=[p for p in products if p['id']==pilot_id]
+        assert len(pilot)==1 and pilot[0]['status']=='ARCHIVED'
+        assert history[pilot_id]['custom']==pilot[0]['custom']
+        assert history[pilot_id]['dwc']==pilot[0]['dwc']
+        assert history['gid://shopify/Product/'+r['earlier_generation_product_id']] is None
+        plan=[]
+        for generation,p in [('archived_pilot',pilot[0]),('active_v2',active[0])]:
+            real=[v for v in p['variants']['nodes'] if 'sample' not in v['sku'].lower()]
+            assert len(real)==1 and real[0]['sku']==sku, 'Grouped product cannot receive a scalar SKU'
+            fields=[]
+            for ns in ['custom','dwc']:
+                field=p[ns]
+                assert field and field['value']==old and field['type']=='single_line_text_field'
+                fields.append(dict(namespace=ns,key='manufacturer_sku',id=field['id'],
+                    type=field['type'],before=old,after=target,updated_at=field['updatedAt']))
+            plan.append(dict(generation=generation,id=p['id'],status=p['status'],handle=p['handle'],
+                variant_id=real[0]['id'],variant_sku=sku,metafields=fields))
+        excluded=[p for p in products if p['id'] not in {q['id'] for q in plan}]
+        assert len(excluded)==1 and excluded[0]['status']=='ARCHIVED'
+        assert excluded[0]['custom'] is None and excluded[0]['dwc'] is None
+        rows.append(dict(dw_sku=sku,catalog_id=r['catalog_id'],before=old,after=target,
+            canonical_action='NOOP: already correct',local_updated_at=local_by[sku]['updated_at'],
+            products=plan,excluded_grouped_product=excluded[0]['id']))
+    assert len(set(proposed.values()))==5928, 'Restoration introduces identity collision'
+    assert len({p['id'] for r in rows for p in r['products']})==52
+    return dict(ticket='TK-11246',approval='REQUIRED — NOT EXECUTED',
+        counts=dict(local_staging_rows=26,canonical_writes=0,active_products=26,archived_products=26,metafields=104),
+        preconditions=['Re-read canonical/local rows and Shopify owner, exact variant SKU, status, metafield ID/type/value immediately before write.',
+            'Abort entire scope on any identity, value, membership, uniqueness or status mismatch.',
+            'Apply and verify suffix-preserving creation patch before any data repair.',
+            'Create durable rollback prestate; local database transaction first, then one active-product canary, then bounded Shopify batches.',
+            'Fresh API and DB readback must prove all targets plus unchanged exclusions; do not change SKU/title/handle/price/status/tags.',
+            'Rollback only this repair using captured before values, conditional on current value equaling the proposed after value.'],
+        historical_limit='Aug18 standalone write-ID log missing; pilot membership is corroborated by exact SKU, prior retitle IDs and metafield timestamps. Plan uses fresh observed defects, not assumed historical membership.',
+        scope_limit='No claim about total current Carnegie storefront defects; broader stripping impact requires a separate read-only inventory.',rows=rows)
+
+def main():
+    args=[read(f) for f in ['prior-identity-report.json','current-catalog.json','canonical-catalog.json','current-by-sku.json','historical-products.json']]
+    plan=derive(*args)
+    save('repair-plan.json',plan)
+    negatives=[]
+    for label in ['wrong_vendor','wrong_metafield','extra_active','wrong_canonical','grouped_product']:
+        a=copy.deepcopy(args); sku=next(iter(a[3])); variants=a[3][sku]
+        p=next(v['product'] for v in variants if v['product']['status']=='ACTIVE')
+        if label=='wrong_vendor':p['vendor']='Other'
+        if label=='wrong_metafield':p['custom']['value']='different'
+        if label=='extra_active':variants.append(copy.deepcopy(variants[-1]))
+        if label=='wrong_canonical':a[2]['rows'][0]['mfr_sku']='wrong'
+        if label=='grouped_product':p['variants']['nodes'].append(dict(id='other',sku='DWAG-OTHER'))
+        try:derive(*a)
+        except AssertionError:negatives.append(dict(case=label,verdict='PASS',rejected=True))
+        else:raise AssertionError('Accepted unsafe fixture: '+label)
+    sources=pathlib.Path.home()/'Projects/carnegie-split'
+    patches=[]; checks=[]
+    codes=[r['mfr_sku'] for r in args[1]['catalog']]+[r['after'] for r in plan['rows']]
+    for name in ['rollout.mjs','rollout2.mjs','build-siltech-grain-v2-archived.mjs']:
+        old=(sources/name).read_text()
+        lines=[line for line in old.splitlines() if line.startswith('const cleanMfr')]
+        assert len(lines)==1
+        replacement='const cleanMfr = s => String(s); // Preserve category-bearing manufacturer identity (TK-11246).'
+        new=old.replace(lines[0],replacement)
+        patches.extend(difflib.unified_diff(old.splitlines(True),new.splitlines(True),fromfile='a/'+name,tofile='b/'+name))
+        script="const vm=require('node:vm');const input="+json.dumps(dict(before=lines[0],after=replacement,codes=codes))+";const run=s=>vm.runInNewContext(s+'\\n;codes.map(cleanMfr)',{codes:input.codes});const before=run(input.before),after=run(input.after);if(after.some((x,i)=>x!==input.codes[i]))throw Error('Identity changed');console.log(JSON.stringify({tested:after.length,before_changed:before.filter((x,i)=>x!==input.codes[i]).length,after_changed:0}));"
+        result=subprocess.run(['node','-'],input=script,text=True,capture_output=True,check=True)
+        syntax=subprocess.run(['node','--check','--input-type=module'],input=new,text=True,capture_output=True,check=True)
+        checks.append(dict(file=name,source_sha256=hashlib.sha256(old.encode()).hexdigest(),syntax='PASS',**json.loads(result.stdout)))
+    (BASE/'preserve-manufacturer-identity.patch').write_text(''.join(patches))
+    save('e2e-proof.json',dict(intent='Prepare exact read-only restoration evidence; no live repair performed',risk_tier='R3 read-only; proposed repair R4',
+        timestamp=datetime.datetime.now(datetime.timezone.utc).isoformat(),environment='Local audit repo; Shopify read queries; read-only PostgreSQL local and Kamatera',
+        commands=['python3 collect.py','ssh kamatera read-only SELECT (canonical-catalog.json)','python3 prepare.py','node isolated cleanMfr evaluation and module syntax check'],
+        build_identity='Source digests per patch check; final git commit recorded on TK-11246',
+        assertions=[dict(check='Exact26 canonical/local mapping and full-table postrepair uniqueness',verdict='PASS'),
+            dict(check='52 product/104 namespace current prestate by exact SKU and generation',verdict='PASS'),
+            dict(check='Missing historical generation excluded; missing node returns null',verdict='PASS'),
+            dict(check='Original Aug18 standalone mutation membership log',verdict='SKIP',reason='Unavailable; only corroboration, no claim of recovered log'),
+            dict(check='Production mutation and after-state verification',verdict='SKIP',reason='Approval required; no mutation executed')],
+        negative_tests=negatives,patch_checks=checks,cleanup='No business writes or test entities; evidence retained locally.',
+        result='PREPARATION VERIFIED; TICKET BLOCKED FOR APPROVAL',counts=plan['counts']))
+    print(json.dumps(dict(counts=plan['counts'],negative_tests=len(negatives),patch_checks=checks),indent=2))
+
+if __name__=='__main__':main()
diff --git a/verification/dtd-verdict.md b/verification/dtd-verdict.md
new file mode 100644
index 0000000..bf32ad0
--- /dev/null
+++ b/verification/dtd-verdict.md
@@ -0,0 +1,30 @@
+# DTD Verdict — Carnegie repair scope
+
+## Decision: A — verify and stage the scoped restoration
+
+Confidence: medium. Vote: 2/2 valid voters; availability: 2/6.
+
+| Reference | Runtime/model | Vote | Reason |
+|---|---|---|---|
+| Claude | Anthropic/sonnet | Abstain | Disabled by zero-cost guard |
+| Codex | OpenAI CLI/configured model (CLI artifact does not establish gpt-5.3-codex) | A | Preserve identities and verify scope before approved execution |
+| Qwen | Ollama/qwen3:14b | A | Fix recurrence and prepare exact comparisons |
+| Grok | xAI/grok-4.5 | Abstain | Unavailable with paid calls disabled |
+| Kimi | Moonshot/kimi-k2.5 | Abstain | Unavailable with paid calls disabled |
+| Muse | Ollama/muse-spark-1.2 (environment override) | Abstain | Unavailable |
+
+## Dissent
+
+None among valid panel votes. Post-decision prosecutor objected that aggregate
+identity collisions do not prove each individual replacement or product mapping.
+
+## Post-decision Codex debate
+
+Result: KEEP. The recommendation is valid only with exact product mappings,
+canonical values, unchanged exclusions, and explicit approval before writes.
+Counts alone do not establish correctness. The plan verifier therefore checks
+each canonical ID/SKU/value, each exact Shopify variant and product generation,
+both metafield namespaces, scalar-versus-grouped identity, and full-table
+uniqueness after the proposed restoration. Five negative fixtures fail closed.
+
+The recommendation authorizes no writes. Full responses are in `dtd/`.
diff --git a/verification/dtd/codex-debate.txt b/verification/dtd/codex-debate.txt
index 4960b69..bfd4980 100644
--- a/verification/dtd/codex-debate.txt
+++ b/verification/dtd/codex-debate.txt
@@ -1 +1,9 @@
-[codex debate unavailable]
+**PROSECUTOR:** A confuses evidence against blanket stripping with evidence that these specific corrections are right. The 1,327 identity collapses demonstrate danger, but do not establish the proper values for the 52 Shopify products. Canonical suffix retention in 26/26 cases also does not prove the staging-to-product mapping. A patch affecting three scripts could change other generations unintentionally. Packaging 26 staging changes and 104 metafield changes as “verified” risks giving an unproven migration the appearance of certainty.
+
+**DEFENDER:** Those objections establish what A must verify; they do not defeat its approach. A authorizes preparation of a patch and an exact comparison, while retaining explicit approval before data writes. Verification must establish each product mapping, justify each replacement against canonical values, and demonstrate that other generations remain unchanged. A historical-only draft leaves the stripping scripts unresolved, while broader stripping faces direct evidence of identity loss. A addresses both the proposed repairs and their cause without authorizing premature execution.
+
+**JUDGE:** The prosecutor successfully challenges any claim that the supplied counts alone prove correctness. However, A makes verification and write approval prerequisites, preserves canonical values, and keeps TK11246 blocked until execution and verification. Its scope accommodates the necessary checks.
+
+FINAL: KEEP
+
+The controlling argument is that A advances a bounded, reviewable correction while withholding data writes until verification and explicit approval. The evidence supports rejecting blanket stripping, not automatically accepting every replacement; A remains sound because its required verification must close that gap and demonstrate preservation of other generations before execution.
\ No newline at end of file
diff --git a/verification/e2e-proof.json b/verification/e2e-proof.json
index b2eb5ba..563aef1 100644
--- a/verification/e2e-proof.json
+++ b/verification/e2e-proof.json
@@ -7,7 +7,8 @@
     "python3 collect.py",
     "ssh kamatera read-only SELECT (canonical-catalog.json)",
     "python3 prepare.py",
-    "node isolated cleanMfr evaluation and module syntax check"
+    "node isolated cleanMfr evaluation and module syntax check",
+    "git -C ~/Projects/carnegie-split apply --check preserve-manufacturer-identity.patch"
   ],
   "build_identity": "Source digests per patch check; final git commit recorded on TK-11246",
   "assertions": [
@@ -32,6 +33,10 @@
       "check": "Production mutation and after-state verification",
       "verdict": "SKIP",
       "reason": "Approval required; no mutation executed"
+    },
+    {
+      "check": "git apply --check against current Carnegie source",
+      "verdict": "PASS"
     }
   ],
   "negative_tests": [
diff --git a/verification/sha256-manifest.json b/verification/sha256-manifest.json
new file mode 100644
index 0000000..1a12f62
--- /dev/null
+++ b/verification/sha256-manifest.json
@@ -0,0 +1,27 @@
+{
+  "collect.py": "952633c0f51ff5d47729f0f2a573f38d6aab63ae1d5a72c09557d44b38b563ab",
+  "preserve-manufacturer-identity.patch": "99ae63d98664cd86353de07d88380e4b6d4694eb8dda803881821563d36172bb",
+  "README.md": "93f9b7b8f85d3a423316d2cc478261b1490a983fbd63d6eee366d98c539ff508",
+  ".gitignore": "bb60f03d06ae3b1c591ec1795d20fc6c3d6ed13623d1d0cf4312ca4a142f42a9",
+  "approval-request.md": "6ce1bd62b4e3170f59896dbf0a6454662b9e486abe490eb28f8e4a58bfe0b7cf",
+  "prepare.py": "8e7bb00601eeabf857fcab116db978b23973bc3eb6deb49b6fe6e1c087d3d2ce",
+  "verification/dtd-verdict.md": "d68dc36171904c79d4fe57296b51f8c67bc701313dc36eca778214d5052bd816",
+  "verification/current-readonly.sql": "ac1d47c5eecc3bf3a94cd3c02be693a4c6af7e4625236db27c8684e5b3f29a24",
+  "verification/negative-missing-product.json": "5edc2966ff8643550312f5b56511b52c1912fac2d449039362e52e6b3ac34d80",
+  "verification/historical-products.json": "5727fa722ce65b497b86387b991c372239a70bb6614425c9e4dab4a746437285",
+  "verification/prior-identity-report.json": "7f90323034fc0c8b2920e333f26b34265002997cb916c1be9bcb0b3761303d89",
+  "verification/repair-plan.json": "9c515edae5c908ff6f1ea9bf278717b9a9027bd67e73d20eedc3eed88b0b61b7",
+  "verification/canonical-catalog.json": "a930227571942e3cf2da39ad06d4aaf57d5e4e01ebfc4ed460b38a7cfe83886f",
+  "verification/e2e-proof.json": "b7ffc773aac26538c196a0334af5d377fbc27255dba404a9e18ff55a91fdf570",
+  "verification/collection.json": "47130b247ec069f019cdbe0f61c3ad2a95d6695defb0ed24f54a55dbf70453a8",
+  "verification/current-catalog.json": "1949d6f5975261afd9fd16f1b6e84b1dbb9afe3fc50891207b6ba2d188564979",
+  "verification/current-by-sku.json": "67a68c3591a4f5860bf5660dcb6db7e6dfc6e80497d7d6d36f4cf0e3e5fd866a",
+  "verification/dtd/codex-debate.txt": "9828d700aab7f7e71e0a90d6d53545c9a167498dda1e7202a88a86310bed1a7d",
+  "verification/dtd/claude.txt": "70c9ba1a8605090befbc30cb78ddf5e419ef25576543c10930506a7cf5bc6abe",
+  "verification/dtd/kimi.txt": "cd8c0da65ed7177b4c37b4b45d85c829eccd5e1586153d60ad35460847683a1b",
+  "verification/dtd/question.txt": "95543b2023ee6f7e1bbd10b57dc2f0a35326ce544ff63e8d80b422143e9de353",
+  "verification/dtd/grok.txt": "5856c08a09dcf961f7f24785763005bafb25c4c09acc12e527c5db677b3315ee",
+  "verification/dtd/qwen.txt": "a75f7363c01cb4ece330dc2ac36ed1362000b4d440d82e423e44757ba7faeef6",
+  "verification/dtd/codex.txt": "8dab2cdb6c50f0ab0b0610f27ee31008ed38d28a6814a58ba9e0ce7345c9a986",
+  "verification/dtd/muse.txt": "7d1a540d21906df45f874d97c7dd0db8981232a60975119e8803c6898d767d95"
+}

← f518a1e auto-data-snapshot: 2026-09-10T18:07:04 (19 data files) — pr  ·  back to Carnegie Identity Audit  ·  auto-data-snapshot: 2026-09-11T08:57:34 (1 data files) — __p 4209318 →