feat(review): the entry-thesis question quotes what the user already said, instead of asking them to remember it (refs #636) - #653
Merged
Conversation
…said, instead of asking them to remember it (refs #636) A first review asked every un-thesised holding to reconstruct its entry motive from memory, offering five buckets. For a position the user had already discussed through `consider`, their exact `reason` was sitting in `trade_evaluations.jsonl` the whole time -- stored verbatim by schemas/decision-context.schema.json and read by nothing outside `consider` itself. The stem now quotes that statement, dated, and asks whether it was the thesis they entered on. Same question kind, same choices, same event, same slot in the #291 density band: the question is asked better, not asked twice. Recall deliberately does not route through `_evaluation_reconciliation`. That surface is open-evaluations-only, and a resolved evaluation is still something the user said; its schema also declares itself a supply-side fact surface and not a question. `_evaluation_recall` reads the store directly and ignores `decision` entirely. Three boundaries, each locked by a test: - a statement recorded after the cycle's entry is a different decision than the one this question asks about, so it is never quoted; - the latest qualifying statement wins, because an earlier one it superseded is not the user's account of why they entered; - an evaluation carrying no `reason` or `why_now` is dropped rather than quoted empty -- `consider` runs fine with no `--decision-context`, and a recalled blank is worse than the canned question it replaces. This states a fact and never a cause. The stem says the user said this on this date; it never says the position was opened because of it. `initial_thesis` stays in `evals/run_episodes.py`'s `KNOWN_UNWIRED`. This improves the question; the answer still has no consumer, and #429 is not fixed by it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… and the field it adds is declared where readers look (refs #636) Independent review of the first cut found two blockers and four smaller defects. Every one is a claim the offline suite could not make false, which is the point of the review. **A re-entered position quoted the previous one's reason.** A cycle id carries no lower bound, so every statement made before a ticker's *first* entry also satisfies `created <= start` for its second. The owner's ruling on #636 is per cycle: a ticker fully exited and re-entered is a new position with its own reason. Bounding the window properly needs the prior cycle's exit date, which this layer does not have, so a re-entry now recalls nothing rather than attributing the old reason to the new position. **The new `recalled_statement` made the emitted plan invalid.** A question row is `additionalProperties: false` in `review-plan.schema.json`, and the field was not declared. Nothing failed: no offline test fed a first_review question queue through that schema. The field is declared now, and the recall test pins every emitted row against the schema's own property set, so the next undeclared field fails here instead of in a reader. **`_cycle_start_date` did not enforce the contract it cited.** It split on `#` and parsed the second segment, which accepts shapes `trade_recap` can never produce. It is now `_cycle_entry`, matching `trade_recap.CYCLE_ID_RE` — the single source of truth — and returning the sequence the re-entry rule needs. The first version of the test did not catch this: `int()` and `fromisoformat()` already reject the malformed cases it listed, so the strictness was decorative until the test grew the shapes only the regex rejects (a ticker with whitespace, an empty ticker, a trailing space). Three corrections to claims that were wrong rather than incomplete: - the docstring called an earlier statement "superseded". It is not: `_evaluation_id` seeds on `context`, so the same premise re-asked with a different `why_now` mints a *distinct* evaluation. Taking the latest is a choice of the statement closest to the entry, not a supersede semantic. - a comment offered `recalled_statement` to "the receipt". `ux_receipt`'s `question_presented` accepts only source and digest and rejects content. - the test fixture wrote a context with `reason` alone, a shape `decision-context.schema.json` forbids — it requires `why_now` too, so the core test was asserting against a record `consider` cannot write. `docs/maintainer-guide.md`'s mirrored-surfaces row still said `_evaluation_reconciliation` was the only reader of `trade_evaluations.jsonl` outside `consider`. It now names both readers and states why their filters differ, so a third one has to choose deliberately. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
4 tasks
This was referenced Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What the user sees
A first review asks every un-thesised holding what its entry thesis was, and offers five buckets. For a position the user had already discussed through
consider, their exact words were sitting intrade_evaluations.jsonlthe whole time — stored verbatim, read by nothing outsideconsideritself.Same question kind, same choices, same event, same slot in the #291 density band. The question is asked better, not asked twice.
Why recall does not route through
_evaluation_reconciliationThat surface looked like the obvious source and is the wrong one, twice over:
actedis exactly the case worth recalling;additionalProperties: false._evaluation_recallreads the store directly and does not readdecisionat all.Boundaries, each locked by a test
reason/why_nowis dropped, not quoted emptyconsiderruns fine with no--decision-context; a recalled blank is worse than the canned question it replacesTICKER#unknown) recalls nothingSame-day counts: contemplation and fill routinely land on one date.
This states a fact and never a cause. The stem says the user said this, on this date. It never says the position was opened because of it — the same boundary
_evaluation_reconciliationdocuments for itself.What this deliberately does not do
initial_thesisstays inKNOWN_UNWIRED. This improves the question; the answer still has no consumer. [design·P1] Two questions collect an answer nothing reads: initial_thesis and exit_consistency (proved by a byte-identical card) #429 is not fixed here, and claiming it was would be false.noteslot already exists and is already stored — only the invitation is missing. Wiring it before a reader exists would make [design·P1] Two questions collect an answer nothing reads: initial_thesis and exit_consistency (proved by a byte-identical card) #429 worse, not better (see [epic·design] How we ask, how we collect, how we distill — one view over the question layer #398).considerrequires one, so cold start is untouched. That path needs the thesis aggregate refactor and three product-contract changes, tracked on [feat·M2] DecisionIntent memory — automatically record a live trade intent, then resolve it from execution evidence or one follow-up #636.Verification
python3 tests/run_all.py— 49/49 suites pass, re-run after rebasing ontomain@22417a7._evaluation_recallto return empty → red; removing the entry-date boundary → red.🤖 Generated with Claude Code