Current API returns *[]DCFStore (pointer to slice), hardcodes os filesystem access, and offers no cancellation. Rework: store construction takes an fs.FS (or a path convenience wrapper), walk/scan take context.Context, plain slice returns, errors wrapped with %w. Exact surface follows sneak's pick from the API proposals (tracked in chat 2026-08-30); this issue holds the mechanical cleanup that applies regardless.
Done: no pointer-to-slice in the public surface; store parsing testable against fstest.MapFS; walks cancelable.
Current API returns `*[]DCFStore` (pointer to slice), hardcodes `os` filesystem access, and offers no cancellation. Rework: store construction takes an `fs.FS` (or a path convenience wrapper), walk/scan take `context.Context`, plain slice returns, errors wrapped with `%w`. Exact surface follows sneak's pick from the API proposals (tracked in chat 2026-08-30); this issue holds the mechanical cleanup that applies regardless.
Done: no pointer-to-slice in the public surface; store parsing testable against `fstest.MapFS`; walks cancelable.
Note moved here from the project-management repo's TODO.md (sneak, 25 September: each repo's notes live on that repo). On 30 August sneak was offered options for this API's shape in chat, and his pick was to decide this issue and #5. Neither the options nor an answer were recorded here, and the chat is gone. When dcf resumes, its repo-manager works the options out again from the code and asks him on this issue before either is implemented.
Model: opus-5-5
Note moved here from the project-management repo's `TODO.md` (sneak, 25 September: each repo's notes live on that repo). On 30 August sneak was offered options for this API's shape in chat, and his pick was to decide this issue and https://git.eeqj.de/sneak/dcf/issues/5. Neither the options nor an answer were recorded here, and the chat is gone. When dcf resumes, its repo-manager works the options out again from the code and asks him on this issue before either is implemented.
Model: opus-5-5
Question for sneak, covering this issue and #5. Your 30 August pick was lost with the chat, so here are the options again, worked out from the code. Settled either way (this issue's body): cards are read through fs.FS, every walk takes a context.Context, plain slices, wrapped errors.
1. How a program gets a card.
A (recommended): find, then open.roots, err := dcf.FindCards(ctx) lists mounted volumes with DCIM or PRIVATE/M4ROOT; store, err := dcf.Open(ctx, os.DirFS(root)) reads one. A copied card folder or a test tree opens the same way as a mounted card. The count argument goes away.
B: one call, as now.stores, err := dcf.GetStores(ctx, n) finds and reads every mounted card. Fewer calls, but it only ever sees mounted volumes.
2. Where the import puts files. The call would be res, err := store.Import(ctx, dest, dcf.ImportOptions{SkipExisting: true}), reporting what was copied, skipped and in conflict, verifying each copy by SHA-256 and never deleting from the card.
A (recommended): the card's own layout under dest, e.g. dest/DCIM/100MSDCF/DSC00001.JPG. A different file already at that path is reported as a conflict and left alone, never overwritten. Two cards that reuse the same numbers conflict in one dest, so give each card its own.
B: one folder per day from the file's time, e.g. dest/2026-10-03/DSC00001.JPG, same conflict rule.
C: the program decides by passing a function from file group to destination path, with A as the default.
Reply with a letter for each, or "recommended". #1, #2, #3 and #6 go ahead meanwhile; none of them depends on this.
Model: opus-5-5
Question for sneak, covering this issue and https://git.eeqj.de/sneak/dcf/issues/5. Your 30 August pick was lost with the chat, so here are the options again, worked out from the code. Settled either way (this issue's body): cards are read through `fs.FS`, every walk takes a `context.Context`, plain slices, wrapped errors.
**1. How a program gets a card.**
- **A (recommended): find, then open.** `roots, err := dcf.FindCards(ctx)` lists mounted volumes with `DCIM` or `PRIVATE/M4ROOT`; `store, err := dcf.Open(ctx, os.DirFS(root))` reads one. A copied card folder or a test tree opens the same way as a mounted card. The count argument goes away.
- **B: one call, as now.** `stores, err := dcf.GetStores(ctx, n)` finds and reads every mounted card. Fewer calls, but it only ever sees mounted volumes.
**2. Where the import puts files.** The call would be `res, err := store.Import(ctx, dest, dcf.ImportOptions{SkipExisting: true})`, reporting what was copied, skipped and in conflict, verifying each copy by SHA-256 and never deleting from the card.
- **A (recommended): the card's own layout under `dest`**, e.g. `dest/DCIM/100MSDCF/DSC00001.JPG`. A different file already at that path is reported as a conflict and left alone, never overwritten. Two cards that reuse the same numbers conflict in one `dest`, so give each card its own.
- **B: one folder per day** from the file's time, e.g. `dest/2026-10-03/DSC00001.JPG`, same conflict rule.
- **C: the program decides** by passing a function from file group to destination path, with A as the default.
Reply with a letter for each, or "recommended". https://git.eeqj.de/sneak/dcf/issues/1, https://git.eeqj.de/sneak/dcf/issues/2, https://git.eeqj.de/sneak/dcf/issues/3 and https://git.eeqj.de/sneak/dcf/issues/6 go ahead meanwhile; none of them depends on this.
Model: opus-5-5
sneak
was assigned by clawbot2026-10-03 14:29:51 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Current API returns
*[]DCFStore(pointer to slice), hardcodesosfilesystem access, and offers no cancellation. Rework: store construction takes anfs.FS(or a path convenience wrapper), walk/scan takecontext.Context, plain slice returns, errors wrapped with%w. Exact surface follows sneak's pick from the API proposals (tracked in chat 2026-08-30); this issue holds the mechanical cleanup that applies regardless.Done: no pointer-to-slice in the public surface; store parsing testable against
fstest.MapFS; walks cancelable.Note moved here from the project-management repo's
TODO.md(sneak, 25 September: each repo's notes live on that repo). On 30 August sneak was offered options for this API's shape in chat, and his pick was to decide this issue and #5. Neither the options nor an answer were recorded here, and the chat is gone. When dcf resumes, its repo-manager works the options out again from the code and asks him on this issue before either is implemented.Model: opus-5-5
Question for sneak, covering this issue and #5. Your 30 August pick was lost with the chat, so here are the options again, worked out from the code. Settled either way (this issue's body): cards are read through
fs.FS, every walk takes acontext.Context, plain slices, wrapped errors.1. How a program gets a card.
roots, err := dcf.FindCards(ctx)lists mounted volumes withDCIMorPRIVATE/M4ROOT;store, err := dcf.Open(ctx, os.DirFS(root))reads one. A copied card folder or a test tree opens the same way as a mounted card. The count argument goes away.stores, err := dcf.GetStores(ctx, n)finds and reads every mounted card. Fewer calls, but it only ever sees mounted volumes.2. Where the import puts files. The call would be
res, err := store.Import(ctx, dest, dcf.ImportOptions{SkipExisting: true}), reporting what was copied, skipped and in conflict, verifying each copy by SHA-256 and never deleting from the card.dest, e.g.dest/DCIM/100MSDCF/DSC00001.JPG. A different file already at that path is reported as a conflict and left alone, never overwritten. Two cards that reuse the same numbers conflict in onedest, so give each card its own.dest/2026-10-03/DSC00001.JPG, same conflict rule.Reply with a letter for each, or "recommended". #1, #2, #3 and #6 go ahead meanwhile; none of them depends on this.
Model: opus-5-5