Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ skills/fomo-kernel/dist/
# ledger.jsonl 當預設輸入讀)——延續 *.csv 只留 mock 例外的隱私鐵律精神
ledger.jsonl
.trade-coach/
# #403 同一條防線:position_rationales.jsonl 是使用者自己的原話,比帳本更私人。
# 同樣寫在 coach root 底下,同樣會被從 repo 根目錄啟動的 dogfood run 掉在這裡。
position_rationales.jsonl

# #214 snapshot envelope backstop: *.json cannot be blanket-ignored (it would
# swallow schemas and fixtures), so pin the exact recommended temporary
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Test drive (`prepare --test-drive`) runs in an isolated root: pass `--root <revi
4. Each card has at most one final rule, chosen by the user. Skipping is valid.
5. Keep trade data and engine state local and out of cloud memory. The review card itself is private to the user, not public: local files, terminal output, and private-by-default in-client rendering (for example, a claude.ai Artifact) are permitted, but never publish, post, or send it to a third party. Never mix private-card content into a public card.
6. Every accepted source records the book at the time it arrives, and which kind of source it was never decides whether it may anchor or be analyzed. Never ask whether a holdings view covers the user's whole account: that is an external account this product does not model, and whatever the user handed over is what gets recorded. A newer holdings view reaches the recorded book only through `review.py refresh`, which shows the narrow diff and asks about the differences only the user can settle. Later transaction files may unlock history-dependent diagnostics; ledger-derived current holdings stay canonical. Unreadable input, a missing or incompatible valuation or FX rate, a zero denominator, an unsettled reconciliation, and claims about an unreconciled current broker view all still fail closed.
7. Invoke the engine only through the `engine/review.py` CLI (`prepare`, `resume`, `preview`, `finalize`, `capture`, `consider`, `refresh`, `positions`, `render`, `repair-projections`, `set-cap`, `mute-rule`, `add-cash`, `resolve-market-data`, or `doctor`). Never call another `engine/*` script or import engine modules directly; those paths bypass lifecycle validation, required-question gates, and canonical session state.
7. Invoke the engine only through the `engine/review.py` CLI (`prepare`, `resume`, `preview`, `finalize`, `capture`, `consider`, `refresh`, `positions`, `record-rationale`, `render`, `repair-projections`, `set-cap`, `mute-rule`, `add-cash`, `resolve-market-data`, or `doctor`). Never call another `engine/*` script or import engine modules directly; those paths bypass lifecycle validation, required-question gates, and canonical session state.
8. An ad hoc informational question — including a `consider` call — gets a quick, direct, textual answer: no chart, no rendered artifact, no multi-tool production, unless the user asks for more. A chart is never invented on the spot; it matches a name in the small pre-defined set `references/freeform-answers.md` declares, or it does not exist — that set bounds what the agent decides to produce on its own initiative, never what the user explicitly asks for. Brevity bounds what an answer produces, never which facts it owes: a surface with its own disclosure contract still states all of them. **One exception, and only this one:** recovering a price the engine could not retrieve is completing the input, not production. When `consider` returns a `price_feed` recovery kit, look up the instruments it names — a search may find the publisher's page, the close is read off that page and never off a search-result snippet — transcribe them into the envelope in `skills/fomo-kernel/references/price-feed.md`, and rerun `consider --prices`. It is transcription, not analysis: at most twenty instruments, one attempt each, nothing read beyond the close. It licenses no chart, artifact, or other multi-tool work. The work is bounded and parallelizable and may be delegated to whatever faster tier the host has. Supply whatever you found, partial coverage included; when the sources genuinely publish nothing, run `consider --prices-unavailable '<the sources you checked>'` and the question is refused rather than answered on cost basis — deliberately the opposite of the review-card lane, which delivers its degraded card.
9. A decision the user brings with no recorded book and no snapshot is framed, not refused. `consider` still fails closed for want of a book — boundary 6 is unchanged — and the answer that follows is a separate bounded outcome under `skills/fomo-kernel/references/decision-framing.md`: at most three questions, no computed or placeholder portfolio number anywhere in it, a user-declared size treated as an input and never as a record, nothing written to durable state, and every limitation that matters shaped as a question the user can answer rather than a gap narrated back at them. Refusing is not what earns a transaction history — naming the specific answer the next piece of evidence would buy is.

Expand Down
1 change: 1 addition & 0 deletions docs/maintainer-guide.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions evals/run_episodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ def _load_module(name, path):
# writes a new slot row on the line — which is what the *next* review's due
# list carries forward, criterion and all.
"condition_basis": ("condition_checks", ("card", "state:condition_slots_due")),
# #403: the answer is written straight into the canonical
# position_rationales.jsonl through the one append service, not projected
# out of the session bundle the way every other kind's is -- a second writer
# into a canonical stream would be the parallel store the issue forbids.
# So the verifiable consumer is the plan key the *next* review reads it back
# through, and there is deliberately no card claim: #403 parks card layout,
# and a rationale is a fact surface rather than a card section.
"rationale_refresh": ("position_rationales", ("state:position_rationales",)),
}
# Kinds whose answer reaches nothing, each pinned to the issue that owns the
# disposition. A ratchet, not an exemption: a kind that becomes wired must leave
Expand Down
2 changes: 1 addition & 1 deletion skills/fomo-kernel/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ The product's value is continuity: this review reconciles against the last one,
## Non-negotiable rules

1. **Numbers come from engine artifacts only.** Never calculate, fill in, or adjust a numeric fact, ranking, weight, or identity. Determinism is what makes week-to-week reconciliation trustworthy: this week's 12% and next week's 12% have to be the same 12%.
2. **Invoke the engine only through the `engine/review.py` CLI** (`prepare`, `resume`, `preview`, `finalize`, `capture`, `consider`, `refresh`, `positions`, `render`, `repair-projections`, `set-cap`, `mute-rule`, `add-cash`, `resolve-market-data`, `doctor`). Do not call another `engine/*` script or import engine modules directly — those paths bypass lifecycle validation, required-question gates, and canonical session state.
2. **Invoke the engine only through the `engine/review.py` CLI** (`prepare`, `resume`, `preview`, `finalize`, `capture`, `consider`, `refresh`, `positions`, `record-rationale`, `render`, `repair-projections`, `set-cap`, `mute-rule`, `add-cash`, `resolve-market-data`, `doctor`). Do not call another `engine/*` script or import engine modules directly — those paths bypass lifecycle validation, required-question gates, and canonical session state.
3. **A considered trade earns a computed case, never a prose one.** In a review, discuss behavior, motives, thesis evolution, and process rules; the card's prescription still never names what to buy or sell. For a trade the user is deciding on, `consider` returns what it does to their own book and which of their own rules it would break — build the case for and against from that output, mark every claim you added as your own judgment, cite an engine fact through the anchor `references/trade-consequence.md` documents so it can be checked against the frozen result, and state everything the response's own `challenge` block says this answer owes — the facts, the user's exact words unreworded, the rules this trade collides with, and what nobody checked. That block is computed per call, so none of it is a list to remember. Shape the reply decision-first: one supported decision tension leads and everything owed groups around it, per the decision-first section of `references/trade-consequence.md`. A case that misquotes the record, leaves an owed fact uncovered, or relabels the user's own words as an outside source is refused rather than stored. Current market context — the standing position packet and any event verification — enters only under `references/market-lookup.md`'s bounded lookup contract, as sourced public facts. The decision stays theirs, and a price target or market forecast is still not something this product states.
4. **Never invent, interpolate, or recall a market price.** When a host blocks the engine's own retrieval, `review_plan.input.price_feed.request` names what is unpriced; look those closes up from a recognized market-data source, transcribe them into the envelope in `references/price-feed.md`, and rerun `prepare --prices`. A price you cannot find stays missing — a missing price is never a delisting verdict or a zero return.
5. **Trade data stays local.** The source CSV, session bundles, and the ledger never enter cloud memory. The review card is private to the user: show `card-private.*` by default per `references/card-delivery.md`. Local files, terminal output, and private-by-default in-client rendering are all fine; publishing, posting, or sending it to a third party is not. `card-public.md` is the one share-safe artifact, and only if the user asks.
Expand Down
Loading
Loading