coldpass

intoapex/tas-guard

GitHub ↗ · How this check works

Per-setup public labels: Linux / Haiku: Works

Static status badge · SVG · read-only JSON. Embed with ![Coldpass status](https://coldpass.dev/badge/intoapex--tas-guard.svg).

mcp-server

Works

The recorded run passed on 1 setup.

Answers apply to each recorded setup, revision and operation. Earlier observations remain in Run details.

Tested on Linux
PlatformHaikuLuna
Linuxyes

Linux / Haiku 5.5: yes · Oct 28, 2026 · 0a50a58fba9a · claude-code / 2.1.310 (Claude Code)
Recorded operation: node src/cli.js demo · local stdio MCP start + initialize + tools/list

Does what it says
3 of 3 claims checked out
  • demo runs the guard in front of a built-in paper broker with simulated prices: Real input produced the expected result: simulated

    Source: `tas-guard demo` runs the guard in front of a built-in paper broker with simulated prices.

    Input: {"tool": "get_stock_latest_quote", "arguments": {"symbol": "SPY"}}

    Expected: simulated quote

    Command: node src/cli.js demo tools/call {"tool": "get_stock_latest_quote", "arguments": {"symbol": "SPY"}}

    Observed: …simulated\"\n}"}]}

  • 1 SPY at $580 is allowed: Real input produced the expected result: accepted

    Source: 1 SPY at $580 (allowed)

    Input: {"tool": "place_stock_order", "arguments": {"symbol": "SPY", "side": "buy", "qty": "1", "type": "limit", "limit_price": "580"}}

    Expected: order accepted

    Command: node src/cli.js demo tools/call {"tool": "place_stock_order", "arguments": {"symbol": "SPY", "side": "buy", "qty": "1", "type": "limit", "limit_price": "580"}}

    Observed: …accepted\"\n }\n}"}]}

  • tas_guard_status shows the limits the guard is working under: Real input produced the expected result: \"max_order_value\": 2000

    Source: Ask the agent to call `tas_guard_status` to see the limits it's working under.

    Input: {"tool": "tas_guard_status", "arguments": {}}

    Expected: status reports max_order_value 2000

    Command: node src/cli.js demo tools/call {"tool": "tas_guard_status", "arguments": {}}

    Observed: …\"max_order_value\": 2000,\n \"max_daily_value\": 5000,\n \"max_orders_per_day\": 20,\n \"max_orders_per_minute\": 3,\n \"approve_over\": 1000,\n \"symbols_allow\": [\n \"SPY\",\n \"QQQ\",\n \"AAPL\",\n \"MSFT\",\n \"NVDA\"\n ],\n \"symbols_block\": [],\n \"live_requires_approval\": false\n },\n \"today\": {\n \"day\": \"2026-10-28\",\n \"value_used\": 1160,\n \"value_left\": 3840,\n \"orders\": 2,\n \"orders_left\": 18\n },\n \"pending_approvals\": []\n}"}]}

MCP
Yes, observed
Local or hosted
local
Local: runs on your machine
Needs keys or browser
None seen
Maintained
Maintained
actively maintained: last commit 0 days ago; 21 commits and 4 merged PRs in 90 days; 0 open issues, 0 open PRs; no releases

Last commit Oct 28, 2026

Setup time
8 min 24 s
8 min 24 s to a working result
Issue
none found in recorded check
Examples
2 of 2 ran as expected
  • Solana mode demo runs seven agent transactions through the guard: command completed successfully

    Source: README.md Solana mode / Try it: `npx tas-guard sol-demo`

    Input: sol-demo

    Expected: guard blocks drainer and over-limit transactions and reports hash chain intact

    Command: node src/cli.js sol-demo

    Observed: so directly. Blocked by policy. 5. Agent: Approve unlimited USDC spending for a contract 🚫 Blocked: Unlimited token delegation to 52oh…3Qx6. Blocked by policy. 6. Agent: Send 150 USDC ($150) 🚫 Blocked: Value $150.00 (0.000005 SOL + 150 USDC (devnet)) is over the per-transaction limit of $100.00. 7. Agent: Pay a 0.14 SOL priority fee 🚫 Blocked: Fee of 0.140005 SOL is over max_fee_sol (0.01 SOL). Priority fee: 100000000 micro-lamports × 1400000 units. Today: 2 sent, $45.00 of $300 used. Audit log: 8 entries, hash chain intact. USDC still in the wallet: 500. The drainer got nothing.

  • Repository offline test suite (README Development section): command completed successfully

    Source: README.md Development

    Input: npm test

    Expected: 78 tests pass

    Command: npm test

    Observed: log is hash-chained, redacts secrets and detects tampering ok 76 - audit log is hash-chained, redacts secrets and detects tampering --- duration_ms: 10.221668 type: 'test' ... # Subtest: approvals are single-use and expire ok 77 - approvals are single-use and expire --- duration_ms: 16.924288 type: 'test' ... # Subtest: config files with a Windows UTF-8 BOM are read ok 78 - config files with a Windows UTF-8 BOM are read --- duration_ms: 5.288989 type: 'test' ... 1..78 # tests 78 # suites 0 # pass 78 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 26672.122397

Evidence
README behavior checked
Agent interfaces
MCP
MCP

Observed interfaces were exercised by the checker. Documentation alone does not confirm compatibility.

MCP context
9 tools · about 556 tokens
9 tools · about 556 tokens

Largest returned tools/list page in these observations. Compact UTF-8 definition bytes ÷ 4, rounded up; approximate, excluding client framing and tool results. This is context size, not proof that every tool works.

Measured on linux with Haiku 5.5 · Oct 28, 2026 on 0a50a58fba9a

Tested with
Claude Code / Haiku 5.5
  • Linux: Claude Code / Haiku 5.5 · agent 2.1.310 (Claude Code) · Checked operation passed · Oct 28, 2026 on 0a50a58fba9a

Each entry describes its recorded operation and source revision.

Safety
No unexpected network or file activity found in these checks

No problems traced to this repository code in these checks; a short run cannot prove safety. 4 static matches retained as context.

Reviewed as expected for a test run: attempted writes that failed, so nothing was written.

Full event, path and process lists for each observed setup:

Run details

Haiku 5.5

Native agent · Checked operation passed

Checked operation node src/cli.js demo · local stdio MCP start + initialize + tools/list

Agent-reported scope: Run TAS Guard demo (tas-guard demo) as an MCP stdio server in front of a built-in paper broker, and call its tools: read a simulated quote, place an allowed 1 SPY limit order, and read the guard status

MCP server returned: tas-guard-demo-broker · version 1.

MCP tools returned: get_account_info, get_stock_latest_quote, get_all_positions, get_orders, place_stock_order, cancel_order_by_id, cancel_all_orders, close_all_positions, tas_guard_status. Tool listing does not establish authenticated tool-call success.

Run details
run
intoapex--tas-guard-claude-haiku-5-5-1793207043866476983
date
Oct 28, 2026
time to working
504.0s
product hosting / execution
Local stdio MCP server in the guest
recorded operation scope
product operation
model
claude-haiku-5-5
agent / version
claude-code / 2.1.310 (Claude Code)
platform
linux
reported cost
$0.034219
Recorded source
https://github.com/intoapex/tas-guard
Backend
hyperv
Tool transport
mcp-assigned-vm
Requested source pin (not an observed revision)
{"commit": "0a50a58fba9a4b5733d6502589ba9113998fe5b7", "url": "https://github.com/intoapex/tas-guard"}
Test version
readme-2d57868128a84902c09a58991c46c5fe288928e55b1de8282ab5003e13159c2f
revision
0a50a58fba9a4b5733d6502589ba9113998fe5b7
Whose fault: not assigned · resolved

Safety: No problems traced to this repository code in these checks. 4 static matches retained as context.

No problems traced to this repository code in these checks. 4 static matches retained as context.

Reviewed as expected for a test run: attempted writes that failed, so nothing was written.

2 encoded blob matches retained as context; full list in the evidence.

2 hardcoded secret matches retained as context; full list in the evidence.

OSV scanned supported lockfiles; unpinned dependencies and unsupported formats are outside this check.

A short run cannot establish that code is safe.

Connections show IP addresses; proxies can hide the final hostname.

Tracing covers dispatched commands and their children, not the whole OS; guest root can interfere with tracing.

Full safety evidence →

Answers recorded for this run
  • demo runs the guard in front of a built-in paper broker with simulated prices: Real input produced the expected result: simulated

    Source: `tas-guard demo` runs the guard in front of a built-in paper broker with simulated prices.

    Input: {"tool": "get_stock_latest_quote", "arguments": {"symbol": "SPY"}}

    Expected: simulated quote

    Command: node src/cli.js demo tools/call {"tool": "get_stock_latest_quote", "arguments": {"symbol": "SPY"}}

    Observed: …simulated\"\n}"}]}

  • 1 SPY at $580 is allowed: Real input produced the expected result: accepted

    Source: 1 SPY at $580 (allowed)

    Input: {"tool": "place_stock_order", "arguments": {"symbol": "SPY", "side": "buy", "qty": "1", "type": "limit", "limit_price": "580"}}

    Expected: order accepted

    Command: node src/cli.js demo tools/call {"tool": "place_stock_order", "arguments": {"symbol": "SPY", "side": "buy", "qty": "1", "type": "limit", "limit_price": "580"}}

    Observed: …accepted\"\n }\n}"}]}

  • tas_guard_status shows the limits the guard is working under: Real input produced the expected result: \"max_order_value\": 2000

    Source: Ask the agent to call `tas_guard_status` to see the limits it's working under.

    Input: {"tool": "tas_guard_status", "arguments": {}}

    Expected: status reports max_order_value 2000

    Command: node src/cli.js demo tools/call {"tool": "tas_guard_status", "arguments": {}}

    Observed: …\"max_order_value\": 2000,\n \"max_daily_value\": 5000,\n \"max_orders_per_day\": 20,\n \"max_orders_per_minute\": 3,\n \"approve_over\": 1000,\n \"symbols_allow\": [\n \"SPY\",\n \"QQQ\",\n \"AAPL\",\n \"MSFT\",\n \"NVDA\"\n ],\n \"symbols_block\": [],\n \"live_requires_approval\": false\n },\n \"today\": {\n \"day\": \"2026-10-28\",\n \"value_used\": 1160,\n \"value_left\": 3840,\n \"orders\": 2,\n \"orders_left\": 18\n },\n \"pending_approvals\": []\n}"}]}

Examples

  • Solana mode demo runs seven agent transactions through the guard: command completed successfully

    Source: README.md Solana mode / Try it: `npx tas-guard sol-demo`

    Input: sol-demo

    Expected: guard blocks drainer and over-limit transactions and reports hash chain intact

    Command: node src/cli.js sol-demo

    Observed: so directly. Blocked by policy. 5. Agent: Approve unlimited USDC spending for a contract 🚫 Blocked: Unlimited token delegation to 52oh…3Qx6. Blocked by policy. 6. Agent: Send 150 USDC ($150) 🚫 Blocked: Value $150.00 (0.000005 SOL + 150 USDC (devnet)) is over the per-transaction limit of $100.00. 7. Agent: Pay a 0.14 SOL priority fee 🚫 Blocked: Fee of 0.140005 SOL is over max_fee_sol (0.01 SOL). Priority fee: 100000000 micro-lamports × 1400000 units. Today: 2 sent, $45.00 of $300 used. Audit log: 8 entries, hash chain intact. USDC still in the wallet: 500. The drainer got nothing.

  • Repository offline test suite (README Development section): command completed successfully

    Source: README.md Development

    Input: npm test

    Expected: 78 tests pass

    Command: npm test

    Observed: log is hash-chained, redacts secrets and detects tampering ok 76 - audit log is hash-chained, redacts secrets and detects tampering --- duration_ms: 10.221668 type: 'test' ... # Subtest: approvals are single-use and expire ok 77 - approvals are single-use and expire --- duration_ms: 16.924288 type: 'test' ... # Subtest: config files with a Windows UTF-8 BOM are read ok 78 - config files with a Windows UTF-8 BOM are read --- duration_ms: 5.288989 type: 'test' ... 1..78 # tests 78 # suites 0 # pass 78 # fail 0 # cancelled 0 # skipped 0 # todo 0 # duration_ms 26672.122397

Local or hosted: local

What the agent did

Run TAS Guard demo (tas-guard demo) as an MCP stdio server in front of a built-in paper broker, and call its tools: read a simulated quote, place an allowed 1 SPY limit order, and read the guard status

cd <guest-path> && ls -la && git status 2>&1 | head -3; cat README.md 2>/dev/null | head -c 6000
python3 --version; echo $CDP_URL; curl -sS -m 10 $CDP_URL/json/version; echo; echo EXIT=$?
cd <guest-path> && grep -n '^#' README.md; cat package.json; ls src test profiles docs; node --version; npm --version
cd <guest-path> && sed -n 93,140p README.md; sed -n 464,520p README.md
cd <guest-path> && grep -n "demo\|command ===\|case '" src/cli.js | head -60; grep -n "name:" src/demo-broker.js | head -20; ls -la .coldpass
cd <guest-path> && timeout 280 npm test 2>&1 | tail -25
cd <guest-path> && npm link 2>&1 | tail -3; which tas-guard; tas-guard --help 2>&1 | head -12
cd /tmp && export HOME=/tmp/tg-home && mkdir -p $HOME && printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"get_stock_latest_quote","arguments":{"symbol":"SPY"}}}' | timeout 20 node <guest-path> demo 2>/tmp/tg-err.txt; echo EXIT=$?; cat /tmp/tg-err.txt | head -5
cd <guest-path> && sed -n 14,16p src/demo-broker.js | cut -c1-600; grep -n "tas_guard_status" src/*.js | head -3
cd /tmp && export HOME=/tmp/tg-home && printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"10","type":"limit","limit_price":"580"}}}' '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"1","type":"limit","limit_price":"580"}}}' | timeout 20 node <guest-path> demo 2>/dev/null | cut -c1-700
cd <guest-path> && grep -n "defaultStateDir" -A4 src/state.js | head -12; sed -n 102,125p src/cli.js | cut -c1-300
cd <guest-path> && grep -n -i "setInterval\|cron\|--once\|--now\|poll\|webhook" src/*.js README.md | cut -c1-220 | head -20; sed -n 152,160p README.md | cut -c1-400
mkdir -p <guest-path> && cat > <guest-path> <<'EOF'
{"kind":"mcp","argv":["node","src/cli.js","demo"],"cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-probe"},"tool":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"1","type":"limit","limit_price":"580"},"expected_text":"accepted"}
EOF
cat > <guest-path> <<'EOF'
[
{"kind":"claim","claim":"demo runs the guard in front of a built-in paper broker with simulated prices","source":"`tas-guard demo` runs the guard in front of a built-in paper broker with simulated prices.","input":"get_stock_latest_quote SPY","expected":"simulated quote","probe_kind":"mcp","argv":["node","src/cli.js","demo"],"tool":"get_stock_latest_quote","arguments":{"symbol":"SPY"},"expected_text":"simulated","cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-claim1"}},
{"kind":"claim","claim":"1 SPY at $580 is allowed","source":"1 SPY at $580 (allowed)","input":"place_stock_order qty 1 limit 580","expected":"order accepted","probe_kind":"mcp","argv":["node","src/cli.js","demo"],"tool":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"1","type":"limit","limit_price":"580"},"expected_text":"accepted","cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-claim2"}},
{"kind":"claim","claim":"10 SPY is blocked over the per-order limit","source":"10 SPY (blocked: over the $2,000 per-order limit)","input":"place_stock_order qty 10 limit 580","expected":"blocked by guard","probe_kind":"mcp","argv":["node","src/cli.js","demo"],"tool":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"10","type":"limit","limit_price":"580"},"expected_text":"is over the per-order limit of 2,000","cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-claim3"}}
]
EOF
python3 -I -c 'import json;json.load(open("<guest-path>"));json.load(open("<guest-path>"));print("ok")'
cd <guest-path> && export TAS_GUARD_HOME=/tmp/tg-state-ex && timeout 120 node src/cli.js sol-demo 2>&1 | tail -15; echo EXIT=${PIPESTATUS[0]}
cd <guest-path> && cat > examples.json <<'EOF'
[
{"kind":"example","claim":"Solana mode demo runs seven agent transactions through the guard","source":"README.md Solana mode / Try it: `npx tas-guard sol-demo`","input":"sol-demo","expected":"guard blocks drainer and over-limit transactions and reports hash chain intact","argv":["node","src/cli.js","sol-demo"],"cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-ex"},"expected_text":"hash chain intact"},
{"kind":"example","claim":"Repository offline test suite (README Development section)","source":"README.md Development","input":"npm test","expected":"78 tests pass","argv":["npm","test"],"cwd":"<guest-path>","env":{},"expected_text":"# fail 0"}
]
EOF
cat > cycles.json <<'EOF'
{"detected":false,"checks":[],"reason":"Inspected README.md (Quick start, Try it, Phone approvals and kill switch) and src/cli.js, src/telegram.js, src/proxy.js. The only recurring loop is Telegram long-polling (src/telegram.js poll) that talks to an external Telegram Bot API; it cannot be triggered locally without external notifications, which are not allowed. No cron, --once, --now or webhook trigger exists in the product, so no manual cycle was run."}
EOF
python3 -I -c 'import json;[json.load(open(f)) for f in ["examples.json","cycles.json"]];print("ok")'
cd <guest-path> && <env-var>=<guest-path> timeout 900 python3 -I <guest-path> --validate --replay 2>&1 | tail -c 5000; echo EXIT=${PIPESTATUS[0]}
cd <guest-path> && grep -n -i "isError\|is_error" checker/check.py | head -20; grep -n "def .*expected_text\|expected_text" checker/check.py | head -20
cd <guest-path> && <env-var>=<guest-path> timeout 900 python3 -I <guest-path> --validate --replay > /tmp/validate.out 2>&1; echo EXIT=$?; python3 -I -c '
import json,sys
t=open("/tmp/validate.out").read()
print(t[:1500])' 
ls -la /tmp/tg-state-* /tmp/tg-home/.tas-guard/guards 2>&1 | head -30; grep -n "per_minute\|perMinute\|minute" <guest-path> <guest-path> | head; grep -n "TAS_GUARD_HOME\|env" <guest-path> | head -20
cd <guest-path> && sed -n 1108,1118p checker/check.py; sed -n 1160,1170p checker/check.py; ls -d /tmp/tg-state-* ; cat /tmp/tg-state-probe/audit.jsonl | cut -c1-160 | tail -5
cd /tmp && printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"tas_guard_status","arguments":{}}}' | TAS_GUARD_HOME=/tmp/tg-state-status timeout 20 node <guest-path> demo 2>/dev/null | tail -1 | cut -c1-1200
cd /tmp && printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"tas_guard_status","arguments":{}}}' | TAS_GUARD_HOME=/tmp/tg-state-status timeout 20 node <guest-path> demo > /tmp/st.out 2>/tmp/st.err; echo EXIT=$?; cut -c1-1500 /tmp/st.out; cat /tmp/st.err | head -5
cd <guest-path> && cat > probe.json <<'EOF'
{"kind":"mcp","argv":["node","src/cli.js","demo"],"cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-run2"},"tool":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"1","type":"limit","limit_price":"580"},"expected_text":"accepted"}
EOF
cat > claims.json <<'EOF'
[
{"kind":"claim","claim":"demo runs the guard in front of a built-in paper broker with simulated prices","source":"`tas-guard demo` runs the guard in front of a built-in paper broker with simulated prices.","input":"get_stock_latest_quote SPY","expected":"simulated quote","probe_kind":"mcp","argv":["node","src/cli.js","demo"],"tool":"get_stock_latest_quote","arguments":{"symbol":"SPY"},"expected_text":"simulated","cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-run2"}},
{"kind":"claim","claim":"1 SPY at $580 is allowed","source":"1 SPY at $580 (allowed)","input":"place_stock_order qty 1 limit 580","expected":"order accepted","probe_kind":"mcp","argv":["node","src/cli.js","demo"],"tool":"place_stock_order","arguments":{"symbol":"SPY","side":"buy","qty":"1","type":"limit","limit_price":"580"},"expected_text":"accepted","cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-run2"}},
{"kind":"claim","claim":"tas_guard_status shows the limits the guard is working under","source":"Ask the agent to call `tas_guard_status` to see the limits it's working under.","input":"tas_guard_status","expected":"status reports max_order_value 2000","probe_kind":"mcp","argv":["node","src/cli.js","demo"],"tool":"tas_guard_status","arguments":{},"expected_text":"\"max_order_value\": 2000","cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-run2"}}
]
EOF
python3 -I -c 'import json;json.load(open("probe.json"));json.load(open("claims.json"));print("ok")'
cd <guest-path> && <env-var>=<guest-path> timeout 900 python3 -I <guest-path> --validate --replay > /tmp/validate2.out 2>&1; echo EXIT=$?; python3 -I -c '
import json
t=open("/tmp/validate2.out").read()
print(t[:900])
d=json.loads(t[t.index("{"):]) if False else None
print("valid" , "valid\": true" in t, "problems:", t.count("problems"))
' ; grep -o '"valid": [a-z]*' /tmp/validate2.out; grep -o '"problems": \[[^]]*\]' /tmp/validate2.out | cut -c1-600
cd <guest-path> && sed -n 1266,1274p checker/check.py | cut -c1-260
cd <guest-path> && python3 -I - <<'EOF'
import json
p="<guest-path>"
c=json.load(open(p))
c[2]["expected_text"]='\\"max_order_value\\": 2000'
json.dump(c,open(p,"w"),indent=1,ensure_ascii=False)
print(repr(c[2]["expected_text"]))
EOF
cd <guest-path> && <env-var>=<guest-path> timeout 900 python3 -I <guest-path> --validate --replay > /tmp/validate3.out 2>&1; echo EXIT=$?; grep -o '"valid": [a-z]*' /tmp/validate3.out; grep -o '"problems": \[[^]]*\]' /tmp/validate3.out | cut -c1-400
cd <guest-path> && cat > probe.json <<'EOF'
{"kind":"mcp","argv":["node","src/cli.js","demo"],"cwd":"<guest-path>","env":{"TAS_GUARD_HOME":"/tmp/tg-state-run3"},"tool":"get_stock_latest_quote","arguments":{"symbol":"SPY"},"expected_text":"simulated"}
EOF
python3 -I -c 'import json;json.load(open("<guest-path>"));print("ok")'; sleep 75; cd <guest-path> && <env-var>=<guest-path> timeout 900 python3 -I <guest-path> --validate --replay > /tmp/validate4.out 2>&1; echo EXIT=$?; grep -o '"valid": [a-z]*' /tmp/validate4.out; grep -o '"problems": \[[^]]*\]' /tmp/validate4.out | cut -c1-400
cd /tmp && grep -o '"status": "[A-Za-z]*"' /tmp/validate4.out | sort | uniq -c; grep -o '"verdict": "[a-z]*"' /tmp/validate4.out | sort | uniq -c; grep -o '"evidence_strength": "[a-z_]*"' /tmp/validate4.out; TAS_GUARD_HOME=/tmp/tg-state-run3 true; cat /tmp/tg-state-run2/guards/demo.usage.json 2>/dev/null | head -c 300
cd <guest-path> && python3 -I - <<'EOF'
import json
r = {
 "outcome": "working",
 "fault_owner": None,
 "operation": "Run TAS Guard demo (tas-guard demo) as an MCP stdio server in front of a built-in paper broker, and call its tools: read a simulated quote, place an allowed 1 SPY limit order, and read the guard status",
 "operation_scope": "Node.js >=18 (engines), tested on Node v22.23.4 / npm 10.9.9; zero npm dependencies; no broker account, no real money; local stdio only; CDP endpoint not used (no browser operation)",
 "steps": [
  "Read README.md (Try it in 10 seconds; Quick start; Development)",
  "node --version / npm --version (v22.23.4 / 10.9.9 present; README requires node >=18 per package.json engines)",
  "npm test (README Development: 78 tests) -> 78 pass, 0 fail",
  "node src/cli.js demo (stands in for `npx -y tas-guard demo`; see deviations) driven over MCP stdio",
  "tools/call get_stock_latest_quote {symbol: SPY} -> simulated bid/ask 579.71/580.29",
  "tools/call place_stock_order {SPY, buy, qty 1, limit 580} -> status accepted",
  "tools/call place_stock_order {SPY, buy, qty 10, limit 580} -> blocked: 'Order value 5,800 is over the per-order limit of 2,000' (isError true, observed manually)",
  "tools/call tas_guard_status {} -> max_order_value 2000, max_daily_value 5000, max_orders_per_minute 3",
  "node src/cli.js sol-demo -> exit 0, 'hash chain intact' (README Solana mode example)",
  "<env-var>=<guest-path> python3 -I <guest-path> --validate --replay -> valid true, replay PASS"
 ],
 "deviations": [
  "`npx -y tas-guard demo` was not used: the repo is the pinned source, so the local bin target src/cli.js was run with node instead. `npm link` to install the tas-guard bin failed with EACCES on the global npm prefix (not writable); no sudo install was attempted.",
  "Replacing the README's sequence of 1 SPY allowed / 10 SPY blocked claims: the checker treats any MCP result with isError:true as a failure (check.py line ~1273), and the guard reports blocks with isError:true by design. The blocked-order behavior was observed manually (see steps) but is NOT validated by claims.json; the status claim (tas_guard_status) was used instead.",
  "First validation attempt failed for harness reasons, not product reasons: the checker applies each probe/claim env to os.environ globally, so all replays shared one TAS_GUARD_HOME state directory, and the guard's max_orders_per_minute=3 limit tripped when the probe and order claims ran within one minute. Fixed by using one fresh state dir (/tmp/tg-state-run2 for claims, /tmp/tg-state-run3 for the probe), making the probe a read-only quote, and waiting 75s before the final run. The policy was not changed.",
  "The demo's stdio server exits with code 1 when stdin closes (`upstream exited (null)`), which is the demo's normal end-of-session behavior; the checker accepted this.",
  "Daily state persists in /tmp/tg-state-run2 (3 orders, 1740 of 5000 spent). Repeat replays of the allowed-order claim add 580 each until the daily cap; the per-minute cap of 3 applies to order calls within a rolling minute.",
  "cycles: no product cycle detected. The only loop is Telegram long-polling against an external service, which cannot be exercised locally without external notifications."
 ],
 "stuck_step": None,
 "main_blocker": None,
 "plain_failure": None,
 "suggested_fix": "None needed for the product. For the checker: treat an MCP isError result that carries an expected blocked message as a valid verdict, and scope env/state per claim so policy counters do not leak between replays."
}
json.dump(r, open("<guest-path>","w"), indent=1, ensure_ascii=False)
print(open("<guest-path>").read()[:400])
EOF
ls -la <guest-path>; ls <guest-path> | grep -c '^report.json$'