Commit Graph
2661 Commits
Author SHA1 Message Date
Haozhe Wu e1dbea8ad3 release: 0.1.16 — a number that can show where it came from
Rolls up 492 commits / 116 merged pull requests since 0.1.15, from 16
contributors.

The final-answer grounding gate stopped guessing what a number is from
the words around it: the model declares each figure's role (observed,
derived, proposed, cited or count), the gate checks the declaration
against the session's tool evidence, and a figure that fails is cut from
the answer instead of the whole answer being refused. A backtest's own
output now grounds the report written about it, run cards cite a metric
only where the saved CSV agrees, and the generated broker matrix states
each profile's permissions as declarations. Research runs keep what they
fetched: compaction follows the model's real context window instead of a
fixed 40K estimate. The missing-data sweep reached 59 more alphas.
Argentina (BYMA), weekly and monthly bars, Bahasa Indonesia, Gildata,
OpenCode, Email and WebSocket channels and four broker connectors (KIS,
Upbit, Toss Securities, Scalable Capital) land alongside.

Verified before release: the reporter's risk-parity prompt, which had
stopped with no_progress after 93 seconds on DeepSeek V4 Pro, completed
on 4a40a7f6's parent in 8m13s with both backtests run, 13 steps saved and
the report released with its core figures grounded.

Version declarations bumped in pyproject.toml, agent/SKILL.md,
Dockerfile, frontend/package.json, both package-lock.json entries, all
nine locales and the Layout test mock. CHANGELOG cites 116/116 merged
pull requests and credits 16/16 authors. README News carries the release
in seven languages, three entries visible.
v0.1.16
2026-09-29 16:13:16 +08:00
Haozhe Wu 4a40a7f647 fix(grounding): tell the model when a formula runs the other way, and to answer only
A live DeepSeek V4 risk-parity run after c8c2dc38 completed and released
its report, with every declared backtest figure grounded. Its second
draft still lost eight differences: the prose wrote "−1.51pp" (risk
parity minus equal weight) beside "12.87% − 11.36%", the size right and
the direction reversed. That stays refused, because the sign is part of
the claim, but the correction said only "its own note evaluates to
1.51%", and the model rewrote the numbers instead of the formulas. The
issue now carries sign_reversed and the correction says the formula runs
the other way round. The hint for a figure declared in the other unit
matches by size and says when the declared value has the opposite sign
("0.0151" for "−1.51pp"), where before it said nothing at all.

The same draft opened with "The rejection was because several figures
... were not declared", in English to a user writing Chinese, and that
sentence was released. The correction now asks for the corrected answer
alone, in the user's language, without mentioning the rejection, the
check or the figures block.
2026-09-29 16:09:28 +08:00
Haozhe Wu c8c2dc3811 fix(read_file): say where the agent may read, and list a directory
A live risk-parity run on DeepSeek V4 stopped with no_progress after 93
seconds, before any backtest ran: the model went looking for the backtest
engine's source (../../agent/src/backtest, the checkout's absolute path,
skills/../backtest/engine.py) and every attempt got "File not found or
path escapes workspace". Each spelling was a new call, so none was
blocked, and none was an observation, so eight rounds exhausted the
no-progress budget. This is the reporter's 1m03s failure: same prompt,
same shape, no compaction involved.

The refusal now says which it was (error_code outside_readable_roots or
not_found), where read_file may open files (the run directory, skills/),
and that the engine's contracts are in the skills (load_skill lists a
skill's sections). A path that names a directory inside those roots
returns its entries instead of an error. The boundary is unchanged.
2026-09-29 15:38:47 +08:00
Haozhe Wu c1542cb3f2 fix(grounding): read a comparison report's arithmetic as it is written
The same replayed risk-parity drafts, after d2dd7006:

- A derivation note with labels glued to its operands ("等权 Sortino
  1.2115 − 风险平价 1.1329") or an aside in brackets ("0.09297 − 0.10469
  (收益差,约−1.17pp)") was "not arithmetic". When the note as written
  fails, its words and bracketed asides are now removed, never read, and
  the arithmetic between them evaluated: formula_not_evaluable 11 -> 1.
- An operand written as a percent is the fraction the evidence holds:
  "13.28% − 12.98%" is 0.1328 − 0.1298 (it was 13.28 − 12.98, which no
  observation anchors), and "0.666 × (1 − 3%)" is 0.666 × 0.97.
- A square or cube (HHI is a sum of squared weights) is evaluated; the
  exponent is not an operand and anchors nothing, and any other power
  stays unsupported (9^9^9 would never return).
- A declared value may be a fraction ("1/3") or carry a multiple mark
  ("5.5x", "3 倍"); one unreadable line fails the whole draft.
- A draft ending in DeepSeek's closing tool-call tags
  ("</||DSML||invoke>") is recognised as tool-call syntax; the
  fullwidth pattern only matched opening tags, so the tags reached the
  gate as figures-block lines.

The formulas that now evaluate and still fail are the model's own errors
(operands rounded before subtracting, a reversed sign, 0.1357 − 0.1287
written as 0.0069).
2026-09-29 15:33:37 +08:00
Haozhe Wu 67271863da docs: add September 29 news in seven languages 2026-09-29 15:22:16 +08:00
Haozhe Wu 711f26c8a9 fix(market-data): ask only a US equity for its .US suffix
a71d5312 refused every bare letters-and-digits code under source=auto as a
US ticker without its suffix. Chinese futures codes (RB0, rb2501, IF2412)
and joined crypto pairs (BTCUSDT) have that shape too; the market detector
the loaders route by reads them as futures and crypto, and they were
answered "US equity symbols must include the .US suffix". The check now
asks the same detector and refuses only what it reads as a US equity.
2026-09-29 15:20:22 +08:00
Haozhe Wu d2dd7006df fix(grounding): let a backtest's own output ground the report about it
A risk-parity vs equal-weight backtest report ended in the canned refusal in
12 of 15 replayed runs. Replaying all 26 stored drafts through the gate
(880 of 882 recorded rejections reproduced) showed why:

- Only kind-named metrics (Sharpe, return, drawdown ...) became evidence.
  Sortino, Calmar, turnover, final value, Monte Carlo p-values, the risk
  X-ray and the optimiser's weights were refused although the backtest
  wrote every one of them. The run card, metrics row, risk X-ray,
  validation and rebalance summaries are now recorded whole (lists are
  not descended; files other than metrics.csv/json must match the run
  card's artifact manifest). A per-bar table counts only for the rows a
  read_file showed, while it is still byte for byte what the engine wrote.
  A file the model wrote is never evidence.
- A ref naming the run (rp, rp/artifacts/metrics.csv, rp/metrics.csv,
  "risk_parity target_positions.csv", backtest::rp, rp::sortino) resolved
  to nothing. The run directory now names that backtest's output and no
  other run's; one run's same-named fields are one source, two runs are
  two (correction candidates are written rp::field).
- Naming a symbol in the request made it a market answer, and a market
  answer with no fetched price could never be released with its failing
  figures cut. A completed analysis now can; the refusal for a price
  question with neither prices nor analysis is unchanged, and the refusal
  after an analysis no longer claims the draft cited prices.
- Derivations: formula constants parse unsigned, so a negative observation
  (a drawdown) could never anchor; operands now match by magnitude. A field
  ref two runs hold anchors both for arithmetic. With several instruments'
  bars and no symbol, symbol-less evidence the ref names may anchor;
  instrument prints still may not.
- A figure declared as a fraction but written as a percent stays
  undeclared (spec section 2), and the correction now says which value
  was declared.

Replay: value_mismatch 196 -> 1, not_in_referenced_call 167 -> 7,
formula_not_anchored 35 -> 18; releasable final drafts 3/15 -> 15/15.
Two-sided on the same runs (decimals): a real value declared with its run
directory passes 97% (was 23%), the same value moved 2-10% passes 0.7%.
The undeclared path is unchanged: widening it to the metrics row would
have passed 16% of invented values (4.6% today).
2026-09-29 15:16:11 +08:00
Haozhe Wu ef2a1e0e9f fix(agent): size context compaction to the model's real window
A user on gpt-6-sol saw "failed · 0 steps · no_progress" for a risk-parity
backtest and a 12-company comparison. Reproduced on v0.1.15 with
deepseek-v4-pro: layer 1 fired from iteration 3 (the system prompt alone
estimates ~12.5K of the fixed 20K trigger), cleared every tool result but the
last three, and the run re-fetched the same filings 4-5 times each until
no_progress at iteration 16. Raising the threshold alone took re-fetches from
54 to 0 across 8 runs.

- Compaction budget: window from VIBE_TRADING_CONTEXT_WINDOW > limit learned
  from a context-length error > context_windows.json (sourced: Codex models
  272K, deepseek-v4-pro/flash 1M) > 128K default; capped by
  VIBE_TRADING_CONTEXT_MAX_TOKENS (200K); measured in real input tokens.
  Layer 1 clears oldest-first only back to its line. A context-length error
  compacts and retries once. TOKEN_THRESHOLD is deprecated and ignored.
- No-progress limits are unchanged; the stop message now names the tool,
  reason and count instead of one fixed compaction-era sentence.
- Failed and cancelled attempts keep their tool trail (history said 0 steps).
- Codex: mid-run system messages become developer input instead of replacing
  instructions; encrypted reasoning items are replayed; no fabricated fc_0
  ids; prompt_cache_key per session; default model gpt-6-sol (gpt-5.4 is
  rejected for ChatGPT accounts).
- get_market_data: no symbol resolved is an error envelope; grounding still
  records each symbol as unavailable.
- loop.TOKEN_THRESHOLD test hook is a real attribute: monkeypatch used to
  write the lazy 40000 back on undo and switch later tests to the old path.
2026-09-29 11:50:14 +08:00
Haozhe Wu a71d5312d9 fix: harden free market data failure handling 2026-09-28 23:57:42 +08:00
Haozhe Wu 18988fbedf fix: honor backtest timeout and preserve timeout logs 2026-09-28 23:49:56 +08:00
Haozhe Wu 47a036d66d fix: harden grounding corrections and MT5 identity integration 2026-09-28 16:44:55 +08:00
Haozhe Wu a366ccdd11 Merge PR #1600: text-only grounding corrections 2026-09-28 16:19:43 +08:00
Haozhe Wu 5160aa60b1 Merge PR #1598: MT5 terminal attachment in backtests 2026-09-28 16:19:43 +08:00
Haozhe Wu 0c31121afb Merge PR #1597: broker-specific MT5 symbol search 2026-09-28 16:19:43 +08:00
Haozhe Wu 68e5eaa43e Merge PR #1588: localized grounding numbers 2026-09-28 16:19:43 +08:00
Haozhe Wu be8f3afb14 Merge PR #1586: preserve exact grounding field references 2026-09-28 16:19:43 +08:00
Haozhe Wu 5becb95777 Merge PR #1584: resolve observed evidence symbols 2026-09-28 16:19:43 +08:00
Haozhe Wu dec2c0e6b8 fix: complete September 28 reliability reviews and broker documentation
Bound BaoStock messages and serialize SDK sessions; verify Copilot credential
lookup expiry without changing the SDK's per-call credential resolution.
Run public-loader health checks in isolated, credential-free processes and a
separate dependency environment, with explicit failure reports and a weekly
workflow. Render broker capabilities per profile and document verification
requirements. Update September 28 News in all seven README languages.

Closes #1626
Closes #1623
Closes #1617
Closes #1492
2026-09-28 16:07:06 +08:00
Haozhe Wu 3562ac7696 Merge PR #1629: generated broker capability matrix 2026-09-28 15:38:54 +08:00
Haozhe Wu ab3a49a825 Merge PR #1627: loader health canary 2026-09-28 15:38:54 +08:00
Haozhe Wu 3716bdf109 Merge PR #1615: bound BaoStock socket reads 2026-09-28 15:38:54 +08:00
Haozhe Wu 7f43c3d86d Merge PR #1619: refresh Copilot CLI credentials 2026-09-28 15:38:54 +08:00
Yufeng He bdddef0177 feat(trading): broker capability matrix generated into README
Which read and order paths each connector exposes lived in per-connector
code. The profiles already declare it, so render them into a marked block in
the README's connector onboarding section; a drift test fails CI the moment
a profile changes without `python -m src.trading.capability_matrix`, so the
table cannot go stale.

Refs #1626

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
2026-09-28 15:30:21 +08:00
Yufeng He 68f4565109 feat(trading): generate the broker capability matrix from the profile registry
Which read tools, quote paths and order kinds each connector actually has
lived in per-connector code and tribal knowledge. The profiles already
declare it, so render them: docs/broker-capabilities.md is generated by
`python -m src.trading.capability_matrix`, and a drift test fails CI the
moment a profile changes without a regenerate, so the table cannot go stale.
README's connector onboarding section links to it.

Refs #1626

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
2026-09-28 15:23:44 +08:00
Yufeng He 0a53cf8def ci: drop the weekly workflow from this push (follow-up once workflow scope lands)
Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
2026-09-28 13:39:01 +08:00
Yufeng He 54f222b743 feat(loaders): weekly live-source health canary lane
The last few loader failures were all found by users rather than by us:
the northbound feed died silently (#1481), baostock can hang forever
(#1492), the A-share qfq caliber drifted (#1541). This adds a weekly lane
that hits every no-auth loader with one known-liquid symbol and asserts a
non-empty, correctly shaped, fresh frame, so a dead or drifted endpoint
goes red on CI instead of in someone's run.

The canary module is env-gated (VIBE_TRADING_LOADER_HEALTH=1) and
integration-marked, so the default CI lane skips it entirely. Loaders that
cannot be reached from the runner at all are reported as unreachable, not
failed; empty or stale answers fail, with one retry to ride out flaky
connections.

Closes #1623

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
2026-09-28 13:38:14 +08:00
lorenzozanee f740e906f0 fix(providers): expire cached Copilot CLI token
Signed-off-by: lorenzozanee <wyz0707@proton.me>
2026-09-27 22:32:53 +08:00
Yufeng He 4726f69fbe fix(loaders): bound baostock socket IO with a per-read deadline
baostock 0.9.3's send_msg reads with no socket timeout and loops until a
terminator that never comes on a closed connection: a silent server hangs
the loader forever, a closed one spins at 100% CPU. The loader now swaps in
a bounded send_msg and a connect with a deadline for the lifetime of each
fetch. The replacement is byte-compatible on a healthy server and returns
None on timeout, EOF, or a malformed reply, which every baostock caller
already maps to BSERR_RECVSOCK_FAIL, so a dead server degrades into an
ordinary per-symbol failure that falls through the loader chain.

The inactivity deadline defaults to 30s per read and can be tuned with
VIBE_TRADING_BAOSTOCK_TIMEOUT. Fake-server tests cover the silent-server,
close-immediately, healthy-roundtrip, malformed-reply, and refused-connect
cases.

Closes #1492

Signed-off-by: Yufeng He <40085740+he-yufeng@users.noreply.github.com>
2026-09-27 15:05:47 +08:00
Haozhe Wu 0244eceaaf fix: complete September 27 reviews and surface verified run-card evidence 2026-09-27 10:57:33 +08:00
Haozhe Wu 71a8c2b005 Merge pull request #1612 2026-09-27 10:46:02 +08:00
Haozhe Wu 826f9ef3df Merge pull request #1608 2026-09-27 10:46:00 +08:00
Haozhe Wu a1ea05e351 Merge pull request #1607 2026-09-27 10:45:58 +08:00
Haozhe Wu 19b141c1cc Merge pull request #1606 2026-09-27 10:45:56 +08:00
Haozhe Wu 186d32dee0 Merge pull request #1605 2026-09-27 10:45:53 +08:00
Haozhe Wu 2ada384679 Merge pull request #1604 2026-09-27 10:45:51 +08:00
lorenzozanee d25d9f93c6 feat(backtest): add hash-only run card traces
Signed-off-by: lorenzozanee <wyz0707@proton.me>
2026-09-27 07:40:58 +08:00
Haozhe Wu b4569ffbef docs: add September 26 maintenance news in seven languages 2026-09-26 23:36:25 +08:00
Lanre Shittu d17f2ccbea fix(backtest): India engine checks the right circuit band when covering a short
Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
2026-09-26 09:58:36 +00:00
Lanre Shittu 19d2920a1d fix(tools): MCP tool schemas with a malformed properties field no longer lose the properties key entirely
Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
2026-09-26 09:48:15 +00:00
Lanre Shittu 5b3b5dc84f fix(tools): stop redacting token budget and usage fields as credentials
Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
2026-09-26 09:32:22 +00:00
Lanre Shittu e3fa7af20b fix(goal): reject execution objectives that put the immediacy cue before the verb
Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
2026-09-26 09:29:40 +00:00
Lanre Shittu 3ec76be812 fix(factors): GTJA HIGHDAY and LOWDAY recency direction no longer inverted
Signed-off-by: Lanre Shittu <136805224+Shizoqua@users.noreply.github.com>
2026-09-26 09:19:34 +00:00
Haozhe Wu d0ef98a606 fix: finish numeric boundaries, replay coverage and Trigger inheritance 2026-09-26 13:15:58 +08:00
Haozhe Wu 1e369c0afe Merge pull request #1599 2026-09-26 13:10:47 +08:00
Haozhe Wu afe736b7e1 Merge pull request #1590 2026-09-26 13:10:47 +08:00
Haozhe Wu 3ebae920ae Merge pull request #1591 2026-09-26 13:10:47 +08:00
Haozhe Wu 3849d3597c Merge pull request #1601 2026-09-26 13:10:47 +08:00
Haozhe Wu a5d47c200f fix: finish exact Dhan quantities and four-PR boundary coverage 2026-09-26 13:03:21 +08:00
Haozhe Wu a2416bbf25 Merge pull request #1594 2026-09-26 12:55:30 +08:00
Haozhe Wu 93c534e317 Merge pull request #1592 2026-09-26 12:55:29 +08:00