From d28082f19cc28cb0fe26bef16a9453a70a9c54ad Mon Sep 17 00:00:00 2001 From: Chris0Jeky Date: Sat, 5 Sep 2026 03:08:12 +0100 Subject: [PATCH 1/2] docs: record the eleventh v0.3 integration block (alpha product-trust lane, 2026-09-04 to 2026-09-05) --- docs/STATUS.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/docs/STATUS.md b/docs/STATUS.md index 7a265ee2a..cca4a67b2 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -1,6 +1,6 @@ # Taskdeck Status (Source of Truth) -Last Updated: 2026-09-04 +Last Updated: 2026-09-05 **Authority.** This file owns *shipped reality* - what is built, verified, and running today. **Precedence** when documents disagree: `docs/STATUS.md` > `AGENTS.md` > `CLAUDE.md`. @@ -180,6 +180,38 @@ Docs only: - **Docs only:** PR `#2543` (merge `49e89f991`) records the ninth block above in `docs/STATUS.md` (+20 lines) and amends the SC-10 human-action item in `OUTSTANDING_TASKS.md` §J so the parked control-plane PRs are named by number (`#2502`, `#2506`, `#2522`, `#2532`, plus the CI-07 `#2331` proposal). Its own review verified all nine behavioural claims against the tree and re-measured the 17-check clean run at `b461be49f` with `gh api …/check-runs` rather than transcribing it. It records open items and ticks nothing off. Not verified: the per-PR evidence counts inside the block are transcribed from each PR body and review-gate comment, not re-run. - **Not shipped reality:** open at the time of writing: PRs `#2502`, `#2506`, `#2522`, `#2531`, `#2532`, `#2535`, `#2541`, `#2542`, `#2547` and `#2550`. The control-plane PRs `#2502`, `#2506`, `#2522`, `#2532` and `#2550` are deliberately **not** merged by the orchestrator — under ADR-0066's 2026-09-03 private-Pro amendment they wait for the maintainer's review, queued as human-action item SC-10. `#2522` is now **CONFLICTING** with `main`: `#2548` landed in this range and both change `scripts/ci/dev-up.test.mjs`, so its owner must rebase before it can merge; `#2531` is stacked on `#2522`'s `issue-1898/port-release-deadline` branch and inherits that wait, and merging it before its base lands would repeat the eighth block's dead-base trap. `main` at `a865637a6` reports 19 completed checks, all `success` with `Secret Scan` `skipped` — the second clean tip run of the lane. Their state lives on the PRs and their issues, and `docs/releases/V0_3_0_READINESS.md` carries the release-gate view. +v0.3 integration wave, eleventh block (2026-09-04 to 2026-09-05, `main` `a865637a6` to `35c7ba2b5`; four Claude sessions in parallel, lane split recorded in `.codex/memories/00_ACTIVE.md` by PR `#2560`: alpha product-trust, beta platform-integrity, an open-PR reconciliation session, and a coordinator; this block records the alpha lane's slices plus the reconciliation session's product-lane merges, and the coordinator adds its own entries separately). Codex review credits stayed exhausted (SC-9), so **every PR below carried one fresh-context independent reviewer subagent instead of a Codex outcome**, and the connector's usage-limit notice was classified once per PR as informational. Control-plane PRs stay parked for the maintainer under SC-10; none merged in this range. The SC-10 queue itself gained two post-hoc disclosures and a new SC-11 branch-hygiene item via PR `#2564` (merge `7155f1042`, docs-only), measured against the Actions API and re-verified before recording: + +Review and proposal frontend: +- **Incomplete move-card headlines are enriched with the destination column (`#1761`, PR `#2541`, merge `8c511205d`; closes `#1761`).** `useProposalDisplayNames` and `PaperReviewView` enrich the backend's bare `Move card.` headline to `Move card to "".` when the destination resolves from a column already loaded for that proposal; an unavailable column stays un-enriched rather than guessed. The first head compared `actionType` against `'movecard'`, which no backend path emits (every producer writes `actionType "move"` with `targetType "card"`: `WriteTools.cs:225`, `ProposeMoveCardExecutor.cs:100`, `ProposeBulkMoveExecutor.cs:165`, `AutomationPlannerService.cs:737`; `OperationHandlerRegistry.cs:83` accepts only that pair), so the feature was inert on production data and its three specs passed only on invented fixtures. Fixed as `155b49630` with a shared gate helper, corrected fixtures and two regression guards (the real `{cardId, columnId}` payload without `boardId`; a non-canonical spelling does not enrich). Evidence: reverting the gate turns 3 tests red, 189/189 on the four affected specs, typecheck clean, 24 pass / 11 skipped hosted at the exact head. Not verified: no live end-to-end run. Tracked non-blocking: `#2563` (headlines paired to operations by index while the arrays use different orderings). +- **Overlapping revision metadata survives a rejected in-flight read (`#2524` partial, PR `#2565`, merge `3b91876c8`; `#2524` closed with its remaining LOW on `#2579`).** `useProposalRevisions` no longer bumps the load generation when a POST publishes metadata, so a strictly newer in-flight GET lands and merges instead of being dropped; `history.invalid` is cleared only by a response that is a whole chain of its own. Review round 1 found a real HIGH, confirmed by running the interleaving: with the bump removed, a GET that rejected after the POST left `revisionsLoaded` true with `revisionCount` 0, the state that renders the diff pane as no-operations, blocks Apply with a false zero-op toast and pins the editor to pre-revision operations. The merged head `b0421100d` clears count and latest in the catch only when the metadata was already non-authoritative (behaviour-identical to `main` on every pre-existing path: all eight `loadRevisionState` callers drop `revisionsLoaded` first or are guarded by it). Evidence: the rejected-GET regression red then green, 31/31 in the composable spec, 350 across four Review specs, typecheck, ESLint, build, diff check; two review rounds, both scoped verdicts SHIP after the fix. Not verified: Playwright, full vitest. Tracked non-blocking on `#2579`: the invalid-clearing gate does not cover the disputed number (needs a self-contradicting server; the unique `(ProposalId, RevisionNumber)` index rules it out short of corruption), failure-toast noise after a proven save, the clear-half coverage, the unbounded per-proposal history map. +- **The post-revision Review lock reason reaches every disabled decision control (`#2461`, PR `#2568`, merge `330ccb4de`; closes `#2461`).** `ReviewDecisionRail` takes a `decisionDescriptionIds` prop joined into each control's `aria-describedby` with the existing edit-lock description; `ReviewMain` forwards the `aria-describedby` it already receives, read through a function rather than a computed because fallthrough attrs are not reactive, and only while `busy` holds the controls disabled, which the round-1 MEDIUM required: without the gate, enabled Reject, Request edit and Defer announced the evidence-unavailable note about a different action. No dangling id is possible because the notes and `ReviewMain` share one `v-if` block and one set of flags; `PaperReviewView.vue` was not edited. Evidence: red-first 5 failed then 44/44 on the two component specs, the busy-gate regression red then green, 205 across `ReviewDecisionRail`, `ReviewMain` and `PaperReviewView` specs, typecheck, ESLint, diff check. Not verified: `tests/e2e/review-proposals.spec.ts` (untouched), screen-reader run. Tracked non-blocking on `#2578`: a per-note split so the Apply unavailable note keeps its association, cleanup-stack robustness, prop doc wording, a view-level union case. +- **The post-revision truth refresh is bounded and retryable (`#2460`, PR `#2576`, merge `35c7ba2b5`; closes `#2460`).** `PaperReviewView` owns one `AbortController` plus one deadline (`POST_REVISION_REVIEW_DEADLINE_MS = 12_000`) per attempt covering the explicit queue read (now `skipRetry: true`, like the background poll, so one transient failure's backoff cannot eat the budget) and the six core selector reads (deliberately still retrying, because `ensureCoreBatch` may reuse a batch the automatic watcher started for the same key; the constant's comment states the budget must cover one interceptor pass). An attempt ends as exactly one of refreshed, failed, timed-out, aborted or superseded; only refreshed with the full identity/status/expiry/defer/effective-revision match clears the per-proposal epoch, now via `clearRevisionReviewBarrier` after the attempt-generation check and re-reading the epoch so a save that lands mid-attempt keeps its newer barrier; every other ending retains the barrier and unlocks the rail in `finally`; failed and timed-out get distinct persistent notes and toasts (new `review.toast.revisionReviewTimedOut` in en/es/it), aborted and superseded stay silent, and no note or toast is shown at all once the reviewer moved to another proposal. `dispose()` aborts the controller as well as the timer and `onUnmounted` bumps the generation then disposes, so an attempt cannot outlive the route. Evidence: 416 tests across seven Review files (398 in the six-file set, 394 at round 1, 319 before), locale parity, typecheck, ESLint, build, diff check; 5 of 5 new composable specs and the two stall specs red against the pre-change sources, and the four round-2 specs red against the round-1 sources; two review rounds (SHIP with three MEDIUMs taken in scope, then a scoped pass). Not verified: Playwright `review-proposals.spec.ts` (untouched), real-network deadline behaviour. Tracked non-blocking on `#2581`: the failed/timed-out note is keyed to the pre-save revision identity and vanishes when the poll lands the new one; the same-action retry re-issues an unheld batch after an abort. + +Inbox frontend: +- **Background batch-poll reconciliation tells the truth (`#2301`, `#2303`, `#2304`, `#2305`, PR `#2567`, merge `46fb41d53`; closes all four).** One root-cause PR: all four defects lived in `pollBatchTriageCompletion` / `refreshTerminalDetails` and the generation guards they read. The accepted success path of the background list read clears `listError` (superseded, aborted, 401 and 403 responses never reach it), so rows recovered by a later poll are visible without manual Retry; summary reads now stamp the shared monotonic capture generation and `applyBackgroundListSnapshot` merges per row, so a delayed batch snapshot cannot regress a newer per-item summary (no new timer); workload counts refresh once per newly observed terminal outcome plus a sweep at the 60 s deadline, replacing the unconditional all-terminal notify; `refreshTerminalDetails` passes `trackLoading: false` so batch reconciliation never raises the store-wide `loadingDetail` flag (the Legacy `InboxDetailPanel` was its only consumer). Evidence: `captureStore.spec.ts` 76 passed (65 at base, each defect red first), six Inbox files 303, thirteen neighbours 257, typecheck, ESLint, build, diff check; one fresh-context review, SHIP, no CRITICAL/HIGH. Not verified: Playwright, manual browser pass, full vitest. Tracked: `#2570` (pre-existing: `batchTriage`'s post-POST `fetchItems()` is unscoped and replaces a board-scoped Legacy inbox's rows; for `triage` the scoped poll's first tick corrects it within 3 s, for `ignore` / `cancel` it persists until the next scoped load) and `#2571` (foreground `loadingDetail` during `batchTriage` unpinned by a spec, count-refresh amplification on `/workspace/home`, summary-generation map growth, no "aborted" negative control). +- **The Paper Inbox stops asserting a column filter it never applies (`#1984` finding 2, PR `#2580`, merge `92a8192f6`; `Refs #1984`, which stays open for the ruled-on real-column-contract branch).** With `?boardId=B&columnId=C` the scope chip read `Board: X · Column: Y` and the scoped empty state named the column while the list request sent only `boardId`; the board's `+ capture` control promised column-scoped capture through both its pushed query and its accessible name, and nothing delivers it (`CaptureListQuery` has no column, `CreateCaptureItemDto` has no `ColumnId`, triage targets the default column). The chip is now always `inbox.scope.board` (the `boardAndColumn` key deleted from en, it and es), the empty state names the board only, `openCapture` pushes `{ boardId }` alone and `boardDetail.card.captureAria` reads "Capture a note into Inbox from {column}"; no capture-destination line was added because the column is not a destination. `useInboxOrchestrator.ts` is untouched, so a hand-written `columnId` is still cleared by `clearScope`. Two green pins that defended the untruth were rewritten on purpose. Evidence: the new coupled spec `PaperInboxScopeTruth.spec.ts` (chip text and `fetchItems` call shape in one test) red on exactly the defect, the standing Inbox glob 466 to 471 passed, typecheck, ESLint, build, diff check. Not verified: Playwright, native review of the it/es wording. Review round 1 SHIP with one MEDIUM taken: the reworded accessible name still gave every column's control a different name for one behaviour; it is now a board-level statement in en, it and es. Tracked non-blocking on `#2589`: `activeColumnId` / `activeColumnName` have no producer until the column-contract ruling. + +Paper and shared dialogs: +- **Dialog sheets honor the visual viewport without `dvh`, and the mobile-safari specs measure in the right coordinate space (`#2180` partial, PR `#2574`, merge `1f75473f1`; `Refs #2180`, which stays open for the two-consecutive-green-nights bullet).** The nightly `E2E (mobile-safari)` red since 2026-08-24 (`y` 112 instead of 120 under the synthetic contracted viewport) was measured from the CI trace and reproduced in isolation: `src/style.css`'s 8 px `::-webkit-scrollbar` rule makes WebKit's root scroller use classic scrollbars, the visual viewport ends up 8 px shorter than the layout viewport and parks at `offsetTop` 8 once the document is scrolled, and WebKit reports client rects relative to the visual viewport while `position: fixed` resolves against the layout viewport (`clientTop = cssTop - offsetTop`), so the dialog rendered correctly and only the assertions assumed the two spaces coincide. No CSS or component change in the `14042c023..53ef459c9` window explains the flip (only `236e5f980` touched the dialog files, adding no geometry); the trigger stays between `#2039`'s font change altering page height and a runner image roll, and the fix makes it moot. The specs now measure a `position: fixed; top: 0` sentinel and convert with it (no tolerance band), assert `origin === -visualViewport.offsetTop` on WebKit only, and the synthetic harness's height is lazy. The real defect from the PR `#2397` review residual is fixed too: `PaperBoardDialogShell` and `TdDialog` consumed the live visual-viewport height only inside `@supports (height: 100dvh)`, so a VisualViewport-present / dvh-absent browser got a sheet pushed down by `offsetTop` while staying `100vh` tall; both now use a three-declaration ladder (`100vh` floor, `var(..., 100vh)` unconditionally, `@supports` upgrading the fallback to `100dvh`), byte-equivalent on every browser CI runs. Evidence: 71 vitest tests across five files (TdDialog 16 and CardModal 30 unchanged, so the `#1821`/`#1864` binding is intact); a source-text spec (`DialogVisualViewportCss.spec.ts`, Vite `?raw` imports) fails 3 cases on reverting the shell commit and 5 on reverting the TdDialog commit; typecheck, ESLint, build, diff check; local E2E `mobile-safari` 7/7 and `mobile-chrome` 7/7 against a stack on distinct ports. Not verified: a hosted mobile-safari run (local WebKit keeps `offsetTop` at 0, so the pre-change spec also passes locally); the proof on CI is the next two nightlies, which the beta lane watches under CI-15 `#2339` with its quarantine on hold. + +Backend and LLM, closed on evidence: +- **Partial transcript dates resolve against the capture date (`#2193`, closed on evidence 2026-09-04, no new PR).** All three acceptance boxes are on `main`: PR `#2206` (merge `08ac35505`) added the reference date to `LlmCaptureTriagePrompt.cs` and the plausibility window plus dropped-date note in `CaptureTriageContracts.cs`; PR `#2380` (merge `36fd01d41`) extended the fixtures; PR `#2515` (merge `49ace6799`) anchored the reference to the capture's own day (`CaptureTriageAnchor.cs`, server-stamped instant in the capture's reported UTC offset clamped to +/-14 h), which was the maintainer's 2026-09-02 keep-open condition. Re-measured: `LlmCaptureTriagePromptTests` plus `CaptureTriageAnchorTests` 43 passed, `LlmCaptureTriageExtractorTests` 51 passed. Residuals recorded on `#2210`: the dropped-date note reaches only the server log, the reference-aware `Validate` overload is unreachable at its five production call sites, and no live-provider derivation proof exists in the tree. + +Platform lane (beta-platform-integrity, recorded here from the lane's own merge packets, verbatim facts): +- **The notification paging integration test no longer asserts a wall-clock bound (`#2489`, PR `#2566`, merge `ea3e39e7d`).** It asserts paging behaviour only (a Windows API Integration false-red source in the SC-4 window); the SQL-shape regression for `#1133` stays pinned by the interceptor test in `NotificationRepositoryIntegrationTests`, proven red on an in-memory-paging revert. Test-only. Follow-up: `docs/releases/V0_3_0_READINESS.md` still named the deleted test in its clause-4 noise list at the time of the packet. +- **The MCP API-key middleware logs a sanitized token prefix (`#2519`, PR `#2569`, merge `0886b6c42`).** The eight-character prefix logged on a key-not-found failure is sliced first, then stripped, so no caller-controlled CR/LF/U+2028/C1 can forge a log line and no token material past index 7 is ever logged; the shared log control-character sanitizer now also strips every BMP Unicode format character (zero-width and bidi overrides) for all log-only consumers. Four middleware regressions plus sanitizer unit cases, full backend solution green, one fresh-context review SHIP with its findings fixed before merge; `docs/security/SECURITY_LOGGING_REDACTION.md` updated. +- **The standalone CLI keeps a bounded, always-on diagnostic record for every unexpected failure (`#2468`, PR `#2573`, merge `2803355a7`).** Records live under `/diagnostics/` (never the CWD): exclusive create, owner-only on POSIX, 8 KB per record, 20 records with oldest-first eviction, a redacted exception summary plus argv and the same correlation reference the generic stderr line prints; every IO failure fails open with the unchanged generic line and no raw exception text. Supersedes the `#2466` sentence that the exception was retained nowhere outside the harness trace. One fresh-context review found and the fix closed a HIGH (a malformed `TASKDECK_CONNECTION_STRING` escaped as a raw stack trace before the boundary existed); follow-up LOWs on `#2577`; `docs/security/SECURITY_LOGGING_REDACTION.md` and the surface inventory updated. + +Docs and governance: +- **The fail-closed producer-triple projection is documented (`#2499` option (a), PR `#2586`, merge `fecc7d734`; refs `#2499`, `#2494`, `#1987`).** `UPGRADING.md`'s `AddProposalProvenanceProducerTriple` note now says that a pre-migration row whose required `ModelId` holds a real model id has that model withheld by `GET /automation/proposals/{id}/provenance/metadata` (all three fields null) because `ModelId` also stores the origin labels `chat-tools`, `manual`, `queue` and `unknown`, that the Paper Review capture-detail fallback can still surface a capture-linked proposal's own recorded provenance, and that a deterministic backfill from the `CaptureProvenanceV1` block the triage workers stamp into `LlmRequest.Payload` is possible but undecided; `docs/architecture/DATA_MODEL.md`'s `ProposalProvenance` table gains the `Provider` and `PromptVersion` columns (both max 64) and the projection rule. The same clause applies to the `#2494` paragraph in this file. Option (b), a sentinel allow-list, is recommended for decline because `ProvenanceModelId` is body-bound on `CreateProposalDto` without `[JsonIgnore]` (hardening filed for the platform lane); option (c) awaits a ruling. Review SHIP with three accuracy corrections taken in the same round (the `Provider` row's Queue contradiction, the recorded provider values `OpenAI` and `deterministic-extractor`, and `ModelId`'s trust wording), plus the `/api` route prefix. Its first CI red was the Linux dev-up launcher suite, filed as `#2588` by the platform lane. +- **Stale release and test claims reconciled across four documents (`#2133` slice, PR `#2547`, merge `22ec0d333`; refs `#2133`, `#2079`, `#2081`, `#2082`; `#2133` stays open).** `docs/STATUS.md`, `docs/IMPLEMENTATION_MASTERPLAN.md`, `docs/TESTING_GUIDE.md` and `docs/platform/V0_1_1_WINDOWS_STARTUP_INCIDENT.md` now carry measured values: ADR-0059's status corrected Proposed to Accepted, the `#2073` E2E scope corrected seven to six chromium specs, the retired `EvidenceLinkTests.cs` / `CompilerValidationResult*` entries replaced, and a stale "70 tests" RFAI-04 count dropped rather than guessed. Every corrected value was re-measured by the reviewer (`v0.1.2` peels to `9766edbb5`; the six-spec count against `playwright.config.ts` `testIgnore` plus `manual-audit.spec.ts`'s `TASKDECK_RUN_AUDIT` gate at the `#2073` merge head; both published `dotnet test` filters run, RFAI-04 54/54 and RFAI-03 103/103); 20/20 hosted at the exact head. Lesson recorded rather than hidden: the sweep's rewritten "Current continuation" list routed work to "the current v0.2 queue", which closed 2026-08-29; fixed as `6becc4973` by naming no milestone, since any hard-coded milestone in present-tense guidance goes stale on the next ship. +- **Two post-hoc control-plane disclosures and a branch-hygiene item reach the maintainer's queue (PR `#2564`, merge `7155f1042`; docs-only, `OUTSTANDING_TASKS.md`).** SC-10 records that `#2529` merged while its `ci-required.yml` run had concluded `cancelled` (branch protection could not stop it: only the three security contexts are required), that `#2548`, `#2556` and `#2549` merged on a fresh-context review alone, that the queued control-plane PR bases are 46 to 138 commits behind `main` and need `gh pr update-branch` plus a fresh hosted run and review re-check before merge, and that `#2531`'s `Closes #2526` registers no closing reference while it targets a stacked base. New SC-11: `delete_branch_on_merge` is false and 448 remote branches exist; the setting flip is the maintainer's and the one-time sweep needs its own recorded authorization, ancestry proof per tip and exclusion of every open-PR head and base. Nothing was lost: all 80 head and merge SHAs of the 40 most recently merged PRs are ancestors of `origin/main`. Two review passes, both SHIP. + +Not shipped reality, open at the time of writing (alpha lane, each with one fresh-context review already posted): PR `#2584` (`#2501` and `#2022`, count-free Inbox eyebrow during scope replacement plus the applied-response signal from `fetchItems`; two rounds SHIP, re-proving on its refreshed base after `#2580` landed), PR `#2590` (`#2215` Legacy diff-pane re-adoption; two rounds SHIP), PR `#2593` (`#2214` Legacy unavailable-pin state and the loading/revoked gate on both queue live regions; two rounds SHIP, Paper rail wiring being added now that `#2576` released `PaperReviewView.vue`), PR `#2597` (`#1307` batch-approve parity: a null selection element answers 400 instead of 500 and the board-write ACL is re-validated inside the approval transaction; SHIP, two LOWs taken, full backend solution green with mutation checks), PR `#2603` (`#2435` board-detail arbitration: board-settings and label writes advance the mutation epoch, an invalidated background read queues exactly one successor, a current background 403 stays authoritative; review in progress), and the `#2563` headline/operation pairing slice (in implementation). Their facts land in the next block with merge SHAs. Tracked non-blocking residual issues opened by the lane's reviews: `#2570`, `#2571`, `#2578`, `#2579`, `#2581`, `#2589`, `#2591`, `#2598`, `#2599`. + +Corrections to earlier blocks in this file: the sentence "Page-level counts during replacement remain on open `#2022`" is closed by PR `#2584`. the `#2448` line that says section A of `#2215` "is not shipped" and section B "is not demonstrably shipped" is false against `main`: both shipped in PR `#2247` (merge `17102ae6d`) with dedicated regressions, and the same false claim sits in `#2215`'s final comment. The `#2214` line saying "deep-link re-authorization ... remain open" is false since PR `#2357` (merge `8c748831e`), which this file never recorded. The `#1304` block's closing sentence "Explicit batch execute and its public atomic-versus-partial failure contract remain open" and the `#1307` "remains owner-decision gated" sentence are stale: batch execute shipped in PR `#2253` (merge `2468c41b0`), and the decisions still open on `#1307` are the batch-execute eligibility width, AC4's home and the human-only dogfooding week, not `#1992`'s ADR-0064 ruling. The `#2193` bullet now reads closed on evidence (PRs `#2206`, `#2380`, `#2515`; residuals on `#2210`). The `#2494` paragraph gains the withheld-model clause above. The `#2194` line that says the Legacy review skin "renders no translated strings" is superseded once PR `#2593` lands: its unavailable-pin panel renders four `$t` calls, and the summary-card labels were already translated through the composable. the tenth block's line saying `#2522` "is now CONFLICTING with `main`: `#2548` landed in this range" should read that `#2548` (`6c10850e6`) and `#2556` (`8c0779fca`) both landed and all three change `scripts/ci/dev-up.test.mjs`; `#2522` is no longer conflicting (head `18d214ba2`, `main` merged in rather than rebased because `#2531`'s head has `#2522`'s old head as an ancestor), and its later red is `#2378`'s recorded signature plus `#2572`. The historical wave block below still names `#1938`, `#1967` and `#2121` as open; all three are closed (2026-08-27, 2026-08-27, 2026-09-04). The `v0.1.2 SHIPPED` header reads 2026-08-25 while the tag and release are both dated 2026-08-24 UTC. + v0.3.0-rc.1 SHIPPED (2026-08-30, annotated tag `3fc9f6e8e` peels to `9d2ea3c7c`): - **The public v0.3.0-rc.1 pre-release exists**, cut by the agent under the maintainer's v0.3 RC deck reply q-1 A (2026-08-30; map `map:v1:bec0a8dd…dd9138`; record `#1947`) and the repository's declared authority. The GitHub Release is `prerelease=true`, `draft=false`, published 2026-08-30T02:26:06Z with three assets — `taskdeck-v0.3.0-rc.1-win-x64.zip` (53,916,746 bytes), its `.sha256` sidecar, and `taskdeck-v0.3.0-rc.1-provenance.txt` — and a composed page (download badge first, RC banner, SHA-256, quick-start link, `## Breaking changes` lifted from UPGRADING, `## Highlights` from `docs/releases/notes/v0.3.0-rc.1.md`, grouped `## What's changed`). `/releases/latest` still resolves to `v0.2.0`. - **Tag workflows:** CI Release 33287786328, Release Security 33287786318, Release Container 33287786267, Release Desktop 33287786253 — all four success. **GHCR:** `ghcr.io/chris0jeky/taskdeck:0.3.0-rc.1` published (`sha256:d47bdf2d…2db67`), `latest` and `0.2` both still `sha256:e4915d72…8c752`, and no `0.3` alias exists — the floating `latest` / `0.2` index digest is unchanged from the pre-tag capture (`sha256:e4915d72…8c752`) and no `0.3` alias was created, which is the live proof of `#2217`/PR `#2223` that the threat-model row was waiting for. From ea2ad976b65e44dafc7d3310e83947602142ed08 Mon Sep 17 00:00:00 2001 From: Chris0Jeky Date: Sat, 5 Sep 2026 03:21:24 +0100 Subject: [PATCH 2/2] docs: correct two claims in the eleventh block after review (#2584 still open, shipped captureAria string) and tidy wording --- docs/STATUS.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/STATUS.md b/docs/STATUS.md index cca4a67b2..99ff1b9da 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -190,16 +190,16 @@ Review and proposal frontend: Inbox frontend: - **Background batch-poll reconciliation tells the truth (`#2301`, `#2303`, `#2304`, `#2305`, PR `#2567`, merge `46fb41d53`; closes all four).** One root-cause PR: all four defects lived in `pollBatchTriageCompletion` / `refreshTerminalDetails` and the generation guards they read. The accepted success path of the background list read clears `listError` (superseded, aborted, 401 and 403 responses never reach it), so rows recovered by a later poll are visible without manual Retry; summary reads now stamp the shared monotonic capture generation and `applyBackgroundListSnapshot` merges per row, so a delayed batch snapshot cannot regress a newer per-item summary (no new timer); workload counts refresh once per newly observed terminal outcome plus a sweep at the 60 s deadline, replacing the unconditional all-terminal notify; `refreshTerminalDetails` passes `trackLoading: false` so batch reconciliation never raises the store-wide `loadingDetail` flag (the Legacy `InboxDetailPanel` was its only consumer). Evidence: `captureStore.spec.ts` 76 passed (65 at base, each defect red first), six Inbox files 303, thirteen neighbours 257, typecheck, ESLint, build, diff check; one fresh-context review, SHIP, no CRITICAL/HIGH. Not verified: Playwright, manual browser pass, full vitest. Tracked: `#2570` (pre-existing: `batchTriage`'s post-POST `fetchItems()` is unscoped and replaces a board-scoped Legacy inbox's rows; for `triage` the scoped poll's first tick corrects it within 3 s, for `ignore` / `cancel` it persists until the next scoped load) and `#2571` (foreground `loadingDetail` during `batchTriage` unpinned by a spec, count-refresh amplification on `/workspace/home`, summary-generation map growth, no "aborted" negative control). -- **The Paper Inbox stops asserting a column filter it never applies (`#1984` finding 2, PR `#2580`, merge `92a8192f6`; `Refs #1984`, which stays open for the ruled-on real-column-contract branch).** With `?boardId=B&columnId=C` the scope chip read `Board: X · Column: Y` and the scoped empty state named the column while the list request sent only `boardId`; the board's `+ capture` control promised column-scoped capture through both its pushed query and its accessible name, and nothing delivers it (`CaptureListQuery` has no column, `CreateCaptureItemDto` has no `ColumnId`, triage targets the default column). The chip is now always `inbox.scope.board` (the `boardAndColumn` key deleted from en, it and es), the empty state names the board only, `openCapture` pushes `{ boardId }` alone and `boardDetail.card.captureAria` reads "Capture a note into Inbox from {column}"; no capture-destination line was added because the column is not a destination. `useInboxOrchestrator.ts` is untouched, so a hand-written `columnId` is still cleared by `clearScope`. Two green pins that defended the untruth were rewritten on purpose. Evidence: the new coupled spec `PaperInboxScopeTruth.spec.ts` (chip text and `fetchItems` call shape in one test) red on exactly the defect, the standing Inbox glob 466 to 471 passed, typecheck, ESLint, build, diff check. Not verified: Playwright, native review of the it/es wording. Review round 1 SHIP with one MEDIUM taken: the reworded accessible name still gave every column's control a different name for one behaviour; it is now a board-level statement in en, it and es. Tracked non-blocking on `#2589`: `activeColumnId` / `activeColumnName` have no producer until the column-contract ruling. +- **The Paper Inbox stops asserting a column filter it never applies (`#1984` finding 2, PR `#2580`, merge `92a8192f6`; `Refs #1984`, which stays open for the ruled-on real-column-contract branch).** With `?boardId=B&columnId=C` the scope chip read `Board: X · Column: Y` and the scoped empty state named the column while the list request sent only `boardId`; the board's `+ capture` control promised column-scoped capture through both its pushed query and its accessible name, and nothing delivers it (`CaptureListQuery` has no column, `CreateCaptureItemDto` has no `ColumnId`, triage targets the default column). The chip is now always `inbox.scope.board` (the `boardAndColumn` key deleted from en, it and es), the empty state names the board only, `openCapture` pushes `{ boardId }` alone and `boardDetail.card.captureAria` reads "Capture a note into this board's Inbox" (the round-1 head had reworded it to "from {column}", which still varied per column); no capture-destination line was added because the column is not a destination. `useInboxOrchestrator.ts` is untouched, so a hand-written `columnId` is still cleared by `clearScope`. Two green pins that defended the untruth were rewritten on purpose. Evidence: the new coupled spec `PaperInboxScopeTruth.spec.ts` (chip text and `fetchItems` call shape in one test) red on exactly the defect, the standing Inbox glob 466 to 471 passed, typecheck, ESLint, build, diff check. Not verified: Playwright, native review of the it/es wording. Review round 1 SHIP with one MEDIUM taken: the reworded accessible name still gave every column's control a different name for one behaviour; it is now a board-level statement in en, it and es. Tracked non-blocking on `#2589`: `activeColumnId` / `activeColumnName` have no producer until the column-contract ruling. Paper and shared dialogs: - **Dialog sheets honor the visual viewport without `dvh`, and the mobile-safari specs measure in the right coordinate space (`#2180` partial, PR `#2574`, merge `1f75473f1`; `Refs #2180`, which stays open for the two-consecutive-green-nights bullet).** The nightly `E2E (mobile-safari)` red since 2026-08-24 (`y` 112 instead of 120 under the synthetic contracted viewport) was measured from the CI trace and reproduced in isolation: `src/style.css`'s 8 px `::-webkit-scrollbar` rule makes WebKit's root scroller use classic scrollbars, the visual viewport ends up 8 px shorter than the layout viewport and parks at `offsetTop` 8 once the document is scrolled, and WebKit reports client rects relative to the visual viewport while `position: fixed` resolves against the layout viewport (`clientTop = cssTop - offsetTop`), so the dialog rendered correctly and only the assertions assumed the two spaces coincide. No CSS or component change in the `14042c023..53ef459c9` window explains the flip (only `236e5f980` touched the dialog files, adding no geometry); the trigger stays between `#2039`'s font change altering page height and a runner image roll, and the fix makes it moot. The specs now measure a `position: fixed; top: 0` sentinel and convert with it (no tolerance band), assert `origin === -visualViewport.offsetTop` on WebKit only, and the synthetic harness's height is lazy. The real defect from the PR `#2397` review residual is fixed too: `PaperBoardDialogShell` and `TdDialog` consumed the live visual-viewport height only inside `@supports (height: 100dvh)`, so a VisualViewport-present / dvh-absent browser got a sheet pushed down by `offsetTop` while staying `100vh` tall; both now use a three-declaration ladder (`100vh` floor, `var(..., 100vh)` unconditionally, `@supports` upgrading the fallback to `100dvh`), byte-equivalent on every browser CI runs. Evidence: 71 vitest tests across five files (TdDialog 16 and CardModal 30 unchanged, so the `#1821`/`#1864` binding is intact); a source-text spec (`DialogVisualViewportCss.spec.ts`, Vite `?raw` imports) fails 3 cases on reverting the shell commit and 5 on reverting the TdDialog commit; typecheck, ESLint, build, diff check; local E2E `mobile-safari` 7/7 and `mobile-chrome` 7/7 against a stack on distinct ports. Not verified: a hosted mobile-safari run (local WebKit keeps `offsetTop` at 0, so the pre-change spec also passes locally); the proof on CI is the next two nightlies, which the beta lane watches under CI-15 `#2339` with its quarantine on hold. Backend and LLM, closed on evidence: -- **Partial transcript dates resolve against the capture date (`#2193`, closed on evidence 2026-09-04, no new PR).** All three acceptance boxes are on `main`: PR `#2206` (merge `08ac35505`) added the reference date to `LlmCaptureTriagePrompt.cs` and the plausibility window plus dropped-date note in `CaptureTriageContracts.cs`; PR `#2380` (merge `36fd01d41`) extended the fixtures; PR `#2515` (merge `49ace6799`) anchored the reference to the capture's own day (`CaptureTriageAnchor.cs`, server-stamped instant in the capture's reported UTC offset clamped to +/-14 h), which was the maintainer's 2026-09-02 keep-open condition. Re-measured: `LlmCaptureTriagePromptTests` plus `CaptureTriageAnchorTests` 43 passed, `LlmCaptureTriageExtractorTests` 51 passed. Residuals recorded on `#2210`: the dropped-date note reaches only the server log, the reference-aware `Validate` overload is unreachable at its five production call sites, and no live-provider derivation proof exists in the tree. +- **Partial transcript dates resolve against the capture date (`#2193`, closed on evidence 2026-09-04, no new PR).** All three acceptance boxes are on `main`: PR `#2206` (merge `08ac35505`) added the reference date to `LlmCaptureTriagePrompt.cs` and the plausibility window plus dropped-date note in `CaptureTriageContracts.cs`; PR `#2380` (merge `36fd01d41`) extended the fixtures; PR `#2515` (merge `49ace6799`) anchored the reference to the capture's own day (`CaptureTriageAnchor.cs`, server-stamped instant in the capture's reported UTC offset, an out-of-range offset beyond +/-14 h being discarded in favour of UTC rather than trusted), which was the maintainer's 2026-09-02 keep-open condition. Re-measured: `LlmCaptureTriagePromptTests` plus `CaptureTriageAnchorTests` 43 passed, `LlmCaptureTriageExtractorTests` 51 passed. Residuals recorded on `#2210`: the dropped-date note reaches only the server log, the reference-aware `Validate` overload is unreachable at its five production call sites, and no live-provider derivation proof exists in the tree. Platform lane (beta-platform-integrity, recorded here from the lane's own merge packets, verbatim facts): -- **The notification paging integration test no longer asserts a wall-clock bound (`#2489`, PR `#2566`, merge `ea3e39e7d`).** It asserts paging behaviour only (a Windows API Integration false-red source in the SC-4 window); the SQL-shape regression for `#1133` stays pinned by the interceptor test in `NotificationRepositoryIntegrationTests`, proven red on an in-memory-paging revert. Test-only. Follow-up: `docs/releases/V0_3_0_READINESS.md` still named the deleted test in its clause-4 noise list at the time of the packet. +- **The notification paging integration test no longer asserts a wall-clock bound (`#2489`, PR `#2566`, merge `ea3e39e7d`).** It asserts paging behaviour only (a Windows API Integration false-red source in the SC-4 window); the SQL-shape regression for `#1133` stays pinned by the interceptor test in `NotificationRepositoryIntegrationTests`, proven red on an in-memory-paging revert. Test-only. - **The MCP API-key middleware logs a sanitized token prefix (`#2519`, PR `#2569`, merge `0886b6c42`).** The eight-character prefix logged on a key-not-found failure is sliced first, then stripped, so no caller-controlled CR/LF/U+2028/C1 can forge a log line and no token material past index 7 is ever logged; the shared log control-character sanitizer now also strips every BMP Unicode format character (zero-width and bidi overrides) for all log-only consumers. Four middleware regressions plus sanitizer unit cases, full backend solution green, one fresh-context review SHIP with its findings fixed before merge; `docs/security/SECURITY_LOGGING_REDACTION.md` updated. - **The standalone CLI keeps a bounded, always-on diagnostic record for every unexpected failure (`#2468`, PR `#2573`, merge `2803355a7`).** Records live under `/diagnostics/` (never the CWD): exclusive create, owner-only on POSIX, 8 KB per record, 20 records with oldest-first eviction, a redacted exception summary plus argv and the same correlation reference the generic stderr line prints; every IO failure fails open with the unchanged generic line and no raw exception text. Supersedes the `#2466` sentence that the exception was retained nowhere outside the harness trace. One fresh-context review found and the fix closed a HIGH (a malformed `TASKDECK_CONNECTION_STRING` escaped as a raw stack trace before the boundary existed); follow-up LOWs on `#2577`; `docs/security/SECURITY_LOGGING_REDACTION.md` and the surface inventory updated. @@ -208,9 +208,9 @@ Docs and governance: - **Stale release and test claims reconciled across four documents (`#2133` slice, PR `#2547`, merge `22ec0d333`; refs `#2133`, `#2079`, `#2081`, `#2082`; `#2133` stays open).** `docs/STATUS.md`, `docs/IMPLEMENTATION_MASTERPLAN.md`, `docs/TESTING_GUIDE.md` and `docs/platform/V0_1_1_WINDOWS_STARTUP_INCIDENT.md` now carry measured values: ADR-0059's status corrected Proposed to Accepted, the `#2073` E2E scope corrected seven to six chromium specs, the retired `EvidenceLinkTests.cs` / `CompilerValidationResult*` entries replaced, and a stale "70 tests" RFAI-04 count dropped rather than guessed. Every corrected value was re-measured by the reviewer (`v0.1.2` peels to `9766edbb5`; the six-spec count against `playwright.config.ts` `testIgnore` plus `manual-audit.spec.ts`'s `TASKDECK_RUN_AUDIT` gate at the `#2073` merge head; both published `dotnet test` filters run, RFAI-04 54/54 and RFAI-03 103/103); 20/20 hosted at the exact head. Lesson recorded rather than hidden: the sweep's rewritten "Current continuation" list routed work to "the current v0.2 queue", which closed 2026-08-29; fixed as `6becc4973` by naming no milestone, since any hard-coded milestone in present-tense guidance goes stale on the next ship. - **Two post-hoc control-plane disclosures and a branch-hygiene item reach the maintainer's queue (PR `#2564`, merge `7155f1042`; docs-only, `OUTSTANDING_TASKS.md`).** SC-10 records that `#2529` merged while its `ci-required.yml` run had concluded `cancelled` (branch protection could not stop it: only the three security contexts are required), that `#2548`, `#2556` and `#2549` merged on a fresh-context review alone, that the queued control-plane PR bases are 46 to 138 commits behind `main` and need `gh pr update-branch` plus a fresh hosted run and review re-check before merge, and that `#2531`'s `Closes #2526` registers no closing reference while it targets a stacked base. New SC-11: `delete_branch_on_merge` is false and 448 remote branches exist; the setting flip is the maintainer's and the one-time sweep needs its own recorded authorization, ancestry proof per tip and exclusion of every open-PR head and base. Nothing was lost: all 80 head and merge SHAs of the 40 most recently merged PRs are ancestors of `origin/main`. Two review passes, both SHIP. -Not shipped reality, open at the time of writing (alpha lane, each with one fresh-context review already posted): PR `#2584` (`#2501` and `#2022`, count-free Inbox eyebrow during scope replacement plus the applied-response signal from `fetchItems`; two rounds SHIP, re-proving on its refreshed base after `#2580` landed), PR `#2590` (`#2215` Legacy diff-pane re-adoption; two rounds SHIP), PR `#2593` (`#2214` Legacy unavailable-pin state and the loading/revoked gate on both queue live regions; two rounds SHIP, Paper rail wiring being added now that `#2576` released `PaperReviewView.vue`), PR `#2597` (`#1307` batch-approve parity: a null selection element answers 400 instead of 500 and the board-write ACL is re-validated inside the approval transaction; SHIP, two LOWs taken, full backend solution green with mutation checks), PR `#2603` (`#2435` board-detail arbitration: board-settings and label writes advance the mutation epoch, an invalidated background read queues exactly one successor, a current background 403 stays authoritative; review in progress), and the `#2563` headline/operation pairing slice (in implementation). Their facts land in the next block with merge SHAs. Tracked non-blocking residual issues opened by the lane's reviews: `#2570`, `#2571`, `#2578`, `#2579`, `#2581`, `#2589`, `#2591`, `#2598`, `#2599`. +Not shipped reality, open at the time of writing (alpha lane, each with one fresh-context review already posted): PR `#2584` (`#2501` and `#2022`, count-free Inbox eyebrow during scope replacement plus the applied-response signal from `fetchItems`; two rounds SHIP, re-proving on its refreshed base after `#2580` landed), PR `#2590` (`#2215` Legacy diff-pane re-adoption; two rounds SHIP), PR `#2593` (`#2214` Legacy unavailable-pin state and the loading/revoked gate on both queue live regions; two rounds SHIP, Paper rail wiring being added now that `#2576` released `PaperReviewView.vue`), PR `#2597` (`#1307` batch-approve parity: a null selection element answers 400 instead of 500 and the board-write ACL is re-validated inside the approval transaction; SHIP, two LOWs taken, full backend solution green with mutation checks), PR `#2603` (`#2435` board-detail arbitration: board-settings and label writes advance the mutation epoch, an invalidated background read queues exactly one successor, a current background 403 stays authoritative; SHIP, a comment-only MEDIUM and two test-precision LOWs in a fix round), and the `#2563` headline/operation pairing slice (in implementation). Their facts land in the next block with merge SHAs. Tracked non-blocking residual issues opened by the lane's reviews: `#2570`, `#2571`, `#2578`, `#2579`, `#2581`, `#2589`, `#2591`, `#2598`, `#2599`. -Corrections to earlier blocks in this file: the sentence "Page-level counts during replacement remain on open `#2022`" is closed by PR `#2584`. the `#2448` line that says section A of `#2215` "is not shipped" and section B "is not demonstrably shipped" is false against `main`: both shipped in PR `#2247` (merge `17102ae6d`) with dedicated regressions, and the same false claim sits in `#2215`'s final comment. The `#2214` line saying "deep-link re-authorization ... remain open" is false since PR `#2357` (merge `8c748831e`), which this file never recorded. The `#1304` block's closing sentence "Explicit batch execute and its public atomic-versus-partial failure contract remain open" and the `#1307` "remains owner-decision gated" sentence are stale: batch execute shipped in PR `#2253` (merge `2468c41b0`), and the decisions still open on `#1307` are the batch-execute eligibility width, AC4's home and the human-only dogfooding week, not `#1992`'s ADR-0064 ruling. The `#2193` bullet now reads closed on evidence (PRs `#2206`, `#2380`, `#2515`; residuals on `#2210`). The `#2494` paragraph gains the withheld-model clause above. The `#2194` line that says the Legacy review skin "renders no translated strings" is superseded once PR `#2593` lands: its unavailable-pin panel renders four `$t` calls, and the summary-card labels were already translated through the composable. the tenth block's line saying `#2522` "is now CONFLICTING with `main`: `#2548` landed in this range" should read that `#2548` (`6c10850e6`) and `#2556` (`8c0779fca`) both landed and all three change `scripts/ci/dev-up.test.mjs`; `#2522` is no longer conflicting (head `18d214ba2`, `main` merged in rather than rebased because `#2531`'s head has `#2522`'s old head as an ancestor), and its later red is `#2378`'s recorded signature plus `#2572`. The historical wave block below still names `#1938`, `#1967` and `#2121` as open; all three are closed (2026-08-27, 2026-08-27, 2026-09-04). The `v0.1.2 SHIPPED` header reads 2026-08-25 while the tag and release are both dated 2026-08-24 UTC. +Corrections to earlier blocks in this file: the sentence "Page-level counts during replacement remain on open `#2022`" is superseded once PR `#2584` lands. The `#2448` line that says section A of `#2215` "is not shipped" and section B "is not demonstrably shipped" is false against `main`: both shipped in PR `#2247` (merge `17102ae6d`) with dedicated regressions, and the same false claim sits in `#2215`'s final comment. The `#2214` line saying "deep-link re-authorization ... remain open" is false since PR `#2357` (merge `8c748831e`), which this file never recorded. The `#1304` block's closing sentence "Explicit batch execute and its public atomic-versus-partial failure contract remain open" and the `#1307` "remains owner-decision gated" sentence are stale: batch execute shipped in PR `#2253` (merge `2468c41b0`), and the decisions still open on `#1307` are the batch-execute eligibility width, AC4's home and the human-only dogfooding week, not `#1992`'s ADR-0064 ruling. The `#2193` bullet now reads closed on evidence (PRs `#2206`, `#2380`, `#2515`; residuals on `#2210`). The `#2494` paragraph gains the withheld-model clause above. The `#2194` line that says the Legacy review skin "renders no translated strings" is superseded once PR `#2593` lands: its unavailable-pin panel renders four `$t` calls, and the summary-card labels were already translated through the composable. The tenth block's line saying `#2522` "is now CONFLICTING with `main`: `#2548` landed in this range" should read that `#2548` (`6c10850e6`) and `#2556` (`8c0779fca`) both landed and all three change `scripts/ci/dev-up.test.mjs`; `#2522` is no longer conflicting (head `18d214ba2`, `main` merged in rather than rebased because `#2531`'s head has `#2522`'s old head as an ancestor), and its later red is `#2378`'s recorded signature plus `#2572`. The historical wave block below still names `#1938`, `#1967` and `#2121` as open; all three are closed (2026-08-27, 2026-08-27, 2026-09-04). The `v0.1.2 SHIPPED` header reads 2026-08-25 while the tag and release are both dated 2026-08-24 UTC. v0.3.0-rc.1 SHIPPED (2026-08-30, annotated tag `3fc9f6e8e` peels to `9d2ea3c7c`): - **The public v0.3.0-rc.1 pre-release exists**, cut by the agent under the maintainer's v0.3 RC deck reply q-1 A (2026-08-30; map `map:v1:bec0a8dd…dd9138`; record `#1947`) and the repository's declared authority. The GitHub Release is `prerelease=true`, `draft=false`, published 2026-08-30T02:26:06Z with three assets — `taskdeck-v0.3.0-rc.1-win-x64.zip` (53,916,746 bytes), its `.sha256` sidecar, and `taskdeck-v0.3.0-rc.1-provenance.txt` — and a composed page (download badge first, RC banner, SHA-256, quick-start link, `## Breaking changes` lifted from UPGRADING, `## Highlights` from `docs/releases/notes/v0.3.0-rc.1.md`, grouped `## What's changed`). `/releases/latest` still resolves to `v0.2.0`.