Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/logs/INDEX.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Logs Index

- 2026-08-03 — Issue #1136 records immutable submission timeout capability,
one-shot dispatch, and reset/load all-stream detachment separately from #1133.

- 2026-08-03 — Issue #1133 corrects the prior displaced-result wording:
displacement revokes controls but does not end A outcome observation.

- 2026-08-03 — Issue #1130 submission-local outcome ownership, deterministic
barriers, and ToolWalk timeout ordering are recorded in all durable logs.

Expand Down
30 changes: 30 additions & 0 deletions docs/logs/engineering-log.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
# Engineering Log

## 2026-08-03 (Issue #1136 immutable timeout authority)

- Replaced the provisional mutable-pointer authorization with a private
`RunSubmission` owner-token/generation capability. It atomically dispatches
only once while A is started; terminal, failure, reset, and load revoke it.
- `RunSession` now tracks every submission stream by handle. Reset/load cancels
both displaced A and selected C rather than only the most recent stream.
- Deterministic gated evidence proves B -> C -> A emits exactly one A cancel,
zero B/C actions, and terminal/failure/reset have no dispatch. Full native
Swift passes 245 tests in 46 suites; repository regression awaits #1135.

## 2026-08-03 (Issue #1133 passive displaced-submission outcome)

- Corrected the #1130 wait-policy gap: displacement is now a permanent action
fence, not a terminal ToolWalk result. Runner waits for its immutable A
handle's terminal/failure through deadline and never auto-answers/approves a
mismatched or displaced selected B.
- `cancelTimedOutSubmission` retains exact locally owned A transport authority
after B selection, but its displaced path is transport-only: it cannot alter
B selection, transcript, pending UI, or cancellation state.
- Test-first evidence: four URLSession-gated `RunSession.submit()` + Runner
tests were red before the repair (terminal/EOF/timeout returned displaced;
delayed ACK returned without A identity). The resulting #1133 tests prove
passive terminal, EOF failure, delayed acknowledgement, and B-safe timeout
policy. The stronger B -> C authority and revocation proof is tracked in
the separate #1136 entry above.
- Verification: strict format (0/7 touched Swift files require formatting) and
full `swift test --package-path macapp` (244 tests / 46 suites) pass. Full
regression, independent review, and hosted checks remain.

## 2026-08-03 (Issue #1130 submission-local outcomes)

- Split `RunSubmission` into independent A-local `Lifecycle` and displacement
Expand Down
21 changes: 21 additions & 0 deletions docs/logs/long-term-thinking-log.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Long-Term Thinking Log

## 2026-08-03 (Issue #1136 immutable timeout authority)

- Command intent: make a timed-out submitted A independently and exactly
cancellable after B/C selection without allowing the timeout path to affect
B or C.
- Success: one A handle can consume its started-only capability once; terminal,
failure, reset, and load revoke it; reset/load physically stop every A/C
submission stream. Direct deterministic proof complements #1133 policy waits.
- Non-goal: reintroducing run-ID lookup, changing server cancellation, or
mutating selected-run UI from timeout transport.

## 2026-08-03 (Issue #1133 intent correction)

- Command intent: a callback/cron continuation must visibly continue B while
the initiating tool walk truthfully observes its own submitted A outcome.
- Success: B displacement is sticky for control authority; A terminal/failure
after B is a valid A verdict; an A deadline cancels only A and produces no B
action or visible-state mutation.
- Non-goal: making B a hidden fallback, treating displacement as success, or
using shared `currentRunID` to judge/control A.

## 2026-08-03 (Issue #1130 submission-local outcomes)

- Command intent: repair the #1128 review findings without weakening the
Expand Down
23 changes: 23 additions & 0 deletions docs/logs/observational-log.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Observational Log

## 2026-08-03 (Issue #1136 timeout capability proof)

- A real deadline is suitable for #1133 wait-policy coverage but is not an
authority proof. Direct synchronous capability consumption makes B -> C -> A
exact-one dispatch and terminal/failure/reset non-dispatch deterministic.
- A single mutable stream task would leave displaced A running when C starts.
The handle-keyed task registry permits reset/load to stop both streams.

## 2026-08-03 (Issue #1133 passive outcome observation)

- The #1130 handle correctly retained A lifecycle after B selection, but the
consumer stopped polling it on `.displaced`; durable A evidence was therefore
present but unobserved. A control authority and outcome observation are
separate concerns.
- Gated integration runs show B can precede A terminal, A stream EOF, A timeout,
or A start acknowledgement. Each retains B as the selected scheduled run;
only the deadline scenario emits an A cancel request.
- B can itself terminal before A while a user submits C. This proved timeout
authorization must follow A's stream lifetime, not `activeSubmission` or the
one current local-stream pointer. The final contract uses an immutable A
handle owner token plus reset/load generation and cancels every live local
submission stream when detaching a session.

## 2026-08-03 (Issue #1130 submission-outcome observation)

- The original single `State` made displacement overwrite terminal/failure
Expand Down
22 changes: 22 additions & 0 deletions docs/logs/system-log.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# System Log

## 2026-08-03 (Issue #1136 immutable timeout capability)

- `RunSubmission` privately binds owner token, generation, lifecycle, and a
consumed bit. `RunSession` is the only authority that can consume it, and
`cancelTimedOutSubmission` dispatches a transport-only A cancel only on that
success. A handle-keyed task registry lets reset/load cancel all local streams.

## 2026-08-03 (Issue #1133 passive A outcome after B selection)

- Flow: ToolWalk captures `RunSubmission(A)` -> conversation stream selects B
and marks A displaced -> Runner disables all automatic controls yet continues
reading A-local lifecycle -> A terminal/failure is judged, or deadline sends
the existing A cancel endpoint through a local-ownership fence.
- The selected-run reducer remains the only B UI authority. The displaced A
timeout path intentionally performs no shared-state transition, so it cannot
clear B pending controls, selection, transcript, or acknowledgement state.
- `RunSubmission` carries a session-owner token and reset/load generation plus
a one-shot started-only timeout capability. It preserves A-only authority
through B -> C replacement without reconstructing it from an ID/set; terminal
or failure consume no capability, and reset/load cancels all live submission
tasks while invalidating old handles.

## 2026-08-03 (Issue #1130 submission-local outcome flow)

- Flow: local composer/ToolWalk A -> `RunSubmission.lifecycle` plus
Expand Down
28 changes: 28 additions & 0 deletions docs/plans/2026-08-03-issue-1136-timeout-authority-impact-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Cross-Surface Impact Map: Issue #1136

## Task and ownership

- Issue: #1136 immutable submitted-run timeout authority.
- Source of truth: a `RunSubmission` created by its owning `RunSession`.
- Search evidence: `RunSubmission`, `consumeTimeoutCancellation`,
`cancelTimedOutSubmission`, and `submissionStreamTasks` under `macapp/`.

## Surfaces

- Native model: private owner UUID plus reset/load generation and lifecycle
form an unforgeable, one-shot A cancellation capability.
- ToolWalk: invokes only the handle API. Its timeout is transport-only; it
cannot alter B/C selection, transcript, controls, or cancellation state.
- HTTP/API: unchanged existing `POST /v1/runs/{A}/cancel` endpoint only.
- Persistence, harness, TUI, schema, CLI, providers: none; search found no
changed contract or stored state.

## Reliability, test, and rollback

- Concurrent A SSE, B/C conversation events, delayed ACK, timeout, and reset
are scoped by immutable handle. Terminal/failure/reset/load make later A
dispatch impossible; displacement deliberately does not.
- Gated URLProtocol integration uses actual `RunSession.submit()` and proves
B -> C -> A sends exactly one A cancel, zero B/C actions, and reset stops
both concurrent A/C event streams.
- Rollback is the stacked native PR; no data migration or server rollback.
36 changes: 36 additions & 0 deletions docs/plans/2026-08-03-issue-1136-timeout-authority-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Plan: Issue #1136 immutable timeout authority

## Context and scope

- Governing issue: #1136, stacked after #1133 on the #1131 native ownership
line.
- Problem: a mutable session pointer cannot prove that an A timeout remains
owned by A after B terminals and C starts.
- In scope: private A-handle capability authority, reset/load invalidation,
one-shot transport dispatch, and deterministic native proof.
- Out of scope: harness endpoints, selected-run reducer behavior, tool grammar,
and production scheduling semantics.

## TDD and implementation

- Red: B -> C -> A timeout lost authority when only mutable session pointers
were consulted.
- Repair: each `RunSubmission` captures a private owner token and session
generation. `RunSession` atomically consumes a started-only capability once;
terminal, failure, reset, and load revoke it. Reset/load cancel every live
submission stream by immutable handle, including displaced A plus selected C.
- Deterministic proof: direct capability dispatch proves exactly one A cancel
after B -> C, zero B/C actions, no cancel after terminal/failure/reset, and
physical A+C stream detachment. #1133 continues to prove ToolWalk timeout
policy and passive terminal/failure observation.

## Status and gates

- [x] Write red and repair the authority model.
- [x] Add deterministic capability/revocation/detachment tests.
- [x] Re-run strict format (0/7 touched Swift files) and full Swift (245 tests
/ 46 suites) after the final proof update.
- [x] Run `./scripts/test-regression.sh` after the #1135 baseline repair:
normal, race, and coverage passed (85.5% total; zero uncovered production
functions).
- [x] Publish the separate stacked draft PR with `Closes #1136`.
10 changes: 10 additions & 0 deletions docs/plans/INDEX.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Plans Index

- `2026-08-03-issue-1136-timeout-authority-plan.md` — Issue #1136 immutable
A-handle timeout cancellation authority across B/C selection.
- `2026-08-03-issue-1136-timeout-authority-impact-map.md` — Cross-surface map
for #1136 owner-token/generation capability and stream detachment.

- `2026-08-03-issue-1133-passive-outcome-plan.md` — Issue #1133 passive
A-outcome observation after scheduled B displacement.
- `2026-08-03-issue-1133-passive-outcome-impact-map.md` — Cross-surface map
for #1133 submission-local outcome versus selected-run authority.

- `2026-08-03-issue-1130-submission-outcomes-plan.md` — Issue #1130
submission-local lifecycle and ToolWalk outcome repair.
- `2026-08-03-issue-1130-submission-outcomes-impact-map.md` — Cross-surface
Expand Down
13 changes: 12 additions & 1 deletion docs/plans/active-plan.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Active Plan

Current status: Issue #1130 is implemented locally on #1128 `654b7da`. It
Current status: Issue #1133 is implemented locally on #1131 `63cf9fcd`. It
corrects the residual #1130 wait-policy defect: B displacement revokes A
controls but not A outcome observation. ToolWalk now passively waits for A
terminal/failure through its deadline, while a displaced timeout can POST only
the exact locally owned A without mutating selected B. Eight URLSession-gated
`RunSession.submit()` + `Runner` tests cover B-before-A terminal, EOF, timeout,
B -> C -> A timeout authority, one-shot/terminal/failure/reset revocation,
and delayed acknowledgement with zero B/C actions. Strict formatting and full
Swift pass; full repository regression awaits the independent #1135 baseline
fixture repair, followed by review, hosted checks, and stacked PR promotion.
Comment on lines +11 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reconcile the regression-gate status

This current-status entry says the repository regression still awaits the #1135 repair, while the newly added issue #1136 plan marks that repair and the complete normal/race/coverage regression as passed. Agents using the active plan cannot tell whether the mandatory gate remains blocked or has completed, so update these records to report one verified state.

AGENTS.md reference: AGENTS.md:L31-L35

Useful? React with 👍 / 👎.


Historical status: Issue #1130 was implemented locally on #1128 `654b7da`. It
separates A's submission lifecycle from displacement, makes late
acknowledgement/EOF/failure identity-safe, and gives ToolWalk typed
terminal/failure/displaced/timeout outcomes so only timeout cancels A. Strict
Expand Down
12 changes: 12 additions & 0 deletions macapp/Sources/GoCodeUI/ProjectSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,18 @@ public final class ProjectSession {
self.serverEnvironment = serverEnvironment
}

/// Deterministic native/ToolWalk integration seam. Production callers use
/// the URL/supervisor initializer above; tests inject the same client used
/// by their URLProtocol fixture so `Runner.walk` exercises ProjectSession.
init(workspace: URL, client: HarnessClient) {
self.workspace = workspace
externalBaseURL = nil
serverEnvironment = [:]
self.client = client
run = RunSession(client: client)
phase = .ready
}

public var name: String { workspace.lastPathComponent }
public var isReady: Bool { phase == .ready }

Expand Down
21 changes: 14 additions & 7 deletions macapp/Sources/GoCodeUI/RunSession+RunControls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ extension RunSession {
/// True only while the first, cooperative cancel request awaits harnessd's
/// acknowledgement. Once it succeeds, a second press remains available
/// for the existing local force-stop behavior.
public var cancelInFlight: Bool { cancelState == .requesting }
public var cancelInFlight: Bool {
cancelState == .requesting
}

/// Requests cancellation only if the run that rendered the affordance is
/// still selected. A later scheduled/local continuation must never inherit
Expand All @@ -16,12 +18,17 @@ extension RunSession {
cancel(runID: runID)
}

/// ToolWalk's timeout action has already decided which run timed out. Keep
/// that captured identity at the RunSession boundary rather than resolving
/// the currently selected continuation during cancellation.
public func cancelTimedOutRun(expectedRunID: String?) {
guard let expectedRunID else { return }
cancel(expectedRunID: expectedRunID)
/// Consumes the exact submitted A timeout capability. Unlike a bare run
/// string, this cannot be redirected to selected B, replayed after reset,
/// or re-used after terminal/failure. The transport-only path deliberately
/// makes no shared UI state change.
@discardableResult
public func cancelTimedOutSubmission(_ submission: RunSubmission) -> Bool {
guard let runID = consumeTimeoutCancellation(for: submission) else { return false }
Task { [client] in
try? await client.cancel(runID: runID)
}
Comment on lines +28 to +30

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Surface failed timeout cancellation before advancing

When the cancellation POST fails because of a transient transport or server error, this task suppresses the error and the method has already returned true. Runner.walk then sleeps briefly and starts the next tool, whose newConversation() detaches A's event stream even though A can still be executing on the server, leaving an unobserved concurrent run that can consume resources or interfere with the walk. Await and propagate the cancellation result before advancing, while retaining the one-shot authority boundary.

Useful? React with 👍 / 👎.

return true
}

/// Compatibility entry point for programmatic callers that do not retain
Expand Down
Loading
Loading