Skip to content

Commit 519b459

Browse files
committed
[docs] Bound GitHub import resource retries
Signed-off-by: Viwat Vchirawongkwin <viwat.v@chula.ac.th>
1 parent f48e27f commit 519b459

3 files changed

Lines changed: 47 additions & 24 deletions

File tree

‎docs/decisions/0040-sha-pinned-connected-github-import.md‎

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,14 @@ the selected `.py` files sequentially to the current board directory.**
5555
3. **Directory browsing is lazy and selection is folder-scoped.** Resolving a
5656
repository does not recursively enumerate its tree. Opening a directory
5757
fetches only that directory at the pinned commit; Up is bounded at the repo
58-
root. A selection contains direct children of one currently chosen remote
59-
directory only. Changing directory clears it. Only Git-tree entries with an
60-
ordinary blob mode (`100644` or `100755`) and a lowercase `.py` suffix are
61-
eligible. Directories remain browsable; symlink mode `120000`, submodule
62-
mode `160000`, non-files, `.mpy`, `.pyc`, and every other suffix are visible
63-
only as ineligible or omitted and are never fetched or written by this
64-
increment.
58+
root. One response is capped at 2 MiB and 512 direct entries; exceeding
59+
either limit rejects the folder before it reaches the eager tablet view. A
60+
selection contains direct children of one currently chosen remote directory
61+
only. Changing directory clears it. Only Git-tree entries with an ordinary
62+
blob mode (`100644` or `100755`) and a lowercase `.py` suffix are eligible.
63+
Directories remain browsable; symlink mode `120000`, submodule mode `160000`,
64+
non-files, `.mpy`, `.pyc`, and every other suffix are visible only as
65+
ineligible or omitted and are never fetched or written by this increment.
6566

6667
4. **The board target is explicit and flat for this subset.** Opening the
6768
action captures the Files controller's current board directory (`cwd`).
@@ -124,7 +125,11 @@ the selected `.py` files sequentially to the current board directory.**
124125
offline/not-found/forbidden/rate-limit/server/malformed-response failures
125126
map to localized user actions. `403`/`429` rate limiting shows the public
126127
API limit and reset/retry guidance when GitHub supplies it; the app performs
127-
no tight or unbounded automatic retry.
128+
no tight or unbounded automatic retry. A positive supplied retry delay gates
129+
every network-producing action on the surface until its deadline; local
130+
navigation, selection, and review transitions cannot clear or bypass it.
131+
Header-rejected HTTP responses have their body streams cancelled before the
132+
typed failure is returned so repeated failures do not strand resources.
128133

129134
10. **The surface is adaptive and accessible.** Import examples is an action
130135
on the connected Files surface, enabled only for a ready connection. Below

‎docs/specifications/App/TDD.md‎

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,10 @@ disabled (or independently revalidated and rejected unless the destination is
766766
the same exact host). It sends GitHub's required API version/accept/user-agent
767767
headers but no authorization, token, cookie, board fact, or user source. It
768768
does not follow `download_url`, HTML links, or any arbitrary URL returned in a
769-
response (SEC-10).
769+
response. A response rejected from headers alone (including status or declared
770+
body length) has its body stream cancelled before the adapter publishes the
771+
typed failure, so repeated hostile responses cannot strand transport resources
772+
(SEC-10).
770773

771774
Resolution is a two-step logical operation:
772775

@@ -782,6 +785,10 @@ from that tree. Thus every object is derived from the resolved commit without
782785
reading through the original moving ref or trusting a response URL. An
783786
explicit **Refresh ref** starts a new operation generation, resolves again, and
784787
clears directories, selection, candidate bytes, conflicts, and consent.
788+
Tree response bodies are capped at 2 MiB and each decoded non-recursive tree is
789+
rejected above 512 direct entries before the directory model reaches the eager
790+
tablet view. These are hard resource ceilings, not pagination: the subset never
791+
silently presents a partial folder.
785792

786793
### 10.3 Lazy browse, selection, and adaptive state
787794

@@ -795,9 +802,10 @@ enterRepository → resolving → browsing → selecting → reviewing
795802

796803
The implementation does not introduce a second Riverpod workflow controller.
797804
The adaptive `StatefulWidget` owns presentation-only state: a
798-
`browse | review | result` surface step, `resolving | loadingDirectory`
799-
network phase, directory stack, selection, failure/retry/focus data, and the
800-
current progress/result. Resolve/list operations capture the view's increasing
805+
`browse | review | result` surface step,
806+
`resolving | loadingDirectory | checkingBoardTargets` operation phase,
807+
directory stack, selection, failure/retry/focus data, and the current
808+
progress/result. Resolve/list operations capture the view's increasing
801809
epoch and a `GithubCancellation`; cancel, ref refresh, directory change, or
802810
disposal advances that epoch, and a late completion cannot repopulate the
803811
view. `GithubBoardImporter` separately owns its fetch/commit generation,
@@ -942,9 +950,14 @@ never echo fetched bytes.
942950
For `403`/`429`, the REST adapter captures bounded numeric rate-limit metadata
943951
(`remaining`, reset instant or retry delay when valid). The view explains the
944952
unauthenticated public limit and offers a user-driven retry after the supplied
945-
time. There is no automatic tight loop; transient retries, if later admitted,
946-
must be separately bounded and cancellable. Ordinary GitHub failure does not
947-
disable Files, Editor, Run, or any offline workflow (NFR-OFF-2).
953+
time. A positive supplied delay establishes one surface-wide not-before
954+
deadline independent of the currently rendered error object. Repository/ref
955+
edits, folder navigation, selection changes, review entry/cancellation, and
956+
other local state transitions cannot shorten or clear it; every action that can
957+
start a GitHub request is disabled and guarded until it expires. There is no
958+
automatic tight loop; transient retries, if later admitted, must be separately
959+
bounded and cancellable. Ordinary GitHub failure does not disable Files,
960+
Editor, Run, or any offline workflow (NFR-OFF-2).
948961

949962
### 10.7 Explicit deferred full-A-33 design
950963

‎docs/specifications/App/specs.md‎

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,14 @@ to `[red]` before implementation:
226226
MUST
227227
- **A33-SUB-AC-3 (lazy folder-scoped browse)** — The client MUST load only the
228228
opened directory at the pinned commit; it MUST NOT recursively enumerate the
229-
repository. Up MUST be bounded at repository root. Multi-selection MUST be
230-
limited to direct, eligible children of one chosen remote directory, and a
231-
directory change MUST clear it. Only GitHub-confirmed regular files with a
232-
lowercase `.py` suffix are eligible; directories MAY be opened, while
233-
symlinks, submodules, non-files, `.mpy`, `.pyc`, and other suffixes MUST NOT
234-
be selected, fetched, or written. MUST
229+
repository. A non-recursive tree response MUST be at most 2 MiB and contain
230+
at most 512 direct entries; a larger response MUST fail closed before entries
231+
are published to the eager tablet view. Up MUST be bounded at repository
232+
root. Multi-selection MUST be limited to direct, eligible children of one
233+
chosen remote directory, and a directory change MUST clear it. Only
234+
GitHub-confirmed regular files with a lowercase `.py` suffix are eligible;
235+
directories MAY be opened, while symlinks, submodules, non-files, `.mpy`,
236+
`.pyc`, and other suffixes MUST NOT be selected, fetched, or written. MUST
235237
- **A33-SUB-AC-4 (exact targets and overwrite consent)** — Review MUST show
236238
every exact remote path and its exact board target
237239
`join(capturedCwd, basename(remotePath))`. This subset MUST NOT preserve the
@@ -276,9 +278,12 @@ to `[red]` before implementation:
276278
forbidden, rate-limited, server, malformed-response, validation, board, and
277279
stale-session failures MUST map to distinct localized, actionable messages.
278280
A GitHub `403`/`429` MUST show bounded retry/reset guidance when the response
279-
supplies it; the importer MUST NOT tight-loop or retry without a bound and an
280-
explicit user action. Browse/fetch loading MUST retain location and selection
281-
context without presenting stale data as current. MUST
281+
supplies it. A positive server-supplied retry delay MUST gate every network-
282+
producing action on that import surface until its deadline; navigation,
283+
selection, review cancellation, or another local state transition MUST NOT
284+
clear or bypass it. The importer MUST NOT tight-loop or retry without a bound
285+
and an explicit user action. Browse/fetch loading MUST retain location and
286+
selection context without presenting stale data as current. MUST
282287
- **A33-SUB-AC-9 (accessibility)** — All visible and semantic text MUST come
283288
from ARB except ASCII technical URL/ref/SHA/path values. Fields, directory
284289
rows, file eligibility/selection, loading, pinned SHA, target mappings,

0 commit comments

Comments
 (0)