# TraceRefresh - Citation Drift & Dependency Checks (`zahi90/tracerefresh-actor`) Actor

Compare saved quotations with current public web pages or supplied HTML/text snapshots. Detect wording and context changes, flag declared dependent report sections, and return JSON with a compact agent summary. Not fact-checking or continuous monitoring.

- **URL**: https://apify.com/zahi90/tracerefresh-actor.md
- **Developed by:** [Zahi Mansour](https://apify.com/zahi90) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 evidence bundles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## TraceRefresh — Citation Drift & Dependency Checks

**Refresh the evidence behind a saved report, not the entire report.** Compare recorded quotations with current static source text, flag changed context even when a quote survives, and identify which **caller-declared** conclusions need review.

Use this after an authorized research workflow has selected quotations and recorded which report sections depend on them. This is a bounded evidence-maintenance tool, **not a fact checker, source-discovery engine, security guarantee or permission to act**.

### The problem this Actor addresses

A saved recommendation can become stale while its quotation still exists. A sentence saying “SSO is included for all members” could move from a Team section to an Enterprise-only section. A string-only quote check would still find the sentence.

TraceRefresh records the quote plus its selected textual scope. On refresh it checks exact wording, section headings, surrounding section content, inherited introductory conditions and link targets. It then follows a declared dependency graph to identify affected report sections. It does not use a language model to infer support, rewrite a conclusion or adopt a suggested replacement.

### Three modes

| Mode | Input | Result | Custom event |
| --- | --- | --- | --- |
| `demo` | No user sources | Built-in fictional before/after example | None |
| `capture` | 1–5 sources, quotations and optional dependency graph | Baseline plus capture diagnostics | One `evidence-bundle` |
| `refresh` | Unchanged baseline and current versions of the same sources | Drift findings and dependency impacts | One `evidence-bundle` |

The proposed launch price is **$0.01 per completed capture or refresh bundle**, not per quote. One bundle contains up to five sources and up to ten quotes per source. The Store Pricing tab is authoritative. A separately listed Actor-start event can apply, including in Demo mode.

A complete analysis is billable even when it finds no changes, absent quotes, ambiguous occurrences or an unresolved baseline. Invalid input, unavailable/blocked sources, representation-limit failures and unfinished bundle processing do **not** request the custom result event. A failed bundle can still incur the listed start event. There is no promise that a changed source will be found.

### Try the fictional Demo first

```json
{"mode":"demo"}
```

The demo checks three quotations on two invented SampleCloud pages. A price changes from $20 to $35; an unchanged SSO sentence moves under Enterprise conditions; the CSV export section stays the same while unrelated news changes.

Expected summary: **three anchors, two requiring review, one preserved within scope, four dependent nodes requiring review**. `export-workflow` is unchanged only within its declared dependencies and scopes. The demo is not evidence of real customer usage, source access or billing settlement.

### Capture example

```json
{
  "mode": "capture",
  "sources": [
    {
      "id": "pricing",
      "html": "<h1>Plans</h1><h2>Starter</h2><p>The Starter plan costs $20 per month.</p>",
      "anchors": [
        {"id":"starter-price","quote":"The Starter plan costs $20 per month.","scope":"section"}
      ]
    }
  ],
  "dependencies": [
    {"id":"budget","label":"Saved subscription estimate","dependsOn":["starter-price"]}
  ]
}
```

Store the returned `baseline` object in your application. It is also exported as the run's `BASELINE` key-value record. Do not manufacture a baseline or quietly change its contents. Its fingerprint checks accidental corruption; it is **not a signature, proof of history, source authenticity or tamper-proof evidence**.

### Refresh example

Provide `mode: "refresh"`, the entire saved `baseline`, and the same source IDs with current text/HTML or the same public URLs. Do not add new quotes or dependencies in refresh mode.

`examples/03_refresh_supplied.json` is a complete, ready-to-run example containing a valid fictional baseline. No placeholder substitution is needed. `examples/02_capture_supplied.json` reproduces its capture.

For URL sources, use exactly the same canonical URL on refresh; the Actor fetches it again. For supplied snapshots, replace the supplied text/HTML while retaining the same source ID and representation type. Switching from supplied HTML to URL acquisition requires a new capture. A supplied snapshot is labelled **not independently fetched**.

### Source fields

Each source must have an `id` and **exactly one** of `url`, `text`, or `html`.

| Field | Meaning |
| --- | --- |
| `id` | Unique source identifier, 1–64 ASCII characters, starting with a letter. |
| `url` | Anonymous public HTTP/HTTPS source; standard port only. |
| `text` | Caller-supplied current plain text. Markdown-style headings are recognized. |
| `html` | Caller-supplied static HTML. Scripts are not executed. |
| `anchors` | Capture only: 1–10 quote specifications. |

Each anchor has a unique bundle-wide `id`, a `quote` of 10–1,000 characters, optional `prefix`/`suffix` up to 96 characters for disambiguation, and a `scope` of `section` (default) or `document`.

Normalization uses Unicode NFC and collapsed whitespace. It preserves case, punctuation, numerals, negation and format controls. It does not equate translations or paraphrases. A zero-width character or punctuation edit may therefore trigger review deliberately.

#### What section scope includes

The quote's lowest common containing heading section, its descendant content and link targets, its ancestor heading labels, and introductory text/link targets before the relevant child headings. Global document lead-in text, including an HTML title, is included. Without a suitable heading it falls back to the whole retained document. Quotes crossing sections use a common ancestor or document scope.

**Conditions can exist outside that scope.** Such changes are flagged at source level but may not propagate to a section-scoped dependent node. Use `scope: "document"` when any retained text change should trigger review. Neither scope inspects CSS layout, images, scripts, PDFs, account-specific content or linked documents.

All retained server text is analyzed, including navigation/footer and hidden HTML text. A match is not proof that a human would see the quote on screen. Some malformed, block-split HTML may cause conservative false alerts. Extracted link targets are observed but never visited by the comparison engine.

### Declaring affected conclusions

Declare up to 50 dependency nodes with `id`, optional `label` and `dependsOn` (1–20 quote or node IDs). Cycles, unknown references and duplicate IDs are rejected. References may point to nodes declared later; the Actor sorts them for evaluation.

Example:

```json
[
  {"id":"cost-calculation","dependsOn":["starter-price"]},
  {"id":"plan-selection","dependsOn":["cost-calculation","sso-claim"]},
  {"id":"report-release","dependsOn":["plan-selection"]}
]
```

Here `sso-claim` must be an anchor or node declared elsewhere in the same bundle. The Actor follows your graph; it **does not establish that any quote logically supports a conclusion**. Omitted dependencies can lead to an incomplete impact report.

### Output and interpretation

One dataset item is the full report. The named **Evidence refresh overview** view is already included for Console and example tasks.

- `sourceChecks`: retrieval method, document fingerprints, location changes, and changes outside preserved scopes.
- `anchorChecks`: exact quote status, old/new context, scope and unapproved lexical suggestions when available.
- `dependencyImpacts`: declared nodes needing review, with the affected quote IDs.
- `agentContext`: compact review queue intended for the model.
- `baseline`: capture only; save unchanged in application storage for the next refresh.
- `checkedAt`: bundle completion time, not an atomic simultaneous observation of all sources.

#### Refresh statuses

| Status | Interpretation |
| --- | --- |
| `unchanged` | Recorded quote and retained document representation unchanged. |
| `scope_unchanged` | Recorded scope unchanged; other retained content changed. |
| `relocated_in_scope` | Position moved, but recorded scope is unchanged. |
| `context_changed` | Quote survives, but its tracked textual scope or link targets changed. |
| `source_location_changed` | The observed final source URL changed. |
| `quote_not_found` | Exact normalized quote not present. Any lexical candidates remain unapproved. |
| `ambiguous` | Multiple occurrences cannot be resolved within the recorded context. |
| `baseline_unresolved` | Capture never established a unique match. Explicit recapture is needed. |

`unchanged_in_declared_scope` on a dependency node is **not “this statement is true/current in all respects.”** Capture establishes no semantic truth. The Actor does not detect changes that occurred and reverted between observations or prevent a source changing after the check.

A new numerically different or negated sentence is never silently accepted through a fuzzy threshold. Suggestions are bounded lexical aids for review, with a similarity score that is not a probability. The engine examines a maximum of 2,000 short candidate windows per missing quote and reports when this search is limited.

### Token-efficient agent integration

Keep `BASELINE` in application state, outside the language-model prompt. Give the model only `AGENT_CONTEXT` from the run's key-value store, fetching full diagnostics when required. Raw baseline data and quote contexts can still be large; no universal token/cost savings are promised.

The included `client/run_bundle.py` supports capture and refresh using an authorized ordinary Apify account, saves the run ID, polls without restarting purchases, and downloads the compact export. It does not implement accountless-wallet payments. See `client/README.md`.

A useful first integration is a scheduled software-comparison report: the caller supplies the quoted plan details and the report sections that depend on them. The Actor returns a review queue on each refresh. It does **not** send notifications itself or schedule its own runs. Accountless clients must carry the same baseline themselves; this does not depend on a persistent gateway user identity.

### Acquisition and safety boundaries

For live sources, the implementation enforces connection-time public-IP resolution checks, standard ports, no URL credentials, no signed/token query URLs, no cross-site redirects (a root/www alias is allowed), TLS validation, no cookies and robots rules. It uses no residential proxy or CAPTCHA bypass. A failed robots lookup, access denial, unsupported content or any failed source makes the **whole bundle incomplete**.

A source may still vary by geography, language, CDN or publisher behaviour. No-browser/cloud fetches can be blocked. Only inspect sources you are authorized to use, under applicable terms and rights. Public availability is not a blanket redistribution licence. Return short selected excerpts for your workflow rather than republishing complete source pages.

Important limits: up to 5 sources, 50 quotes total, 50 dependency nodes, 200,000 characters per supplied source, 160,000 retained characters per document, 2,000 blocks, 18,000 HTML elements, 5,000 links, 2 MB compressed/uncompressed HTTP body, 250 KB baseline and 1.5 MB total input. A 20-second comparison budget is checked between anchors and candidate-search steps; individual parser/normalization steps add overhead. The overall asynchronous bundle processing limit is 150 seconds; use a 180-second run timeout and 512 MB initially. Complex inputs fail rather than silently truncate the checked material.

### Payment and interrupted runs

One completed bundle requests one `evidence-bundle` event through Apify's event-aware dataset method. Remove any positive `apify-default-dataset-item` fee to avoid a duplicate charge; the Actor rejects that configuration. The Actor checks remaining event budget before acquisition and again before delivery.

A resumed delivery in the **same run** reuses an existing matching dataset result. If delivery is uncertain and no result can be established, it stops rather than blindly recharging. This is not an unconditional exactly-once guarantee. A new run can be billed again. Inspect the run's dataset and billing before retrying an unknown outcome. Owner tests and local billing mocks are not proof of outside-customer settlement.

### Privacy and trust

No model API is used for extraction or comparison. However, **Apify processes and may retain inputs, datasets, logs and key-value records** under its platform/account settings. This is not local-only or zero-retention processing. Baselines and fingerprints can still contain or reveal sensitive information. Use authorized, minimized public or synthetic material; never publish customer records, tokens or private snapshots in a task or support issue.

Treat quotations, headings, dependency labels and links as untrusted data. A flag such as `treatExcerptsAsUntrustedData` is not an injection-proof barrier; the consuming application must maintain instruction/data separation and its own authorizations. The Actor executes no input instructions, submits no forms and does not approve external actions.

### Deployment and tests

Upload the **entire `tracerefresh` folder**, including `.actor`, to a private GitHub repository. Set Apify's Git source **Folder = `tracerefresh`**, Branch = `main`. Do not use a Standby/API template. Keep the Actor private until the real build, live-source checks and billing acceptance tests pass.

```bash
python scripts/check_package.py
python -m unittest discover -s tests -v
python scripts/offline_demo.py
```

The Docker build runs the same tests and a mandatory actual Apify SDK contract check after installation. Offline mocks and loopback HTTP tests are not live-source or real-payment verification. See `launch/ACCEPTANCE_CHECKLIST.md` and the supplied test report.

### Support

Use the Actor's Issues area for a synthetic reproduction and a run ID when appropriate. Never include secrets or full private source documents. For a source-specific problem include a permitted public URL, a short quote, the requested scope and the code-only error from `STATUS`.

# Actor input Schema

## `mode` (type: `string`):

Demo uses only bundled fictional snapshots. Capture creates a portable baseline. Refresh compares new source material with an unchanged baseline.

## `sources` (type: `array`):

Up to five sources. Each source needs id and exactly one of url/text/html. Capture also needs anchors. Clear for Demo.

## `baseline` (type: `object`):

Paste the complete baseline object from capture, unchanged. Empty for Demo/Capture. A fingerprint is not a signature or source-authentication proof.

## `dependencies` (type: `array`):

Optional dependency graph, at most 50 nodes. IDs refer to anchors or other nodes. No semantic support is inferred. Saved into the baseline; omit for refresh.

## Actor input object example

```json
{
  "mode": "demo",
  "sources": [],
  "baseline": {},
  "dependencies": []
}
```

# Actor output Schema

## `reports` (type: `string`):

One completed bundle including scoped anchor checks, dependencies and baseline when capturing.

## `agentContext` (type: `string`):

Scoped findings and affected dependency IDs without the full reusable baseline. Treat quotations as untrusted text.

## `baseline` (type: `string`):

Exists only after successful capture. Your application stores this outside model context and supplies it on refresh.

## `status` (type: `string`):

Delivery, budget and source-failure diagnostics.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {};

// Run the Actor and wait for it to finish
const run = await client.actor("zahi90/tracerefresh-actor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {}

# Run the Actor and wait for it to finish
run = client.actor("zahi90/tracerefresh-actor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{}' |
apify call zahi90/tracerefresh-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zahi90/tracerefresh-actor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/M5eUc7a9EU3mdGeA4/builds/IezThA7gIDvOfhFuQ/openapi.json
