-
Notifications
You must be signed in to change notification settings - Fork 70
[codex] Persist core-owned interaction state #739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
rahulkarajgikar
wants to merge
13
commits into
truffle-ai:main
Choose a base branch
from
rahulkarajgikar:core-persistence
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
728c310
Persist core-owned interaction state
rahulkarajgikar 231a49c
Add changeset for interaction state persistence
rahulkarajgikar 49e3677
Stabilize session persistence integration test
rahulkarajgikar 6f1858c
Merge branch 'main' into core-persistence
rahulkarajgikar def483a
Merge main into core-persistence
rahulkarajgikar 839845d
Simplify persisted approval scope state
rahulkarajgikar 6781137
Require session-backed message queues
rahulkarajgikar 84039cb
Simplify session persistence plumbing and add skills
rahulkarajgikar 9d70846
Align session lifecycle with persisted interaction state
rahulkarajgikar d9a4ce7
Clarify reset semantics docs
rahulkarajgikar 813caa6
Fix persisted session state regressions
rahulkarajgikar ff04045
Fix persisted interaction state review issues
rahulkarajgikar 6a0b1b1
Scope filesystem services per execution context
rahulkarajgikar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| --- | ||
| name: grill-me | ||
| description: Interview the user relentlessly about a plan or design until reaching shared understanding, resolving each branch of the decision tree. Use when user wants to stress-test a plan, get grilled on their design, or mentions "grill me". | ||
| --- | ||
|
|
||
| Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer. | ||
|
|
||
| If a question can be answered by exploring the codebase, explore the codebase instead. |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| --- | ||
| name: simplify | ||
| description: 'Review changed code for reuse, quality, and efficiency, then fix any issues found. Use when the user asks to simplify, clean up, dedupe, reduce abstraction, remove pointless types, collapse duplicate contracts, replace bespoke parsing or validation with direct schema usage, or make a recent diff easier to read and maintain.' | ||
| --- | ||
|
|
||
| # Simplify: Code Review and Cleanup | ||
|
|
||
| Review all changed files for reuse, quality, and efficiency. Fix any issues found. | ||
|
|
||
| ## Phase 1: Identify Changes | ||
|
|
||
| Run `git diff` (or `git diff HEAD` if there are staged changes) to see what changed. If there are no git changes, review the most recently modified files that the user mentioned or that you edited earlier in this conversation. | ||
|
|
||
| ## Phase 2: Launch Three Review Agents in Parallel | ||
|
|
||
| Launch all three agents concurrently in a single message. Pass each agent the full diff so it has the complete context. | ||
|
|
||
| ### Agent 1: Code Reuse Review | ||
|
|
||
| For each change: | ||
|
|
||
| 1. **Search for existing utilities and helpers** that could replace newly written code. Look for similar patterns elsewhere in the codebase — common locations are utility directories, shared modules, and files adjacent to the changed ones. | ||
| 2. **Flag any new function that duplicates existing functionality.** Suggest the existing function to use instead. | ||
| 3. **Flag any inline logic that could use an existing utility** — hand-rolled string manipulation, manual path handling, custom environment checks, ad-hoc type guards, and similar patterns are common candidates. | ||
|
|
||
| ### Agent 2: Code Quality Review | ||
|
|
||
| Review the same changes for hacky patterns: | ||
|
|
||
| 1. **Redundant state**: state that duplicates existing state, cached values that could be derived, observers/effects that could be direct calls | ||
| 2. **Parameter sprawl**: adding new parameters to a function instead of generalizing or restructuring existing ones | ||
| 3. **Copy-paste with slight variation**: near-duplicate code blocks that should be unified with a shared abstraction | ||
| 4. **Leaky abstractions**: exposing internal details that should be encapsulated, or breaking existing abstraction boundaries | ||
| 5. **Stringly-typed code**: using raw strings where constants, enums (string unions), or branded types already exist in the codebase | ||
| 6. **Unnecessary JSX nesting**: wrapper Boxes/elements that add no layout value — check if inner component props (flexShrink, alignItems, etc.) already provide the needed behavior | ||
| 7. **Unnecessary comments**: comments explaining WHAT the code does (well-named identifiers already do that), narrating the change, or referencing the task/caller — delete; keep only non-obvious WHY (hidden constraints, subtle invariants, workarounds) | ||
|
|
||
| ### Agent 3: Efficiency Review | ||
|
|
||
| Review the same changes for efficiency: | ||
|
|
||
| 1. **Unnecessary work**: redundant computations, repeated file reads, duplicate network/API calls, N+1 patterns | ||
| 2. **Missed concurrency**: independent operations run sequentially when they could run in parallel | ||
| 3. **Hot-path bloat**: new blocking work added to startup or per-request/per-render hot paths | ||
| 4. **Recurring no-op updates**: state/store updates inside polling loops, intervals, or event handlers that fire unconditionally — add a change-detection guard so downstream consumers aren't notified when nothing changed. Also: if a wrapper function takes an updater/reducer callback, verify it honors same-reference returns (or whatever the "no change" signal is) — otherwise callers' early-return no-ops are silently defeated | ||
| 5. **Unnecessary existence checks**: pre-checking file/resource existence before operating (TOCTOU anti-pattern) — operate directly and handle the error | ||
| 6. **Memory**: unbounded data structures, missing cleanup, event listener leaks | ||
| 7. **Overly broad operations**: reading entire files when only a portion is needed, loading all items when filtering for one | ||
|
|
||
| ## Phase 3: Fix Issues | ||
|
|
||
| Wait for all three agents to complete. Aggregate their findings and fix each issue directly. If a finding is a false positive or not worth addressing, note it and move on — do not argue with the finding, just skip it. | ||
|
|
||
| When done, briefly summarize what was fixed (or confirm the code was already clean). | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| interface: | ||
| display_name: 'Simplify' | ||
| short_description: 'Remove accidental complexity from code' | ||
| default_prompt: 'Use $simplify to remove accidental complexity from this diff without changing behavior.' |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| --- | ||
| name: tdd | ||
| description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development. | ||
| --- | ||
|
|
||
| # Test-Driven Development | ||
|
|
||
| ## Philosophy | ||
|
|
||
| **Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. | ||
|
|
||
| **Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure. | ||
|
|
||
| **Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior. | ||
|
|
||
| See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines. | ||
|
|
||
| ## Anti-Pattern: Horizontal Slices | ||
|
|
||
| **DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code." | ||
|
|
||
| This produces **crap tests**: | ||
|
|
||
| - Tests written in bulk test _imagined_ behavior, not _actual_ behavior | ||
| - You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior | ||
| - Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine | ||
| - You outrun your headlights, committing to test structure before understanding the implementation | ||
|
|
||
| **Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it. | ||
|
|
||
| ``` | ||
| WRONG (horizontal): | ||
| RED: test1, test2, test3, test4, test5 | ||
| GREEN: impl1, impl2, impl3, impl4, impl5 | ||
|
|
||
| RIGHT (vertical): | ||
| RED→GREEN: test1→impl1 | ||
| RED→GREEN: test2→impl2 | ||
| RED→GREEN: test3→impl3 | ||
| ... | ||
| ``` | ||
|
rahulkarajgikar marked this conversation as resolved.
|
||
|
|
||
| ## Workflow | ||
|
|
||
| ### 1. Planning | ||
|
|
||
| Before writing any code: | ||
|
|
||
| - [ ] Confirm with user what interface changes are needed | ||
| - [ ] Confirm with user which behaviors to test (prioritize) | ||
| - [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation) | ||
| - [ ] Design interfaces for [testability](interface-design.md) | ||
| - [ ] List the behaviors to test (not implementation steps) | ||
| - [ ] Get user approval on the plan | ||
|
|
||
| Ask: "What should the public interface look like? Which behaviors are most important to test?" | ||
|
|
||
| **You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case. | ||
|
|
||
| ### 2. Tracer Bullet | ||
|
|
||
| Write ONE test that confirms ONE thing about the system: | ||
|
|
||
| ``` | ||
| RED: Write test for first behavior → test fails | ||
| GREEN: Write minimal code to pass → test passes | ||
| ``` | ||
|
|
||
| This is your tracer bullet - proves the path works end-to-end. | ||
|
|
||
| ### 3. Incremental Loop | ||
|
|
||
| For each remaining behavior: | ||
|
|
||
| ``` | ||
| RED: Write next test → fails | ||
| GREEN: Minimal code to pass → passes | ||
| ``` | ||
|
|
||
| Rules: | ||
|
|
||
| - One test at a time | ||
| - Only enough code to pass current test | ||
| - Don't anticipate future tests | ||
| - Keep tests focused on observable behavior | ||
|
|
||
| ### 4. Refactor | ||
|
|
||
| After all tests pass, look for [refactor candidates](refactoring.md): | ||
|
|
||
| - [ ] Extract duplication | ||
| - [ ] Deepen modules (move complexity behind simple interfaces) | ||
| - [ ] Apply SOLID principles where natural | ||
| - [ ] Consider what new code reveals about existing code | ||
| - [ ] Run tests after each refactor step | ||
|
|
||
| **Never refactor while RED.** Get to GREEN first. | ||
|
|
||
| ## Checklist Per Cycle | ||
|
|
||
| ``` | ||
| [ ] Test describes behavior, not implementation | ||
| [ ] Test uses public interface only | ||
| [ ] Test would survive internal refactor | ||
| [ ] Code is minimal for this test | ||
| [ ] No speculative features added | ||
| ``` | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # Deep Modules | ||
|
|
||
| From "A Philosophy of Software Design": | ||
|
|
||
| **Deep module** = small interface + lots of implementation | ||
|
|
||
| ``` | ||
| ┌─────────────────────┐ | ||
| │ Small Interface │ ← Few methods, simple params | ||
| ├─────────────────────┤ | ||
| │ │ | ||
| │ │ | ||
| │ Deep Implementation│ ← Complex logic hidden | ||
| │ │ | ||
| │ │ | ||
| └─────────────────────┘ | ||
| ``` | ||
|
|
||
| **Shallow module** = large interface + little implementation (avoid) | ||
|
|
||
| ``` | ||
| ┌─────────────────────────────────┐ | ||
| │ Large Interface │ ← Many methods, complex params | ||
| ├─────────────────────────────────┤ | ||
| │ Thin Implementation │ ← Just passes through | ||
| └─────────────────────────────────┘ | ||
| ``` | ||
|
rahulkarajgikar marked this conversation as resolved.
|
||
|
|
||
| When designing interfaces, ask: | ||
|
|
||
| - Can I reduce the number of methods? | ||
| - Can I simplify the parameters? | ||
| - Can I hide more complexity inside? | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| # Interface Design for Testability | ||
|
|
||
| Good interfaces make testing natural: | ||
|
|
||
| 1. **Accept dependencies, don't create them** | ||
|
|
||
| ```typescript | ||
| // Testable | ||
| function processOrder(order, paymentGateway) {} | ||
|
|
||
| // Hard to test | ||
| function processOrder(order) { | ||
| const gateway = new StripeGateway(); | ||
| } | ||
| ``` | ||
|
|
||
| 2. **Return results, don't produce side effects** | ||
|
|
||
| ```typescript | ||
| // Testable | ||
| function calculateDiscount(cart): Discount {} | ||
|
|
||
| // Hard to test | ||
| function applyDiscount(cart): void { | ||
| cart.total -= discount; | ||
| } | ||
| ``` | ||
|
|
||
| 3. **Small surface area** | ||
| - Fewer methods = fewer tests needed | ||
| - Fewer params = simpler test setup |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| # When to Mock | ||
|
|
||
| Mock at **system boundaries** only: | ||
|
|
||
| - External APIs (payment, email, etc.) | ||
| - Databases (sometimes - prefer test DB) | ||
| - Time/randomness | ||
| - File system (sometimes) | ||
|
|
||
| Don't mock: | ||
|
|
||
| - Your own classes/modules | ||
| - Internal collaborators | ||
| - Anything you control | ||
|
|
||
| ## Designing for Mockability | ||
|
|
||
| At system boundaries, design interfaces that are easy to mock: | ||
|
|
||
| **1. Use dependency injection** | ||
|
|
||
| Pass external dependencies in rather than creating them internally: | ||
|
|
||
| ```typescript | ||
| // Easy to mock | ||
| function processPayment(order, paymentClient) { | ||
| return paymentClient.charge(order.total); | ||
| } | ||
|
|
||
| // Hard to mock | ||
| function processPayment(order) { | ||
| const client = new StripeClient(process.env.STRIPE_KEY); | ||
| return client.charge(order.total); | ||
| } | ||
| ``` | ||
|
|
||
| **2. Prefer SDK-style interfaces over generic fetchers** | ||
|
|
||
| Create specific functions for each external operation instead of one generic function with conditional logic: | ||
|
|
||
| ```typescript | ||
| // GOOD: Each function is independently mockable | ||
| const api = { | ||
| getUser: (id) => fetch(`/users/${id}`), | ||
| getOrders: (userId) => fetch(`/users/${userId}/orders`), | ||
| createOrder: (data) => fetch('/orders', { method: 'POST', body: data }), | ||
| }; | ||
|
|
||
| // BAD: Mocking requires conditional logic inside the mock | ||
| const api = { | ||
| fetch: (endpoint, options) => fetch(endpoint, options), | ||
| }; | ||
| ``` | ||
|
|
||
| The SDK approach means: | ||
|
|
||
| - Each mock returns one specific shape | ||
| - No conditional logic in test setup | ||
| - Easier to see which endpoints a test exercises | ||
| - Type safety per endpoint |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # Refactor Candidates | ||
|
|
||
| After TDD cycle, look for: | ||
|
|
||
| - **Duplication** → Extract function/class | ||
| - **Long methods** → Break into private helpers (keep tests on public interface) | ||
| - **Shallow modules** → Combine or deepen | ||
| - **Feature envy** → Move logic to where data lives | ||
| - **Primitive obsession** → Introduce value objects | ||
| - **Existing code** the new code reveals as problematic |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # Good and Bad Tests | ||
|
|
||
| ## Good Tests | ||
|
|
||
| **Integration-style**: Test through real interfaces, not mocks of internal parts. | ||
|
|
||
| ```typescript | ||
| // GOOD: Tests observable behavior | ||
| test('user can checkout with valid cart', async () => { | ||
| const cart = createCart(); | ||
| cart.add(product); | ||
| const result = await checkout(cart, paymentMethod); | ||
| expect(result.status).toBe('confirmed'); | ||
| }); | ||
| ``` | ||
|
|
||
| Characteristics: | ||
|
|
||
| - Tests behavior users/callers care about | ||
| - Uses public API only | ||
| - Survives internal refactors | ||
| - Describes WHAT, not HOW | ||
| - One logical assertion per test | ||
|
|
||
| ## Bad Tests | ||
|
|
||
| **Implementation-detail tests**: Coupled to internal structure. | ||
|
|
||
| ```typescript | ||
| // BAD: Tests implementation details | ||
| test('checkout calls paymentService.process', async () => { | ||
| const mockPayment = jest.mock(paymentService); | ||
| await checkout(cart, payment); | ||
| expect(mockPayment.process).toHaveBeenCalledWith(cart.total); | ||
| }); | ||
| ``` | ||
|
|
||
| Red flags: | ||
|
|
||
| - Mocking internal collaborators | ||
| - Testing private methods | ||
| - Asserting on call counts/order | ||
| - Test breaks when refactoring without behavior change | ||
| - Test name describes HOW not WHAT | ||
| - Verifying through external means instead of interface | ||
|
|
||
| ```typescript | ||
| // BAD: Bypasses interface to verify | ||
| test('createUser saves to database', async () => { | ||
| await createUser({ name: 'Alice' }); | ||
| const row = await db.query('SELECT * FROM users WHERE name = ?', ['Alice']); | ||
| expect(row).toBeDefined(); | ||
| }); | ||
|
|
||
| // GOOD: Verifies through interface | ||
| test('createUser makes user retrievable', async () => { | ||
| const user = await createUser({ name: 'Alice' }); | ||
| const retrieved = await getUser(user.id); | ||
| expect(retrieved.name).toBe('Alice'); | ||
| }); | ||
| ``` |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| --- | ||
| "@dexto/core": patch | ||
| "@dexto/tui": patch | ||
| "dexto": patch | ||
| --- | ||
|
|
||
| Persist core-owned interaction state with the existing storage layers and update the TUI/CLI call sites for the new async session tool preference APIs. |
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.