Skip to content

Commit 8028e57

Browse files
authored
Merge pull request #1909 from link-assistant/issue-1902-0b473b50cb74
fix: rely on gh-upload-log default log routing
2 parents 9d79e20 + 65fcde2 commit 8028e57

39 files changed

Lines changed: 2134 additions & 24 deletions
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@link-assistant/hive-mind': patch
3+
---
4+
5+
Use the latest gh-upload-log package for attached log uploads and rely on its default auto mode/shared repository fallback instead of passing explicit strategy flags.

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ RUN echo "Installing @link-assistant/hive-mind@${HIVE_MIND_VERSION}" && \
124124
bun install -g gh-pull-all && \
125125
bun install -g gh-load-issue && \
126126
bun install -g gh-load-pull-request && \
127-
bun install -g gh-upload-log
127+
bun install -g gh-upload-log@latest
128128

129129
# --- Playwright MCP Setup ---
130130
# Box 2.1.1 pre-installs Playwright browsers and @playwright/test.

Dockerfile.dind

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ RUN echo "Installing @link-assistant/hive-mind@${HIVE_MIND_VERSION}" && \
9797
bun install -g gh-pull-all && \
9898
bun install -g gh-load-issue && \
9999
bun install -g gh-load-pull-request && \
100-
bun install -g gh-upload-log
100+
bun install -g gh-upload-log@latest
101101

102102
RUN npm install -g @playwright/mcp@latest --no-fund --force
103103

coolify/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ RUN echo "Installing @link-assistant/hive-mind@${HIVE_MIND_VERSION}" && \
119119
bun install -g gh-pull-all && \
120120
bun install -g gh-load-issue && \
121121
bun install -g gh-load-pull-request && \
122-
bun install -g gh-upload-log
122+
bun install -g gh-upload-log@latest
123123

124124
# --- Playwright MCP Setup ---
125125
# Box 2.1.1 pre-installs Playwright browsers and @playwright/test.
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Case Study: Issue #1902 - Prevent One-Off Log Repositories
2+
3+
## Summary
4+
5+
Issue #1902 reported that two log uploads created dedicated public repositories:
6+
7+
- `konard/log-tmp-solution-draft-log-pr-1781180521736.txt`
8+
- `konard/log-tmp-solution-draft-log-pr-1781180537724.txt`
9+
10+
Both uploaded files were under Hive Mind's 25 MB file limit, so they should have
11+
used gist uploads first through `gh-upload-log` auto mode. If gist upload fails
12+
and `gh-upload-log` falls back to repository mode, or if a log is larger than the
13+
gist limit, repository storage should use the shared visibility repositories:
14+
`public-logs` for public targets and `private-logs` for private targets.
15+
16+
The root cause was in `gh-upload-log` 0.8.0 auto fallback routing. In the
17+
captured run, automatic mode first tried to create a gist. GitHub returned a
18+
secondary content-creation rate limit for the gist API. `gh-upload-log` then
19+
fell back to repository mode. Because the file still fit within the gist limit,
20+
upstream shared-repository routing did not apply, so the fallback created a
21+
dedicated `log-tmp-*` repository even though shared repository mode was enabled.
22+
23+
The upstream bug was fixed in `gh-upload-log` 0.8.1 by
24+
[link-foundation/gh-upload-log#32](https://github.com/link-foundation/gh-upload-log/pull/32).
25+
Hive Mind now installs `gh-upload-log@latest` in its Docker images and relies on
26+
the package defaults for auto mode and shared repository fallback.
27+
28+
## Captured Evidence
29+
30+
| File | Purpose |
31+
| ------------------------------------------------------- | --------------------------------------------------------- |
32+
| `raw-data/issue-1902.json` | Issue title, body, labels, timestamps, and URL |
33+
| `raw-data/issue-1902-comments.json` | Issue comments, empty at capture time |
34+
| `raw-data/pr-1909.json` | Prepared PR metadata |
35+
| `raw-data/pr-1909-issue-comments.json` | PR conversation comments, empty at capture time |
36+
| `raw-data/pr-1909-review-comments.json` | PR inline comments, empty at capture time |
37+
| `raw-data/pr-1909-reviews.json` | PR reviews, empty at capture time |
38+
| `raw-data/linked-repo-1781180521736.json` | First linked one-off repository metadata |
39+
| `raw-data/linked-repo-1781180521736-contents.json` | First linked repository file metadata |
40+
| `raw-data/linked-repo-1781180521736-commits.json` | First linked repository initial commit |
41+
| `raw-data/linked-repo-1781180537724.json` | Second linked one-off repository metadata |
42+
| `raw-data/linked-repo-1781180537724-contents.json` | Second linked repository file metadata |
43+
| `raw-data/linked-repo-1781180537724-commits.json` | Second linked repository initial commit |
44+
| `raw-data/gh-upload-log-README.md` | Upstream `gh-upload-log` documentation snapshot |
45+
| `raw-data/gh-upload-log-cli.js` | Upstream CLI argument handling snapshot |
46+
| `raw-data/gh-upload-log-index.js` | Upstream upload-strategy and fallback snapshot |
47+
| `raw-data/gh-upload-log-repository-upload.js` | Upstream shared-vs-dedicated repository logic snapshot |
48+
| `raw-data/gh-upload-log-pr-28.json` | Related upstream collision-handling PR metadata |
49+
| `raw-data/gh-upload-log-pr-30.json` | Related upstream shared-repository PR metadata |
50+
| `raw-data/gh-upload-log-issue-31.json` | Filed upstream fallback-routing issue metadata |
51+
| `raw-data/gh-upload-log-issue-31-comments.json` | Filed upstream fallback-routing issue comments |
52+
| `raw-data/gh-upload-log-pr-32.json` | Upstream fallback-routing fix PR metadata |
53+
| `raw-data/gh-upload-log-npm-metadata.json` | Current npm package metadata for `gh-upload-log` |
54+
| `logs/tmp-solution-draft-log-pr-1781180521736.txt.gz` | Full 20,632,466 byte linked log, compressed |
55+
| `logs/tmp-solution-draft-log-pr-1781180537724.txt.gz` | Full 20,653,037 byte linked log, compressed |
56+
| `logs/gist-upload-evidence-1781180008338.txt` | Earlier successful gist upload from the same run |
57+
| `logs/dedicated-repo-upload-evidence-1781180521736.txt` | Gist rate-limit failure and dedicated-repository fallback |
58+
| `logs/linked-repo-summary-1781180521736.json` | Concise first linked repository summary |
59+
| `logs/linked-repo-summary-1781180537724.json` | Concise second linked repository summary |
60+
| `logs/run-version-evidence.txt` | Focused run/version/upload command evidence |
61+
| `research-sources.json` | Online and repository source list |
62+
| `upstream-gh-upload-log-issue.md` | Body used to file the upstream fallback-routing issue |
63+
64+
The full downloaded logs were verified before compression:
65+
66+
- `tmp-solution-draft-log-pr-1781180521736.txt`: 73,484 lines, 20,632,466 bytes.
67+
- `tmp-solution-draft-log-pr-1781180537724.txt`: 73,790 lines, 20,653,037 bytes.
68+
69+
## Timeline
70+
71+
| Time (UTC) | Event |
72+
| ------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
73+
| 2026-06-11 12:13:29 | Hive Mind uploaded a 9.26 MB solution draft log through `gh-upload-log` automatic mode. The gist upload succeeded. |
74+
| 2026-06-11 12:13:35 | Hive Mind posted the gist-backed log comment to `lefinepro/kefine#173`. |
75+
| 2026-06-11 12:13:56 to 12:21:59 | GitHub repeatedly returned secondary content-creation rate limits while the process tried to create comments. |
76+
| 2026-06-11 12:22:03 | Hive Mind invoked `gh-upload-log` automatic mode for `/tmp/solution-draft-log-pr-1781180521736.txt`, a 19.68 MB file. |
77+
| 2026-06-11 12:22:05 | Gist creation failed with a GitHub secondary rate limit, and `gh-upload-log` fell back to repository mode. |
78+
| 2026-06-11 12:22:06 | The first one-off public repository was created: `log-tmp-solution-draft-log-pr-1781180521736.txt`. |
79+
| 2026-06-11 12:22:21 | The second linked repository initial commit was created. |
80+
| 2026-06-11 12:22:22 | The second one-off public repository was created: `log-tmp-solution-draft-log-pr-1781180537724.txt`. |
81+
| 2026-06-11 14:16:43 | Issue #1902 was opened to report the unexpected one-off repositories. |
82+
| 2026-06-11 22:32:15 | Upstream issue `link-foundation/gh-upload-log#31` was filed with reproduction details and a suggested fix. |
83+
| 2026-06-12 08:05:39 | Upstream PR `link-foundation/gh-upload-log#32` was merged and issue #31 was closed. |
84+
| 2026-06-12 08:06:44 | `gh-upload-log` 0.8.1 was published to npm as the latest version. |
85+
86+
## Requirements
87+
88+
1. Default Hive Mind log uploads must not create a separate repository per log.
89+
2. Hive Mind should keep using `gh-upload-log` auto mode.
90+
3. Logs that fit the GitHub file limit should attempt gist uploads first.
91+
4. If gist upload fails and repository fallback is used, the fallback should use
92+
shared `public-logs` or `private-logs` repositories.
93+
5. Repository-per-log behavior should only happen when explicitly requested with
94+
`gh-upload-log` options such as `--no-shared-repository`.
95+
6. Report the fallback-routing bug upstream with a reproduction, workarounds, and
96+
a suggested code fix.
97+
7. The fix needs a regression test that would have failed for the captured path.
98+
8. Preserve logs, metadata, timeline, root-cause analysis, and solution notes in
99+
`docs/case-studies/issue-1902/`.
100+
9. After the upstream fix is available, apply the latest `gh-upload-log` package
101+
and avoid explicit strategy flags unless Hive Mind needs to override the
102+
package defaults.
103+
104+
## Root Cause
105+
106+
Hive Mind called `gh-upload-log` in automatic mode:
107+
108+
```text
109+
gh-upload-log "/tmp/solution-draft-log-pr-1781180521736.txt" --public --description "..." --verbose
110+
```
111+
112+
That is the correct high-level integration point: auto mode should select gist
113+
when possible and repository storage when needed. In the captured run,
114+
`gh-upload-log` chose gist mode for the 19.68 MB file because it was under the
115+
25 MB gist limit. When GitHub rejected gist creation with a secondary rate limit,
116+
upstream automatic mode fell back to repository mode.
117+
118+
The fallback still had `useSharedRepository: true`, but upstream shared-repository
119+
routing only applies when the file is larger than the gist limit:
120+
121+
```js
122+
return useSharedRepository && getFileSize(filePath) > GITHUB_GIST_FILE_LIMIT;
123+
```
124+
125+
For a 19.68 MB file, that returned `false`, so repository fallback used the legacy
126+
dedicated repository path and created `log-tmp-solution-draft-log-pr-1781180521736.txt`.
127+
The second linked repository has the same shape: a single public repository with one
128+
20.65 MB log file and an initial `Add log file` commit.
129+
130+
The bug was therefore not that auto mode exists, and not that shared repositories
131+
were unavailable. The bug is that `gh-upload-log` repository fallback only uses
132+
shared repositories when the original file is larger than the gist limit. Once
133+
auto mode has already fallen back into repository upload, repository routing
134+
should depend on `useSharedRepository`, not on the original gist-size decision.
135+
136+
## Solution
137+
138+
Implemented changes:
139+
140+
1. Filed upstream issue
141+
[link-foundation/gh-upload-log#31](https://github.com/link-foundation/gh-upload-log/issues/31)
142+
with the reproduction, workarounds, and suggested routing fix.
143+
2. Confirmed upstream PR
144+
[link-foundation/gh-upload-log#32](https://github.com/link-foundation/gh-upload-log/pull/32)
145+
fixed fallback routing by using shared repositories whenever
146+
`useSharedRepository` is enabled.
147+
3. Updated Hive Mind Docker images to install `gh-upload-log@latest`, which
148+
resolves to 0.8.1 at the time of this case study.
149+
4. Kept Hive Mind uploads in the package's default auto mode by passing only the
150+
log file, visibility, description, and optional verbose flag.
151+
5. Added `buildGhUploadLogArgs()` so tests can assert the exact wrapper CLI
152+
arguments without invoking GitHub.
153+
154+
With this fix, Hive Mind preserves `gh-upload-log` auto behavior without
155+
duplicating upstream strategy policy. Dedicated one-off repositories remain an
156+
upstream opt-in via `--no-shared-repository` or `useSharedRepository: false`.
157+
158+
## Regression Coverage
159+
160+
Added `tests/test-issue-1902-log-upload-routing.mjs`.
161+
162+
The test covers:
163+
164+
- Default wrapper arguments rely on `gh-upload-log` defaults for auto mode.
165+
- Default wrapper arguments do not include `--auto`, `--shared-repository`,
166+
`--only-gist`, `--only-repository`, or `--no-shared-repository`.
167+
- Public and private wrapper arguments still set visibility and preserve the log
168+
description.
169+
170+
Focused verification:
171+
172+
```bash
173+
node tests/test-issue-1902-log-upload-routing.mjs
174+
```
175+
176+
## Online Research
177+
178+
GitHub documents secondary REST API limits and recommends pausing when a secondary
179+
limit is returned. The captured failure is consistent with those docs: GitHub
180+
returned HTTP 403 secondary-rate-limit responses for content creation around the
181+
same time as the gist upload failed.
182+
183+
GitHub's file attachment and repository large-file documentation confirm the 25 MB
184+
boundary used by Hive Mind's `githubLimits.fileMaxSize`. The upstream `gh-upload-log`
185+
README and implementation confirm that gist is the intended path under that limit,
186+
and shared repositories are the intended path for repository-mode logs. The 0.8.1
187+
package metadata confirms the fallback-routing fix was published after upstream
188+
PR #32 merged.
189+
190+
Sources are listed in `research-sources.json`.
191+
192+
## External Issues
193+
194+
Filed upstream issue
195+
[link-foundation/gh-upload-log#31](https://github.com/link-foundation/gh-upload-log/issues/31).
196+
The issue includes the captured reproduction, the `shouldUseSharedRepositoryMode()`
197+
root cause, caller workarounds, and a suggested code-level fix: repository routing
198+
should use shared repositories whenever `useSharedRepository` is true, including
199+
auto-mode fallback after a gist failure below the gist limit.
200+
201+
The issue is now closed by
202+
[link-foundation/gh-upload-log#32](https://github.com/link-foundation/gh-upload-log/pull/32),
203+
and the fix is published in `gh-upload-log` 0.8.1.

0 commit comments

Comments
 (0)