fix(prompts): render locally recorded lessons and pitfalls - #1464
fix(prompts): render locally recorded lessons and pitfalls#1464rpoornac wants to merge 1 commit into
Conversation
|
The defect is real — locally recorded lessons and pitfalls never reach 5b/5c. But Suggested direction:
Also worth noting: a non-empty input list can still render as |
993905b to
740d245
Compare
|
You're right, and the correction goes further than the patch: I justified the And the Reworked along your six points: 1–2. Flat reads. 3. One unwrap, at the boundary. Silence. Same helper drops rows missing the required field and logs the count and the field name. This is the part of your review I'd underweighted: the bug wasn't that the reader was wrong, it was that being wrong cost nothing — a non-empty list rendered 4. Contract docs. Fixed all four you listed — the section docstrings, 5. Fixtures. Flat now, including a wrapped fixture in 6. Rebased onto current main. Full suite: 16,281 passed, 8 failed — the same 8 that fail on a clean One thing I did not touch, so it's a deliberate omission rather than an oversight: both renderers still accept a bare |
|
Correcting one thing I said above, since you may act on it: "There is no remote KB" was too broad. The Cortex/gbrain KB backend is gone — It doesn't change the fix, and it doesn't rescue the fallback I removed. No code in this repo writes an I found this while working through your review on #1466, which turns on |
Sections 5b and 5c read `point["attrs"]["statement"]` /
`point["attrs"]["description"]`, but nothing writes an `attrs`-wrapped
experience row. `Recipe.to_dict`, `_normalise_lessons` and
`_normalise_str_dicts` all write flat rows, `writeback` appends
`{statement, measured_impact}` flat, and
`test_t0_anchor_surfaces_pitfalls_and_lessons_from_existing_row` already
asserted `state.warm_start_lessons[0]["statement"]`. A flat row resolved
`attrs` to `{}`, produced an empty statement, hit the `if not statement:
continue` guard, and both sections fell through to their `(none)`
placeholder. Every lesson and pitfall a session recorded was invisible to
the next one.
The wrapped form survived only in hand-written test fixtures, so delete
it rather than accommodate it: the renderers read the flat fields
directly, and the single place a legacy wrapped row is unwrapped is
`recipe_kb_t0._experience_rows`, where `warm_start_lessons` /
`warm_start_pitfalls` are assigned. No reader downstream knows two shapes.
That normalisation is also where an unusable row is dropped, with a
warning naming the field and the count. The silence is what let this run
so long: a non-empty list could render as `(none)` with no log and no
error. Rejecting at the boundary puts the complaint where the shape is
known, instead of adding a warning to a renderer that should not be
inspecting shapes at all.
Correct the contract docs that caused the drift — the section docstrings
("KB `kind=lesson` points"), `_render_measured_impact`
("`attrs.measured_impact`"), `_format_version_note`'s `lesson_attrs`
parameter, and the `SharedState.warm_start_pitfalls` / `warm_start_lessons`
field comments ("list of KB point dicts"). Fixtures are flat, and two are
built by calling the writer so the reader and the stored shape cannot
drift apart again.
Co-authored-by: Cursor <cursoragent@cursor.com>
740d245 to
c4b2841
Compare
|
Closing the sub-clause in your point 3 that I'd skipped — "assert there that the snapshot carries no Writing the on-disk case for it turned up something that sharpens where the tolerance belongs. I seeded a wrapped row directly into So the unwrap is remote-only, and I've said so in the helper docstring rather than calling it "legacy", which was a guess dressed as a reason. The disk case is now tested for what it does do, which is the part that matters here: the unparseable row is dropped with Same 8 pre-existing failures as clean |
Description: what and why
Sections 5b (
RELATED LESSONS) and 5c (KNOWN PITFALLS) of the specialistprompt read
point["attrs"]["statement"]/point["attrs"]["description"],which is the shape a remote KB point arrives in. The local store flattens
both on the way to disk —
_normalise_lessonswrites{statement, measured_impact}and_normalise_str_dicts(pitfalls, ("description", "severity"))writes{description, severity}, neither wrapped inattrs.A flat row therefore resolved
attrsto{}, produced an empty statement,hit the
if not statement: continueguard, and both sections fell through totheir
(none)placeholder. Every lesson and pitfall a local-mode sessionrecorded was invisible to the next session — both halves of the KB's memory,
what worked and what to avoid.
Both readers now use the
(point.get("attrs") or point)form already used forthis same wrapped-vs-flat split at three sites in
phases/prelude.py, soremote points and local rows both render. Fixing the reader rather than the
writer keeps the on-disk format and the remote path untouched, and that
renderer is already the designated tolerance point — it carries an explicit
"tolerate shape drift" comment for bare-string rows and simply missed this
shape.
Nothing failed loudly, which is why it survived: the sections are advisory
prose, and every existing test built its fixture in the wrapped shape by
hand, so the writer was never on the other end of an assertion.
Linked issue(s): close/fix refs
None filed.
Tests: added/updated? commands run?
Two added, both in
test_specialist_lessons_section.py. They build theirinput by calling the writer (
_normalise_lessons/_normalise_str_dicts)instead of hand-writing a dict, which is what stops the two sides drifting
apart silently again. Both fail on
mainwith the section rendering(none).Also verified as a real round trip: written through
LocalRecipeStore.put_recipe,read back off disk, rendered into the prompt.
Breaking changes: yes/no (details if yes)
No. Remote (wrapped) points render exactly as before; this only adds a
fallback for rows that previously rendered as nothing.
PR addresses single concern: yes/no (details if no)
Yes — one defect, in the two renderers that share it.
Noting one adjacent bug found while tracing this, deliberately not fixed
here:
SharedState.to_warm_start_summaryrenders the=== Warm start ===section by reading
entry.get("raw") or entry.get("symptom"), field names nowriter produces. It is broken for the flat and wrapped shapes, so the root
cause is different (wrong field names, not the wrapper), and it emits a
misleading
pitfalls (1):header with nothing beneath it. Worth its ownchange.
Root cause is upstream (Magpie/TraceLens/GEAK/IntelliKit/AgentKernelArena), ticket filed:
No — root cause is in this repo.