From 9fab72ce098b04826faa388148ce74e07b1b790d Mon Sep 17 00:00:00 2001 From: Carr1005 Date: Thu, 16 Jul 2026 23:40:44 +0800 Subject: [PATCH] Add as-is decision gate and clarify course defaults --- .../references/spec-generation-guide.md | 49 ++++++++++-------- .../spec.md | 50 +++++++++++-------- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/.claude/skills/generate-spec/references/spec-generation-guide.md b/.claude/skills/generate-spec/references/spec-generation-guide.md index f84141c..2b36858 100644 --- a/.claude/skills/generate-spec/references/spec-generation-guide.md +++ b/.claude/skills/generate-spec/references/spec-generation-guide.md @@ -256,10 +256,11 @@ A Decision Ledger that no one is shown is worthless. A build agent's default beh - **Imperative and build-agent-addressed.** "You are the build agent. Before writing ANY code, you MUST…" — not a passive "review before build" header (which reads as a note to a human skimming and gets skipped). - **First.** It is spec section `## 0`, ahead of everything including the Decision Ledger, visually isolated. +- **An express lane for the as-is builder, asked first.** The gate's FIRST question offers exactly two paths: build the course-default takeaway **as-is** (every Ledger row resolves to its Default), or **customize** the decisions row by row. Choosing as-is skips the per-row questions entirely — the agent prints the full resolved-decision checklist (every row = its Ledger default) and begins building; choosing customize enters the one-question-per-row loop. This is NOT an escape clause (§12.10): the user gave an explicit answer that covers every row — the same "defaults are fine" reply the determinism argument already sanctions — and the printed checklist still makes completeness visible. What stays forbidden is proceeding on *silence*. - **Presents EVERY Ledger row.** Do not have the gate re-filter or tier rows — the §5.5 surfacing bar already decided what became a row, so every row is by construction worth showing. (Never key the gate on row numbers; row identities are course-specific.) - **One question per row — do not depend on a channel's item cap.** Interactive question tools cap how many questions fit in one call (Claude Code's `AskUserQuestion` allows at most a few), and a Ledger can have many rows. If the gate says "present every row" without saying *how*, the agent improvises — batching inconsistently, or (worse) presenting a first batch, getting a reply, and treating the build as unblocked while the rest are never asked (§12.11). Fix the mechanism deterministically: **one row = one question**, looped until every row is asked. One-per-row has no batch boundary to mis-track and its completeness is a plain count (N rows ⇒ N questions). **Never hardcode a numeric cap** ("4") into the gate — that is one environment's limit; state the capacity-relative rule instead so it holds for an uncapped or plain-text channel too. - **Checklist-echo gates the build, not "a reply happened".** Keying resumption on "the user replied" fails the moment many rows exist: a reply to *some* rows satisfies it, and the rest are buried. Require a **visible artifact** instead — before any code, the agent prints a checklist of every row with its resolved value. A completion-driven agent cannot produce that checklist without having resolved every row, and the user/reviewer can *see* completeness. A printed artifact beats an internal "did I ask N times?" count precisely because the same agent that skips rows is the one that would judge the count. -- **Labels each row's value "course default", never "recommended".** The default is factual provenance (what the course did / the §3 precedence branch), not advice about *this* learner's project — the generator has no learner context and must not imply the default is best for them. The gate must carry this labeling instruction **explicitly, naming the forbidden label**: a structured question tool's own conventions may tell the agent to tag an option "(Recommended)" (Claude Code's `AskUserQuestion` does exactly this), and weak wording ("with the course default marked") loses to the tool's convention — observed in a real run. +- **Labels the course's actual choice "(course default)"; the build agent's own "(Recommended)" flag may coexist.** "(course default)" is factual provenance — what the course actually did — and must always mark the option the course actually used. On a **substitution row** (§3 dependency-precedence branch 1) that is the course-faithful **Options** entry, NOT the substituted Ledger Default: labeling the substitute "(course default)" misattributes it (observed in real learner feedback — a SQLite+Chroma default presented as the course's choice when the course ran Oracle). Separately, the build agent may mark an option "(Recommended)" per its own judgment or its question tool's convention (Claude Code's `AskUserQuestion` suggests exactly this) — that is advice about *this* learner's project, a different claim from provenance, and it is allowed. The two labels compose: when the agent's recommended option differs from the course's choice, both labels appear, each on its own option; when the recommended option IS the course's choice, use the single combined label **"(Recommended - course default)"**. A recommendation never removes or moves the "(course default)" label. - **A hard stop, with no escape clause.** Presenting the decisions must end the agent's turn: it stops and waits for the user's reply before writing any code or touching any file. Do **not** give it a "proceed if there's no response" release valve — that is the loophole that re-opens §12.10: the agent *always* trivially has "no response" the instant it finishes presenting, so it reads the valve as immediate permission and the ask becomes theater. A narrower "proceed if launched non-interactively" escape is the same hole, smaller — drop it too; a completion-driven agent steers into whatever escape exists. Determinism is **not** at risk from waiting: it comes from every row having one course-derived default (§3, Known-Trap #7), so a user who replies "defaults are fine" lands on the identical target. Waiting changes *when* the agent proceeds, never *what* it builds. (If a genuinely headless harness cannot answer, the absent reply stalls that build — the harness's constraint to resolve by pre-answering, not a hole the spec should pre-drill.) - **Structured tool required when available; still portable.** If the environment has an interactive structured-question tool (Claude Code's `AskUserQuestion` or an equivalent), the gate MUST require using it — it is the reliability lever, not a mere suggestion. Name specific tools only as *examples* of the class, never as a hard dependency: a non-Claude agent (Codex, Cursor, plain chat) with no such tool must still comply by listing the rows in its reply and asking. So the rule is "use a structured question tool **if you have one**, else ask in plain text" — mechanism-*required* where possible, mechanism-*agnostic* in fallback. @@ -275,26 +276,33 @@ not because they are the right choice for this person's project. 1. **Use a structured question tool if you have one.** If your environment offers an interactive structured-question tool (e.g. Claude Code's `AskUserQuestion`, or the equivalent - in yours), you MUST use it to present the decisions — do not paraphrase them into a prose + in yours), you MUST use it for the questions below — do not paraphrase them into a prose paragraph. Only if no such tool exists, list the rows in your reply and ask the user to respond to each. -2. **Present the Ledger ONE ROW AT A TIME — one question per row.** For each row ask a single - question: the **Decision** as the prompt, its **Options** as the choices with the **course - default** marked — append "(course default)" to that option's label, NEVER "(Recommended)"; - if your question tool's own guidance suggests a "Recommended" labeling convention, do not - use it here (the default is factual course provenance, not advice for this person's - project). Put any realizations beyond the tool's option slots (or the free-form case) - under the tool's "Other"/free-text. Ask about **every** row. A per-call item limit is NEVER a - reason to drop, skip, merge, or silently default a row — make as many separate calls as there - are rows. -3. **Presenting the decisions ENDS YOUR TURN — stop here; write no code, create or edit no file, - take no other build action.** Keep asking, one row at a time, until **every** row has an - answer (a chosen option, or an explicit "use the course default"). Answers to *some* rows do - NOT release the build; "no reply yet" is not an answer — wait for the user. -4. **Before the first line of code, print a resolved-decision checklist** — every Ledger row - with its final value (the user's choice, or "course default"). Begin implementation ONLY +2. **First question — build as-is, or customize?** Ask exactly one question with two options: + build the course-default takeaway **as-is** (every Ledger row resolves to its Default), or + **customize** the decisions row by row. If the user chooses as-is, skip step 3 — go straight + to the step-5 checklist and build. If the user chooses customize, continue with step 3. +3. **Present the Ledger ONE ROW AT A TIME — one question per row.** For each row ask a single + question: the **Decision** as the prompt, its **Options** as the choices. Append + "(course default)" to the option the course actually used — on a substitution row that is + the course-faithful Options entry, not the Ledger Default. You may also mark an option + "(Recommended)" per your own judgment or your question tool's convention; when your + recommended option IS the course's actual choice, merge the labels into + "(Recommended - course default)". A recommendation never removes or moves the + "(course default)" label. Put any realizations beyond the tool's option slots (or the + free-form case) under the tool's "Other"/free-text. Ask about **every** row. A per-call item + limit is NEVER a reason to drop, skip, merge, or silently default a row — make as many + separate calls as there are rows. +4. **Presenting any of these questions ENDS YOUR TURN — stop here; write no code, create or edit + no file, take no other build action.** Keep asking, one row at a time, until **every** row has + an answer (a chosen option, an explicit "use the course default", or the step-2 as-is answer, + which resolves every row at once). Answers to *some* rows do NOT release the build; "no reply + yet" is not an answer — wait for the user. +5. **Before the first line of code, print a resolved-decision checklist** — every Ledger row + with its final value (the user's choice, or its Ledger default). Begin implementation ONLY after this complete checklist is shown; if any row is unresolved you are not done — return to - step 2. Build on the checklist's values. + step 3. Build on the checklist's values. ``` --- @@ -380,7 +388,7 @@ Each occurred in a real run; check for them explicitly. 7. **Ambiguous default → inconsistent builds.** A spec that leaves the no-intake target unresolved — readable as either "build the course's own carried-in example" or "build some agnostic project" — makes the coding agent pick differently run to run. Fix: resolve **one** deterministic default per Decision Ledger row (§3, §5.5) and bake it in, so every build-from-spec run with no intake lands on the same target. 8. **Contract-instead-of-default.** A Ledger row whose "default" is actually a *contract* ("any store that supports vector similarity and exact lookup") or a *menu* ("e.g. SQLite / pgvector / Oracle") names no single target — so the build agent picks, and two builds diverge. This is the exact failure observed when one generation baked a concrete local store and another wrote a menu. Fix: a default is **one buildable target**; the alternatives live in the **Options** column, not the Default. For a heavy-dependency row, apply the §3 dependency precedence and state the branch. 9. **Live decision buried as prose.** A design-structural, course-argued, or course-contradicted decision (store type, a narrated architecture trade-off, a contradicted metric or `k`) written only as a CTX-C paragraph is never *surfaced* — no one is asked to decide, and the generator silently resolves it (often inconsistently run to run). Fix: promote it to a Decision Ledger row (§5.5 surfacing bar); leave only the durable background in CTX-C, cross-referenced to the row. -10. **Silent-default build.** Even a perfect Decision Ledger is never shown to the learner if nothing tells the *build* agent to present it. Because every row carries a complete default, the build never *blocks*, so a build agent proceeds silently on defaults and the learner sees no decision at all — the worst failure, since the decisions are on the page and still invisible. Fix: the spec MUST open with the §0 pre-build gate (§6.0) — an imperative, build-agent-addressed instruction to present every Ledger row and then **hard stop** (end the turn; write no code and touch no file until the user replies). **The gate MUST NOT carry a "proceed if there's no response" escape** — that re-opens this very trap: the agent *always* trivially has "no response" the moment it finishes presenting, so it reads the escape as immediate permission and the ask becomes theater. A narrower "proceed if launched non-interactively" escape is the same hole, smaller; omit it. A visible Ledger without the §0 hard-stop gate — or a gate with an escape clause — is a defect. +10. **Silent-default build.** Even a perfect Decision Ledger is never shown to the learner if nothing tells the *build* agent to present it. Because every row carries a complete default, the build never *blocks*, so a build agent proceeds silently on defaults and the learner sees no decision at all — the worst failure, since the decisions are on the page and still invisible. Fix: the spec MUST open with the §0 pre-build gate (§6.0) — an imperative, build-agent-addressed instruction to present every Ledger row and then **hard stop** (end the turn; write no code and touch no file until the user replies). **The gate MUST NOT carry a "proceed if there's no response" escape** — that re-opens this very trap: the agent *always* trivially has "no response" the moment it finishes presenting, so it reads the escape as immediate permission and the ask becomes theater. A narrower "proceed if launched non-interactively" escape is the same hole, smaller; omit it. The §6.0 express lane is NOT such an escape: choosing "build as-is" is an explicit user reply that resolves every row to its default — the trap is proceeding on *silence*, never proceeding on an answer. A visible Ledger without the §0 hard-stop gate — or a gate with an escape clause — is a defect. 11. **Partial-present build.** A distinct failure from §12.10, triggered by *many* rows plus a per-call-capped question tool (e.g. Claude Code's `AskUserQuestion` takes only a few questions per call; a Ledger may have a dozen-plus rows). The agent presents a first batch, @@ -418,7 +426,8 @@ Fix, don't annotate. **Decision Ledger** - [ ] The spec opens with the `## 0. Before you build — REQUIRED` gate (§6.0), positioned **before** the Decision Ledger. -- [ ] The gate is imperative and addressed to the build agent, and instructs it to present **every** Ledger row with its value labeled **"course default"** (not "recommended"). +- [ ] The gate is imperative and addressed to the build agent, and instructs it to present **every** Ledger row, labeling the option the course actually used **"(course default)"** — on a substitution row the course-faithful Options entry, never the substituted Default — with the agent's own "(Recommended)" flag allowed and merged into "(Recommended - course default)" when both land on the same option (§6.0). +- [ ] The gate opens with the **as-is / customize express-lane question** (§6.0); the as-is path skips the per-row questions but still prints the full resolved-decision checklist. - [ ] The gate is a **hard stop**: it tells the build agent that presenting the decisions ends its turn — write no code and touch no file — with **no "proceed if there's no response" (or "proceed if non-interactive") escape clause** (§12.10). - [ ] The gate requires a **structured question tool when the environment has one** (e.g. `AskUserQuestion`), named as an example of the class, not a hard dependency; a non-Claude agent (Codex, Cursor, plain chat) can still comply by listing rows in its reply. - [ ] The gate presents **one question per Ledger row** and states that a per-call item limit is never a reason to drop/merge/default a row — **no numeric cap is hardcoded** (§12.11). diff --git a/courses/agent-memory-building-memory-aware-agents/spec.md b/courses/agent-memory-building-memory-aware-agents/spec.md index 0cd0695..08bb611 100644 --- a/courses/agent-memory-building-memory-aware-agents/spec.md +++ b/courses/agent-memory-building-memory-aware-agents/spec.md @@ -21,26 +21,34 @@ not because they are the right choice for this person's project. 1. **Use a structured question tool if you have one.** If your environment offers an interactive structured-question tool (e.g. Claude Code's `AskUserQuestion`, or the equivalent - in yours), you MUST use it to present the decisions — do not paraphrase them into a prose + in yours), you MUST use it for the questions below — do not paraphrase them into a prose paragraph. Only if no such tool exists, list the rows in your reply and ask the user to respond to each. -2. **Present the Ledger ONE ROW AT A TIME — one question per row.** For each row ask a single - question: the **Decision** as the prompt, its **Options** as the choices with the **course - default** marked — append "(course default)" to that option's label, NEVER "(Recommended)"; - if your question tool's own guidance suggests a "Recommended" labeling convention, do not - use it here (the default is factual course provenance, not advice for this person's - project). Put any realizations beyond the tool's option slots (or the free-form case) - under the tool's "Other"/free-text. Ask about **every** row (there are 18). A per-call item - limit is NEVER a reason to drop, skip, merge, or silently default a row — make as many - separate calls as there are rows. -3. **Presenting the decisions ENDS YOUR TURN — stop here; write no code, create or edit no file, - take no other build action.** Keep asking, one row at a time, until **every** row has an - answer (a chosen option, or an explicit "use the course default"). Answers to *some* rows do - NOT release the build; "no reply yet" is not an answer — wait for the user. -4. **Before the first line of code, print a resolved-decision checklist** — every Ledger row - with its final value (the user's choice, or "course default"). Begin implementation ONLY +2. **First question — build as-is, or customize?** Ask exactly one question with two options: + build the course-default takeaway **as-is** (every Ledger row resolves to its Default), or + **customize** the decisions row by row. If the user chooses as-is, skip step 3 — go straight + to the step-5 checklist and build. If the user chooses customize, continue with step 3. +3. **Present the Ledger ONE ROW AT A TIME — one question per row.** For each row ask a single + question: the **Decision** as the prompt, its **Options** as the choices. Append + "(course default)" to the option the course actually used — on a substitution row (e.g. + row 7, where the course ran Oracle AI Database 26ai but this spec's Default is + SQLite + Chroma) that is the course-faithful Options entry, not the Ledger Default. You may + also mark an option "(Recommended)" per your own judgment or your question tool's + convention; when your recommended option IS the course's actual choice, merge the labels + into "(Recommended - course default)". A recommendation never removes or moves the + "(course default)" label. Put any realizations beyond the tool's option slots (or the + free-form case) under the tool's "Other"/free-text. Ask about **every** row (there are 18). + A per-call item limit is NEVER a reason to drop, skip, merge, or silently default a row — + make as many separate calls as there are rows. +4. **Presenting any of these questions ENDS YOUR TURN — stop here; write no code, create or edit + no file, take no other build action.** Keep asking, one row at a time, until **every** row has + an answer (a chosen option, an explicit "use the default", or the step-2 as-is answer, which + resolves every row at once). Answers to *some* rows do NOT release the build; "no reply yet" + is not an answer — wait for the user. +5. **Before the first line of code, print a resolved-decision checklist** — every Ledger row + with its final value (the user's choice, or its Ledger default). Begin implementation ONLY after this complete checklist is shown; if any row is unresolved you are not done — return to - step 2. Build on the checklist's values. + step 3. Build on the checklist's values. ## Decision Ledger (§0 above requires the build agent to present these before building) @@ -55,12 +63,12 @@ for your specific project. | 1 | design-argued | Memory-store topology | Seven distinct memory types exist as separate stores: Conversational and Tool Log in an exact-key, time-ordered relational store; Knowledge Base, Workflow, Toolbox, Entity, and Summary in semantic-similarity (vector) stores with metadata filtering. One manager class fronts all reads/writes. | The 7-store layout exactly as taught: 2 SQL tables (`CONVERSATIONAL_MEMORY`, `TOOL_LOG_MEMORY`) + 5 vector stores (`SEMANTIC_MEMORY`, `WORKFLOW_MEMORY`, `TOOLBOX_MEMORY`, `ENTITY_MEMORY`, `SUMMARY_MEMORY`), unified behind a `MemoryManager` (CTX-A, CTX-C1). | Merge some vector types into one collection with a type field; add graph store; fewer memory types. | Lesson 3 argues it aloud: conversational memory needs *exact retrieval by thread id, not similarity*, so it must not live in a vector store; each memory type has distinct data-model + retrieval needs. Merging types loses per-type retrieval strategies and the memory-aware prompt segmentation. | course | | 2 | design-argued | Deterministic vs agent-triggered operation split | Context-bootstrapping reads and post-turn persistence run deterministically every turn (never at the model's discretion); judgment-heavy operations (deep retrieval, summary expansion, external search) are agent-triggered tools. Conversation summarization is reachable BOTH ways: deterministically at the context threshold and as an agent tool. | The Lesson 6 loop's split: deterministic = read conversational/KB/workflow/entity/summary-context at loop start, write user msg + final answer + workflow + entities + tool logs; agent-triggered = `expand_summary`, `summarize_and_store`, knowledge-acquisition tools; `read_toolbox` is both (CTX-C2). | Make more ops agent-triggered (leaner, riskier); make summarization deterministic-only. | Lesson 3 narrates the argument: "the agent can't choose to look up what it doesn't know exists — you need memory to know which memory you need"; deterministic ops buy predictability/continuity, agent-triggered ops buy signal-to-noise and cost control. NOTE the course self-contradicts in detail: the Lesson 3 classification table marks `read_summary_context` and `write_entity` agent-triggered, but the Lesson 6 loop executes both deterministically every turn. Default follows the Lesson 6 loop (the end-to-end app). | course | | 3 | design-argued | Context-reduction strategy | Reducing context must be *recoverable*: any compression stores a link back to the original units, and an agent-callable expansion path exists. The current `# Question` is never summarized away. | Recoverable compaction as taught: LLM summarization into structured summaries stored with `summary_id`, source conversation rows marked with that id, `expand_summary(id)` retrieves summary + all original messages (CTX-B4, CTX-C3). | Pure lossy summarization (no write-back links); sliding-window truncation; no reduction. | Lesson 5 argues it explicitly: summarization "will always be a lossy technique"; compaction offloads to the database with an ID + description so the model can pull full detail back on demand. Dropping the link severs recoverability. | course | -| 4 | design-argued | Tool exposure to the LLM | The LLM never receives the full toolbox. Tools live in a searchable vector store keyed on their (optionally augmented) descriptions; per query, only the top-k semantically relevant tools are passed, deduplicated by name. | Toolbox vector store + semantic retrieval, `k=5` at the agent loop (CTX-C4). | Static hand-picked toolset per agent; all tools in every prompt (only viable for very few tools). | Lesson 4 argues the failure: too many tool definitions cause context confusion/bloat, tool-selection degradation, higher latency and cost; the notebook cites provider guidance of ~10–20 tools max for reliable selection, with 3–5 retrieved typically. | course | +| 4 | design-argued | Tool exposure to the LLM | The LLM never receives the full toolbox. Tools live in a searchable vector store keyed on their (optionally augmented) descriptions; per query, only the top-k semantically relevant tools are passed, deduplicated by name. | Toolbox vector store + semantic retrieval, top-k per query — k pinned in row 17 (CTX-C4). | Static hand-picked toolset per agent; all tools in every prompt (only viable for very few tools). | Lesson 4 argues the failure: too many tool definitions cause context confusion/bloat, tool-selection degradation, higher latency and cost; the notebook cites provider guidance of ~10–20 tools max for reliable selection, with 3–5 retrieved typically. | course | | 5 | design-argued | Tool docstring augmentation | Each registered tool is retrievable by semantic search over a text that includes at least its name, description, and signature. | Augment heavy/ambiguous tools at registration: an LLM rewrites the docstring from docstring + source code, plus ~5 synthetic trigger queries, and that enriched text is embedded (`augment=True`). Final-lesson config: `fetch_and_save_paper_to_kb_db`, `expand_summary`, `summarize_and_store` augmented; `arxiv_search_candidates`, `get_current_time` registered raw (helper `register_common_tools`). | Raw docstrings only (cheaper registration, weaker separability); augment everything. | Lesson 4 argues augmentation gives better separability in embedding space, higher recall, higher-signal embedding text — at the cost of LLM calls per registration. Minor course drift: the Lesson 4 notebook registered `get_current_time` with `augment=True`; the final helper registers it raw. Default follows the final helper. | course | | 6 | design-structural | Partitioned context window + memory-aware system prompt | The prompt context is assembled as a `# Question` section followed by one markdown `##` segment per memory type (Conversation, Knowledge Base, Workflow, Entity, Summary), each carrying what-this-memory-is and how-to-use-it guidance; the system prompt names the segments, their semantics, the summary-expansion policy, and a conflict-priority order (Question > latest Conversation > KB evidence > older summaries/workflows). | Exactly that structure, as taught in Lesson 6 (CTX-C5). | One undifferentiated context blob; JSON-structured context. | Lesson 6 explains the mechanism: markdown headings let the LLM exploit its latent grasp of hierarchical structure, making the agent *aware* of its memories instead of merely augmented by them. Restructuring the segments changes what every memory read returns (each read formats its own segment). | course | -| 7 | realization | Persistent store technology | One durable local system providing (a) exact-key relational tables with timestamp ordering for Conversational + Tool Log memory and (b) vector similarity search **with metadata filtering** (equality and numeric `$gt`) for the 5 vector stores. All memory survives process restarts. | **SQLite (two relational tables) + Chroma `PersistentClient` (five collections), both under `./data/`.** §3 dependency-precedence **branch 1**: the course realizes this on Oracle AI Database 26ai in Docker (admin bootstrap, `VECTOR` user, DSN `127.0.0.1:1521/FREEPDB1`), a heavy dependency that merely realizes the taught dual-store pattern — the pattern, not Oracle, is the subject, so the default substitutes the lightest self-contained equivalent. | Oracle AI Database 26ai + `langchain-oracledb` `OracleVS` (course-faithful; needs Docker + admin setup); Postgres + pgvector; any store meeting the invariant. | Switching store later means migrating rows and re-creating indexes; Oracle adds infra setup cost but restores 1:1 fidelity with course APIs (OracleVS, hybrid-search preference, IVF indexes). | course+learner | +| 7 | realization | Persistent store technology | One durable local system providing (a) exact-key relational tables with timestamp ordering for Conversational + Tool Log memory and (b) vector similarity search **with metadata filtering** (equality and numeric `$gt`) for the 5 vector stores. All memory survives process restarts. | **SQLite (two relational tables) + Chroma `PersistentClient` (five collections), both under `./data/`.** §3 dependency-precedence **branch 1**: the course realizes this on Oracle AI Database 26ai in Docker (admin bootstrap, `VECTOR` user, DSN `127.0.0.1:1521/FREEPDB1`), a heavy dependency that merely realizes the taught dual-store pattern — the pattern, not Oracle, is the subject, so the default substitutes the lightest self-contained equivalent. | Oracle AI Database 26ai + `langchain-oracledb` `OracleVS` (course default — what the course actually ran; needs Docker + admin setup); Postgres + pgvector; any store meeting the invariant. | Switching store later means migrating rows and re-creating indexes; Oracle adds infra setup cost but restores 1:1 fidelity with course APIs (OracleVS, hybrid-search preference, IVF indexes). | course+learner | | 8 | realization | Knowledge-acquisition toolset | At least one agent-triggered tool acquires external knowledge and **persists what it finds to the Knowledge Base** (the search-and-store pattern), so discovered information is reusable without re-fetching. | The final lesson's common toolset: `arxiv_search_candidates` (metadata-only discovery) + `fetch_and_save_paper_to_kb_db` (full PDF→text, chunked 1500/200, stored with metadata) + `get_current_time`, plus the summary tools. **Tavily web search is NOT in the default build** — §3 branch 1: it needs a paid API key and the final lesson's agent doesn't register it; the search-and-store pattern it demonstrated is preserved by the arXiv ingestion tool. | Add `search_tavily` (course showed it in Lesson 4; requires `TAVILY_API_KEY`); substitute your own domain's fetch/search tools. | Tavily gives open-web reach at key + cost; arXiv tools are keyless but network-dependent and domain-narrow. | course+learner | -| 9 | realization | Knowledge-base seed data | The KB starts non-empty so retrieval grounding is demonstrable on day one; each record carries searchable text (title+subjects+abstract concatenated) and metadata for filtering/attribution. | **The synthetic fixture corpus defined in §5** (6 self-authored paper records baked into this repo). §3 branch 1: the course streamed 100 records from the HuggingFace dataset `nick007x/arxiv-papers` — an external download that can't be baked into this file; the fixture corpus preserves the record shape (title, subjects, abstract, submission_date, arxiv_id). | The HF dataset (course-faithful); the learner's own documents. | Fixtures make acceptance tests deterministic/offline; the HF stream gives realistic scale but non-reproducible content and a network dependency. | course+learner | +| 9 | realization | Knowledge-base seed data | The KB starts non-empty so retrieval grounding is demonstrable on day one; each record carries searchable text (title+subjects+abstract concatenated) and metadata for filtering/attribution. | **The synthetic fixture corpus defined in §5** (6 self-authored paper records baked into this repo). §3 branch 1: the course streamed 100 records from the HuggingFace dataset `nick007x/arxiv-papers` — an external download that can't be baked into this file; the fixture corpus preserves the record shape (title, subjects, abstract, submission_date, arxiv_id). | The HF dataset (course default — what the course actually streamed); the learner's own documents. | Fixtures make acceptance tests deterministic/offline; the HF stream gives realistic scale but non-reproducible content and a network dependency. | course+learner | | 10 | learner | Project — [project] | — (the pattern imposes nothing) | A **memory-aware research-assistant chat agent** (CLI), the course's own running example shape ("agentic research assistant … over multiple sessions", a.k.a. ArxivScout), instantiated on the §5 fixture corpus. §3 project precedence **branch 1** (course example shape on synthetic fixtures). | Any project the learner wants to graft the pattern onto. | Retitling to a real project means re-deriving fixtures and goals; the default is judged by §5 as-is. | learner | | 11 | learner | Data / inputs — [data] | — | Synthetic fixture corpus (§5) + live arXiv metadata/PDFs fetched on demand by the row-8 tools. | Learner's own corpus/APIs. | Real data invalidates the fixture-based ACs until equivalents are authored. | learner | | 12 | learner | Goal / definition of "working" — [goal] | — | Pass all §5 acceptance criteria: cross-session continuity, capped semantic tool retrieval, threshold-triggered recoverable compaction, summary expansion, audit-logged tool execution. | Learner-defined retrieval/answer guarantees. | — | learner | @@ -69,7 +77,7 @@ for your specific project. | 15 | learner | Out of scope — [out-of-scope] | — | Exactly the §1 "Not Included" list. | Learner may pull items in or push more out. | — | learner | | 16 | contradicted | Vector distance strategy | All five vector stores use the **same** distance strategy as each other and as their indexes, chosen once before any data is embedded. | **EUCLIDEAN (L2)** — the final application's config: the Lesson 5 and Lesson 6 notebooks both construct the StoreManager with `DistanceStrategy.EUCLIDEAN_DISTANCE`. The course contradicts itself: the Lesson 3 and Lesson 4 notebooks (and the Lesson 3 narration, "which in this case is going to be cosine") use `COSINE`, and the Lesson 3 notebook's own intro table says EUCLIDEAN while its code says COSINE. Default follows the end-to-end app config per the multiple-configs rule. | COSINE (Lessons 3–4 config); DOT product. | Changing strategy after ingest invalidates similarity semantics and requires re-indexing; mixed strategies across lessons is exactly the stale-data hazard the notebooks' "drop all tables for a consistent distance strategy" warning exists for. | course | | 17 | contradicted | Toolbox retrieval k | Tool retrieval returns a small bounded set (course guidance: providers recommend ~10–20 tools max exposed; typically 3–5 retrieved). | **k=5 at the agent loop** (Lesson 6 `read_toolbox(query, k=5)`). The course contradicts itself: `MemoryManager.read_toolbox` signature defaults `k=3`; the Lesson 4 registered `read_toolbox` tool's signature says `k: int = 3` while its own docstring says "default: 5". Keep the manager default 3 and pass 5 in the loop, matching the course's call site. | Any small k. | Larger k re-introduces the context-bloat/selection-degradation failure the toolbox pattern exists to prevent (Lesson 4). | course | -| 18 | contradicted | Vector index type | Every vector store has an ANN index created before serving queries; index distance matches row 16. | Follow the row-7 default store's native ANN index (Chroma manages its own). If Oracle is chosen: **IVF** (`ORGANIZATION NEIGHBOR PARTITIONS … WITH TARGET ACCURACY 95`) — what the course's `safe_create_index` actually creates. The course contradicts itself: Lesson 3's notebook markdown and lesson objectives narrate an **HNSW** index, but the helper deliberately uses IVF to dodge Oracle Free bugs (ORA-00600, ORA-51928, ORA-51962). | HNSW (as narrated); IVF (as coded). | HNSW was shown to be crash-prone on the course's own Oracle build; IVF trades some recall for stability there. | course | +| 18 | contradicted | Vector index type | Every vector store has an ANN index created before serving queries; index distance matches row 16. | Follow the row-7 default store's native ANN index (Chroma manages its own). If Oracle is chosen: **IVF** (`ORGANIZATION NEIGHBOR PARTITIONS … WITH TARGET ACCURACY 95`) — what the course's `safe_create_index` actually creates (course default when Oracle is chosen). The course contradicts itself: Lesson 3's notebook markdown and lesson objectives narrate an **HNSW** index, but the helper deliberately uses IVF to dodge Oracle Free bugs (ORA-00600, ORA-51928, ORA-51962). | HNSW (as narrated); IVF (as coded). | HNSW was shown to be crash-prone on the course's own Oracle build; IVF trades some recall for stability there. | course | ## 1. Objective