← Shared activity

Local SEO operations: 16 reviewed answers

GeoGrid, freshness, review requests and KML. Compare original answers and per-output reviews; response completion is not a blanket skill pass.

Download portable evidence JSON

Local SEO operations: results

Sixteen original answers are complete: four procedures, each without and with its original source, on signed-in Codex and Kimi CLIs inside Herdr. Models requested: gpt-6-astra and kimi-code/k3; the CLI receipts did not expose resolved model versions. No metered API, account change or production action was used. Inputs, criteria and source hashes were fixed before the runs. Codex ran baseline first; Kimi ran the guided case first. One case per procedure is limited evidence, not a benchmark of overall model capability.

Fourteen of sixteen responses passed the fixed data/format checks. Kimi baseline GeoGrid misstates current AGR in JSON (5.8 instead of 5.0), while its prose is correct; it also infers a center point without point-order evidence. Kimi guided freshness incorrectly excludes a 25-day-old photo from the stale list. Originals and failures are retained. Review-copy editing findings are separate from these mechanical counts.

Decisions

Code actually executed

The freshness SOP's two pure calculation functions matched known-stale channels in only 3 of 6 cases. This is not a 3/6 overall pass: explicit unknown-data handling was absent throughout. It uses the first item instead of the newest valid timestamp and substitutes 999 days for missing dates. The separate offline repair in freshness-runtime/freshness_calculation.py passes all 12 fixed and boundary cases. It has not been installed into the old API/Discord/scheduler pipeline, and that pipeline has not been run.

All four unmodified model-generated KML scripts were executed in separate guarded directories. Each passed 30 checks for four files, XML namespace, 37 combined points, three ring folders, 8/12/16 split points, supplied center, coordinate order, sample labels, escaping, angular spacing and a 25 m distance tolerance. The independent distance checker uses a sphere; it does not certify ellipsoidal precision. Google My Maps import and rendering remain untested. The generation scripts overwrite their four named files, so use a fresh output directory.

Source corrections

Local Brand Manager defines AGR over positions where the business is found in the first 20 and ATGR over the total grid, including not-found locations. The archive's best-three definition of ATGR is wrong. The fixture explicitly supplies a not-found cap of 21; this test does not claim that cap is universal. A centered 13 by 13 grid with one-mile spacing reaches six miles from center to an edge. Local Brand Manager metric documentation.

Treat 25 days as the supplied internal scheduling threshold. The source's claimed Google ranking penalty was not established by this test. Google permits neutral requests for genuine reviews, but prohibits incentives, selective positive solicitation and requesting specific review content. Keep approved quotations and real experience; remove keyword pressure. Google review guidance and contribution policy.

KML uses XML and longitude,latitude,altitude point order. Preserve XML and embedded-HTML escaping separately. Google KML tutorial.

The collection remains five domain entry points, five working local helper commands and zero imported custom global skills. The short local-operations note is a correction/reference, not a separately model-tested replacement. No source original was changed.

Output reviews

Original source versions

Portable operator reference

Local SEO operations: load the section needed

Corrected operator reference from four original procedures. The source versions and 16 paired Codex/Kimi answers are preserved in the results. This condensed note has not been separately model-tested. Full integrations remain shelved.

GeoGrid reporting

Use the actual export definition: AGR averages found ranks; ATGR includes not-found points using that export's documented cap. ATGR does not mean the three best cells. Keep grid center, dimensions, spacing and points consistent between runs; changed geometry prevents a like-for-like trend. A centered 13 by 13 grid at one-mile spacing reaches six miles from center to an edge. Label date windows and percentage points. Do not infer a point's location from an unlabeled list or claim an activity caused a rank change.

Freshness scheduling

Use the approved scheduling threshold, currently 25 completed 24-hour days for the tested case. This is an internal rule, not a verified Google penalty. Select the newest valid, timezone-aware, nonfuture timestamp. Missing, failed or unusable records are unknown with null age, never 999 days or an all-green result. Keep status by channel. The separate pure calculation repair passed 12 offline cases; API retrieval, alerts and scheduling are not integrated or tested.

Reviews

Invite eligible consenting customers neutrally regardless of sentiment. No incentive, rating pressure, keyword request or positive-only selection. The house cadence can use an initial request, a next-day reminder and a final reminder after three to five days when appropriate; stop on a review or opt-out. Use only approved, exact attributed quotes. Count published replies separately from drafts. Keep internal instructions out of customer copy. Google policy.

KML planning files

Use verified supplied coordinates and requested ring sizes. Preserve longitude,latitude,altitude order and separate XML/HTML escaping. Label sample points as planning points, never business branches. Do not invent social URLs or substitute a city center for an address. Generate into a fresh directory because the tested scripts overwrite four named files. All four tested generators passed file/geometry checks; map import, rendering and enrichment are untested.

Tested pure calculation

This is the separately authored offline repair, not a model test answer. Twelve fixture/boundary cases passed. It does not retrieve data or send alerts. Save as freshness_calculation.py only when this calculation is needed. The existing source monitor has not been modified.

SHA-256: e9b2e80c3e5f36725c5dc62bb4ce71612cd496384a0b5ce10f95503177ac8618

"""Offline calculation only. Does not fetch data, send alerts or schedule work."""
from datetime import datetime, timezone

def channel_status(items, as_of=None, threshold_days=25):
    as_of = as_of or datetime.now(timezone.utc)
    if as_of.tzinfo is None or as_of.utcoffset() is None:
        raise ValueError("as_of must include its timezone")
    if not isinstance(threshold_days, int) or threshold_days < 1:
        raise ValueError("threshold_days must be a positive integer")
    dates = []
    invalid = 0
    for item in items if isinstance(items, list) else []:
        value = item.get("timestamp") if isinstance(item, dict) else None
        try:
            date = datetime.fromisoformat(value.replace("Z", "+00:00"))
            if date.tzinfo is None or date.utcoffset() is None or date > as_of:
                raise ValueError("Unusable timestamp")
            dates.append(date)
        except (AttributeError, TypeError, ValueError):
            invalid += 1
    if not dates:
        return {"status": "unknown", "age_days": None, "timestamp": None, "invalid_items": invalid}
    latest = max(dates)
    age = (as_of.astimezone(timezone.utc) - latest.astimezone(timezone.utc)).days
    return {"status": "stale" if age >= threshold_days else "fresh", "age_days": age,
            "timestamp": latest.isoformat(), "invalid_items": invalid}

def assess_client_details(client_name, gbp_info, posts_info, as_of=None, threshold_days=25):
    posts = posts_info.get("items") if isinstance(posts_info, dict) else None
    photos = gbp_info.get("photos") if isinstance(gbp_info, dict) else None
    return {"client": client_name, "post": channel_status(posts, as_of, threshold_days),
            "photo": channel_status(photos, as_of, threshold_days)}

def assess_client(client_name, gbp_info, posts_info, as_of=None, threshold_days=25):
    """Retains the old alert-list interface while making missing data explicit."""
    result = assess_client_details(client_name, gbp_info, posts_info, as_of, threshold_days)
    alerts = []
    for name in ("post", "photo"):
        item = result[name]
        if item["status"] == "stale":
            alerts.append(f"Last {name}: {item['age_days']}d ago ({item['timestamp']})")
        elif item["status"] == "unknown":
            alerts.append(f"Unknown last {name}: no usable timestamp; check the data source.")
    return alerts
geogrid-reporting-sop · codex · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: ee09e24cff394c9e678c4defee348d842807c98db767f1825452114f27b62ec8

usable bounded draft: Correct metrics, grid comparability, extent and causality limits. Baseline already met the case.

{
  "metrics": {
    "previous": {
      "AGR": 5.80,
      "ATGR": 12.56,
      "top3_percent": 22.22
    },
    "current": {
      "AGR": 5.00,
      "ATGR": 12.11,
      "top3_percent": 33.33
    },
    "AGR_change": -0.80,
    "ATGR_change": -0.44,
    "top3_percentage_point_change": 11.11
  },
  "report_markdown": "**Cedar & Finch Drain Care: weekly grid report**\n\nFor “drain cleaning madison,” visibility improved between September 5 and September 12, 2026, across the same 3×3 grid with one-mile spacing, center and sampling points.\n\n| Metric | September 5 | September 12 | Change |\n|---|---:|---:|---:|\n| AGR | 5.80 | 5.00 | -0.80 |\n| ATGR | 12.56 | 12.11 | -0.44 |\n| Top-three coverage | 22.22% | 33.33% | +11.11 percentage points |\n\nLower AGR and ATGR values indicate better rankings. AGR averages only the five found ranks. ATGR includes all nine points, assigning 21 to each null solely under this export’s rules. Four points remained outside the top 20. Top-three coverage increased from two to three of nine sampled points; it is not broad market share.\n\nOne GBP post was published September 8. No experiment or other evidence establishes why rankings changed, so the improvement cannot be attributed to that post.\n\nFor “drain inspection,” supplied AGR fell from 6.00 to 4.00, but the grid changed from 3×3 at one-mile spacing to 5×5 at three-mile spacing. The sampling footprint changed, and other metadata is missing, so this is not a like-for-like trend.\n\nThese results compare two weekly snapshots. No historical average was supplied or calculated.",
  "operator_answers": {
    "ATGR": "No. For this export, ATGR is the mean across all nine points, substituting 21 for nulls. It is not the average of the best three cells.",
    "13x13_extent": "No. A centered 13×13 grid with one-mile spacing has 12 intervals across each side, spanning 12 miles. Its center is six miles from each edge along a row or column."
  },
  "next_steps": [
    "Repeat the primary keyword scan using the same center, points, spacing and comparable scan settings.",
    "Establish a consistent grid for drain inspection before making trend claims.",
    "Retain comparable scans to support a separately labeled historical average."
  ],
  "limits": [
    "This is an offline fictional fixture, not verification of a real business location.",
    "Changes use unrounded values before rounding to two decimals; negative rank changes indicate improvement.",
    "Nulls mean not found in the top 20, not an observed rank of 21.",
    "No evidence supports suspension, competitor campaigns, causation or a neighborhood pattern.",
    "Next steps are planning recommendations, not completed or published actions. The supplied September 8 GBP post is the only observed publication."
  ]
}
geogrid-reporting-sop · codex · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 7849b3075375b070d2b3f0a31aa2ce17edef0fee3c693bcdcc2fa1df6f03c1c3

usable after light editing: Correct metrics and operator answers. Remove the internal fictional-fixture label from a real client deliverable. No clear improvement over its baseline.

{
  "metrics": {
    "previous": {
      "AGR": 5.80,
      "ATGR": 12.56,
      "top3_percent": 22.22
    },
    "current": {
      "AGR": 5.00,
      "ATGR": 12.11,
      "top3_percent": 33.33
    },
    "AGR_change": -0.80,
    "ATGR_change": -0.44,
    "top3_percentage_point_change": 11.11
  },
  "report_markdown": "# Cedar & Finch Drain Care\nDraft GeoGrid report | Fictional offline fixture\n\n**Weekly comparison:** September 5 to September 12, 2026  \n**Keyword:** drain cleaning madison  \n**Grid:** 3×3, one-mile spacing, unchanged center and points\n\n| Metric | Previous | Current | Change |\n|---|---:|---:|---:|\n| AGR | 5.80 | 5.00 | -0.80 |\n| ATGR | 12.56 | 12.11 | -0.44 |\n| Top-three coverage | 22.22% | 33.33% | +11.11 percentage points |\n\nRankings improved across the comparable grid. Top-three coverage increased from two to three of nine sampled points. Five points returned top-20 rankings in both runs; four remained outside the top 20.\n\nAGR averages found ranks only. ATGR includes all nine points, using 21 for each missing result under this export’s rules. Lower values indicate improvement. Coverage describes these sampled points, not broader market share. Historical averages were not supplied and are separate from this weekly comparison.\n\n**Observed activity:** The fixture records one GBP post published September 8. No experiment or other evidence establishes why rankings changed.\n\n**Second keyword:** drain inspection shows AGR moving from 6.00 to 4.00, but the grid changed from 3×3 at one-mile spacing to 5×5 at three-mile spacing. The sampled footprint and number of points changed, so this is not a like-for-like trend. Other comparison metadata is unavailable.\n\n**Recommended follow-up:** Repeat the unchanged primary grid and establish a consistent comparison for drain inspection before assessing its trend.",
  "operator_answers": {
    "ATGR": "No. Under the supplied export rules, ATGR averages all nine cells, substituting 21 for nulls. It does not average the best three cells.",
    "grid_extent": "No. A centered 13×13 grid with one-mile spacing has 12 intervals across each axis: 12 miles between outer point rows or columns, and 6 miles from the center to an outer point along either axis. Center-to-corner distance is approximately 8.49 miles."
  },
  "next_steps": [
    "Repeat the primary keyword scan with the same center, points, spacing and comparable timing.",
    "Use matching grid settings and verify remaining metadata before comparing drain inspection runs.",
    "Review point-level results before making geographic claims; retain the GBP post as an activity record without attributing ranking changes to it."
  ],
  "limits": [
    "This is a draft based on a fictional fixture, not a published report or verification of a real business location.",
    "No tools, network access, messages, account changes or publication occurred.",
    "Nulls mean not found in the top 20; exact ranks are unknown. The value 21 is used only for this export’s ATGR calculation.",
    "Changes were calculated before rounding. Historical averages and evidence of causation, suspension, competitor campaigns or neighborhood patterns were not supplied."
  ]
}
geogrid-reporting-sop · kimi · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: c23d6ac41b52568c2a395dc8b8318a835e21eecec72f107740a34b01119c632c

needs correction: Structured current AGR is 5.8 instead of 5.0 although report prose says 5.0. Calls the first array item the center point without supplied point ordering. Preserve both errors.

```json
{
  "metrics": {
    "previous": {
      "AGR": 5.8,
      "ATGR": 12.56,
      "top3_percent": 22.22
    },
    "current": {
      "AGR": 5.8,
      "ATGR": 12.11,
      "top3_percent": 33.33
    },
    "AGR_change": -0.8,
    "ATGR_change": -0.44,
    "top3_percentage_point_change": 11.11
  },
  "report_markdown": "# Cedar & Finch Drain Care — Grid Report\n**Keyword:** drain cleaning madison\n**Comparison:** 2026-09-05 vs 2026-09-12 (weekly)\n**Grid:** 3x3, 1-mile spacing, same center and points both weeks\n\n## Results\n- **AGR** (mean of found ranks only): 5.80 → 5.00, a change of -0.80 (lower is better).\n- **ATGR** (all 9 points, nulls = 21 per export rule): 12.56 → 12.11, a change of -0.44.\n- **Top-3 coverage** (share of the 9 grid points ranking 1–3): 22.22% → 33.33%, up 11.11 percentage points. This describes only this grid's point coverage, not market share.\n\n## Read\nFive of nine points ranked in the top 20 both weeks. The four unranked points stayed unranked, so the ATGR improvement comes entirely from the five found points ranking better (e.g., center point 2 → 1). The business gained one additional top-3 position.\n\n## Observed activity\n- One GBP post was published on September 8, between the two snapshots.\n\n## Interpretation limits\n- This was not an experiment. No evidence establishes why rankings changed, so the GBP post is noted as timing only — no causal claim is made.\n- There is no evidence of suspension, competitor campaigns, or any neighborhood-wide pattern; none should be assumed.\n- This is a week-over-week comparison, not a comparison against a historical average (no historical series was supplied).\n\n## Second keyword note\nFor \"drain inspection\" (AGR 6 → 4), the grid changed from 3x3 at 1 mile to 5x5 at 3 miles. See operator answers — this is not a like-for-like trend.",
  "operator_answers": {
    "atgr_best_three_cells": "No. ATGR is the mean across all nine grid points, with unranked points (not found in the top 20) counted as 21 per the export rule. It is not the average of the best three cells. AGR is the separate metric that averages only the points where a rank was found.",
    "grid_13x13_extent": "No. A 13x13 grid with one-mile spacing has 6 points on each side of the center, so it extends 6 miles from center to edge (12 miles edge to edge), not 13 miles. In general, center-to-edge distance is (N-1)/2 times the spacing.",
    "second_keyword_not_like_for_like": "The 'drain inspection' comparison is not like-for-like because the measurement grid changed: 3x3 at 1-mile spacing previously versus 5x5 at 3-mile spacing currently. The two snapshots sample different numbers of points over different geographic areas, so the AGR change (6 to 4) mixes any true ranking movement with the effect of a different set of measurement locations. Other metadata was not supplied, so no further adjustment is possible. The AGRs can be reported side by side, but they should not be presented as a single trend."
  },
  "next_steps": [
    "Re-run 'drain inspection' on a fixed grid (same size, spacing, and center across dates) before reporting any trend for that keyword.",
    "Continue weekly snapshots of 'drain cleaning madison' on the identical 3x3/1-mile grid to build a historical average so future reports can separate weekly movement from baseline.",
    "If the client wants to evaluate the September 8 GBP post, treat it as a hypothesis and track multiple weeks before and after; a single interval cannot show causation.",
    "Investigate the four consistently unranked points (not found in top 20) as the main coverage gap if expanding visibility is a goal."
  ],
  "limits": [
    "Offline fictional fixture; figures reflect only the supplied export rules and data.",
    "Four of nine points were unranked both weeks; ATGR uses 21 for those points per the export rule, which caps measurable ATGR movement.",
    "No historical series supplied, so no comparison to a historical average is possible — this is a two-week snapshot only.",
    "No experiment was run; causation (including for the September 8 GBP post) cannot be established.",
    "No evidence of suspension, competitor campaigns, or neighborhood-wide patterns; none are inferred.",
    "Top-3 coverage is the fraction of this grid's nine points ranking 1–3, not a market-share claim.",
    "Second keyword lacks comparable grid geometry and other metadata, so its AGR change is not a valid trend measure."
  ]
}
```
geogrid-reporting-sop · kimi · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: e511c5c340c9bc1f011a8cdf816c50180f159da6b736317bf06d7bb56a146e0e

usable bounded draft: Correct metrics and explicit corrections to archived ATGR and grid-extent definitions. Separate second_keyword_trend explains the changed geometry; that context should accompany the client report. Improved over this model baseline on this fixture.

{
  "metrics": {
    "previous": {
      "AGR": 5.80,
      "ATGR": 12.56,
      "top3_percent": 22.22
    },
    "current": {
      "AGR": 5.00,
      "ATGR": 12.11,
      "top3_percent": 33.33
    },
    "AGR_change": -0.80,
    "ATGR_change": -0.44,
    "top3_percentage_point_change": 11.11
  },
  "report_markdown": "# Cedar & Finch Drain Care — GeoGrid Visibility Report\n**Keyword:** drain cleaning madison\n**Period:** 2026-09-05 to 2026-09-12 | **Grid:** 3x3, 1-mile spacing (same center and points both runs)\n\n## Summary Metrics (weekly comparison, not historical average)\n| Metric | 2026-09-05 | 2026-09-12 | Change |\n|---|---|---|---|\n| AGR (mean of found ranks) | 5.80 | 5.00 | -0.80 (improving) |\n| ATGR (all 9 points, 21 for not-found) | 12.56 | 12.11 | -0.44 (improving) |\n| Top-3 coverage | 22.22% | 33.33% | +11.11 pts |\n\n## Overall Assessment\nBoth weekly metrics improved modestly. The business was found in the top 20 at the same 5 of 9 grid points in both runs, but ranks at those points improved (e.g., position 2 to 1, 4 to 3, 8 to 7, 12 to 11). One additional point entered the top 3. No historical average is available for this client, so this is strictly a week-over-week comparison.\n\n## Coverage Context\nFour of nine grid points still show no top-20 ranking. Top-3 coverage of 33.33% describes this 9-point grid only; it is not a market-share claim about Madison overall.\n\n## Actions Observed\n- One GBP post published September 8.\n\n## Causality Note\nThere was no experiment and no evidence establishes why rankings changed. The GBP post cannot be credited for the improvement, and no suspension, competitor activity, or neighborhood-level pattern can be confirmed or ruled out from this data.\n\n## Recommended Next Steps\n1. Continue weekly tracking on the same 3x3 grid to build a historical average for trend context.\n2. Investigate the four points with no top-20 presence before expanding keyword coverage.\n3. Document ongoing GBP and citation activity so future changes can be compared against actions taken.",
  "operator_answers": {
    "atgr_meaning": "Not in this export. Under the supplied export rules, ATGR is the mean across ALL nine grid points, substituting 21 for points where the business was not found in the top 20. That differs from the archived reference definition (average of the top 3 best-performing cells). For this report, the export rule governs: previous ATGR = (2+3+4+8+12+21+21+21+21)/9 = 12.56; current = (1+3+3+7+11+21+21+21+21)/9 = 12.11.",
    "grid_extent": "No. A 13x13 grid at 1-mile spacing has 12 intervals between its 13 points, so the total span is 12 miles. Measured from the center point to an edge point, that is 6 intervals = 6 miles. The archived reference description of a '~13-mile radius' overstates it; center-to-edge is 6 miles, corner-to-corner is farther still."
  },
  "second_keyword_trend": {
    "keyword": "drain inspection",
    "previous_AGR": 6.00,
    "current_AGR": 4.00,
    "like_for_like": false,
    "explanation": "The two runs used different grid geometry: previous was 3x3 at 1-mile spacing, current is 5x5 at 3-mile spacing. That means a different number of measurement points (9 vs. 25), different spacing, and a much wider coverage area in the current run. AGR is the mean of found ranks over those points, so the two values are computed over non-equivalent samples and cannot be read as a trend. Additionally, no other metadata (ranks, center, dates, export rules) was supplied, so even the AGR values themselves cannot be verified or recomputed. Treat the 6.00 to 4.00 change as unverified and not comparable."
  },
  "next_steps": [
    "Re-run 'drain inspection' on a consistent grid configuration before reporting any trend for that keyword.",
    "Keep the 'drain cleaning madison' grid identical week to week (same center, size, spacing) to preserve comparability.",
    "Investigate the four grid points with no top-20 presence before drawing conclusions about coverage.",
    "Log all GBP, citation, and content activity weekly so future rank changes can be compared against actions taken (without assuming causation)."
  ],
  "limits": [
    "Two-run snapshot only; no historical average exists, so no long-term trend or average comparison is possible.",
    "Causation is unknown: no experiment was run, and the single GBP post cannot be credited or ruled out.",
    "No evidence of GBP suspension, penalties, competitor campaigns, or negative review activity; none can be inferred.",
    "Top-3 coverage (33.33%) reflects only this 9-point grid for one keyword and is not a market-share claim.",
    "The 3x3 grid covers a 2-mile total span (1 mile center-to-edge); results say nothing about rankings beyond those points.",
    "Second-keyword data lacks ranks, dates, and metadata; its AGR values are unverified and not comparable across the differing grids.",
    "This is a fictional offline fixture, not a published report or a real business location."
  ]
}
gmb-freshness-monitor · codex · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 3d6e3850fd141b33b4d143d03ae30e6ded87de7f2293fc4e09b96cf850fd786b

usable bounded draft: Correct completed-day counts, stale channels and explicit unknown states; no invented ranking penalty.

{
  "clients": [
    {
      "id": "a",
      "post_status": "fresh",
      "post_age_days": 2,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": ["Selected the latest valid post; photos meet the 25-day threshold."]
    },
    {
      "id": "b",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": ["Posts retrieval failed with null data; photos array is empty."]
    },
    {
      "id": "c",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": ["The only post timestamp is in the future and was excluded."]
    },
    {
      "id": "d",
      "post_status": "fresh",
      "post_age_days": 24,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": ["Photos are 25 completed days old, with one additional hour elapsed."]
    },
    {
      "id": "e",
      "post_status": "stale",
      "post_age_days": 25,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": ["Posts meet the 25-day threshold; photos match the evaluation time."]
    },
    {
      "id": "f",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": ["Post timestamp lacks a timezone; photo timestamp is invalid."]
    }
  ],
  "stale_client_ids": ["a", "d", "e"],
  "unknown_client_ids": ["b", "c", "f"],
  "draft_alert": "Draft only: Known staleness requires scheduling review for photos on a and d and posts on e, each at 25 completed days. Missing or unusable data requires follow-up for b (posts and photos), c (posts), and f (posts and photos). These unknowns do not establish inactivity. The roster is not all green. No alert was sent and no content was published.",
  "limits": [
    "Evaluated as of 2026-09-12T12:00:00Z using completed 24-hour periods; stale means age greater than or equal to 25 days.",
    "For successful records, selected the latest valid, timezone-aware, nonfuture timestamp.",
    "The threshold is for internal scheduling, not an established Google ranking penalty.",
    "This is an offline fictional fixture; client IDs do not establish real business locations.",
    "No tools, network, messages, account changes, or publication were used."
  ]
}
gmb-freshness-monitor · codex · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 6b1f0d8b96cd72d6a85722491383cc0d1ca6aa96a21a34f1db5dd0e574d9c226

usable bounded draft: Correct counts and alerts. No measurable correctness gain over baseline.

{
  "clients": [
    {
      "id": "a",
      "post_status": "fresh",
      "post_age_days": 2,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": "Selected the latest valid post from the unsorted array. Photo age meets the threshold."
    },
    {
      "id": "b",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": "Posts retrieval failed with null data; photos array is empty."
    },
    {
      "id": "c",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": "The only post timestamp is in the future and cannot establish published activity. Photo age is 4 hours."
    },
    {
      "id": "d",
      "post_status": "fresh",
      "post_age_days": 24,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": "Photo age is 25 days and 1 hour, or 25 completed days."
    },
    {
      "id": "e",
      "post_status": "stale",
      "post_age_days": 25,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": "Post age meets the threshold exactly. Photo timestamp equals the assessment time."
    },
    {
      "id": "f",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": "Post timestamp lacks a timezone; photo timestamp is invalid."
    }
  ],
  "stale_client_ids": ["a", "d", "e"],
  "unknown_client_ids": ["b", "c", "f"],
  "draft_alert": "DRAFT ONLY | GBP freshness assessment as of 2026-09-12 12:00 UTC. Known staleness: a photos 25 days; d photos 25 days; e posts 25 days. Review these for scheduling. Missing or unusable data: b posts retrieval failed and photos empty; c posts future-only; f post timezone missing and photo timestamp invalid. Verify these records before assessing freshness. The roster is not all green: 3 clients have known staleness and 3 have unknown data.",
  "limits": [
    "Offline fictional fixture; no tools, network, messages, account changes, or publication performed. Client IDs do not establish real business locations.",
    "Ages use completed 24-hour periods as of the supplied assessment time. Stale means at least 25 completed days.",
    "For successful records, use the latest valid nonfuture timezone-aware timestamp. Unknown data has null age and does not prove inactivity.",
    "The threshold is an internal scheduling policy, not an established Google ranking penalty.",
    "The alert and scheduling suggestions are drafts, not completed actions."
  ]
}
gmb-freshness-monitor · kimi · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 2bf063cd8dd7ff16a875170070e14a49d7b002a7cc3dcee4fcc4e792c25e6aaf

usable after light editing: Correct channel statuses and stale IDs. Trim meta-commentary; unknown applies to channels, not every channel of a partially unknown client.

{
  "clients": [
    {
      "id": "a",
      "post_status": "fresh",
      "post_age_days": 2,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": "Latest valid post 2026-09-10T12:00:00Z (2 days). Latest photo 2026-08-18T12:00:00Z is exactly 25 completed days old, meeting the staleness threshold."
    },
    {
      "id": "b",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": "Posts fetch returned an error and photos list is empty. No evidence of activity or inactivity; cannot be called stale or fresh."
    },
    {
      "id": "c",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": "Only post timestamp is in the future (2026-09-13), so post recency is unknown rather than evidence of activity. Photo 2026-09-12T08:00:00Z is 4 hours old (0 completed days)."
    },
    {
      "id": "d",
      "post_status": "fresh",
      "post_age_days": 24,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": "Post 2026-08-19T12:00:00Z is 24 completed days old. Photo 2026-08-18T11:00:00Z is 25 completed days old (the extra hour does not count as a 26th day)."
    },
    {
      "id": "e",
      "post_status": "stale",
      "post_age_days": 25,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": "Post 2026-08-18T12:00:00Z is exactly 25 completed days old, meeting the staleness threshold. Photo timestamp equals as_of time (nonfuture), age 0 days."
    },
    {
      "id": "f",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": "Post timestamp is naive (no timezone); per policy no timezone is guessed. Photo value 'not-a-date' is invalid. Both treated as unknown."
    }
  ],
  "stale_client_ids": ["a", "d", "e"],
  "unknown_client_ids": ["b", "c", "f"],
  "draft_alert": "DRAFT - internal planning only, not a published action or verified business-location fact. Known staleness (data present): client a photos, client d photos, and client e posts have each reached 25 completed days since the latest valid update, hitting the 25-day internal scheduling threshold. Missing data (cannot be judged): client b has no post or photo data (error/empty), client c has only a future-dated post so post recency is unknown, and client f has a timezone-naive post timestamp and an invalid photo timestamp. Roster is NOT all green: 3 of 6 clients have at least one unknown dimension, so unknowns must be resolved before any client-wide freshness claim. Staleness here indicates only an internal scheduling review trigger, not an established Google ranking penalty.",
  "limits": [
    "Threshold is an internal scheduling rule, not an established Google ranking penalty.",
    "Ages use completed 24-hour periods; an item is stale when it reaches 25 completed days.",
    "Null, error, empty, invalid, future-only, and timezone-naive timestamps are treated as unknown, never as evidence of 999 days of inactivity or of freshness.",
    "No timezone was guessed for naive timestamps.",
    "For successful records, the latest valid nonfuture aware timestamp was selected.",
    "This is a draft planning assessment, not a published action or a claim about a real business location.",
    "Unknown clients (b, c, f) are excluded from both stale and fresh conclusions; the roster is not all green."
  ]
}
gmb-freshness-monitor · kimi · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 5b25a0241dc247650f169087f72ef84bd66ce2392fa566e4193cba5ba54be63a

needs correction: Client d photo is 25 days and one hour old, but output says 24 days/fresh and excludes d from the stale list. Regression against its correct baseline.

```json
{
  "clients": [
    {
      "id": "a",
      "post_status": "fresh",
      "post_age_days": 2,
      "photo_status": "stale",
      "photo_age_days": 25,
      "notes": "Latest post 2026-09-10T12:00:00Z (2d). Latest photo 2026-08-18T12:00:00Z is exactly 25 completed days old, meeting the 25-day scheduling threshold."
    },
    {
      "id": "b",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": "Posts lookup errored and photos array is empty. Missing data is not evidence of inactivity; needs re-check, not assumed staleness."
    },
    {
      "id": "c",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": "Only post timestamp is future-only (2026-09-13T12:00:00Z), treated as unknown per policy. Photo 2026-09-12T08:00:00Z is 0 completed days old (fresh)."
    },
    {
      "id": "d",
      "post_status": "fresh",
      "post_age_days": 24,
      "photo_status": "fresh",
      "photo_age_days": 24,
      "notes": "Post 2026-08-19T12:00:00Z = 24 completed days. Photo 2026-08-18T11:00:00Z = 24 completed 24-hour periods (25h short of threshold). Both fresh, but both hit 25 days within the next day."
    },
    {
      "id": "e",
      "post_status": "stale",
      "post_age_days": 25,
      "photo_status": "fresh",
      "photo_age_days": 0,
      "notes": "Post 2026-08-18T12:00:00Z is exactly 25 completed days old, meeting the threshold. Photo 2026-09-12T12:00:00Z equals as-of time, 0 days, fresh."
    },
    {
      "id": "f",
      "post_status": "unknown",
      "post_age_days": null,
      "photo_status": "unknown",
      "photo_age_days": null,
      "notes": "Post timestamp is naive (no timezone); policy forbids guessing a timezone. Photo timestamp 'not-a-date' is invalid. Both unknown."
    }
  ],
  "stale_client_ids": ["a", "e"],
  "unknown_client_ids": ["b", "c", "f"],
  "draft_alert": "DRAFT — not sent. GBP Freshness check as of 2026-09-12T12:00:00Z (internal 25-day scheduling threshold; not a confirmed Google ranking penalty). Known staleness: (a) photo exactly 25 days old — schedule new photo; (e) post exactly 25 days old — schedule new post. Insufficient data (cannot confirm fresh or stale): (b) posts lookup errored, no photos on record; (c) only post timestamp is future-dated (invalid); (f) timestamps unusable (naive/invalid values). Action: fix data gaps for b, c, f and re-run before clearing them. Note: client d is fresh at 24 days for both post and photo but crosses the threshold within ~1 day — queue content now.",
  "limits": "Offline fictional fixture; no tools, network calls, Discord messages, or account actions performed and nothing published. Alert above is a draft only. Client IDs are fixture labels, not verified real business locations; roster business names from the reference were not resolved or used. The 25-day threshold is an internal scheduling heuristic, not an established Google penalty. Unknown reflects missing/invalid/future/naive/errored data, not inferred inactivity (no 999-day assumption). All-clear was not declared because unknowns remain."
}
```
gmb-review-generation-sop · codex · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: f2ef8e671ea5947e1fe6ad1258484a2f811ae937f88d7198f73d9aab71c0eea1

usable bounded draft: Neutral requests, exact approved Riley quote and correct response/rating metrics. Optional two-touch plan respects the maximum of three and stop rules.

{
  "sms": "Thanks for choosing Cedar & Finch Drain Care. If you’d like, share an honest review of your experience: https://cedar-finch.example/review. All feedback is welcome. For optional service support, email care@cedar-finch.example. Reply STOP to opt out of follow-up requests.",
  "email_subject": "Share your Cedar & Finch Drain Care experience",
  "email_body": "Thanks for choosing Cedar & Finch Drain Care for residential drain cleaning. We welcome your honest feedback, whatever your experience.\n\nIf you’d like to leave a review, visit https://cedar-finch.example/review. Reviewing is optional.\n\nFor service questions or support, you can also contact care@cedar-finch.example. You do not need to contact us before reviewing.\n\nTo stop review-request follow-ups, reply “unsubscribe.”\n\nAvery\nManager, Cedar & Finch Drain Care",
  "follow_up_plan": {
    "status": "Draft plan only; no sending or automation configured.",
    "audience": "All real customers with permission to contact, regardless of satisfaction.",
    "touches": [
      {
        "timing": "After confirmed service completion",
        "action": "Send either the SMS or email through a permitted channel."
      },
      {
        "timing": "Seven days after the initial request",
        "action": "If no review or opt-out is known, send one brief reminder that honest feedback is welcome and reviewing is optional."
      }
    ],
    "stop_rule": "Stop on review or opt-out; otherwise end after the second touch.",
    "support": "Optional service support is available at care@cedar-finch.example and is never a gate to reviewing."
  },
  "feature_post": "Customer feedback highlights both results and room to improve:\n\n“The drain is clear. The arrival window could have been clearer.” — Riley\n\nThank you, Riley, for sharing your experience with Cedar & Finch Drain Care. Clear communication matters alongside residential drain cleaning. We welcome honest feedback about every part of the experience.",
  "response_drafts": {
    "r2": "Thank you, Riley, for your feedback. We’re glad the drain is clear, and we’re sorry the arrival window wasn’t clearer. If you’d like to discuss your experience, please contact care@cedar-finch.example.\nAvery, Manager",
    "r3": "Thank you, Sam, for bringing this to our attention. We’re sorry the work area needed more cleanup when the team left. If you’d like to discuss your concerns, please contact care@cedar-finch.example.\nAvery, Manager"
  },
  "metrics": {
    "review_count": 3,
    "mean_rating": 3.67,
    "published_response_rate_percent": 33.33,
    "mean_response_hours_among_replied": 12
  },
  "limits": [
    "Offline fictional fixture. All kit content, the feature post and new replies are drafts; nothing was sent, configured or published.",
    "Madison is supplied context, not a verified business location. Service dates, neighborhoods and a physical address are unknown.",
    "No refund, specific arrival-time promise, complaint diagnosis or resolution is approved or claimed.",
    "Metrics use only the three supplied monthly reviews. Only r1 has a published response; draft replies do not affect metrics. Mean rating and response rate are rounded to two decimals.",
    "Requests offer no incentives, satisfaction screening, prescribed keywords or ratings, or pressure to review.",
    "Policy guidance follows the supplied brief; current online policy was not independently verified."
  ]
}
gmb-review-generation-sop · codex · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: a498d410cb58dd0fde3ba446330cda31e86f557ed9572ac68c1179329f0ec281

usable bounded draft: Correct facts and metrics; retains the house three-touch cadence. No correctness advantage over baseline.

{
  "sms": "Hi [Name], thank you for choosing Cedar & Finch Drain Care for residential drain cleaning. You're welcome to share an honest Google review: https://cedar-finch.example/review. All feedback is welcome, and reviewing is optional. For service support, contact care@cedar-finch.example. Reply STOP to opt out of review requests.",
  "email_subject": "Share your experience with Cedar & Finch Drain Care",
  "email_body": "Hi [Name],\n\nThank you for choosing Cedar & Finch Drain Care for residential drain cleaning in Madison. We'd welcome an honest review of your experience, whatever your feedback:\n\nhttps://cedar-finch.example/review\n\nPlease share only what reflects your own experience, in your own words. Reviewing is entirely optional.\n\nIf you would like service support, email care@cedar-finch.example. You can leave a review whether or not you contact us.\n\nTo stop review requests, reply with “unsubscribe.”\n\nThank you,\nAvery\nCedar & Finch Drain Care",
  "follow_up_plan": {
    "status": "Draft plan only; no sending or automation setup.",
    "audience": "All real customers with permission to contact, regardless of satisfaction.",
    "touches": [
      {
        "touch": 1,
        "timing": "At service completion",
        "action": "Offer an optional invitation to leave an honest review and provide the review URL."
      },
      {
        "touch": 2,
        "timing": "24 hours after service",
        "action": "Send the SMS draft if contact permission remains valid and no review or opt-out has been recorded."
      },
      {
        "touch": 3,
        "timing": "3–5 days after service",
        "action": "Send the email draft as the final request if no review or opt-out has been recorded."
      }
    ],
    "stop_rules": "Stop remaining requests when a review or opt-out is recorded. No further review requests after touch three.",
    "support": "Optional support is available at care@cedar-finch.example and is never a prerequisite to reviewing."
  },
  "feature_post": "“The drain is clear. The arrival window could have been clearer.”\n— Riley\n\nThank you, Riley, for sharing both the result and your feedback about the arrival window. Cedar & Finch Drain Care provides residential drain cleaning in Madison. Have an experience to share? Honest feedback is welcome: https://cedar-finch.example/review",
  "response_drafts": {
    "r2": "Hi Riley, thank you for your feedback. We're glad the drain is clear, and we're sorry the arrival window wasn't clearer. If you'd like to discuss your experience, please contact care@cedar-finch.example.\n\nAvery\nCedar & Finch Drain Care",
    "r3": "Hi Sam, thank you for letting us know. We're sorry the work area needed more cleanup when our team left. We'd appreciate the opportunity to hear more. You're welcome to contact care@cedar-finch.example.\n\nAvery\nCedar & Finch Drain Care"
  },
  "metrics": {
    "review_count": 3,
    "mean_rating": 3.67,
    "published_response_rate_percent": 33.33,
    "mean_response_hours_among_replied": 12
  },
  "limits": [
    "Offline fictional fixture. All content is draft only; nothing was sent, published, configured or independently verified.",
    "Metrics use only the three supplied monthly reviews. Only r1 has a published response; r2 and r3 drafts do not affect response metrics. Rating and percentage are rounded to two decimals.",
    "Madison is the supplied city context, not a verified business address. No service date, neighborhood or street address was supplied.",
    "No refund, specific arrival-time promise, complaint diagnosis or resolution is approved or claimed.",
    "Invitations offer no rewards, satisfaction screening, prescribed keywords or ratings, or ranking guarantees.",
    "The approved Riley quote is preserved exactly. No customer review was invented, and current Google policy was not independently checked."
  ]
}
gmb-review-generation-sop · kimi · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: d5c0b70fe266e9fcd71e9c445a010cfcef541da60c6f2e8ef520ed953509c19a

needs copy editing: All fixed factual checks pass. Customer-facing SMS, email and feature copy contain internal draft/process restrictions. Replies over-explain prohibited promises instead of simply offering help.

{
  "sms": "Thanks for choosing Cedar & Finch Drain Care in Madison. If you have a minute, we’d value an honest review—good or bad—about your residential drain cleaning: https://cedar-finch.example/review. No reward, no pressure. Questions? care@cedar-finch.example. Reply STOP to opt out. Draft only.",
  "email_subject": "Quick honest review for Cedar & Finch Drain Care?",
  "email_body": "Hi, thanks for trusting Cedar & Finch Drain Care with residential drain cleaning in Madison. If you’re willing, please leave an honest review here: https://cedar-finch.example/review. We invite every permitted customer regardless of satisfaction; there’s no reward, no requested rating, and no wording to copy. If anything needs attention, you may email care@cedar-finch.example, but support is optional and never required to review. This is a draft request only—no sending or automation is set up.",
  "follow_up_plan": [
    "Touch 1: Send the draft SMS or email only to real customers with contact permission; identical invitation regardless of satisfaction.",
    "Touch 2: One reminder after several days only if no review and no opt-out; keep the same honest-review link and no incentive.",
    "Touch 3: Optional final note. Stop immediately on any posted review or opt-out. Care email may be offered for service/support, never as a gate to reviewing."
  ],
  "feature_post": "Review-derived draft post: \"The drain is clear. The arrival window could have been clearer.\" — Riley. We’re sharing this approved customer feedback because it names both what worked and what needs clearer communication. No rating guarantee, no invented praise; planning draft only, not a published action.",
  "response_drafts": {
    "r2": "Draft reply, not published: Thanks, Riley. We’re glad the drain is clear, and we’re sorry the arrival window wasn’t clearer. We can’t promise a specific arrival time here, but we’d value any details you want Avery to review at care@cedar-finch.example. Contact is optional and never required to review.",
    "r3": "Draft reply, not published: Sam, thank you for telling us. We’re sorry the work area needed more cleanup when the team left. We won’t diagnose or claim resolution here; if you’re open to it, Avery can listen at care@cedar-finch.example. Support is optional and separate from leaving an honest review."
  },
  "metrics": {
    "review_count": 3,
    "mean_rating": 3.67,
    "published_response_rate_percent": 33.33,
    "mean_response_hours_among_replied": 12
  },
  "limits": "Fictional offline fixture; draft/planning only with no tools, sending, automation, account changes, messages, or publication. New replies are drafts and do not change actual response metrics. Only r1 has a published response at 12 hours; r2/r3 remain unpublished. No approved refund, specific arrival-time promise, diagnosis, resolution claim, service date, or neighborhood beyond Madison. Invite honest reviews from all permitted customers; no rewards, review gating, dictated keywords/rating, pressure, customer-voice ghostwriting, fake reviews, invented quotes, or ranking guarantees."
}
gmb-review-generation-sop · kimi · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 7c8062d58a018030891490531aade45dfc9d6074e9e754958ee5ad31d4fa1664

needs copy editing: Correct facts and metrics, cleaner requests than baseline. Feature/reply text still includes unnecessary policy explanations. Do not publish without editing.

{
  "sms": "Hi [Name], thanks for choosing Cedar & Finch Drain Care for residential drain cleaning in Madison. If willing, please leave an honest Google review—good or bad—here: https://cedar-finch.example/review. No pressure. Reply STOP to opt out.",
  "email_subject": "Honest feedback for Cedar & Finch Drain Care?",
  "email_body": "Hi [Name], thank you for choosing Cedar & Finch Drain Care for residential drain cleaning in Madison. If you have a moment, we welcome an honest Google review about your experience, whether positive or critical: https://cedar-finch.example/review. Please share only what you choose; no rating, wording, or keyword is required. If something needs attention, email care@cedar-finch.example; contacting support is optional and never a gate to reviewing. No pressure, and thank you either way. —Avery",
  "follow_up_plan": [
    "Touch 1: Send the approved request once to permitted customers; stop immediately on opt-out or posted review.",
    "Touch 2: If no review or opt-out after 3-5 days, send one brief reminder with the same honest-review wording.",
    "Touch 3: Final optional reminder after 7-10 days; then stop. Support via care@cedar-finch.example is optional and never required to review."
  ],
  "feature_post": "Riley told us: The drain is clear. The arrival window could have been clearer. Thanks for the honest feedback, Riley. Cedar & Finch Drain Care provides residential drain cleaning in Madison, and we are listening. Questions? care@cedar-finch.example is optional and never required to leave a review.",
  "response_drafts": {
    "r2": "Hi Riley, thank you for the honest feedback. We are glad the drain is clear, and we are sorry the arrival window was not clearer. We appreciate you pointing that out. If you want to share more, email care@cedar-finch.example; leaving or changing a review is never required. —Avery, Cedar & Finch Drain Care",
    "r3": "Hi Sam, thank you for telling us. We are sorry the work area needed more cleanup when our team left; that is not the experience we aim to leave behind. If you are open to it, email care@cedar-finch.example so we can understand what happened. Contact is optional and never affects any review. —Avery, Cedar & Finch Drain Care"
  },
  "metrics": {
    "review_count": 3,
    "mean_rating": 3.6666666666666665,
    "published_response_rate_percent": 33.33333333333333,
    "mean_response_hours_among_replied": 12
  },
  "limits": "No approved refund, specific arrival-time promise, diagnosis of the complaint, resolution claim, service date or neighborhood beyond Madison. All three are the only reviews in this fictional monthly dataset. New replies remain drafts, not published responses. No fake reviews, invented quotes, incentives, review gating, dictated ratings or keywords, pressure, or ranking guarantees."
}
kml-generator · codex · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 35b43c1bdcd0002ca4806a2e39efbd6c18bf93314e96d0f2c1a267c6c97af4a9

runtime passed; import untested: Unmodified script wrote the four required KML files with correct geometry, counts, escaping and sample labels. Thirty checks passed; baseline needed no full workflow.

{
  "script": "from pathlib import Path\nimport html\nimport math\nimport xml.etree.ElementTree as ET\n\nNS = 'http://www.opengis.net/kml/2.2'\nET.register_namespace('', NS)\nBUSINESS = 'Cedar & Finch <Drain Care>'\nCATEGORY = 'Drain cleaning & inspection'\nWEBSITE = 'https://cedar-finch.example/?a=1&b=2'\nCENTER_LAT, CENTER_LON = 43.0731, -89.4012\nEARTH_RADIUS_M = 6371008.8\nRINGS = [(500, 8), (1000, 12), (2500, 16)]\nFILES = ['sitemap.kml', 'ring_01.kml', 'ring_02.kml', 'ring_03.kml']\n\n\ndef element(parent, name, text=None):\n    node = ET.SubElement(parent, '{' + NS + '}' + name)\n    if text is not None:\n        node.text = str(text)\n    return node\n\n\ndef document(name):\n    root = ET.Element('{' + NS + '}kml')\n    doc = element(root, 'Document')\n    element(doc, 'name', name)\n    return root, doc\n\n\ndef destination(radius_m, bearing_deg):\n    lat1 = math.radians(CENTER_LAT)\n    lon1 = math.radians(CENTER_LON)\n    bearing = math.radians(bearing_deg)\n    angle = radius_m / EARTH_RADIUS_M\n    lat2 = math.asin(math.sin(lat1) * math.cos(angle)\n                     + math.cos(lat1) * math.sin(angle) * math.cos(bearing))\n    lon2 = lon1 + math.atan2(\n        math.sin(bearing) * math.sin(angle) * math.cos(lat1),\n        math.cos(angle) - math.sin(lat1) * math.sin(lat2))\n    return (math.degrees(lon2) + 180) % 360 - 180, math.degrees(lat2)\n\n\ndef distance_m(lon, lat):\n    lat1, lat2 = map(math.radians, (CENTER_LAT, lat))\n    dlat = lat2 - lat1\n    dlon = math.radians(lon - CENTER_LON)\n    a = math.sin(dlat / 2) ** 2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2) ** 2\n    return 2 * EARTH_RADIUS_M * math.asin(math.sqrt(min(1.0, max(0.0, a))))\n\n\ndef description(note):\n    # Escape supplied values for HTML, then let ElementTree escape HTML for XML.\n    escape = html.escape\n    return (\n        '<p><strong>' + escape(BUSINESS, quote=True) + '</strong></p>'\n        '<p>Category: ' + escape(CATEGORY, quote=True) + '</p>'\n        '<p>Website: <a href=\"' + escape(WEBSITE, quote=True) + '\">'\n        + escape(WEBSITE, quote=True) + '</a></p>'\n        '<p>' + escape(note, quote=True) + '</p>'\n        '<p>Offline fictional draft fixture. No publication or verified service availability. '\n        'Address and social URLs were not supplied.</p>'\n    )\n\n\ndef placemark(parent, name, lon, lat, note):\n    mark = element(parent, 'Placemark')\n    element(mark, 'name', name)\n    element(mark, 'description', description(note))\n    point = element(mark, 'Point')\n    element(point, 'coordinates', f'{lon:.10f},{lat:.10f},0')\n\n\ndef main():\n    combined_root, combined_doc = document(BUSINESS + ' | Draft planning sitemap')\n    placemark(\n        combined_doc, BUSINESS + ' | Supplied fictional business center',\n        CENTER_LON, CENTER_LAT,\n        'Supplied business center for this fictional fixture; not a verified real business location.'\n    )\n    outputs = []\n    for ring_index, (radius_m, count) in enumerate(RINGS, start=1):\n        title = f'Ring {ring_index:02d} | {radius_m} m | Planning samples'\n        folder = element(combined_doc, 'Folder')\n        element(folder, 'name', title)\n        split_root, split_doc = document(title)\n        for index in range(count):\n            bearing = 360.0 * index / count\n            lon, lat = destination(radius_m, bearing)\n            assert abs(distance_m(round(lon, 10), round(lat, 10)) - radius_m) < 0.01\n            name = f'Planning sample | Ring {ring_index:02d} | Point {index + 1:02d}'\n            note = (\n                f'Planning sample only. Requested radius: {radius_m} meters; '\n                f'bearing: {bearing:g} degrees clockwise from true north. '\n                'Not a business branch, office, or verified service location.'\n            )\n            placemark(folder, name, lon, lat, note)\n            placemark(split_doc, name, lon, lat, note)\n        outputs.append((FILES[ring_index], split_root, count, 0))\n    outputs.insert(0, (FILES[0], combined_root, 37, 3))\n\n    # Validate every document in memory before writing the four requested files.\n    serialized = []\n    for filename, root, expected_points, expected_folders in outputs:\n        payload = ET.tostring(root, encoding='utf-8', xml_declaration=True)\n        parsed = ET.fromstring(payload)\n        assert len(parsed.findall('.//{' + NS + '}Placemark')) == expected_points\n        assert len(parsed.findall('.//{' + NS + '}Folder')) == expected_folders\n        serialized.append((filename, payload))\n    for filename, payload in serialized:\n        Path(filename).write_bytes(payload)\n\n\nif __name__ == '__main__':\n    main()\n",
  "run_instructions": "Save the script as generate_kml.py and run python generate_kml.py using Python 3 from the desired output directory. No arguments or dependencies are required. It writes only sitemap.kml, ring_01.kml, ring_02.kml, and ring_03.kml.",
  "expected_counts": {
    "sitemap.kml": {
      "placemarks": 37,
      "business_centers": 1,
      "planning_samples": 36,
      "ring_folders": 3
    },
    "ring_01.kml": {
      "placemarks": 8,
      "radius_m": 500,
      "bearing_step_degrees": 45,
      "folders": 0
    },
    "ring_02.kml": {
      "placemarks": 12,
      "radius_m": 1000,
      "bearing_step_degrees": 30,
      "folders": 0
    },
    "ring_03.kml": {
      "placemarks": 16,
      "radius_m": 2500,
      "bearing_step_degrees": 22.5,
      "folders": 0
    }
  },
  "limitations": [
    "Script supplied without execution, as requested.",
    "Uses spherical geodesic destinations with Earth radius 6371008.8 meters. At the supplied latitude and radii, differences from WGS84 ellipsoidal distances remain below the requested 25-meter tolerance.",
    "All locations are fictional draft fixture data. Ring points are planning samples, not branches, offices, or verified service availability.",
    "No address or social URLs were supplied; none are invented. No remote access, publication, or account actions occur."
  ]
}
kml-generator · codex · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: f0b5dc0bda3acc20a529c5b96cf9126e52f6f7b5d00f712dafea74dfb352c080

runtime passed; import untested: Thirty checks passed on the original generated code. No demonstrated output advantage over baseline; paid enrichment and publishing branches were outside scope.

{
  "script": "import math\nimport html\nimport xml.etree.ElementTree as ET\nfrom pathlib import Path\n\nBUSINESS = 'Cedar & Finch <Drain Care>'\nCATEGORY = 'Drain cleaning & inspection'\nWEBSITE = 'https://cedar-finch.example/?a=1&b=2'\nCENTER_LAT = 43.0731\nCENTER_LON = -89.4012\nRINGS = [(500, 8), (1000, 12), (2500, 16)]\nEARTH_RADIUS_M = 6371008.8\nNS = 'http://www.opengis.net/kml/2.2'\nET.register_namespace('', NS)\n\n\ndef element(parent, tag, text=None):\n    node = ET.SubElement(parent, '{' + NS + '}' + tag)\n    if text is not None:\n        node.text = text\n    return node\n\n\ndef document(name):\n    root = ET.Element('{' + NS + '}kml')\n    doc = element(root, 'Document')\n    element(doc, 'name', name)\n    return root, doc\n\n\ndef destination(radius_m, bearing):\n    lat1 = math.radians(CENTER_LAT)\n    lon1 = math.radians(CENTER_LON)\n    angular_distance = radius_m / EARTH_RADIUS_M\n    sin_lat2 = (math.sin(lat1) * math.cos(angular_distance)\n                + math.cos(lat1) * math.sin(angular_distance)\n                * math.cos(bearing))\n    lat2 = math.asin(max(-1.0, min(1.0, sin_lat2)))\n    lon2 = lon1 + math.atan2(\n        math.sin(bearing) * math.sin(angular_distance) * math.cos(lat1),\n        math.cos(angular_distance) - math.sin(lat1) * math.sin(lat2))\n    return math.degrees(lat2), (math.degrees(lon2) + 180.0) % 360.0 - 180.0\n\n\ndef description(note):\n    # Escape inserted values for HTML; ElementTree separately escapes XML.\n    return (\n        '<b>' + html.escape(BUSINESS, quote=True) + '</b><br/>'\n        + 'Category: ' + html.escape(CATEGORY, quote=True) + '<br/>'\n        + html.escape(note, quote=True) + '<br/>'\n        + '<a href=\"' + html.escape(WEBSITE, quote=True) + '\">Website</a>'\n    )\n\n\ndef placemark(parent, name, note, lat, lon):\n    pm = element(parent, 'Placemark')\n    element(pm, 'name', name)\n    element(pm, 'description', description(note))\n    point = element(pm, 'Point')\n    element(point, 'coordinates', f'{lon:.10f},{lat:.10f},0')\n\n\ndef write_kml(filename, root):\n    ET.ElementTree(root).write(\n        Path(filename), encoding='utf-8', xml_declaration=True)\n\n\ndef main():\n    combined_root, combined_doc = document(BUSINESS + ' - Draft planning map')\n    placemark(\n        combined_doc,\n        BUSINESS + ' - Fictional business center',\n        'Supplied fictional fixture center; not a verified real business location. '\n        'Draft planning only. Address not supplied.',\n        CENTER_LAT, CENTER_LON)\n\n    outputs = [('sitemap.kml', combined_root)]\n    for ring_number, (radius_m, count) in enumerate(RINGS, start=1):\n        ring_name = f'Ring {ring_number} - {radius_m} m - Planning samples'\n        folder = element(combined_doc, 'Folder')\n        element(folder, 'name', ring_name)\n        split_root, split_doc = document(BUSINESS + ' - ' + ring_name)\n        for index in range(count):\n            bearing = 2.0 * math.pi * index / count\n            lat, lon = destination(radius_m, bearing)\n            name = f'{BUSINESS} - Planning sample R{ring_number}-{index + 1:02d}'\n            note = (\n                f'Draft planning sample; ring {ring_number}, radius {radius_m} m. '\n                'Not an office or business branch; service availability is unverified.')\n            placemark(folder, name, note, lat, lon)\n            placemark(split_doc, name, note, lat, lon)\n        outputs.append((f'ring_{ring_number:02d}.kml', split_root))\n\n    for filename, root in outputs:\n        write_kml(filename, root)\n\n\nif __name__ == '__main__':\n    main()\n",
  "run_instructions": [
    "Save the script as kml_generator.py.",
    "In the intended output directory, run python kml_generator.py with Python 3. No arguments or dependencies are needed.",
    "The script writes sitemap.kml, ring_01.kml, ring_02.kml and ring_03.kml using relative paths."
  ],
  "expected_counts": {
    "sitemap.kml": {
      "center_placemarks": 1,
      "ring_folders": 3,
      "ring_placemarks": [8, 12, 16],
      "total_placemarks": 37
    },
    "ring_01.kml": {"radius_m": 500, "total_placemarks": 8},
    "ring_02.kml": {"radius_m": 1000, "total_placemarks": 12},
    "ring_03.kml": {"radius_m": 2500, "total_placemarks": 16}
  },
  "limitations": [
    "Not executed or externally verified; no files were created during this response.",
    "Uses spherical direct geodesics with equally spaced bearings. At these coordinates and radii, the difference from WGS84 ellipsoidal distance is below the requested 25-meter tolerance.",
    "Fictional draft only. The supplied center is not a verified business location, and ring samples do not establish branches or service availability.",
    "Address and social URLs remain unknown and are omitted. No enrichment, network access, publication or account actions are included."
  ]
}
kml-generator · kimi · without skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: f19a25b946e89cd9a14b62d514936eaaa2b6dd4795c189a61a231f8cd4d36330

runtime passed; import untested: Thirty checks passed on the original spherical-distance generator. Ring descriptions omit business HTML, which was not required; no invented social links or branches.

{
  "script": "from math import asin, atan2, cos, degrees, radians, sin\nfrom pathlib import Path\nfrom xml.sax.saxutils import escape\n\nBUSINESS = 'Cedar & Finch <Drain Care>'\nCATEGORY = 'Drain cleaning & inspection'\nWEBSITE = 'https://cedar-finch.example/?a=1&b=2'\nCENTER_LAT = 43.0731\nCENTER_LON = -89.4012\nRINGS = [\n    {'radius_m': 500, 'markers': 8},\n    {'radius_m': 1000, 'markers': 12},\n    {'radius_m': 2500, 'markers': 16},\n]\nFILES = ['sitemap.kml', 'ring_01.kml', 'ring_02.kml', 'ring_03.kml']\nEARTH_RADIUS_M = 6371008.8\nNL = chr(10)\nQ = chr(39)\n\n\ndef xml_text(value):\n    return escape(str(value))\n\n\ndef destination_point(lat_deg, lon_deg, bearing_deg, distance_m):\n    angular = distance_m / EARTH_RADIUS_M\n    lat1 = radians(lat_deg)\n    lon1 = radians(lon_deg)\n    bearing = radians(bearing_deg)\n    lat2 = asin(sin(lat1) * cos(angular) + cos(lat1) * sin(angular) * cos(bearing))\n    lon2 = lon1 + atan2(\n        sin(bearing) * sin(angular) * cos(lat1),\n        cos(angular) - sin(lat1) * sin(lat2),\n    )\n    lon_norm = ((degrees(lon2) + 180.0) % 360.0) - 180.0\n    if lon_norm == -180.0:\n        lon_norm = 180.0\n    return degrees(lat2), lon_norm\n\n\ndef ring_points(radius_m, markers):\n    pts = []\n    for idx in range(markers):\n        bearing = (360.0 * idx) / markers\n        lat, lon = destination_point(CENTER_LAT, CENTER_LON, bearing, float(radius_m))\n        pts.append((idx + 1, lat, lon, bearing))\n    return pts\n\n\ndef placemark(name, description, lon, lat):\n    return NL.join([\n        '<Placemark>',\n        '<name>' + xml_text(name) + '</name>',\n        '<description>' + xml_text(description) + '</description>',\n        '<Point><coordinates>' + f'{lon:.7f},{lat:.7f},0' + '</coordinates></Point>',\n        '</Placemark>',\n    ])\n\n\ndef kml_document(name, body_lines):\n    lines = [\n        '<?xml version=' + Q + '1.0' + Q + ' encoding=' + Q + 'UTF-8' + Q + '?>',\n        '<kml xmlns=' + Q + 'http://www.opengis.net/kml/2.2' + Q + '>',\n        '<Document>',\n        '<name>' + xml_text(name) + '</name>',\n    ]\n    lines.extend(body_lines)\n    lines.extend(['</Document>', '</kml>'])\n    return NL.join(lines) + NL\n\n\ndef ring_description(radius_m, bearing):\n    return (\n        'Planning sample only: equally spaced point at bearing ' + f'{bearing:.6f}' +\n        ' degrees on a ' + str(radius_m) + ' m geodesic ring around the supplied center. '\n        'Not a business branch, office, or verified service availability.'\n    )\n\n\ndef center_placemark():\n    desc = (\n        'Supplied business center for ' + BUSINESS + ', category ' + CATEGORY + '. Website: ' +\n        WEBSITE + '. Offline fictional fixture center point only; no supplied street address, '\n        'social URL, geocoding, enrichment, upload, publication, or account action.'\n    )\n    return placemark(BUSINESS, desc, CENTER_LON, CENTER_LAT)\n\n\ndef folder_for_ring(ring_index, radius_m, markers):\n    lines = [\n        '<Folder>',\n        '<name>' + xml_text('Ring ' + str(ring_index) + ': ' + str(radius_m) + ' m planning samples') + '</name>',\n    ]\n    for point_no, lat, lon, bearing in ring_points(radius_m, markers):\n        pname = 'Ring ' + str(ring_index) + ' planning sample ' + str(point_no) + ' of ' + str(markers)\n        lines.append(placemark(pname, ring_description(radius_m, bearing), lon, lat))\n    lines.append('</Folder>')\n    return lines\n\n\ndef build_outputs():\n    combined_body = [center_placemark()]\n    ring_bodies = []\n    for ring_index, ring in enumerate(RINGS, start=1):\n        radius_m = ring['radius_m']\n        markers = ring['markers']\n        combined_body.extend(folder_for_ring(ring_index, radius_m, markers))\n        split_body = []\n        for point_no, lat, lon, bearing in ring_points(radius_m, markers):\n            pname = 'Ring ' + str(ring_index) + ' planning sample ' + str(point_no) + ' of ' + str(markers)\n            split_body.append(placemark(pname, ring_description(radius_m, bearing), lon, lat))\n        ring_bodies.append(split_body)\n\n    outputs = {\n        'sitemap.kml': kml_document(BUSINESS + ' offline radius planning fixture', combined_body),\n    }\n    for ring_index, body in enumerate(ring_bodies, start=1):\n        fname = 'ring_' + f'{ring_index:02d}' + '.kml'\n        outputs[fname] = kml_document('Ring ' + str(ring_index) + ' planning samples only', body)\n    return outputs\n\n\ndef main():\n    outputs = build_outputs()\n    if list(outputs.keys()) != FILES:\n        raise RuntimeError('output file list mismatch')\n    total = 1 + sum(ring['markers'] for ring in RINGS)\n    if total != 37:\n        raise RuntimeError('placemark count mismatch')\n    for fname in FILES:\n        with open(Path.cwd() / fname, 'w', encoding='utf-8', newline=NL) as handle:\n            handle.write(outputs[fname])\n\n\nif __name__ == '__main__':\n    main()\n",
  "run_instructions": [
    "Save the JSON script value as generate_kml_fixture.py.",
    "Run: python3 generate_kml_fixture.py",
    "It writes sitemap.kml, ring_01.kml, ring_02.kml, and ring_03.kml in the current working directory and no other files."
  ],
  "expected_counts": {
    "files_written": 4,
    "sitemap_center_placemarks": 1,
    "sitemap_folders": 3,
    "sitemap_total_placemarks": 37,
    "ring_01_placemarks": 8,
    "ring_02_placemarks": 12,
    "ring_03_placemarks": 16,
    "total_ring_planning_samples": 36,
    "radii_m": [500, 1000, 2500],
    "markers_per_ring": [8, 12, 16],
    "network_links": 0,
    "external_icons": 0,
    "social_urls": 0
  },
  "limitations": [
    "Offline fictional fixture only; ring points are planning samples, not branches, offices, verified service availability, or real business locations.",
    "No street address or social URLs were supplied, so they are omitted rather than invented.",
    "Coordinates are generated with a spherical Earth model using the WGS 84 authalic radius; for 500 to 2500 m around the supplied center the radial error is expected to remain far below the 25 m tolerance, but the script does not call an external geodesy service.",
    "KML is base 2.2 markup with escaped text, longitude,latitude,0 coordinates, no NetworkLink, no external icons, no API keys, no downloads, no uploads, no browser launches, and no account actions.",
    "Running the script overwrites the four named relative files if they exist; they are treated as a fresh fixture and not preserved."
  ]
}
kml-generator · kimi · with skill

Resolved model: Not supplied by this CLI receipt

Original answer SHA-256: 1b332e627dc329701182fcc0c9673849cd60c7c8e0dd39616f45c9aa986869dd

runtime passed; import untested: Thirty checks passed on the original Vincenty-distance generator, within 25 m using the independent spherical checker. HTML descriptions preserve supplied special characters. Extra mathematical complexity did not improve the required outcome.

{
  "script": "#!/usr/bin/env python3\nimport html as h\nimport math as m\nfrom xml.sax.saxutils import escape as x\nNS='http://www.opengis.net/kml/2.2'\nBUSINESS='Cedar & Finch <Drain Care>'\nCATEGORY='Drain cleaning & inspection'\nWEBSITE='https://cedar-finch.example/?a=1&b=2'\nLAT=43.0731\nLON=-89.4012\nRINGS=((500,8),(1000,12),(2500,16))\nFILES=('sitemap.kml','ring_01.kml','ring_02.kml','ring_03.kml')\nA=6378137.0\nF=1/298.257223563\nB=6356752.314245\n\ndef esc(s):\n    return x(str(s))\n\ndef hesc(s):\n    return h.escape(str(s),quote=True)\n\ndef dest(lat,lon,bearing,dist):\n    p1=m.radians(lat); l1=m.radians(lon); a1=m.radians(bearing)\n    tu=(1-F)*m.tan(p1); u1=m.atan(tu)\n    s1=m.atan2(tu,m.cos(a1)); sa=m.cos(u1)*m.sin(a1); ca2=1-sa*sa\n    uu=ca2*(A*A-B*B)/(B*B)\n    aa=1+uu/16384*(4096+uu*(-768+uu*(320-175*uu)))\n    bb=uu/1024*(256+uu*(-128+uu*(74-47*uu)))\n    sig=dist/(B*aa); prev=0\n    for _ in range(100):\n        sm2=2*s1+sig\n        ds=bb*m.sin(sig)*(m.cos(sm2)+bb/4*(m.cos(sig)*(-1+2*m.cos(sm2)**2)-bb/6*m.cos(sm2)*(-3+4*m.sin(sig)**2)*(-3+4*m.cos(sm2)**2)))\n        prev,sig=sig,dist/(B*aa)+ds\n        if abs(sig-prev)<1e-12:\n            break\n    su=m.sin(u1); cu=m.cos(u1); ss=m.sin(sig); cs=m.cos(sig)\n    p2=m.atan2(su*cs+cu*ss*m.cos(a1),(1-F)*m.sqrt(sa*sa+(su*ss-cu*cs*m.cos(a1))**2))\n    lam=m.atan2(ss*m.sin(a1),cu*cs-su*ss*m.cos(a1))\n    c=F/16*ca2*(4+F*(4-3*ca2))\n    dl=lam-(1-c)*F*sa*(sig+c*ss*(m.cos(sm2)+c*cs*(-1+2*m.cos(sm2)**2)))\n    return m.degrees(p2),m.degrees(l1+dl)\n\ndef pts(radius,count):\n    out=[]\n    for i in range(count):\n        lat,lon=dest(LAT,LON,360.0*i/count,radius)\n        out.append((lat,lon,i+1))\n    return out\n\ndef desc(lat,lon,ring_no,radius,idx,center=False):\n    if center:\n        inner='<b>'+hesc(BUSINESS)+'</b><br/>Category: '+hesc(CATEGORY)+'<br/>Fictional offline planning center; not a published business location.<br/><a href=\"'+hesc(WEBSITE)+'\">Website</a>'\n    else:\n        inner='<b>'+hesc(BUSINESS)+'</b><br/>Category: '+hesc(CATEGORY)+'<br/>Ring '+str(ring_no)+' sample '+str(idx)+' at '+str(radius)+' m nominal radius.<br/>Planning sample only - not an office, branch, or verified service availability.<br/><a href=\"'+hesc(WEBSITE)+'\">Website</a>'\n    return esc(inner)\n\ndef placemark(name,description,lat,lon):\n    return '    <Placemark>\\n      <name>'+esc(name)+'</name>\\n      <description>'+description+'</description>\\n      <Point><coordinates>'+format(lon,'.7f')+','+format(lat,'.7f')+',0</coordinates></Point>\\n    </Placemark>'\n\ndef doc(name,body):\n    return '<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<kml xmlns=\"'+NS+'\">\\n  <Document>\\n    <name>'+esc(name)+'</name>\\n'+body+'\\n  </Document>\\n</kml>\\n'\n\ndef combined():\n    parts=[placemark('CENTER - '+BUSINESS+' - fictional planning center',desc(LAT,LON,0,0,0,True),LAT,LON)]\n    for rn,(radius,count) in enumerate(RINGS,1):\n        parts.append('    <Folder>\\n      <name>'+esc('Ring '+str(rn)+' - '+str(radius)+' m planning samples')+'</name>')\n        for lat,lon,idx in pts(radius,count):\n            parts.append(placemark(BUSINESS+' planning sample R'+str(rn)+'-'+str(idx),desc(lat,lon,rn,radius,idx),lat,lon))\n        parts.append('    </Folder>')\n    return doc(BUSINESS+' - offline service-area planning fixture','\\n'.join(parts))\n\ndef split(rn,radius,count):\n    parts=[]\n    for lat,lon,idx in pts(radius,count):\n        parts.append(placemark(BUSINESS+' planning sample R'+str(rn)+'-'+str(idx),desc(lat,lon,rn,radius,idx),lat,lon))\n    return doc(BUSINESS+' - ring '+str(rn)+' planning samples only','\\n'.join(parts))\n\ndef main():\n    outputs=(combined(),split(1,500,8),split(2,1000,12),split(3,2500,16))\n    for path,data in zip(FILES,outputs):\n        with open(path,'w',encoding='utf-8',newline='\\n') as f:\n            f.write(data)\n    print('Wrote: '+', '.join(FILES))\n\nif __name__=='__main__':\n    main()\n",
  "run_instructions": "Save the script value as a local offline file such as generate_kml_fixture.py in an empty working directory, then run: python3 generate_kml_fixture.py. It takes no arguments, uses only the Python 3 standard library, performs no network or account actions, and writes only sitemap.kml, ring_01.kml, ring_02.kml, and ring_03.kml in that working directory.",
  "expected_counts": {
    "sitemap.kml": {
      "placemarks_total": 37,
      "business_center_placemarks": 1,
      "ring_folders": 3,
      "ring_placemarks_by_ring": {
        "ring_1_500m": 8,
        "ring_2_1000m": 12,
        "ring_3_2500m": 16
      }
    },
    "ring_01.kml": {
      "placemarks_total": 8,
      "business_center_placemarks": 0,
      "ring_folders": 0,
      "nominal_radius_m": 500
    },
    "ring_02.kml": {
      "placemarks_total": 12,
      "business_center_placemarks": 0,
      "ring_folders": 0,
      "nominal_radius_m": 1000
    },
    "ring_03.kml": {
      "placemarks_total": 16,
      "business_center_placemarks": 0,
      "ring_folders": 0,
      "nominal_radius_m": 2500
    },
    "geodesic_method": "WGS-84 Vincenty direct formula; equal angular spacing starting at bearing 0 degrees; expected distance error is far below the requested 25 m tolerance."
  },
  "limitations": [
    "Offline fictional fixture only; the center and ring points are planning samples and drafts, not branches, offices, published locations, or verified service availability.",
    "Base KML only: no enrichment service, geocoding, uploads, downloads, browser launches, API keys, NetworkLink, external icons, dependencies, account changes, or publication.",
    "No address or social URLs were supplied, so they are omitted rather than invented.",
    "Descriptions contain HTML source escaped as KML text; HTML-sensitive characters are HTML-escaped first and XML-escaped for both combined and split outputs.",
    "The script overwrites only the four listed relative filenames if present and does not inspect, create, modify, or delete any other files."
  ]
}