With fd=F or fd=D, IPOT's footer covers only that side's buying: BBCA's
foreign/regular summary for 2026-10-16 gives T. Val 1.6 T while its top
seller alone sold 2.0 T. Passing it through as the range total gave
consumers a denominator smaller than one listed broker, so total_value,
total_lots and average_price are now null for an investor-filtered summary.
The page-to-summary step is a pure function, tested on both fixtures.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Adds a BrokerSummaryProvider capability served by Indo Premier's public
broker summary page: the top 10 buyers and sellers of a stock by lots over
a date range, with totals. No login or key.
- api/ipot: pure parser (decimal scaling of `1.6 M`-style figures), a
client that retries the server's spurious 404s, and a fixture mock.
- broker: Broker::summary/latest over the cache (7 days for closed ranges,
5 minutes for today), range checks, and IDX member names bundled from
GetBrokerCodeList.
- foreign_net_value is null for filtered summaries: the source does not
apply the filters to it.
The endpoint's behavior was first mapped by fzn0x/idx (MIT).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Patch release for the full-repo audit of 0.3.2: ownership query
correctness (changes, alias search, graph, investor lookup), snapshot
sync safety, request and lock time limits, the CLI output contract and
terminal-safe output, fundamental rating logic, publisher and installer
robustness, and zip off a yanked release (#51).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Codex re-gate of the 0.3.3 fixes: NUL-separated discovery
fields need jq 1.7 (--raw-output0) and bash 4.4 (mapfile -d); check both
up front with a clear message instead of failing midway on older tools.
ci.yml actions are pinned to commit SHAs like the release workflows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the full-repo Codex audit:
- The publisher read discovery fields one per line, so a report title
with newlines shifted every later field and published a manifest
without source.publish_date, which every client rejects (blocking all
syncs). Read them NUL-separated, and refuse to write a manifest missing
a field clients require.
- The snapshot builder copied the SQLite file with cp; committed data
still in the -wal file of an open database would be missing. Checkpoint
first (a no-op for the publisher's closed database, so the bytes and
hash are unchanged) and refuse to copy when that cannot complete.
- install.sh took the tag from a greedy match, which on a compact
single-line releases response picks the last tag, not the newest (it
installed v0.2.3 over v0.2.4 in the new test). Split fields first.
- scripts/audit-msn-fundamentals.sh read the symbol map from a path that
no longer exists and silently checked no stocks.
- release.yml granted contents: write to every job; only publish gets it
now. Actions in the release and snapshot workflows are pinned to commit
SHAs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the full-repo Codex audit:
- The overall fundamental rating was "healthy" whenever growth was
growing and valuation and risk were merely not "expensive" / not "high
risk", so with no valuation or risk data at all (partial MSN
fundamentals) it still read "healthy". It now needs valuation
undervalued or fairly valued and risk low or moderate.
- Risk recognized only heavy leverage or a weak current ratio as high
risk; negative equity fell through to "moderate risk", and a known
adverse signal with the other metric missing became "incomplete data".
Any known adverse signal now makes it high risk.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
`idx config --help` lists the keys and says when it prints JSON;
`ownership changes` says both dates must be imported releases and that
accounts are summed; `ownership search` and `entity` describe alias and
substring matching. Regenerated the CLI reference page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Auto output stays plain text when piped, as in 0.3.2, so scripts that
read $(idx config path) or $(idx config get KEY) keep working; -o json,
IDX_OUTPUT=json, or general.output = "json" print JSON. The config
goldens return to their 0.3.2 content.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Dropping an unknown argument can expose a later --help, and clap then
returns no matches, losing an -o already read. Keep the last pass that
read one (Pullfrog review on #56).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
clap stops parsing at an unknown argument, so `idx config get --bogus
-o json` lost the -o. Drop each unknown argument and parse again
before reading the output flag (Pullfrog review on #56).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The raw scan took the first -o and missed clustered short flags, so
`idx -o table config -o json get` and `idx -qojson config get` printed
plain-text errors. Resolve -o with clap itself, ignoring the error being
reported (Pullfrog review on #56).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the narrow Codex confirmation: provider, KSEI, and manifest text
still reached the terminal through error messages (a Yahoo error
description, a manifest's `kind`), idx-core diagnostics, the ownership
heading's ticker code and Bing date, the technical heading and
comparison symbol, and printed paths. Sanitize where every error
(emit_error) and every diagnostic (runtime) is printed instead of at each
caller, plus the remaining direct prints. terminal_safe moves to
idx_core::text so the runtime can use it; the CLI re-exports it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the second Codex re-gate: the empty-sentiment line printed MSN's
symbol raw, so a hostile response could clear the screen. Sweep every
print in the table and ownership renderers that interpolates data: the
sentiment and analysis headings, stale-quote notes, sync reasons, flow
period, search query, alias mapping, and DOT graph output.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Codex re-gate of the 0.3.3 fixes:
- Colored signal cells (Bullish/Bearish, ratings, ownership change and
flow labels) were painted before the new cell sanitizer, which turned
their escape codes into U+FFFD on every color terminal; the goldens run
without color and missed it. Labels idx produces itself go into cells
untouched (`painted`), with the label made safe before styling.
- Statement dates and currency, and the entity name in `ownership
entity`, still reached the terminal unsanitized.
- The JSON-mode argument handler read std::env::args(), which panics on
a non-UTF-8 argument (exit 101 instead of 2); use args_os.
- A missing subcommand printed help as plain text in JSON mode; it is an
error (exit 2), so it is a JSON error there too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the full-repo Codex audit:
- Provider and KSEI text reached the terminal raw, so an escape sequence
in a news title or insight could clear or rewrite the screen. Every
table cell, insight line, and graph label now has control characters
and bidirectional overrides replaced.
- Table rendering sliced strings by byte (a description at 200, a URL at
72, an earnings period), panicking when a multi-byte character such as
"’" or "é" fell on the cut. Truncate by character.
- In JSON mode, argument errors were clap's plain text and warnings were
plain lines ahead of the JSON error. Argument errors are now the usual
JSON error (INVALIDINPUT, exit 2) when JSON output is selected, and
diagnostics are JSON lines; --help and --version are unchanged.
- `config` commands ignored the output format; they follow it like every
other command (JSON when piped or with -o json, text on a terminal).
- Ownership argument mistakes (--limit 0, --format, missing or
conflicting import sources, --family, an empty graph root) returned
PARSEERROR / exit 1; they are INVALIDINPUT / exit 2 as documented.
- `cache clear` followed symlinked directories and deleted files outside
the cache; it now removes links without following them.
Output change, intentional: goldens regenerated for the JSON argument
error and the five config commands, which run with stdout piped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Reverts a360d0b. A separate process group let an overflow kill the curl
behind a profile script, but Ctrl+C then reached only idx and left a
stalled transfer running (Pullfrog review on #55). Cancellation is the
common path; on overflow, curl still ends on its next write to the
closed pipe, and the error returns at once either way.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Run curl in its own process group and kill the group, so the curl
behind a curl_* wrapper script ends at once instead of at its next
write or --max-time (Pullfrog review on #55).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The curl_* profiles run curl without exec, so killing the wrapper left
curl holding stderr, and joining stderr waited up to --max-time. Close
stdout and return; curl ends on its next write (Pullfrog review on #55).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Command::output() buffered the whole response before the size check, and
curl before 8.20 does not apply --max-filesize to decoded bodies, so a
small compressed response could exhaust memory. Read stdout up to the
limit, then kill and reap curl (Pullfrog review on #55).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Codex re-gate of the 0.3.3 fixes: the price sanity check also
applied to MSN's priceChange, so a falling stock without a previous close
got change: null. Bound a change by its size instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the full-repo Codex audit:
- MSN and Yahoo clients set connect and body timeouts but none for the
response headers, so a server that stalled before answering hung the
call; four such calls take every MCP call slot. Add a 30 s overall
deadline. Every curl-impersonate run gets --max-time 600 and a 256 MiB
--max-filesize, and output above that is rejected (curl cannot cap a
response without a length); the Yahoo cookie fetch gets --max-time.
- Ownership commands blocked on the database lock without limit, so a
long sync or import, or a stuck process, held MCP call slots
indefinitely. Wait up to 30 s, then fail with a "busy, try again" error.
- A price of 1e20 saturated `as i64` and the change subtraction then
overflowed. Prices that are not finite, negative, or above 1e12 IDR are
treated as missing, and a quote's own price as an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
A pre-0.3.3 install interrupted between its renames left only a backup.
Restoring it inside the install step came after the decision, so an
older snapshot replaced a newer database without --force, and a failed
download left no database (Pullfrog review on #54).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Codex re-gate of the 0.3.3 fixes:
- Imports recorded row_count as the rows parsed, but INSERT OR IGNORE
drops a file's repeated ticker/investor rows, so the count could exceed
what is stored, and the new stored-row validation would then reject a
snapshot the publisher built from such a file. Record the rows stored.
- A local manifest over the 1 MiB limit was read truncated rather than
rejected; read one byte more and fail when it does not fit.
- The backup-recovery test also passed on the old code; it now fails an
install after the leftover backup was found and checks the old data is
back.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the full-repo Codex audit:
- Install moved the database to a backup, then renamed the snapshot in;
a crash between the two left no database, and the next sync deleted the
backup first. Replace it with a single rename (old file or new, never
neither), and restore a backup an older version left behind.
- Validation trusted the release's row_count metadata, so a snapshot with
an empty or missing holdings table passed and replaced good data. Also
count the rows stored for the latest release.
- A manifest fetched over HTTP(S) could name a local download_url such as
/dev/zero, read without a size limit. Remote manifests must give an
HTTP(S) artifact; local reads take regular files only, within the size
limit, and manifests are capped at 1 MiB.
- A same-date build with a different row count replaced the local file
even when it did not list it in replaces_sqlite_sha256, so a replayed
older build could undo a corrected one. Same-date rebuilds now go only
through replaces_sqlite_sha256, which the publisher fills.
Verified against the published snapshot: fresh install, no-op re-sync,
and forced reinstall all succeed with no leftover files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
A KSEI file can carry rows from several report dates; its release is
dated by the latest. Filtering on the release alone pulled January rows
into a February comparison (Pullfrog review on #53).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
id is the rowid alias in the real schema; rowid also works on the
minimal fixture DBs the publisher tests build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Codex re-gate of the 0.3.3 fixes:
- `changes` broke ties between same-date releases by row id, but the
ticker, entity, and graph queries and the snapshot builder did not, so
two files imported in the same second could resolve differently per
query. Order by as_of_date, imported_at, then id everywhere.
- search::fts_search and search::rebuild_fts were public in a published
crate; keep them as deprecated wrappers.
- Invalid --source and --by are INVALIDINPUT, like other argument errors.
- The prefix-ranking test could not tell prefix from exact-alias ranking;
add one where only prefix vs substring differs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From a full-repo Codex audit, each reproduced on the synced ownership DB:
- `changes` paired an investor's accounts across releases instead of
comparing totals: KREN's KRESNA PRIMA INVEST went 9.44% -> 13.45% (a
second 4.01% account) but was reported as decreased 944 -> 401 bps.
Sum a holder's accounts per ticker, and read one release per date (the
latest imported, as other queries do), so a corrected file supersedes
the original instead of mixing with it.
- `changes` / get_ownership_changes accepted any dates: `from: ""`
reported all 7,154 holders as new, unknown dates returned no changes.
Dates must be YYYY-MM-DD imported releases with `from` before `to`.
- get_investor_holdings / `entity` with an empty name matched every
investor and returned an arbitrary one ("AMY"); `%` and `_` acted as
LIKE wildcards. Reject empty names; match wildcards literally.
- Alias search never worked: the FTS table declared an `aliases` column
its content table lacks (`no such column: T.aliases`), so searches
fell back to canonical names and a raw KSEI name such as
"PT ASTRA INTERNATIONAL TBK" found nothing. Search names and aliases
directly, ranked exact name, exact alias, prefix, then shorter names.
- `graph` enumerated every path (exponential in depth) and its cycle
check matched substrings, dropping entity:1 when entity:10 was on the
path. Traverse breadth-first with an exact visited set.
- Name normalization removed leading PT tokens from the front of a Vec,
quadratic in hostile names; narrow a slice instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Every zip 2.x release from 2.4.2 on is yanked; crates.io warned on each
0.3.2 publish. zip 9 returns entry names as a Result (it validates their
encoding): skip undecodable names, which can be neither the archive's TXT
payload nor an XLSX worksheet. zip 9 needs Rust 1.88, within our 1.89.
Closes#51.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Notes in the style of other open-source releases: an upgrade line when
urgent, New Features / Bug Fixes / Improvements with one user-facing
sentence and PR numbers per item, and a Full Changelog compare link.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Patch release for the npm launcher fix (#41, #42): `idx` and `idx-mcp`
now install their binary on first run when the package manager skipped
postinstall, as npm 12 does under `npx` with its `allow-scripts` policy
(and pnpm 10+ and bun by default).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Pullfrog review of #48: an offset at or past `total` returns an
empty page with `next_offset: null`, and every page carries the same
`summary` (it covers all rows). Assert both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
Between the two latest releases there are 1,568 holder changes. With only
`limit` (up to 2000, ~200 KB), agents that wanted them all overflowed
their tool output: Hermes then paged ticker by ticker (32 calls), and
opencode 1 and 2 did the same and timed out.
- `offset` pages through the rows; responses carry `offset` and
`next_offset` (null after the last page). Pages cap at 300 rows
(~40 KB); the over-limit error points to `offset` and `summary`.
- Rows come largest |delta| first, so the first page holds the moves
that matter rather than tickers starting with A.
- `summary` covers every row: counts by change type, the number of
tickers, and the ten tickers with the most changes.
The CLI's `ownership changes` is unchanged. tools.json and the website's
MCP pages are regenerated for the new description and parameter.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
- Why not a browser per user: a full engine per install and fetch, each
user facing the challenge, IDX seeing thousands of scrapers; one
scheduled publisher serving static files instead (diagram). Hosting
left open (GitHub release, Cloudflare Pages/R2, a Worker).
- The IDX challenge is JavaScript-based: curl fails from a second
datacenter (greencloud-vps, Singapore) too, so IP is not what curl
lacks.
- Other sources measured: Google News RSS covers companies MSN misses
(BREN 75/100 titles naming the ticker in 7 days), plain HTTP; Yahoo
search answers 429.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
MSN has no company news for many tickers; IDX's disclosures cover every
issuer. idx.co.id is behind a Cloudflare challenge that plain curl and
curl-impersonate fail from the maintainer host, while the local Camofox
browser gets through. Record the working endpoints (per-issuer and
all-issuer disclosures, exchange news), their shapes and quirks, the
options, and a proposed design: a maintainer publisher writes static JSON
to a GitHub release, as the ownership snapshot does, and idx-core merges
it into news.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
String order put 10:00:00Z before the newer 10:00:00.500Z and mixed
time-zone offsets; with a small --limit the newest item could drop out.
Compare parsed RFC 3339 instants; missing or unparseable dates sort last.
From a Codex review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
MSN's feed for a stock is often mostly general market news: of 10 items,
ADRO, BREN and CUAN had none about the company, BBRI one, yet they were
presented as the company's news. Fetch at least 50 items, label each
`relevance: company` (tagged by MSN with the stock's instrument id, or
naming the ticker or the company) or `market`, and return company items
first, newest first, trimmed to --limit.
Company names come from the quote's short and display names, best
effort: MSN tags Telkom articles with its NYSE ADR, not TLKM, so names
catch what tags miss. Classification stays a pure function in parse_news.
Output change, intentional: news JSON gains `relevance`, the table an
ABOUT column (goldens regenerated), and the get_company tool description
explains the field (tools.json and the website tools page regenerated).
News cache keys change so entries without the field are not reused.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the Codex re-gate: the planted-binary check used only ~/.cache, so
the old macOS fallback (~/Library/Caches) would have escaped it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The release-gate Codex review found the relative-path fix incomplete:
with XDG_CACHE_HOME unset and HOME empty or relative, the fallback was
`.cache/...` under the current directory, so a checkout could plant the
binary the launcher runs. Use the home cache only when the home path is
absolute; otherwise the package's bin/ is the only location. npm smoke
plants such a binary and checks it is never run (it was, before this).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From a second Codex review (gpt-6.1-sol, xhigh):
- A relative XDG_CACHE_HOME (invalid per the XDG spec) made the launcher
look for, and run, a binary under the current directory, which an
untrusted checkout could supply. Use it only when absolute.
- The cache dir now includes <platform>-<arch>, so a home directory shared
across machines cannot hand an arm64 host an x64 binary.
- SIGINT sent to the launcher's PID alone during the first-run install is
forwarded to the installer (it was ignored); the launcher exits 130.
- npm smoke runs the first-run install with an empty user cache and checks
the package binary was created, so a cached binary cannot pass for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
- When the package's bin/ is not writable (a root-owned `sudo npm i -g`
whose postinstall npm 12 skipped), install the binary to a per-user
cache ($XDG_CACHE_HOME, ~/.cache, ~/Library/Caches on macOS, under
<package>/<version>/); the launcher looks in both. Previously the first
run failed with EACCES and advice to rerun npm install.
- Run the first-run installer asynchronously with SIGTERM/SIGHUP
forwarded, so a supervisor stopping the launcher stops the download;
the installer removes its partial file and the launcher exits by the
same signal.
- Verify an IDX_BINARY_URL local file's checksum on the copy, not the
source, so the installed bytes are the checked ones.
- npm smoke covers the read-only fallback.
The last three come from a Codex review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From the checkout, agents read its AGENTS.md and docs: Hermes concluded
from docs/IDX_NEWS.md that news "is not implemented" and failed the news
case it had passed before the doc existed. Users' agents never see our
repo, so run every agent from an empty directory under the work dir.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The release-gate Codex review: news passed on get_company with only
`sections: ["profile"]`, history on any period, search on any query.
Require `sections: ["news"]`, `period: "1mo"`, `filter: "top-performers"`
and a query containing "Salim"; all 24 calls from the last six-harness
run still pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The six cases never asked for get_company (where news lives),
get_price_history, screen_stocks or search_investors; across six agents
only one called get_company and none screen_stocks. Cover each.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The dev shell's bash has no compgen (no programmable completion), so the
npx-install check failed every agent.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
From a Codex review of the harness:
- Drop target/debug from PATH in --npx mode (the dev shell adds it), so
a missing package bin cannot fall through to the local build, and fail
an agent whose npm cache holds no installed idx-mcp binary.
- The live `changes` case must diff the two latest releases, read from
the synced snapshot, not any two dates.
- Hermes: `hermes -z` waits ~15s for MCP tools regardless of
connect_timeout, so a slow cold install lost the first case. Warm up
with `hermes mcp test idx`, which installs through Hermes' own npx and
honors connect_timeout (now 300s).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
opencode 2 (@opencode/cli) moved MCP servers to `mcp.servers`, turns
Code Mode on by default, replaced `permission` with ordered
`permissions` rules, and dropped `run --pure` for `--standalone` (runs
otherwise go through a shared background service). Pick the config and
flag from `opencode --version`.
Its `execute` tool stays allowed: with it denied, opencode 2.0.30 never
offers the idx tools to the model in `opencode run`, though the server
connects before the first step.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
opencode kept its built-in tools, so it could route around the server
under test: on published 0.3.1 it answered a quote from web search, and
on the live `changes` case it queried the ownership SQLite file with
bash and timed out. Deny every tool but `idx_*`, as Claude, pi, and
Hermes already are.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh
The `changes` case names the fixture releases (2026-01-30, 2026-02-27),
which the live snapshot does not have, so under --live/--npx it failed
agents that correctly declined to answer about missing releases and
passed ones that called the tool anyway. A case's `live` fields now
replace the mock ones; this one asks about the two most recent releases.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3syn2fN2LNo5pvTSqc6eh