Connect original sources, board previews and personal planning across experiences - #2866
Connect original sources, board previews and personal planning across experiences#2866Chris0Jeky wants to merge 61 commits into
Conversation
…omparisons # Conflicts: # docs/IMPLEMENTATION_MASTERPLAN.md
…text-base-refresh
…panion-continuity
… into codex/2808-comparison-compat
…omparisons # Conflicts: # docs/STATUS.md # docs/product/WORKSPACE_OVERHAUL_VALIDATION.md
Final recovery qualificationHead75f92c71e preserves private audio/text drafts by disabling question-layer removal (including an already-open removal prompt) until the draft is kept or explicitly discarded. Hosted finding3974598891 is confirmed HIGH due to browser-only recording loss and is repaired. Fresh bounded Luna repair review is CLEAN. 18 targeted components, typecheck, production build, scopedESLint and docs/governance pass. Required run34424282948 at9bac failed exactly two retired dialog-title locators (207passed/13skipped/2failed). Both now name the actual Leave this thinking space? dialog. Both full specs passed locally: seven Chromium journeys in47.6s, isolated real API. The failed log is preserved; no blind rerun or weakened behavior assertions. Exact-head hosted qualification restarts on75f92c71e. Temporary5218/5318 services are stopped. Hosted finding3974598894 (enabled retained-send control) is MEDIUM and already implemented in stacked PR2870. The source-export snapshot finding3974598902 is being scoped separately under #2808; its disposition will record actual snapshot boundaries rather than claim restore acceptance. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 75f92c71e8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
|
||
| public Task<Result<ThinkingAudioDto>> WriteAsync(Guid userId, Guid id, ThinkingAudioWriteDto dto, CancellationToken ct) => TransactionAsync(async () => | ||
| { | ||
| var answer = await OwnedAsync(userId, id, ct); |
There was a problem hiding this comment.
Reject writes after the source question changes
When another collaborator edits or removes the question after this recording was loaded, OwnedAsync verifies only ownership and active-board access, so the stale PUT still appends a written representation to the old recording. ConfirmAsync performs the missing current-question/hash check, and the retained library otherwise treats recordings whose questions changed as read-only; resolve the question and compare QuestionHash before staging this transcript.
Useful? React with 👍 / 👎.
| <button type="button" :disabled="!text.trim() || !dirty || busy || loading || !sourceReady" @click="write">Save written version</button> | ||
| <label>How to treat the confirmed answer<select v-model="status" aria-label="Audio answer status" :disabled="pending"><option value="statement">Statement</option><option value="assumption">Assumption</option><option value="unknown">Unknown</option><option value="needsReview">Needs review</option></select></label> | ||
| <button type="button" :disabled="!saved.representationId || dirty || busy || loading || !sourceReady || answerAlreadyKept" @click="confirm">Confirm written version as my answer</button> |
There was a problem hiding this comment.
Disable mutations after an unsuccessful reload
When a reload fails, load() sets loaded to false but leaves the prior saved receipt rendered; these Save and Confirm buttons can therefore appear enabled even though mutate() immediately returns when !loaded. This occurs after a failed manual reload or a failed reload triggered by a question revision, leaving controls that silently do nothing; include !loaded in both disabled predicates or otherwise mark the retained receipt non-actionable.
AGENTS.md reference: frontend/AGENTS.md:L5-L5
Useful? React with 👍 / 👎.
| saved.value = next; loaded.value = true | ||
| if (!hadDraft && text.value === initialText) text.value = next?.writtenVersions.find(x => x.id === next.representationId)?.text ?? '' |
There was a problem hiding this comment.
Keep written drafts accessible after question revisions
When the user has an unsaved written version and then saves an edit to the shared question, the revision reload returns no matching recording and this assignment replaces saved with null while deliberately retaining text. The !saved template renders only the audio recorder, so the written draft remains dirty but becomes invisible with no way to copy or discard it; the revision repair tracks only file drafts, so preserve a visible stale-written-draft state before replacing the receipt.
AGENTS.md reference: frontend/AGENTS.md:L5-L5
Useful? React with 👍 / 👎.
|
Final disposition of hosted feedback after9bac:3974598891 is HIGH due to loss of browser-only drafts and is repaired in75f92c71e;18focusedcomponents,7browserjourneys,typecheck/build and independent Luna repair reviewpass.3974598894 is MEDIUM disabled-control consistency, already addressed inPR2870.3974598902 is MEDIUM archival source-section consistency, confirmed statically and now implemented in local source-export-snapshot31087565d:11realAPItests pass and independentLunareviewCLEAN;fullbackendqualification is running before publication. Whole-account point-in-time/restore acceptance remains explicitly outside that narrow claim. Current integrationheade3be111a9 adds only the generated-ledger correction after75f92c71e:11projectiontests,doclinks/governance/diffpass. The exact cause of the prior docs failure is recorded in the canonical JSONL and regenerated Markdown. RequiredCI is requalifying; no merge with failing or missing checks. |
# Conflicts: # docs/product/WORKSPACE_OVERHAUL_VALIDATION.md
# Conflicts: # docs/IMPLEMENTATION_MASTERPLAN.md # docs/STATUS.md # docs/product/WORKSPACE_OVERHAUL_VALIDATION.md
# Conflicts: # docs/IMPLEMENTATION_MASTERPLAN.md # docs/STATUS.md # docs/product/WORKSPACE_OVERHAUL_VALIDATION.md
|
The consolidated head a5abe34 preserves the reviewed inputs through #2877. Fresh bounded Luna review of cross-slice identity/cursor/send gating, overlay close/expiry, export snapshot/library and Classic plan continuity found no HIGH/CRITICAL integration defect. Full backend passed 9,186 tests with 34 existing skips; full frontend passed 6,377 with three existing skips; build/typecheck passed. Sixteen selected browser journeys have passing evidence after one checkbox-locator correction and a complete two-spec rerun. The production audio policy, comparison identity and generated-ledger checks also pass. Detailed evidence and limitations are in the updated PR body and workspace validation document. Exact-head hosted CI remains pending. This PR is the single main-based integration gate; contained source PRs should be reconciled after it lands. #2808 remains open for the remaining product capabilities and acceptance work. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a5abe349e1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const status = (cause as { response?: { status?: number } }).response?.status | ||
| if (status === 403 || status === 404) { | ||
| items.value = []; loaded.value = false; nextAfterOrdinal.value = -1; emit('change', []) | ||
| error.value = 'You no longer have access to these private originals. Check board access before retrying.' | ||
| } else error.value = 'Originals could not be checked. Retry, or refresh all sources if this memory changed.' |
There was a problem hiding this comment.
Clear selections when the memory revision conflicts
When an original is already selected and another client revises its memory before the user loads the next page, the source endpoint returns 409, but this branch retains the loaded items and emitted selection. The send controls therefore remain enabled even though ResolveAsync will reject every attempted message using that stale revision; treat 409 as an invalidated selection by clearing it or disabling it until all sources are refreshed.
AGENTS.md reference: frontend/AGENTS.md:L3-L6
Useful? React with 👍 / 👎.
| services.AddScoped<IManualRepresentationStore, EfManualRepresentationStore>(); | ||
| services.AddScoped<IThinkingAudioRepository, ThinkingAudioRepository>(); | ||
| services.AddScoped<ISourcePortabilityStore, SourcePortabilityStore>(); | ||
| services.TryAddSingleton(_ => configuration.GetSection("SourceStorage").Get<BlobStorageSettings>() ?? new BlobStorageSettings()); |
There was a problem hiding this comment.
Validate source-storage quotas during startup
When an operator supplies a nonpositive SourceStorage override such as SourceStorage__OwnerQuotaBytes=0, this singleton binding allows the application to start successfully, but the first audio upload reaches SqliteBlobStore.CheckQuota, throws InvalidOperationException, and becomes a generic 500. Register these settings with range validation and ValidateOnStart, as is already done for database settings in this method, so deployment mistakes fail before user traffic.
Useful? React with 👍 / 👎.
|
Bounded hosted-feedback reconciliation at the combined checkpoint:
These are accepted, tracked product follow-through items, not a new broad audit or an approval/Apply bypass. No new HIGH/CRITICAL path was established in this bounded triage. The consolidated shipping head remains a5abe34; required CI is still pending. The independent plan-operation recovery and comparison-attribution continuations proceed separately. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7886fc93cc
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| var answer = await OwnedAsync(userId, id, ct); | ||
| if (answer.ConfirmedMemoryId.HasValue) return await MapAsync(answer, ct); | ||
| if (answer.Revision != dto.ExpectedRevision || answer.RepresentationId != dto.RepresentationId) throw Conflict(); |
There was a problem hiding this comment.
Reject mismatched retries after audio confirmation
When another tab has already confirmed the recording, this early return accepts any subsequent confirm payload without validating its revision, representation, deck revision, or status. For example, a stale tab can request assumption after the first tab stored statement and receive 200 even though that status was not persisted; preserve lost-response idempotency only when the request matches the completed confirmation and return a conflict otherwise.
AGENTS.md reference: backend/AGENTS.md:L22-L25
Useful? React with 👍 / 👎.
| // The send already succeeded and its messages are retained locally. A | ||
| // failed reconciliation must not hold continuation behind read retries. | ||
| const result = await chatApi.getSession(sessionId, { skipRetry: true }) | ||
| if (isDisposed || requestedSessionId !== sessionId || selectedSession.value?.id !== sessionId) return | ||
| if (!isCurrent()) return |
There was a problem hiding this comment.
Put a timeout on the post-send receipt refresh
When this GET remains pending because the API or connection stalls, chatApi.getSession forwards only skipRetry and the shared Axios client has no request timeout. Since the send path awaits this refresh while refreshingReceipt disables every send control, the successfully sent conversation can remain blocked indefinitely without ever reaching the new retry/error state; give this reconciliation read a bounded timeout or cancellation path.
Useful? React with 👍 / 👎.
| <router-link | ||
| v-if="proposal.boardId && !props.readOnly && ['PendingReview', 'Approved'].includes(normalizeProposalStatus(proposal.status))" | ||
| class="td-review-card__links-dropdown-item" | ||
| role="menuitem" | ||
| :to="{ path: `/workspace/boards/${proposal.boardId}`, query: { proposalId: proposal.id } }" |
There was a problem hiding this comment.
Expose board preview for non-Queue proposals
When Classic/Legacy Review displays a Chat or Manual/MCP proposal, ReviewProposalCard.hasProvenanceContext is false because it recognizes only Queue capture references. This link is nested inside the surrounding v-if="hasProvenance" block, so those pending or approved board proposals never receive the new Preview on board action, even though Paper Review exposes it independently; place the preview action outside the capture-provenance-only disclosure.
Useful? React with 👍 / 👎.
|
|
||
| | Domain | Entry points | Invariants (load-bearing) | Verify | | ||
| | --- | --- | --- | --- | | ||
| | Private audio answers | `Api/Controllers/ThinkingAudioController.cs` → `Application/Services/ThinkingAudioService.cs`; `CaptureIntakeService.StageAudioAnswerAsync` is the canonical capture writer; `Infrastructure/Storage/SqliteBlobStore.cs`, `Repositories/EfManualRepresentationStore.cs`, `Repositories/SourcePortabilityStore.cs`; frontend `components/thinking/ThinkingAudioAnswer.vue` + `AudioAnswerRecorder.vue`; owner library `components/workspace/OriginalAudioLibrary.vue` from Memory, API `library` list/detail/original | Audio alone is untranscribed/unanswered; explicit human writing and confirmation are separate immutable representations. Owner-scoped bytes and current board access; read-only library also permits archived boards with current permission and owner-linked deleted-board originals; upload ID/hash retry; question/revision conflicts; quotas before bounded reads; caller transaction; account erasure deletes representation dependants before source assets. No queued/remote transcription. Legacy representation backfill is separate. Avoid generated migration designers except for schema work; product/status sync: `docs/product/WORKSPACE_OVERHAUL.md` + validation ledger and STATUS/MASTERPLAN | API `ThinkingAudioApiTests`, `SqliteBlobStoreTests`, `ManualRepresentationStoreTests`, `DataPortabilityApiTests`; frontend `ThinkingAudioAnswer.spec.ts`, `AudioAnswerRecorder.spec.ts`, `OriginalAudioLibrary.spec.ts`, `ThinkingQuestionAnswer.spec.ts`, `ThinkingWorkspaceContinuity.spec.ts`; Chromium `tests/e2e/thinking-audio.spec.ts` with an isolated `TASKDECK_E2E_DB`; full backend/frontend per CLAUDE before PR | |
There was a problem hiding this comment.
Reconcile the Context Fabric entries with the implementations
This new seam row declares SqliteBlobStore, EfManualRepresentationStore, and SourcePortabilityStore as the production entry points, but the existing Context Fabric row at line 47 and its linked architecture map still say IBlobStore/IRepresentationStore are contract-only with no implementation registered. Because this index is the repository's required first-hop seam map, the contradictory entries can send subsequent work away from the newly shipped persistence path; update the older entries as part of this implementation change.
AGENTS.md reference: AGENTS.md:L13-L16
Useful? React with 👍 / 👎.
|
Required CI34434084906 passed at7886fc93; before merge, main had advanced through the separate CI-adapter PR2864 to c6a97b7. Reconciled that base to d0e08d5. Backend/frontend/deployment product inputs remain unchanged; new continuation tests and doclinks pass. The new exact-head gate is running; no merge is claimed. New hosted comments are classified once as MEDIUM and retained under #2808: 3975276160 (reject mismatched retries of an already-confirmed audio answer), 3975276166 (bound post-send receipt reconciliation), 3975276175 (show preview for non-Queue proposals in Legacy Review), and 3975276181 (reconcile older Context Fabric interface-map entries with concrete source stores). They do not authorize board writes, overwrite originals or change access boundaries, and will be handled in focused follow-through rather than restarting this reviewed application diff. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d0e08d570b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (!live) return | ||
| if (playbackUrl.value) URL.revokeObjectURL(playbackUrl.value) | ||
| playbackUrl.value = URL.createObjectURL(blob) |
There was a problem hiding this comment.
Discard playback responses after recording changes
When playback starts and the shared question is revised before the download finishes, the revision reload can clear or replace saved, but this response is still accepted because it checks only live, not the requested recording ID or generation. If the revised question already has—or subsequently receives—a recording, the stale blob is rendered and downloaded under the new receipt and filename; capture the request generation/recording ID and discard or revoke responses after the receipt changes.
Useful? React with 👍 / 👎.
Taskdeck now keeps original sources, saved thinking and personal planning connected across Classic, Studio, Companion and Unified. This main-based integration preserves the individually reviewed commits from #2852, #2855, #2856, #2857, #2861, #2870 and #2872 through #2877. It continues #2808; the wider overhaul remains open.
Verification
Combined local evidence at the final integration runtime:
Earlier failed evidence is retained: old navigation-dialog names, the newly ambiguous memory-title locator, and a manually appended generated ledger entry. Locators now target the actual controls; ledger entries live in JSONL with a regenerated Markdown projection. These are identified causes, not blind reruns or claims of flakiness.
Remaining scope
Automatic transcription/provider processing, broader original-representation backfill and export graph work, observation usefulness/opt-in attention, plan failure/navigation/load-coalescing refinements and comparison appearance attribution remain tracked under #2808. Source-storage consistency does not claim one snapshot across every account section or tested restoration. Physical microphones/devices,liveproviders,productiondeployment and release/owner decisions remain unverified. OUTSTANDING_TASKS.md human choices are unchanged.
All browser databases are synthetic under C:/Taskdeck-overhaul/evidence; temporary services are stopped. The primary checkout and working database are untouched. Exact-head hosted checks must pass before merge. Keep contained PR branches until the integration lands, then reconcile their PR/project state and late comments.