Catalog Guard avatar

Catalog Guard

Pricing

from $0.05 / catalog audit

Go to Apify Store
Catalog Guard

Catalog Guard

Pricing

from $0.05 / catalog audit

Rating

0.0

(0)

Developer

Koh Yamamoto

Koh Yamamoto

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Categories

Share

Read-only supplier CSV change audits for AI agents and purchasing workflows.

Compare two supplier catalogs before an import or price update. Get structured evidence for price changes, missing rows, additions, changed unit/currency/tax context, and ambiguous identifiers. No store credentials, web scraping or LLM API key required.

Version 0.1.0 is a working local tool with an official MCP SDK server and an Apify Actor adapter. It has not been published to a marketplace. Paid demand, cloud deployment, platform approval and live billing remain unverified. All examples are synthetic.

What makes this specific

  • Explicit UTF-8, UTF-8 BOM, CP932 (Windows Japanese) and Shift-JIS decoding. No silent encoding guessing.
  • Exact decimal arithmetic. Full-width prices and JPY markers are supported; leading zeros in product keys are preserved.
  • Unit, pack-size, currency and tax-status changes suppress numeric price comparisons when those columns are configured.
  • Duplicate/empty keys, normalization collisions and malformed files block the comparison rather than produce misleading matches.
  • Physical CSV line numbers and source SHA-256 hashes provide traceable evidence, including multiline quoted cells.
  • Local CLI, MCP stdio and hosted Actor share the same deterministic core. No per-call LLM expense.

This is not a generic PDF summarizer or a Shopify importer. It audits supplied CSVs; it never modifies a catalog.

Quick start

Python 3.11+; Python 3.12 recommended. Run from the project directory using your chosen environment:

python -m pip install .
python -m catalog_guard --input examples/request.json

The synthetic example returns 1 added, 1 missing, 3 changed and 1 unchanged row:

  • 0001: 100 → 130, a 30% increase.
  • 0002: 1,200 per box → 250 per piece. No percentage is calculated, because the unit changed.
  • 0003: 800800, format-only change, not a price increase.
  • 0004: absent from the new snapshot. This is not proof of discontinuation.
  • 0005: unchanged.
  • 0006: newly present.

CLI exit codes are intentional: 0 unchanged; 1 review; 2 blocked; 3 CLI/file error. A nonzero review result is not an application crash.

Compare local Japanese files

python -m catalog_guard --before examples/before.csv --after examples/after.csv --config examples/config.json --json audit.json --markdown audit.md

Use --before-encoding cp932 or --after-encoding shift_jis for those file bytes. Each side may use a different encoding. Report files must not already exist; the CLI refuses overwrites. Source files are only opened for reading.

Input contract

{
"before": {"csv": "SKU,Price,Unit,Currency\n001,100,piece,JPY\n"},
"after": {"csv": "SKU,Price,Unit,Currency\n001,130,piece,JPY\n"},
"keyColumns": ["SKU"],
"priceColumns": ["Price"],
"contextColumns": ["Unit", "Currency"],
"priceChangeThresholdPercent": 20
}

Each source accepts exactly one of:

  • {"csv": "decoded Unicode text"}
  • {"base64": "encoded original file bytes", "encoding": "cp932"}

No paths, URLs, callbacks, code or credentials are accepted by the core/MCP/Actor. The CLI is the only interface that opens caller-specified local paths.

FieldDefaultMeaning
before, afterrequiredSource objects above
keyColumnsrequiredOne or more exact header names; composite keys supported
priceColumns[]Columns to parse as decimal amounts
contextColumns[]Configure every unit, currency, pack-size and tax-status column needed for comparability
ignoreColumns[]Explicitly excluded cell comparisons; columns must exist in both files
priceChangeThresholdPercent20Alert when absolute percentage change meets/exceeds this value; smaller changes are still reported
maxRows10000Hard input limit per file; maximum 20000
maxChanges200Returned change details, maximum 1000; counts remain complete
delimiter,Comma, tab or semicolon, explicitly chosen
allowEmptyAfterfalseExplicitly permit an empty new snapshot

Column roles cannot overlap. Header names and keys are not automatically renamed, trimmed, lowercased or converted to numbers. Width/whitespace key changes are warnings and do not cause automatic identity merging. Duplicate or normalization-colliding keys within a snapshot block the audit.

Output contract

  • status: unchanged, review, or blocked. Never interpret unchanged as authorization to update a store.
  • comparisonPerformed: false when reliable matching was impossible; summary is then empty and changes is empty.
  • sources: byte count, decoding method, row counts, headers and SHA-256 of original bytes (or UTF-8 representation for text inputs).
  • summary: complete added/removed/changed/unchanged counts and per-flag row counts. A row may have several flags.
  • changes: row keys, before/after physical line ranges, changed cells and numeric interpretation. Added/missing rows include their non-ignored values.
  • issues: parser/configuration errors and warnings, with evidence where available.
  • schemaChanges: added/removed headers. Only shared, non-ignored columns receive cell comparison.
  • changesTruncated, issuesTruncated: always check these before assuming the detail lists are exhaustive.

removed means missing from the supplied new file, not proven deleted from a shop or discontinued by a supplier. A partial export can produce this result. Structural failures block the whole comparison; detail limits never turn an input into a sampled audit.

Price rules

  • Accepts plain decimal numbers, correctly grouped thousands commas, NFKC full-width digits and ¥, JPY or markers.
  • Does not accept guessed decimal-comma formats, scientific notation, non-JPY currency symbols, negative prices or embedded tax notes. Use a separate currency/tax column with a plain numeric amount.
  • Empty prices are unknown, never zero, and generate warnings.
  • Numeric price comparisons are suppressed for changed/blank configured context or changed explicit JPY markers. Unconfigured context cannot be checked; supply all relevant columns.
  • Zero baseline has no percentage change. Decimal deltas are exact; displayed percentages round to four decimal places with decimal half-even rounding. Threshold decisions use the unrounded percentage.
  • No currency conversion, tax calculation, pack-size conversion, fuzzy matching, semantic aliasing or procurement recommendation.

Bounds

Each input: 2,000,000 bytes, 100 columns, 200-character headers, 8,000-character cells, at most 20,000 data rows. Returned changes also have a 60,000-character JSON detail budget. Issues have a 100-item / 20,000-character budget. Entire entries may be omitted rather than silently shortening raw evidence; truncation flags and full counts expose this. These are not pagination APIs. Split snapshots into complete, matching key partitions upstream if exhaustive large reports are required.

MCP connection

python -m pip install '.[mcp]'
python -m catalog_guard.mcp_server

The second command starts a stdio server and waits for a client; silence is normal. Tool name: audit_supplier_catalog. Arguments: {"request": <the input object above>}. Both structured JSON and text content are returned. The tool is annotated read-only and closed-world.

Configure a stdio-capable MCP host with your absolute environment Python executable and arguments ['-m', 'catalog_guard.mcp_server']. An example host configuration is in examples/mcp.config.example.json; replace the executable placeholder. No host settings have been modified by this project. No public HTTP listener is provided.

The server uses official mcp==2.1.1. It implements a tool for agents; it does not run an autonomous agent, watch files, market itself or generate sales on its own.

Apify Actor

.actor/actor.json, .actor/input_schema.json, Dockerfile and catalog_guard.actor form the hosted adapter. It accepts the same input object directly, pushes one report to the default dataset, and writes OUTPUT JSON plus REPORT Markdown to the run's default key-value store.

The adapter uses apify==4.0.2. A completed comparison invokes the custom catalog-audit event once through the SDK's save-and-charge operation. Blocked input does not invoke this custom event. When a charge cannot fit the run budget, no extra report copy is exported. Platform pricing configuration, synthetic events and live charging must be verified before any paid release; no price is activated by these source files.

See docs/PUBLISHING.md for the explicit release gates. The hosted route sends inputs and outputs to Apify storage; it is not local-only. Use local CLI/MCP when those files must stay on your machine.

Privacy and security

Use only files you are authorized to process. Do not include unnecessary customer or personal data. The core makes no external calls and writes no files. Local MCP receives caller-provided content but cannot browse the filesystem. The CLI writes only explicitly named new reports. The hosted adapter persists input/output in the invoking run's storage according to Apify's configuration and retention; it does not promise automatic deletion.

CSV cells are untrusted data and may contain prompt injection, spreadsheet formulas or markup. The tool never evaluates them. Markdown output escapes source markup; JSON retains original values. Consumers must not execute cell content or paste formula-like strings into a spreadsheet without their own escaping. The prefix warning is advisory, not a complete spreadsheet security scanner.

Development and verification

python -m pip install '.[mcp,actor,dev]'
python -m pytest -q
python -m ruff check src tests
python -m ruff format --check src tests

Tests include exact-price arithmetic, Japanese bytes, adversarial input, bounds, source-overwrite protection, real MCP in-memory/stdio calls, real Apify local-storage execution, and mocked billing/failed-storage paths. Live cloud billing and Docker execution are separate release gates. See docs/VALIDATION.md for recorded results.

Scope and ownership

This is an independently implemented v0.1 product experiment, not a clone, official Shopify integration, financial adviser or automatic purchasing system. No third-party source code or commercial datasets were copied. Marketplace publication and any public source license require an explicit owner decision. An LLM may explain the report, but should not change its computed evidence.