CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/nanoclaw-orders

Order-email triage for NanoClaw as a per-chat overlay plugin: fetches order-related Gmail, maintains the orders SQLite table, flags recent anomalies (cancellations/refunds, overdue deliveries, orders stuck in 'ordered' that never shipped), and ships a cadence companion that runs it on a schedule.

77

Quality

96%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

ack-orders.pyskills/check-orders/scripts/

#!/usr/bin/env python3
"""Acknowledge a set of orders as delivered, by id.

Owner-ack tool (`jbaruch/nanoclaw-orders#61`). When the owner says "these
arrived / I've got them" about flagged orders, the ack must be *persisted
where the stuck detector reads it* — otherwise the row stays `status =
'ordered'` and `compute-stuck-orders.py` (Step 8) re-flags it every run.
`unflag-orders.py` only clears `flagged`; the status stays `ordered`, so
a stuck-order alert the owner acked resurfaces the next night. This is the
"roach motel" half of #61.

This script transitions each acked row to the synthetic terminal
`assumed_delivered` (same status `promote-stale-shipped.py` uses), which
`compute-stuck-orders.py` treats as shipped and Step 9 never flags. The
row leaves the `ordered` pool for good, so the ack sticks.

Only `ordered`/`shipped` rows are eligible — acking is meaningful only for
a live, in-flight order. A `cancelled`/`refunded`/already-terminal row is
left untouched (counted as `not_acked`) rather than silently overwritten.

Reads ids from stdin (one per line, leading/trailing whitespace tolerated,
blank lines ignored). Each `UPDATE` is parameter-bound.

Stdout on success: `{"acked": <int>, "not_acked": <int>}`. `acked` counts
ids whose row was eligible and transitioned (`cursor.rowcount > 0`);
`not_acked` counts ids that matched no eligible row (stale id, never
imported, or already terminal — diagnostic, not an error).

This is an ad-hoc tool invoked outside the nightly flow, in response to an
owner acknowledgement — not a Step in the sequential check-orders run.

Exit codes: 0 success, 1 IO/schema error.
"""

from __future__ import annotations

import json
import os
import sqlite3
import sys
from datetime import datetime, timezone

DB_PATH = os.environ.get("ORDERS_DB_PATH", "/workspace/store/messages.db")


def main() -> int:
    try:
        raw = sys.stdin.read()
    except OSError as exc:
        sys.stderr.write(
            f"ack-orders: failed to read order ids from stdin: {exc}. "
            f"Pipe the ids to ack, one per line, e.g. "
            f"`printf '%s\\n' <id1> <id2> | python3 ack-orders.py`.\n"
        )
        return 1
    ids = [line.strip() for line in raw.splitlines() if line.strip()]
    if not ids:
        # No ids to ack — degenerate but legal.
        json.dump({"acked": 0, "not_acked": 0}, sys.stdout)
        sys.stdout.write("\n")
        return 0

    now_iso = datetime.now(timezone.utc).isoformat()
    acked = 0
    not_acked = 0
    conn = None
    try:
        conn = sqlite3.connect(DB_PATH)
        # Single transaction so the ack set is all-or-nothing per
        # invocation — a transient failure mid-batch leaves the table
        # untouched and the agent can safely re-run with the same ids.
        with conn:
            for order_id in ids:
                cur = conn.execute(
                    """
                    UPDATE orders
                       SET status = 'assumed_delivered',
                           flagged = 0,
                           flag_reason = NULL,
                           last_updated = ?
                     WHERE id = ?
                       AND status IN ('ordered', 'shipped')
                    """,
                    (now_iso, order_id),
                )
                # rowcount is 1 when the id existed AND was in an ackable
                # status; 0 when the id is missing or already terminal.
                if cur.rowcount > 0:
                    acked += 1
                else:
                    not_acked += 1
        json.dump({"acked": acked, "not_acked": not_acked}, sys.stdout)
        sys.stdout.write("\n")
        return 0
    except sqlite3.Error as exc:
        sys.stderr.write(
            f"ack-orders: SQLite error against {DB_PATH}: {exc}. "
            f"Verify the database file exists, is writable, and the "
            f"orders table is present (created by the orchestrator's "
            f"state-001 migration).\n"
        )
        return 1
    finally:
        if conn is not None:
            conn.close()


if __name__ == "__main__":
    sys.exit(main())

README.md

tile.json