You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Owner-approved active implementation front, 2026-07-31. May proceed in parallel with #610.
#610 remains the frozen M1 judgment-quality dogfood lane. This issue is a separate M2 memory vertical slice: continuing-position self-report, not TradeEvaluation answer quality. Development may proceed on isolated branches while #610 runs against its frozen SHA. Do not merge a consider consumer into the #610 candidate mid-walk.
Milestone
M2 — Recall and Compare My Reasons.
This is a narrow owner-approved exception to #475's earlier sequencing gate. It does not unlock broad M2: #636 DecisionIntent, #490 execution linkage, #609 prior-evaluation recall, profile distillation and rule learning remain separately gated.
User outcome
A user can state or update why they currently hold a recorded position without running a review:
「我現在繼續持有 X,是因為 Y。」
FOMO Kernel records the exact words locally, returns a short receipt, and the next relevant review starts from that statement rather than asking from zero.
The same canonical writer is used when the statement arrives through:
direct chat / standalone CLI entry;
a review rationale-refresh question;
the existing light-capture route.
A review is a reader and selective collector, not the aggregate root of the rationale.
Current behavior / evidence
Verified on main@9d56a2d:
review.py capture is not a standalone user entry. It requires a pending light-tier Review Plan, cycle ids already exposed by that plan, and consumes the pending session.
theses.jsonl is documented as rebuildable compatibility state. Generalizing its direct append path would create a second canonical truth outside immutable sessions.
Changed wording is evidence, not automatically drift, dishonesty or rationalization.
2. One canonical stream
Add a dedicated canonical append-only stream:
<root>/position_rationales.jsonl
with one schema and one module owning validation, append, fold and bounded query. theses.jsonl remains a rebuildable thesis projection / agent interpretation source and is not the canonical home of direct user wording.
Register the stream with data-status, export and reset. Corruption, conflicting duplicate identity and partial writes fail closed. Append uses the existing root write lock plus flush/fsync discipline; no second lock hierarchy.
3. Event contract
The first schema carries at least:
schema_version;
engine-assigned event_id, content-addressed from the stable payload and excluding recorded_at;
subject: active cycle_id, ticker, market and currency facts resolved by the engine;
change: initial | changed | no_change;
exact user_statement, byte-for-byte for initial / changed;
continues_event_id for no_change, so the prior substantive wording remains the effective statement without being copied or rewritten;
stated_at for when the statement applies and canonical recorded_at for append time;
voice: user_verbatim;
capture_source: direct | review | light_capture plus the producing interaction/session id when one exists;
the recorded-book state_version used to resolve the active subject;
mapping_status: mapped | unmapped and an optional condition reference when a later slice legally creates one.
A first statement is initial, never falsely labelled changed. Exact retry is a no-op; different wording or a later stated_at creates a new event on the same subject.
Ambiguous active subject or changed book/state version → fail closed and retry; never attach words to a guessed cycle.
No card, Review Plan, commitment, rule choice or second save-confirmation.
5. Review and light-capture collection
A user answer to a rationale-refresh question is independently valid memory. The review invokes the same append service and records the returned event_id; it does not maintain a second session-owned rationale truth.
If the review later aborts, the rationale remains valid: the user explicitly stated why they hold the position, and that fact does not depend on the card finalizing.
The existing light capture UX may remain, but its writer delegates to this service. Any thesis projection it still needs is rebuilt or derived from the canonical event; direct appending to a rebuildable projection is retired.
effective current statement plus latest confirmation/change event;
verbatim text, source/voice, stated_at, recorded_at, event id and subject identity.
The reader follows engine-proven cycle relinks/carry-forward aliases. It never joins by ticker alone across an unproven sale/rebuy boundary.
Review integration
Add a bounded rationale_refresh opportunity/question rather than turning every missing rationale into a questionnaire.
Eligibility requires an existing active rationale plus a fact that could make a new answer useful, for example:
material new trade in the cycle;
due/crossed condition or horizon;
meaningful position change after a stale statement;
behavior/self-report conflict evidence.
The engine supplies those facts and how long since the last statement. The agent chooses whether this question deserves the one available slot. At most one rationale-refresh question per review; the global route question budget is unchanged.
A no_change answer references the prior substantive event. A changed answer writes new exact wording. The question quotes the prior statement; it never asks as if nothing was recorded.
The first user-visible reader is the next review question/context. Do not add an unconditional card section in this slice.
Create one shared engine-side carry-forward/relink primitive used by both refresh-lane and review-lane snapshot adoption. A continuously held position preserves its cycle lineage; a confirmed sale and later re-entry opens a new one. Rationale queries consume the same relink chain. #563's later-history start-date upgrade must preserve aliases rather than orphan memory.
This front touches snapshot/ledger identity and has its own PR/review boundary.
No generic add-memory command or universal memory graph.
No mandatory falsifier for every rationale.
No automatic semantic drift/accusation.
No price target, recommendation or execution claim.
No consider integration in the first vertical slice.
No profile label or standing-rule implementation.
No migration that upgrades legacy classifications into user-verbatim statements.
Decisions still open
No owner decision blocks the first vertical slice above. The design deliberately resolves command shape, canonical source, first reader, snapshot-continuity prerequisite and first-statement semantics.
Later slices still require separate decisions/evidence:
whether an auto-loaded rationale reference changes TradeEvaluation.evaluation_id or remains a non-identity display context — decide before the consider consumer;
how a direct rationale and a direct condition append become atomically/recoverably linked without creating two canonical truths;
All real statements remain local under the user's coach root. Public tests/issues/receipts use fictional wording and instruments only.
Rollback before integration removes the new reader/writer without mutating ledger, sessions or TradeEvaluations. After events exist, rollback must leave the canonical stream exportable/readable even if no runtime surface consumes it; never delete user statements as part of code rollback.
Status
Owner-approved active implementation front, 2026-07-31. May proceed in parallel with #610.
#610 remains the frozen M1 judgment-quality dogfood lane. This issue is a separate M2 memory vertical slice: continuing-position self-report, not TradeEvaluation answer quality. Development may proceed on isolated branches while #610 runs against its frozen SHA. Do not merge a
considerconsumer into the #610 candidate mid-walk.Milestone
M2 — Recall and Compare My Reasons.
This is a narrow owner-approved exception to #475's earlier sequencing gate. It does not unlock broad M2: #636 DecisionIntent, #490 execution linkage, #609 prior-evaluation recall, profile distillation and rule learning remain separately gated.
User outcome
A user can state or update why they currently hold a recorded position without running a review:
FOMO Kernel records the exact words locally, returns a short receipt, and the next relevant review starts from that statement rather than asking from zero.
The same canonical writer is used when the statement arrives through:
A review is a reader and selective collector, not the aggregate root of the rationale.
Current behavior / evidence
Verified on
main@9d56a2d:review.py captureis not a standalone user entry. It requires a pending light-tier Review Plan, cycle ids already exposed by that plan, and consumes the pending session.thesis_decision.note;thesis.reconstruct_statescan fold the bytes into thesis state, but [process·gate-debt] Disposition tracker: 34 fields the deepened QUESTION_CONSUMERS field-level check found unread across 4 sinks #480 records that this user-authored note has no guaranteed visible card reader.theses.jsonlis documented as rebuildable compatibility state. Generalizing its direct append path would create a second canonical truth outside immutable sessions.initial_thesis, add-decision note/evidence,headline_motive, inferred thesis), but [design·P1] Two questions collect an answer nothing reads: initial_thesis and exit_consistency (proved by a byte-identical card) #429/[process·gate-debt] Disposition tracker: 34 fields the deepened QUESTION_CONSUMERS field-level check found unread across 4 sinks #480 prove that collection and future consumption are uneven.Domain decision
1. One object:
PositionRationaleThis issue owns why the user says they currently continue to hold one active position cycle.
It does not own:
Changed wording is evidence, not automatically drift, dishonesty or rationalization.
2. One canonical stream
Add a dedicated canonical append-only stream:
with one schema and one module owning validation, append, fold and bounded query.
theses.jsonlremains a rebuildable thesis projection / agent interpretation source and is not the canonical home of direct user wording.Register the stream with
data-status, export and reset. Corruption, conflicting duplicate identity and partial writes fail closed. Append uses the existing root write lock plus flush/fsync discipline; no second lock hierarchy.3. Event contract
The first schema carries at least:
schema_version;event_id, content-addressed from the stable payload and excludingrecorded_at;subject: activecycle_id, ticker, market and currency facts resolved by the engine;change:initial | changed | no_change;user_statement, byte-for-byte forinitial/changed;continues_event_idforno_change, so the prior substantive wording remains the effective statement without being copied or rewritten;stated_atfor when the statement applies and canonicalrecorded_atfor append time;voice: user_verbatim;capture_source: direct | review | light_captureplus the producing interaction/session id when one exists;state_versionused to resolve the active subject;mapping_status: mapped | unmappedand an optional condition reference when a later slice legally creates one.A first statement is
initial, never falsely labelledchanged. Exact retry is a no-op; different wording or a laterstated_atcreates a new event on the same subject.4. Direct public action
Use one explicit host-neutral facade action:
The host normally hides the CLI and invokes it from natural language.
Route rules:
5. Review and light-capture collection
A user answer to a rationale-refresh question is independently valid memory. The review invokes the same append service and records the returned
event_id; it does not maintain a second session-owned rationale truth.If the review later aborts, the rationale remains valid: the user explicitly stated why they hold the position, and that fact does not depend on the card finalizing.
The existing light
captureUX may remain, but its writer delegates to this service. Any thesis projection it still needs is rebuilt or derived from the canonical event; direct appending to a rebuildable projection is retired.Bounded reader contract (#450 handshake)
The first query is position-specific and bounded:
total_count,shown_count,beyond_cap;stated_at,recorded_at, event id and subject identity.The reader follows engine-proven cycle relinks/carry-forward aliases. It never joins by ticker alone across an unproven sale/rebuy boundary.
Review integration
Add a bounded
rationale_refreshopportunity/question rather than turning every missing rationale into a questionnaire.Eligibility requires an existing active rationale plus a fact that could make a new answer useful, for example:
The engine supplies those facts and how long since the last statement. The agent chooses whether this question deserves the one available slot. At most one rationale-refresh question per review; the global route question budget is unchanged.
A
no_changeanswer references the prior substantive event. A changed answer writes new exact wording. The question quotes the prior statement; it never asks as if nothing was recorded.The first user-visible reader is the next review question/context. Do not add an unconditional card section in this slice.
Ordered implementation
Front A — stable subject continuity (#539 / #536)
Create one shared engine-side carry-forward/relink primitive used by both refresh-lane and review-lane snapshot adoption. A continuously held position preserves its cycle lineage; a confirmed sale and later re-entry opens a new one. Rationale queries consume the same relink chain. #563's later-history start-date upgrade must preserve aliases rather than orphan memory.
This front touches snapshot/ledger identity and has its own PR/review boundary.
Front B — canonical event and bounded query
In parallel with Front A, on disjoint files:
position_rationalemodule;No
review.pyintegration yet.Integration slice — direct entry + next-review reader
After Front A and Front B stabilize:
record-rationalethroughreview.py;state_version;rationale_refreshopportunity/question and duplicate-question suppression;This is the first owner-live stop boundary.
Follow-up slices, not in the first PR
captureand full-review capture paths to the same writer.considerreader after [QA·dogfood] Judgment-quality dogfood — does a real consider answer now carry a supported insight? #610. It must freeze the exact rationale event used and settle whether that reference participates inevaluation_id; do not slip it in as display-only mutable context.Acceptance criteria — first vertical slice
theses.jsonltruth.Non-goals
add-memorycommand or universal memory graph.considerintegration in the first vertical slice.Decisions still open
No owner decision blocks the first vertical slice above. The design deliberately resolves command shape, canonical source, first reader, snapshot-continuity prerequisite and first-statement semantics.
Later slices still require separate decisions/evidence:
TradeEvaluation.evaluation_idor remains a non-identity display context — decide before theconsiderconsumer;Dependencies / relations
Privacy / rollback
All real statements remain local under the user's coach root. Public tests/issues/receipts use fictional wording and instruments only.
Rollback before integration removes the new reader/writer without mutating ledger, sessions or TradeEvaluations. After events exist, rollback must leave the canonical stream exportable/readable even if no runtime surface consumes it; never delete user statements as part of code rollback.