Repository navigation
Fix Astra habit resolution and approval previews - #796
Conversation
There was a problem hiding this comment.
Caution
Revising a date-range log approval can terminate the API process with a stack overflow. The inline finding includes a reproduced failure.
Reviewed changes across all 29 changed files, tracing habit resolution, approval construction and revision through execution.
- Habit resolution: Normalized search and name matching, active-habit reuse, persisted proposal deduplication, and missing-name clarification.
- Batched writes: Existing-parent child creation, multi-date logging, and transactional multi-habit tag assignment.
- Approval integrity: Canonical fingerprints, dependency binding, selectable habit/date items, and rejection of empty or failed previews.
- Proposal grounding: Awaiting-confirmation payloads, counts and proposed fields supplied to the model and grounding checks.
- Verification: 49 focused application tests and 103 focused infrastructure tests passed. Changing the existing date-range revision test to use the new public
datesargument shape crashed the test host; temporary changes were restored.
gpt-6.1-sol | 𝕏
Preserve selected habit/date items and their offered identities across revision, refresh, and execution. Make expanded previews terminal and remove the original date range from revised approvals. Refs thomasluizon/orbit-tickets#1568
Carry the habit schedule expansion and isolated agent audit writes into the Astra fix. Rebuild both OpenAPI documents and verify they match origin/redesign/main exactly. Refs thomasluizon/orbit-tickets#1568
There was a problem hiding this comment.
No new issues found. The resolved stack-overflow finding is fixed, and no new High or Critical findings remain.
Reviewed changes since the prior Pullfrog review at 00d0fe30, with the current full diff read for context.
- Removed recursive expansion: Expanded date ranges inline once and treated
revised_itemsas terminal, rejecting malformed selections without reverting to the original range. - Canonicalized revisions: Removed the original
datesarray when saving selected habit/date items while preserving their offered identities. - Added regression coverage: Exercised the public date-range input through narrowing, date editing, repeated revision, refresh and execution of only the retained item.
- Verified behavior: Passed 202 focused application tests and 109 focused infrastructure tests at the current head, with no failures or skipped tests. The full solution suite was not rerun during this review.
gpt-6.1-sol | 𝕏
There was a problem hiding this comment.
No new High or Critical issues found.
Reviewed changes since the prior Pullfrog review at 1cddaa48, with all 36 files in the current full diff read for context.
- Tightened habit resolution: Added whole-word matching, explicit ambiguity and duplicate questions, exact normalized create deduplication, and replacement of pending proposals.
- Preserved creation intent: Distinguished new root routines from explicitly requested children and exposed the existing parent in each child preview.
- Strengthened approval binding: Required nonempty fingerprint-bound previews for every held chat mutation and checked stored dependencies on direct confirmation-token execution.
- Batched data access: Reused the complete turn snapshot for log selection, batched tag validation and execution, capped date arrays, and deferred history loading until query candidates match.
- Compacted proposal facts: Returned proposed titles, values, counts and dates without sending full preview items back to the model.
Verification passed: 5,507 Application tests and 3,961 Infrastructure tests, with no failures or skipped tests. The full solution and Domain suite were not rerun during this review. The earlier stack-overflow thread remains resolved.
gpt-6.1-sol | 𝕏
|
Copy approval for round 4 ( Strings reviewed (en / pt-BR): the pending creation question ("You already have a preview waiting to create {name}. Approve it, or ask me to prepare a new one." / "Você já tem uma prévia aguardando para criar {name}. Aprove a prévia ou me peça para preparar uma nova."), the multi-item replacement question, and the singular and plural not-found questions. Verdict: DISAGREE, medium confidence. The pt-BR strings use the app's own terms ("prévia", "hábito"), singular and plural agree ("este hábito / Qual" and "estes hábitos / Quais"), and no adjective refers to Astra. One optional polish noted ("aguardando aprovação"), not a defect. |
|
There was a problem hiding this comment.
No new High or Critical issues found.
Reviewed changes since the prior Pullfrog review at d529eb17, with all 39 files in the current full diff read for context.
- Preserved batch proposals: Refused single-item replacement of multi-item create previews and based replacement decisions on persisted proposals rather than assistant reply wording.
- Unified title search: Applied normalized, order-independent word-prefix matching to habit queries and bulk selections, with matching schemas and prompt guidance.
- Clarified merged calls: Returned
merged_into_previewfor coalesced log/tag calls and repeated calls, with explicit instructions not to prepare another preview. - Rejected malformed creates: Checked all titles before duplicate bookkeeping and returned localized failed actions for invalid calls.
- Refined preview presentation: Put titles first, showed the parent once in summary changes, and corrected singular/plural clarification messages.
- Preserved confirmation behavior: Allowed fingerprint-free non-Chat confirmations while retaining stored fingerprint checks for Chat mutations, and distinguished stale previews from preview-generation failures.
Verification passed: 5,700 Application tests and 4,013 Infrastructure tests, with no failures or skipped tests. Focused runs also passed 417 Application and 194 Infrastructure tests. The full solution build, Domain suite, and live model flows were not rerun during this review.
gpt-6.1-sol | 𝕏




Fixes thomasluizon/orbit-tickets#1568
Astra resolves the account's existing habits before preparing writes, returns one approval for repeated log or tag calls, and asks about missing names without an empty preview. Reading goals link to the resolved habit, and breakdowns create children under the existing parent.
Approach
HabitNameMatcher,QueryHabitsTool, andBulkHabitSelectionnormalize case, accents, partial names, and the leitura/ler activity alias. Search runs after the repository's user-scoped SQL query. The previousstring.Contains(..., StringComparison.OrdinalIgnoreCase)predicate throws on the relational provider; the unchanged repository-mock tests missed that path. Other chat tools using this comparison already filter materialized collections.ProcessUserChatCommand.Resolution, the tool loop, andPendingAgentOperationStoreresolve write targets, refuse existing or previously proposed creates, combine date-range logs and tag assignments, and carry missing names into one reply. Duplicate protection reads server-owned pending proposals, including their parent scope. Tag requests do not turn missing habits into new creates.BulkCreateHabitsToolaccepts an existing parent,BulkLogHabitsToolaccepts all requested dates in one call, andAssignTagsToolaccepts multiple existing targets. They reuse existing command validation and domain guards. Child creation and tag replacement retain transaction boundaries. The executor refuses empty selection previews and returns preview_unavailable when preview generation fails, and the response accumulator also excludes empty or repeated approvals.AgentArgumentPreview,PendingOperationChangePreviewer, andPendingOperationRevisionServicecanonicalize property order and nested JSON values. Approval fingerprints bind the affected records and referenced habits or tags. Root creation has no dependency on unrelated habits. Selecting one date from a range preserves the offered item identity.TurnFactSetreads those facts, and the prompt tells the model to describe proposals using the returned facts. A preview of twelve records now grounds both the two-habit and six-date counts without changing the grounding feature flag.The stored argument column is
jsonb. PostgreSQL documents that this type does not preserve object key order: JSON types. Equivalent reordered arguments reproduced different preview fingerprints before the fix. This is the storage-level explanation inferred from the column mapping and regression; the tests do not connect to staging.No REST response field was removed, renamed, or retyped. The tool arguments are additive. The client renderer and model configuration are outside this change. Related thomasluizon/orbit-tickets#19 and thomasluizon/orbit-tickets#246 remain separate.
Assumptions
Used the existing
HeldWriteTestContextfor range regressions instead of adding another mocked execution harness.Test evidence
The account-shaped fixtures use Beber água, Ler 10 minutos, and Academia, with no meditation habit. Fake model responses drive the application handler; relational query tests use the repository's SQLite compatibility factory. No live model, application server, browser, or production database was used.
Unchanged tests with the defects present:
dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~QueryHabitsToolTests --verbosity quiet: 41 passed.dotnet test tests/Orbit.Application.Tests --no-build --filter 'FullyQualifiedName~PendingOperationChangePreviewerTests|FullyQualifiedName~AgentArgumentPreviewTests' --verbosity quiet: 45 passed.dotnet test tests/Orbit.Application.Tests --no-build --filter FullyQualifiedName~ProcessUserChatCommandHandlerTests --verbosity quiet: 241 passed.Strengthened regressions, observed before their fixes:
dotnet test tests/Orbit.Infrastructure.Tests --filter FullyQualifiedName~AstraHabitQueryRegressionTests --verbosity quiet: all three account-shaped search cases failed with the relational translation exception. The same filter passed after the search fix.dotnet test tests/Orbit.Application.Tests --filter 'FullyQualifiedName~PreviewAsync_Create_JsonPropertyOrderDoesNotChangeApproval|FullyQualifiedName~PreviewAsync_NoMatches_DoesNotOfferEmptyPreview' --logger 'console;verbosity=normal': both failed, respectively on unequal fingerprints and an emitted empty preview. Both pass after the fix.dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~Replay_ --logger 'console;verbosity=normal': the initial six new request replays failed on unresolved links, a recreated parent, duplicate/empty log previews, duplicate habit creation during tagging, and absent grounding facts. Two unrelated existing replay cases passed. The six new cases passed after the fix; coverage now includes thirteen application replay cases.dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~Replay_PreviousCreateProposal --logger 'console;verbosity=normal': failed because a changed proposal for the same name reached approval. Passes with the persisted-proposal guard. A later strengthening of the same command also proved the shorter Yoga name failed against a pending Praticar yoga proposal before applying name matching to stored proposals; both cases now pass.dotnet test tests/Orbit.Application.Tests --filter 'FullyQualifiedName~Replay_TagMatchingHabits|FullyQualifiedName~Replay_LogPreview_Grounds' --logger 'console;verbosity=normal': both failed, on two tag approvals and ungrounded habit/date counts. Both pass after batching and returning those counts.dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~PreviewAsync_GoalLink_OnlyLinkedRecordChangesInvalidateApproval --logger 'console;verbosity=normal': failed because changing the linked habit left the fingerprint unchanged. Passes after binding that dependency; an unrelated change preserves approval.dotnet test tests/Orbit.Infrastructure.Tests --filter 'FullyQualifiedName~ExecuteAsync_EmptySelection_NeverReturnsAnApproval|FullyQualifiedName~ExecuteAsync_CreateApproval_JsonStorageOrder' --logger 'console;verbosity=normal': the empty-preview boundary case failed and the create-approval case passed. Both now pass, including approval after an unrelated habit change.dotnet test tests/Orbit.Infrastructure.Tests --filter FullyQualifiedName~ReviseDateRange_KeepingOneDate --logger 'console;verbosity=normal': failed with stale_preview after selecting one offered date. Passed after preserving the offered identity.The infrastructure suite initially had one failure: its old PreviewFailure_KeepsPendingConfirmation test expected approval after a preview exception. That fallback is now a retryable preview_unavailable failure with no pending approval. The updated AgentOperationExecutor_PreviewFailure_DoesNotOfferUnboundApproval test and the other 79 focused infrastructure cases pass.
The generic multi-round accumulation fixture now uses two distinct habit titles. Its former identical empty arguments represented the repeated operation that the server now refuses.
Final verification, all commands exited 0:
dotnet build Orbit.slnx --verbosity quietdotnet test tests/Orbit.Domain.Tests --no-build --verbosity quietdotnet test tests/Orbit.Application.Tests --no-build --verbosity quietdotnet test tests/Orbit.Infrastructure.Tests --no-build --verbosity quietdotnet test tests/Orbit.Analyzers.Tests --no-build --verbosity quietTotal: 10,130 tests passed, none skipped. Build regenerated OpenAPI documents with no tracked diff. Pre-commit formatting, dash, timeless, root-path, and suppression checks passed. Added source has no bare narration comments.
Before the fix, the unchanged single-date test passed with this command, exit 0:
The new
ReviseDateRange_KeepingOneDate_PreservesTheOfferedItemcases each reproduced the stack overflow, exit 1:After the fix and again after merging, this focused run passed all 202 tests, exit 0:
Final verification:
dotnet build Orbit.slnx: exit 0, zero errors, before and after merging.dotnet test tests/Orbit.Domain.Tests: exit 0, 797 passed.dotnet test tests/Orbit.Application.Tests: exit 0, 5,464 passed.dotnet test tests/Orbit.Infrastructure.Tests: exit 0, 3,949 passed.origin/redesign/mainexactly.dotnet test tests/Orbit.Application.Tests --filter 'FullyQualifiedName~RoundThree_|FullyQualifiedName~Replay_HealthTag' --verbosity quietdotnet test tests/Orbit.Infrastructure.Tests --filter FullyQualifiedName~RoundThree_ --verbosity quietRoundThree_FilteredMetrics,RoundThree_ExplicitCreate,RoundThree_PendingDuplicate,Replay_UnresolvedNames_NoEmptyPreviewAndOneQuestion, andReplay_LogSelectionRetainsCompletedHabitsFromTurnSnapshot.dotnet test tests/Orbit.<project>.Tests --no-build --verbosity quiet, exited 0:dotnet build Orbit.slnx: exit 0, zero errors. OpenAPI regenerated without a content change. Commit hooks passed.These focused commands ran before implementation changes and again with strengthened tests:
--no-buildRed-first observations, all passing after the fix:
RoundFour_SupersedeOneChild_PreservesTheMultiItemOperationExecutePendingOperation_InitialPreview_BindsApprovalToTargetSet, MCP casesRoundThree_BulkDelete_UsesNormalizedTitleWordPrefixesRoundFour_Search_MatchesNormalizedTitleWordPrefixesand matcher theoryRoundThree_LogCoalescing_UsesTurnSnapshotAndReturnsCompactFactsmerged_into_preview; five were expected.RoundFour_MalformedCreateAfterDuplicate_DoesNotReachExecutorRoundThree_CreateChildren_ShowsParentInEveryItemAndOnceInChangesRoundFour_Replacement_UsesStoredProposalWithUnrelatedReplyCopyand copy theoriesRoundThree_UnavailablePreview_RefusesEveryWritepreview_unavailableinstead ofstale_preview.Finding 9 was an assertion correction:
Replay_HealthTag_DoesNotRecreateExistingHabitsnow checks held operations and the suppression tool result. It passed before and after; no production failure is claimed for that assertion weakness.The additional localized-error assertion failed before its fix using:
dotnet test tests/Orbit.Application.Tests --filter FullyQualifiedName~RoundFour_MalformedCreateAfterDuplicate_DoesNotReachExecutorFull suites on the committed code:
dotnet test tests/Orbit.Domain.Testsdotnet test tests/Orbit.Application.Testsdotnet test tests/Orbit.Infrastructure.TestsManual steps
None.