Project Memory: serve proposals, drop codemap
Implement the five improvements from the Project Memory audit (Task 6283; the audit report is attached). The audit scanned 251 memory-ON runner sessions (2026-10-11..14): only 21 distinct non-codemap units ever reached a prompt, codemap chunks were 42% of injected bytes with zero reads, 24 of 74 search/read tool calls failed on argument names, 16 accepted runner proposals never became injectable, and memory_feedback was called once. The five changes below are one coherent flywheel fix; each is independently shippable.
1. Serve proposals, stop auto-serving settle narrative.
Flip the injectable-on-accept rule in apps/api/app/project_memory/vocabulary.py (INJECTABLE_ON_ACCEPT feeds, line ~23; consumers curate.py ~266, distill.py ~189): a runner's memory_propose unit (gotcha with repro, recipe, env, qa) becomes injectable on accept after the existing secret and canon checks; a settle-mined qa unit (recon_map.recon[] mining in curate.py settle_candidates) is accepted but NOT injectable until corroborated (curate.py corroborate). Keep distilled units as they are unless the Planner finds a reason otherwise.
2. Take codemap out of prompts and search; retire old generations.
Codemap units never fill a prompt slot (select.py ~151-152: exclude, do not just sort last) and never rank in memory_search results unless kind=codemap is requested explicitly. Keep them for the hook tier on a Read/Glob of their exact directory (tools/project_memory_tier.py). When tools/project_memory_node.py re-maps a directory, the capture path (apps/api/app/project_memory/capture.py _candidates, insert-only today) retires that directory's previous chunks in the same write.
3. Demote on use, not just on age; make gotchas verifiable.
(a) Record an injection count per unit (events.py ~65-68 stores only last_injected_at today) and drop `injectable` after 20 injections with zero read/followed/non-provisional cited events; expose the count in Project > Memory. (b) In gates.py: refuse a gotcha or qa whose body names a repo path (backticked path or file:line) but carries no `paths`, OR auto-fill `paths` from those backticked paths, so the node-side stale verifier can check it (mem-2 was followed 170 times after its fix landed because it had no paths). (c) Add a time-bound gate beside _TASK_STATE in gates.py: a body or title matching "yet", "what is left", "next ", "head is", "currently", "so far", "still" is state, not a fact, and is rejected with reason `time_bound`.
4. Make the tools impossible to misuse, and the hook line free to use.
In apps/jaahd/agent_vocabulary.py (verb table ~676-722, arg handling ~1519-1536): accept the aliases runners keep guessing (`query`->`q`, `id`/`unit_id`->`unit`, `action`->`verdict`) and answer any other unknown argument with a malformed_call-style error that names the accepted argument, instead of silently dropping it or returning a bare bad_request. For the hook tier: carry a short lead (first sentence, <=200 chars) of each unit's body in the bundle (bundle.py _entry ~84-91) and render it on the [memory] line (tools/project_memory_tier.py ~348-352) so a surfacing informs without a memory_read round trip. Respect the router's existing 60-line cap.
5. Close the trust loop at settle.
Collect votes where the runner already is: the settle call (or the Stop hook before it) takes a structured list of injected units used and units found wrong, and the CP mints confirm/flag votes from it (routes/agent_memory.py feedback path ~279-316). Mint `followed` from real use (the unit's own command string appearing in a Bash call, or its mem-N in the settle summary), not from path overlap (tools/context_router.py ~806-815). Update comparison.py read_rate (~183-237) so "used" reflects the new semantics. In Project > Memory (apps/web/src/components/projects/ProjectMemoryTab.tsx ~186-208) show injected/used/followed counts with a sort, so an operator can retire dead units by eye. Merge the duplicate pairs the audit found (mem-6130/mem-11178, mem-2/mem-3) via the existing near-duplicate path once it is exercised.
Out of scope: the two immediate data fixes (purging mem-7834's login triple and retiring mem-2/mem-3) are operator actions in Project > Memory, not code in this epic; profiling the node-side codemap job and curate/nightly cron cost; changing the OFF-arm behaviour (memory OFF must remain byte-identical, see apps/api/tests/memory_off_fixture.py); any new memory kind; org-scoped memory.
Done means:
- A memory_propose gotcha/recipe/env/qa that passes the gates is served in the next dispatch prompt of the same project without corroboration; a settle-mined qa unit is not served until corroborated (test in apps/api/tests/test_project_memory_*.py).
- No codemap unit appears in a composed dispatch prompt's PROJECT MEMORY section, and memory_search without kind=codemap returns none; re-mapping a directory leaves exactly one generation of its chunks accepted.
- A unit injected 20 times with no use event is no longer injectable; a gotcha naming a repo path without `paths` is rejected or auto-pathed; a body matching the time-bound patterns is rejected with reason `time_bound` (gate tests).
- memory_search with `query`, memory_read with `id`, memory_feedback with `action` all succeed; an unknown argument returns an error naming the accepted one (apps/jaahd tests). A hook [memory] line carries the unit's lead text (tools/tests/test_context_router_memory.py).
- A settle that names used and wrong units produces confirm/flag votes visible as trust changes; `followed` is minted only from command-string or mem-N use; Project > Memory shows and sorts by injected/used counts (web test).
- Memory OFF parity fixture unchanged. ./dc check full green.
Subtasks
- [business_analysis] Project Memory: serve proposals, drop codemap PRD settled: 19 asks from the 5 Project Memory audit fixes (serve proposals, drop codemap, use-based demotion + time_bound/paths gates, tool aliases + hook lead, settle votes). 18 in scope with oracles, E5 no-code (mem-6130 already stale). OFF goldens untouched. Assumptions in PRD §2.
- [architecture] Project Memory: serve proposals, drop codemap 7 independent children: serve proposals (+backfill); codemap out of prompt/search + whole-dir batching w/ complete-set retirement; time_bound + path autofill gates; shared used predicate → demotion/read_rate/console sort; strict memory args+aliases; hook lead + command-only followed; settle votes (source settle) + summary followed.
- [plan] Project Memory: serve proposals, drop codemap Split by the Architect's runtime/acceptance boundaries into 7 coder children (6296-6302), one phase "Core"; only edge 6302→6296 serialises the two migrations. Critic tightened backfill negatives + settle-failure ACs. No Required checks line (mem-11178).
- Serve memory proposals on accept memory_propose units now served on accept; settle-mined units wait for corroboration. Backfill flips eligible proposals. PR #5440 merged, Jaah Deploy succeeded. Full gate green pre-rebase; post-rebase only red stage is a vitest case already red on develop. AC-A4 dev chip not observable (dev has no propose units).
- Drop codemap from prompts and search Codemap excluded from prompts and runner memory_search (kind=codemap still works), superseded codemap generations retired per directory, node packs whole directories. Full gate green; PR #5437 merged; deploy 38604561138 succeeded. Dev runner probe unverified: dev operator account isn't a Gmind member.
- Add time bound and path-fill gates Added the time_bound exclusion gate and the gotcha/qa path auto-fill. ./dc check full is green; PR #5439 merged as 190c64c; Jaah Deploy 38605239487 succeeded. Deferred: R-C4's word list also rejects lasting uses of "still"/"yet".
- Demote unused units; console usage sort Nightly demotes never-used units (20 injections, 0 use); one shared USE definition for read_rate, demotion and the console; Memory tab gains Used/Followed and a server-side sort. Full gate green, PR #5448 merged, Jaah Deploy succeeded, verified on dev at 360/768/1280. UX follow-ups are in the report (mem-2, mem-10065).
- Memory tool argument aliases, strict refusal memory_* tools now accept query/id/unit_id/action aliases and refuse other args with a named malformed_call before any CP call (0.75 cutoff via aliases so qry→q). PR #5436 merged b26784ba3; Jaah Deploy 38603938492 success. Full gate green bar one xdist worker crash in test_fixture_db (passes 37/37 alone). F1 deferred.
- Hook memory line lead; command-only followed Bundle entries carry a first-sentence `lead`, shown as `mem-N │ kind │ title — lead`; `followed` now comes only from the unit's own command (env prefixes stripped). Full gate green, PR #5438 merged, Jaah Deploy succeeded. Dev-flow probe (dev task 5007) never dispatched: unverified. mem-2 used.
- Settle trust votes and summary followed task_settle memory_used/memory_wrong votes (source settle, via extracted cast_vote) + summary mem-N followed; full gate green, PR #5449 merged, Jaah Deploy ok. Dev runner flow unobserved (dev dispatch stalled). mem-11867 held.
- [finish] Project Memory: serve proposals, drop codemap All 7 coders merged (#5436-5440, 5448, 5449), deploys green; 298+251+10 tests re-run pass; OFF parity held; dev Memory sort/counts work. Filed 6315 (inferred-path stale flag, repro time_bound, propose codemap) and 6316 (Memory tab UX). mem-2, mem-11178 used.
- Memory serving: fix inferred-path stale flags Fixed D1–D5 (inferred-path stale flags, proposed codemap 422 + unserve, repro-safe time_bound, restored backfill 202610142200, runner text). Full gate green (mem-2); PR #5455 merged; Jaah Deploy 38625182342 success. Deferred: D1 limited to inferred paths (needs a column).
- Project › Memory tab: usability fixes seen Memory tab: Live default (status=live), no Cancel/Save bar, one-line counts, zero-sort note, folded codemap chunks. Full gate green; PR #5454 merged; dev deploy 38625182342 green (own run superseded); dev visual check at 360/768/1280 clean. mem-2 used.
Artifacts
Attachments
Activity
- Created
- Updated
- Runner started
- Ready
- Ready
- Ready
- Runner started
- Runner ended (done)
- Runner started
- Runner ended (done)
- Runner started
- Draft
- Draft
- Draft
- Draft
- Draft
- Draft
- Draft
- Draft
- Ready
- Ready
- Ready
- Ready
- Ready
- Ready
- Ready
- Ready
- Runner ended (done)
- Runner started
- Runner started
- Runner started
- Runner started
- Runner started
- Runner started
- Runner ended (done)
- Runner ended (done)
- Runner ended (done)
- Runner ended (done)
- Runner ended (done)
- Runner started
- Runner ended (done)
- Runner ended (done)
- Runner started
- Ready
- Ready
- Runner ended (done)
- Runner started
- Runner started
- Runner ended (done)
- Runner ended (done)
- Runner ended (done)