diff --git a/docs/analysis/2026-09-20-hard-issue-execution-map.md b/docs/analysis/2026-09-20-hard-issue-execution-map.md new file mode 100644 index 000000000..d301f6a76 --- /dev/null +++ b/docs/analysis/2026-09-20-hard-issue-execution-map.md @@ -0,0 +1,66 @@ +# Hard-issue execution map — 2026-09-20 + +## Evidence boundary + +This is an engineering execution map, not a new roadmap, release acceptance, or exhaustive audit of every open issue. The pass inspected the 100 oldest open issues, the open Priority I search, current open PRs, and the relevant implementation and test seams. Difficulty below is a qualitative judgement about invariants, concurrency, trust boundaries, migration risk, and the evidence needed to falsify a design; it is not a restatement of GitHub priority labels. + +Authoritative starting point: `main` at `ecaccb0d2090c19a93908ee874b4600c0a6f6582`. The supplied source archive identifies `6818072c413609fd2b9a9e37c778e866998d5b1e`. GitHub's comparison found five subsequent commits affecting only `.agent-harness/delegation.json` and `docs/STATUS.md`; the runtime and test files examined in the archive are unchanged at the live starting point. Future passes must repeat the live reconciliation rather than treating this statement as permanent. + +Existing work is not reimplemented merely because an umbrella issue remains open. The open CI, proposal-evidence, frontend-race, and capture-triage PRs were checked for overlap before the quota and export lanes were claimed. No visibility, billing, branch-protection, runner-association, publication, credential, or security-policy setting is changed by this map. + +## Difficulty map + +| Rank | Issue family | Hard part | Smallest useful next proof | Boundary that must not be crossed silently | +| --- | --- | --- | --- | --- | +| 1 | [#1429](https://github.com/Chris0Jeky/Taskdeck/issues/1429), extraction worker containment; [#2258](https://github.com/Chris0Jeky/Taskdeck/issues/2258), worker protocol | OS-enforced memory containment, process lifetime, IPC limits, timeout versus memory-kill classification, and parity between Windows Job Objects and container/cgroup execution | A single-parse worker killed by a bounded fixture, with exactly one content-free failure result and the host remaining healthy | In-process decoder limits are defence in depth, not proof of whole-process containment. Keep the worker path default-off until supported paths are proved; upstream disclosure remains human-owned | +| 2 | [#3170](https://github.com/Chris0Jeky/Taskdeck/issues/3170), [#2326](https://github.com/Chris0Jeky/Taskdeck/issues/2326), [#2327](https://github.com/Chris0Jeky/Taskdeck/issues/2327), trusted CI and private rehearsal | Trusted base policy versus untrusted PR code, complete reusable-workflow reachability, exact-head receipts, fail-closed selection, and non-vacuous Linux-only evidence | Inventory every Windows selector and its call path; prove malformed, missing, or head-controlled inputs cannot suppress required evidence | [#2337](https://github.com/Chris0Jeky/Taskdeck/issues/2337) owns the actual cutover. No agent infers private-mode observation, runner isolation, budget approval, or settings changes from unit tests | +| 3 | [#1435](https://github.com/Chris0Jeky/Taskdeck/issues/1435), quota reservation cold-start concurrency | Distinguishing database atomicity from multiple test hosts, differing database identities, time-window errors, or provider configuration differences | The negative control now observed four different files. Validate the corrected shared-host contracts plus direct fresh-file repository races at the final head | Historical WAL-visibility explanations are hypotheses, not established causes. Do not add startup warmers, global locks, or a counter migration merely to repair a faulty experiment | +| 4 | [#1453](https://github.com/Chris0Jeky/Taskdeck/issues/1453), [#1465](https://github.com/Chris0Jeky/Taskdeck/issues/1465), [#1467](https://github.com/Chris0Jeky/Taskdeck/issues/1467), effective revision identity and bounded snapshots | Preserving exactly the revision a decision observed; distinguishing legacy unpinned data from an intentional original-payload decision; returning at most one revision per proposal without dispatcher drift | Design the reject-time pin and its legacy/original discriminator first; then parity-test SQL narrowing against the shared resolver across every status and a long history | A constructor timestamp is not commit visibility. Dismissal is filing, not a new decision. Do not duplicate the resolver's rules independently in list, detail, and related-evidence reads | +| 5 | [#1399](https://github.com/Chris0Jeky/Taskdeck/issues/1399), streaming extraction-history batching | Reducing N+1 reads while keeping materialisation bounded even when one artefact has arbitrarily many history rows; preserving caller order and SQLite's timestamp/ID-as-TEXT order | A row-limited, owner-scoped stream with long-history, cross-user, empty-history, ordering, cancellation, and actual SQL-count tests | A fixed number of artefact IDs does not bound their histories. The current 64 KiB JSON buffer argument is an initial capacity, not a hard memory ceiling | +| 6 | [#1512](https://github.com/Chris0Jeky/Taskdeck/issues/1512), [#1521](https://github.com/Chris0Jeky/Taskdeck/issues/1521), CI-only concurrency failures | Recovering the first causal server exception under real load without confusing runner slowness, host lifecycle, and SQLite contention | Content-free correlated diagnostics followed by the issue's repeated Windows/Linux reproduction matrix | A green rerun is not a root cause. Do not retry mutations, swallow HubException/HTTP 500, or quarantine away the contract | +| 7 | [#1653](https://github.com/Chris0Jeky/Taskdeck/issues/1653), [#1644](https://github.com/Chris0Jeky/Taskdeck/issues/1644), hosted identity and secret custody | Key custody, plaintext migration, rotation, backup/restore, refresh-session/CSRF semantics, and desktop compatibility | A reviewed design with synthetic raw-database and recovery/rotation acceptance fixtures | Local-first risk treatment does not automatically authorize hosted deployment. Ratification and operational key ownership are separate from implementing encryption | + +The first two ranks combine difficult implementation with platform or maintainer evidence. The next three are the strongest deterministic engineering targets that can progress in isolated code/test PRs without choosing hosting or commercial policy. + +## Execution order + +1. **Quota experiment integrity (#1435).** Complete the corrected head's checks and review after the observed negative control. Restore the quarantined boundary contracts and retain independent fresh-file evidence. Keep this independent of CI-control and frontend PRs. +2. **Bounded export cursor (#1399).** Establish the bounded persistence primitive before switching the streaming consumer. Keep the buffered export's full-history method and size guard unchanged. A primitive-only PR must explicitly leave the export N+1 open. +3. **Decision identity (#1453 + #1465), then bounded reads (#1467).** Review one schema/semantic decision before one query-translation decision. This avoids cementing the rejected timestamp heuristic into a new SQL selector. +4. **Containment (#1429) and CI trust (#3170/#2327).** Proceed in independently reviewable protocol, host, platform-proof, and integration slices, respecting existing lane ownership. Do not collapse these into a single cross-platform/control-plane megacommit. + +This order selects non-overlapping evidence-producing work; it does not change release milestone membership or the maintainer's accepted priority queue. + +## Quota lane: observed result, correction and limits + +[PR #3280](https://github.com/Chris0Jeky/Taskdeck/pull/3280) owns the quota tests and focused evidence note. At head `5686a1e569e28ba63242316209cc3cd36e12dbcc`, the [Ubuntu API job](https://github.com/Chris0Jeky/Taskdeck/actions/runs/35481612562/job/106000432803) observed four different physical database paths from four concurrent first accesses to `WebApplicationFactory.Services`. The complete result was 3319 passed, one failed (this database-identity assertion), and four skipped (the old quota boundary contracts). The direct fresh-file repository theory passed. The two earlier compiler failures from missing/wrong diagnostic imports are not runtime evidence. + +This invalidates the single-database assumption of the reproduced harness shape. It also explains why serializing writes with a process-global semaphore cannot enforce one quota across those files. It does not establish a SQLite WAL visibility defect or explain every historical run whose database identities were never recorded. + +Corrective head `6b9e1d88b4dc59a4af5d7e6d136578cf3233dca6` captures one service provider before the burst, restores all four quarantined boundary contracts, bounds barrier waits, and asserts one persisted reservation. Separate direct-repository tests close setup connections before racing four contenders against one fresh file, with pooling off, real migrations/WAL configuration, and request, user-token, and cross-user per-surface global-token limits. Six fresh files per budget type are tested. Production quota SQL and startup remain unchanged. + +This is same-process independent-connection evidence, not cross-process qualification. The final corrected head needs its own Linux/Windows results and review; the negative-control run does not qualify the corrective commit. Detailed evidence and residual status are on the PR. + +## Export lane: bounded primitive before consumer integration + +[PR #3282](https://github.com/Chris0Jeky/Taskdeck/pull/3282) owns `IArtefactExtractionRepository`, `ArtefactExtractionRepository`, focused integration tests, and a design/evidence note. It begins with a test-only negative control: asynchronously yielding the existing full-history batch still materialises all 123 test rows before the first yield. The interceptor assertion must reject that implementation. Do not count a compiler error or an unobserved expected result as a passing negative-control experiment. + +The selected design snapshots and bounds the raw ID window before de-duplication, preserves first-occurrence caller order, and uses SQLite keyset continuation. A materialized metadata selection limits each page to 50 keys before joining large text payloads. Ownership is checked in SQL. Each page completes before yielding, so output backpressure cannot retain a live reader. Non-SQLite providers retain existing bounded per-artefact pages and native ordering. + +A 50-row page is not a process-RSS ceiling. Text limits, UTF-16 storage, warnings, transient allocations, JSON escaping, consumer retention, and SQLite metadata scanning/sorting remain relevant. There is no whole-export snapshot guarantee. The buffered full-history API is unchanged. + +Required evidence includes long histories, exact page boundaries, timestamp ties and offsets, cross-user IDs, duplicate/raw oversized IDs, empty windows, mutable input snapshotting, method/enumerator cancellation, early disposal, actual EF materialisation before the first yield, and real SQL reader counts. The later consumer switch must additionally compare actual emitted export bytes and prove query reduction at the endpoint, including destination failure and blob-copy interleaving. The primitive alone does not close #1399. + +## Revision lane: design decisions before implementation + +Keep one semantic authority. `AutomationProposalService` now delegates effective-revision selection to the shared `ProposalEffectiveOperationsResolver`; the issue's older private-dispatcher wording is not permission to introduce another authority. + +The reject-pin design must explicitly distinguish a new rejection of original operations from legacy rejected rows whose decision-time payload can only be approximated. Prefer an additive, versioned representation with documented backfill rather than silently changing the meaning of `ApprovedRevisionId`. The same decided identity must survive dismissal. A later bounded query may narrow candidates only when parity fixtures prove it returns the resolver's winner, including intentionally original decisions, missing legacy pins, rejected cutoffs, dismissed states, and long histories. + +Approval/application safety and rejected-display consistency are distinct claims. Do not describe a display-only fix as preventing demonstrated wrong execution when the approval pin already protects execution. No revision-family implementation is claimed by the two active engineering PRs. + +## Verification and continuation + +The supplied workspace has Node and Python but no .NET SDK. One official SDK metadata request failed DNS; no equivalent network workaround was attempted. C# compilation and API integration evidence therefore come from GitHub Actions at the exact PR head and its recorded synthetic merge. Local SQL experiments, static checks, or an earlier green head do not substitute for that evidence. + +For each code PR, record the negative-control result, changed invariant, final source SHA, workflow/run/job identity, checked platforms, and residuals. Keep drafts while validation or review findings remain unresolved. Do not close an issue because a preparatory primitive exists. Re-read live main and open PRs before the next lane, preserve concurrent work, and leave human-owned acceptance boxes unchanged.