appydave-tools 0.76.3 → 0.76.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d2b65bd11cb0b4e0a0c9b1718a9ebb262ad6c998167bfdc8f533ddca754ee850
4
- data.tar.gz: e45a7a56eb7f77249911ea874037c002829cfcca1f8f5cfd8553b60d12e88898
3
+ metadata.gz: 0531bc72c6c4aeac9830f72f552a4d683775d7efc61ee483069d882cdbbbf5af
4
+ data.tar.gz: 1c8e032ddc4e8dfc4c196452465abea40958107d2d68c5e4063c1ec2c36a3a9d
5
5
  SHA512:
6
- metadata.gz: feb57bd1aca715ae2b6b3a587e762e024457b4d14f1172069d1afd19e953c6c432567d9c76c819543f740acb757c53bb36fa7bc839e4e7c8706f13435e94bfb0
7
- data.tar.gz: eba77632d7dad881243726e122d8da5546040910b2851c36a9b751d7310da9ca3d1a4279571baa31b908bb1ff398436253bed4f7e52907adeeb6e4cfe1b1f69a
6
+ metadata.gz: 1787f781bdf758fae98c3388cce0437aca330a3161937f5c214651885c80e05598682e64afc3adea1e2ffd3b2f70d09287a9acca12c8fada89077b7d48791a39
7
+ data.tar.gz: 6cadabed0aa0f0be9d993b4dbda2c304c9a34f717fcc7b86b8cc059777e7cb0a57a494ddc2c3e5432fd4d4d85990330a6d401aa75c89bb7b0be5f5207c68d12b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ ## [0.76.4](https://github.com/appydave/appydave-tools/compare/v0.76.3...v0.76.4) (2026-03-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * add subprocess test for -f json flag to cli_spec ([de6a28a](https://github.com/appydave/appydave-tools/commit/de6a28a39790d29f5141fbf313fa5e44782b90a6))
7
+ * restore youtube_automation_config require accidentally removed in previous commit ([e4180db](https://github.com/appydave/appydave-tools/commit/e4180db9ad90040ec4faf2811fad713a20e6be8e))
8
+
9
+ ## [0.76.3](https://github.com/appydave/appydave-tools/compare/v0.76.2...v0.76.3) (2026-03-19)
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * add field isolation assertions to update_spec non-updated fields ([da678f6](https://github.com/appydave/appydave-tools/commit/da678f68f5ff0384020639069b459d98e0558968))
15
+
1
16
  ## [0.76.2](https://github.com/appydave/appydave-tools/compare/v0.76.1...v0.76.2) (2026-03-19)
2
17
 
3
18
 
data/README.md CHANGED
@@ -43,7 +43,6 @@ ad_config -c
43
43
  This creates empty configuration files at `~/.config/appydave/`:
44
44
  - `settings.json` - Paths and preferences
45
45
  - `channels.json` - YouTube channel definitions
46
- - `youtube-automation.json` - Automation workflows
47
46
 
48
47
  **2. Option A: Copy example files**
49
48
 
@@ -276,38 +275,6 @@ prompt_tools completion -f prompt_template.md -k topic=Ruby,style=tutorial -c
276
275
 
277
276
  ---
278
277
 
279
- ### ⚡ YouTube Automation *(Internal/Experimental)*
280
-
281
- **The problem:** Video content creation workflows involve multiple steps: research → scripting → production.
282
-
283
- **The solution:** Run predefined prompt sequences against OpenAI API to automate research and content generation steps.
284
-
285
- ```bash
286
- # Run automation sequence (requires configuration)
287
- youtube_automation -s 01-1
288
-
289
- # With debug output
290
- youtube_automation -s 01-1 -d
291
- ```
292
-
293
- **What it does:**
294
- - Loads sequence configuration from `~/.config/appydave/youtube_automation.json`
295
- - Reads prompt templates from Dropbox (`_common/raw_prompts/`)
296
- - Executes OpenAI API calls for each sequence step
297
- - Saves responses to output files
298
-
299
- **Configuration required:**
300
- - Sequence definitions in `youtube_automation.json`
301
- - Prompt template files in configured Dropbox path
302
- - `OPENAI_ACCESS_TOKEN` environment variable
303
-
304
- **Current status:** ⚠️ **Internal tool** - Hardcoded Dropbox paths, uses deprecated Completion API, not documented for external use.
305
-
306
- **Relationship to other tools:** This is separate from **Move Images** tool (which organizes downloaded images into video project asset folders).
307
-
308
- **Use cases:** Automated content research, script outline generation, multi-step prompt workflows.
309
-
310
- ---
311
278
 
312
279
  ### ⚙️ Configuration Manager
313
280
 
@@ -338,7 +305,6 @@ ad_config -p
338
305
  |------|---------|-------------------------|
339
306
  | `settings.json` | Paths and preferences (video-projects-root, download folders, etc.) | ✅ Yes (after removing personal paths) |
340
307
  | `channels.json` | YouTube channel definitions (code, name, youtube_handle, locations) | ✅ Yes (share structure, customize paths locally) |
341
- | `youtube_automation.json` | Automation workflow configurations | ✅ Yes (if no sensitive data) |
342
308
  | `.env` | **Secrets and API keys** | ❌ **NEVER** (gitignored) |
343
309
 
344
310
  **Key Settings:**
data/bin/dam CHANGED
@@ -515,63 +515,6 @@ class VatCLI
515
515
  brands.key?(brand_key) || brands.shortcut?(brand_key)
516
516
  end
517
517
 
518
- # Add local sync status to matched projects data
519
- # Mutates the matched_projects hash to add :local_status key
520
- # @param matched_projects [Hash] Map of project_id => S3 data
521
- # @param brand_key [String] Brand key (e.g., 'appydave', 'ss')
522
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
523
- def add_local_sync_status!(matched_projects, brand_key)
524
- matched_projects.each do |project_id, data|
525
- project_path = Appydave::Tools::Dam::Config.project_path(brand_key, project_id)
526
- s3_staging_path = File.join(project_path, 's3-staging')
527
-
528
- if !Dir.exist?(project_path)
529
- data[:local_status] = :no_project # Project directory doesn't exist
530
- elsif !Dir.exist?(s3_staging_path)
531
- data[:local_status] = :no_files # Project exists but no downloads yet
532
- else
533
- # Count local files in s3-staging
534
- local_files = Dir.glob(File.join(s3_staging_path, '**', '*'))
535
- .select { |f| File.file?(f) }
536
- .reject { |f| File.basename(f).include?('Zone.Identifier') } # Exclude Windows metadata
537
-
538
- s3_file_count = data[:file_count]
539
- local_file_count = local_files.size
540
-
541
- data[:local_status] = if local_file_count.zero?
542
- :no_files
543
- elsif local_file_count == s3_file_count
544
- :synced # Fully synced
545
- else
546
- :partial # Some files downloaded
547
- end
548
-
549
- data[:local_file_count] = local_file_count
550
- end
551
- end
552
- end
553
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
554
-
555
- # Format local sync status for display
556
- # @param status [Symbol] :synced, :no_files, :partial, :no_project
557
- # @param local_count [Integer, nil] Number of local files
558
- # @param s3_count [Integer] Number of S3 files
559
- # @return [String] Formatted status string
560
- def format_local_status(status, local_count, s3_count)
561
- case status
562
- when :synced
563
- '✓ Synced'
564
- when :no_files
565
- '⚠ None'
566
- when :partial
567
- "⚠ #{local_count}/#{s3_count}"
568
- when :no_project
569
- '✗ Missing'
570
- else
571
- 'Unknown'
572
- end
573
- end
574
-
575
518
  def parse_share_args(args)
576
519
  # Extract --expires flag
577
520
  expires = '7d' # default
@@ -693,14 +636,14 @@ class VatCLI
693
636
 
694
637
  # Format columns
695
638
  file_col = filename.ljust(40)
696
- size_col = format_bytes(size).rjust(10)
639
+ size_col = Appydave::Tools::Dam::FileHelper.format_size(size).rjust(10)
697
640
  date_col = last_modified ? last_modified.strftime('%Y-%m-%d %H:%M') : 'N/A'.ljust(16)
698
641
 
699
642
  puts "#{file_col} #{size_col} #{date_col}"
700
643
  end
701
644
 
702
645
  puts '-' * 72
703
- puts "Total: #{files.size} #{files.size == 1 ? 'file' : 'files'}, #{format_bytes(total_bytes)}"
646
+ puts "Total: #{files.size} #{files.size == 1 ? 'file' : 'files'}, #{Appydave::Tools::Dam::FileHelper.format_size(total_bytes)}"
704
647
 
705
648
  # Quick actions section
706
649
  puts ''
@@ -1478,7 +1421,7 @@ class VatCLI
1478
1421
  File.write(manifest_path, JSON.pretty_generate(manifest))
1479
1422
 
1480
1423
  # Add local sync status to matched projects
1481
- add_local_sync_status!(matched_projects, brand_key)
1424
+ Appydave::Tools::Dam::LocalSyncStatus.enrich!(matched_projects, brand_key)
1482
1425
 
1483
1426
  # Display table
1484
1427
  display_s3_scan_table(matched_projects, orphaned_projects, bucket, prefix, region)
@@ -1507,8 +1450,8 @@ class VatCLI
1507
1450
  # Display matched projects first (sorted alphabetically)
1508
1451
  matched_projects.sort.each do |project_id, data|
1509
1452
  files = data[:file_count].to_s.rjust(5)
1510
- size = format_bytes(data[:total_bytes]).rjust(10)
1511
- local_status = format_local_status(data[:local_status], data[:local_file_count], data[:file_count])
1453
+ size = Appydave::Tools::Dam::FileHelper.format_size(data[:total_bytes]).rjust(10)
1454
+ local_status = Appydave::Tools::Dam::LocalSyncStatus.format(data[:local_status], data[:local_file_count], data[:file_count])
1512
1455
  modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
1513
1456
 
1514
1457
  puts format('%-36s %5s %10s %-9s %s', project_id, files, size, local_status, modified)
@@ -1520,7 +1463,7 @@ class VatCLI
1520
1463
  puts '-' * 92
1521
1464
  orphaned_projects.sort.each do |project_id, data|
1522
1465
  files = data[:file_count].to_s.rjust(5)
1523
- size = format_bytes(data[:total_bytes]).rjust(10)
1466
+ size = Appydave::Tools::Dam::FileHelper.format_size(data[:total_bytes]).rjust(10)
1524
1467
  local_status = 'N/A'
1525
1468
  modified = data[:last_modified] ? Time.parse(data[:last_modified]).strftime('%Y-%m-%d %H:%M') : 'N/A'
1526
1469
 
@@ -1582,19 +1525,6 @@ class VatCLI
1582
1525
  puts "Total brands scanned: #{successful.size}/#{results.size}"
1583
1526
  end
1584
1527
  # rubocop:enable Metrics/MethodLength
1585
-
1586
- # Format bytes in human-readable format
1587
- # rubocop:disable Style/FormatStringToken
1588
- def format_bytes(bytes)
1589
- return '0 B' if bytes.zero?
1590
-
1591
- units = %w[B KB MB GB TB]
1592
- exp = (Math.log(bytes) / Math.log(1024)).to_i
1593
- exp = [exp, units.length - 1].min
1594
-
1595
- format('%.1f %s', bytes.to_f / (1024**exp), units[exp])
1596
- end
1597
- # rubocop:enable Style/FormatStringToken
1598
1528
  end
1599
1529
 
1600
1530
  # Run CLI
@@ -14,6 +14,18 @@
14
14
 
15
15
  ---
16
16
 
17
+ ## ⚠️ Pre-Commit Check (Mandatory Every Commit)
18
+
19
+ Before running `kfix`, always run:
20
+ ```bash
21
+ git status
22
+ ```
23
+ Confirm ONLY the files you intentionally changed are staged. If unexpected files appear, run `git diff` to investigate before proceeding.
24
+
25
+ **Why:** micro-cleanup (2026-03-19) accidentally staged a pre-existing uncommitted change in `lib/appydave/tools.rb` when running `kfix`.
26
+
27
+ ---
28
+
17
29
  ## Build & Run Commands
18
30
 
19
31
  ```bash
@@ -33,7 +45,7 @@ kfeat "add feature description" # Minor version bump
33
45
  kfix "fix bug description" # Patch version bump
34
46
  ```
35
47
 
36
- **Baseline (2026-03-19):** 748 examples, 0 failures, 84.88% line coverage (7680/9048)
48
+ **Baseline (2026-03-19):** 831 examples, 0 failures, ~85.92% line coverage
37
49
 
38
50
  ---
39
51
 
@@ -82,9 +94,9 @@ docs/
82
94
 
83
95
  Every work unit must satisfy ALL of the following before marking `[x]`:
84
96
 
85
- - [ ] `bundle exec rspec` — 748+ examples, 0 failures
97
+ - [ ] `bundle exec rspec` — 831+ examples, 0 failures
86
98
  - [ ] `bundle exec rubocop --format clang` — 0 offenses
87
- - [ ] Line coverage stays ≥ 84.88%
99
+ - [ ] Line coverage stays ≥ 85.92%
88
100
  - [ ] Any new functionality has ≥ 1 spec covering it
89
101
  - [ ] All new `.rb` files start with `# frozen_string_literal: true`
90
102
  - [ ] No hardcoded brand transformation strings (always use BrandResolver)
@@ -209,9 +221,9 @@ Appydave::Tools::Configuration::Config.configure
209
221
 
210
222
  ## Quality Gates
211
223
 
212
- - **Tests:** `bundle exec rspec` — 748 examples, 0 failures (do not ship if any fail)
224
+ - **Tests:** `bundle exec rspec` — 831 examples, 0 failures (do not ship if any fail)
213
225
  - **Lint:** `bundle exec rubocop --format clang` — 0 offenses (CI will reject)
214
- - **Coverage:** ≥ 84.88% line coverage
226
+ - **Coverage:** ≥ 85.92% line coverage
215
227
  - **frozen_string_literal:** Required on every new `.rb` file
216
228
  - **Commit format:** `kfeat`/`kfix` only — triggers semantic versioning + CI wait
217
229
 
@@ -1,35 +1,20 @@
1
1
  # Project Backlog — AppyDave Tools
2
2
 
3
- **Last updated**: 2026-03-19 (bugfix-and-security assessment + 4 new items from quality audit)
4
- **Total**: 27 | Pending: 17 | Done: 10 | Deferred: 0 | Rejected: 0
3
+ **Last updated**: 2026-03-19 (micro-cleanup campaign complete)
4
+ **Total**: 33 | Pending: 7 | In Progress: 1 | Done: 25 | Deferred: 0 | Rejected: 0
5
5
 
6
6
  ---
7
7
 
8
8
  ## Pending
9
9
 
10
- ### High Priority
11
- - [ ] B024 — Tests: add configure_ssl_options unit tests to s3_operations_spec + share_operations_spec (protects B017 security fix) | Priority: high
12
- - [ ] B015 — BUG-2: FileCollector uses FileUtils.cd without ensure (process dir not restored on exception) | Priority: high
13
- - [x] B006 — BUG-1: Jump CLI get/remove key lookup | Completed: verified fixed 2026-03-19, regression spec added
14
-
15
10
  ### Medium Priority
16
- - [ ] B022 — Tests: expand cli_spec.rb with functional tests (-i, -e, -f, -o flags, exit codes) | Priority: medium
17
- - [ ] B026 — Tests: add determine_range edge cases (b00, b9, a40) to sync_from_ssd_spec + manifest_generator_spec | Priority: medium
18
- - [ ] B027 — Tests: strengthen gpt_context no-args spec to verify file collection actually stops | Priority: medium
19
- - [ ] B023 — Tests: add file_collector_spec coverage for JSON format, aider format, error paths | Priority: medium
20
- - [ ] B018 — Tests: add specs for Jump Commands::Remove, Commands::Add, Commands::Update | Priority: medium
21
- - [ ] B019 — Fix: remove debug puts @working_directory from gpt_context/file_collector.rb | Priority: medium
22
11
  - [ ] B001 — FR-1: GPT Context token counting | Priority: medium
23
12
  - [ ] B012 — Arch: add integration tests for brand resolution end-to-end | Priority: medium
24
-
25
- - [ ] B025 — Fix: stale comment in sync_from_ssd.rb line 173 (says 60-69, should say b50-b99) | Priority: low
26
-
27
- ### Low Priority
28
13
  - [ ] B007 — Performance: parallel git/S3 status checks for dam list | Priority: low
29
14
  - [ ] B008 — Performance: cache git/S3 status with 5-min TTL | Priority: low
30
15
  - [ ] B009 — UX: progress indicators for dam operations > 5s | Priority: low
31
16
  - [ ] B010 — UX: auto-adjust dam table column widths to terminal width | Priority: low
32
- - [ ] B011 — Arch: extract VatCLI business logic from bin/dam (1,600-line God class) | Priority: low
17
+ - [~] B011 — Arch: extract VatCLI business logic from bin/dam (1,600-line God class) | Campaign: extract-vat-cli
33
18
  - [ ] B020 — Arch: split S3Operations (1,030 lines, mixed I/O + logic) | Priority: low
34
19
 
35
20
  ---
@@ -45,6 +30,22 @@
45
30
  - [x] B016 — BUG-3: ManifestGenerator + SyncFromSsd incompatible SSD range strings | Completed: bugfix-and-security (2026-03-19)
46
31
  - [x] B017 — Security: ssl_verify_peer disabled unconditionally in S3Operations + ShareOperations + S3Scanner | Completed: bugfix-and-security (2026-03-19)
47
32
  - [x] B021 — Fix: gpt_context no-args guard had dead format.nil? condition | Completed: bugfix-and-security (2026-03-19)
33
+ - [x] B024 — Tests: configure_ssl_options unit tests (protects B017 fix) | Completed: test-coverage-gaps (2026-03-19)
34
+ - [x] B022 — Tests: functional cli_spec tests for -i -e -f -o flags | Completed: test-coverage-gaps (2026-03-19)
35
+ - [x] B026 — Tests: determine_range edge cases (b00, b9, a40) | Completed: test-coverage-gaps (2026-03-19)
36
+ - [x] B027 — Tests: gpt_context no-args spec verifies collection stops | Completed: test-coverage-gaps (2026-03-19)
37
+ - [x] B025 — Fix: stale comment sync_from_ssd.rb:173 | Completed: test-coverage-gaps (2026-03-19)
38
+ - [x] B018 — Tests: Jump Commands::Remove, Add, Update specs | Completed: test-coverage-gaps (2026-03-19)
39
+ - [x] B015 — BUG-2: FileCollector FileUtils.cd without ensure | Completed: already fixed in commit 13d5f87; closed without campaign 2026-03-19
40
+ - [x] B019 — Fix: remove debug puts @working_directory from file_collector.rb | Completed: already removed prior to test-coverage-gaps campaign; closed without campaign 2026-03-19
41
+ - [x] B006 — BUG-1: Jump CLI get/remove key lookup | Completed: verified fixed 2026-03-19, regression spec added
42
+ - [x] B023 — Tests: file_collector_spec json/aider/error path coverage | Completed: final-test-gaps (2026-03-19)
43
+ - [x] B028 — Tests: cli_spec file body content assertions in -i/-e tests | Completed: final-test-gaps (2026-03-19)
44
+ - [x] B029 — Tests: add_spec validate all returned location data fields | Completed: final-test-gaps (2026-03-19)
45
+ - [x] B030 — Tests: update_spec verify non-updated fields unchanged | Completed: final-test-gaps (2026-03-19)
46
+ - [x] B031 — Tests: add_spec `type` field assertion | Completed: already in commit 8eec40c; closed micro-cleanup (2026-03-19)
47
+ - [x] B032 — Tests: cli_spec `-f json` subprocess test | Completed: micro-cleanup (2026-03-19), v0.76.4
48
+ - [x] B033 — Fix: file_collector.rb return `''` when working_directory missing | Completed: already in commit 13d5f87; closed micro-cleanup (2026-03-19)
48
49
 
49
50
  ---
50
51
 
@@ -64,40 +65,6 @@
64
65
 
65
66
  ---
66
67
 
67
- ### B002 — FR-2: GPT Context AI-Friendly Help System
68
-
69
- **Spec:** `docs/specs/fr-002-gpt-context-help-system.md`
70
-
71
- **User Story**: As an AI agent using GPT Context via skills, I want structured, comprehensive help output so I can understand all options and use the tool correctly.
72
-
73
- **Notes:** Full spec exists. High priority — enables AI skill integration.
74
-
75
- ---
76
-
77
- ### B006 — BUG-1: Jump CLI get/remove Key Lookup Bug
78
-
79
- **Priority:** High — but verify live first
80
-
81
- **⚠️ Three-lens audit (2026-03-19) found:** Static analysis of `Jump::Config#find`, `Config#remove`, and `Search#get` shows correct dual-key guards. Bug may be environmental (stale config file format) or already fixed in a prior commit. **Run `bin/jump.rb get <key>` live before writing any code.**
82
-
83
- **Steps to Reproduce:**
84
- ```bash
85
- bin/jump.rb search awb-team # ✅ finds entry
86
- bin/jump.rb get awb-team # ❌ "Location not found" ← confirm this still fails
87
- bin/jump.rb remove test-minimal --force # ❌ "No locations found."
88
- ```
89
-
90
- **If bug confirmed:** Failure site is in `Jump::Config#find` (`loc.key == key`) or the memoization of `@locations` — NOT in `name_manager/`. The `Commands::Remove#run` → `config.find(key)` → `locations.find { |loc| loc.key == key }` path is the call chain to trace.
91
-
92
- **Acceptance Criteria:**
93
- - [ ] Confirm bug still exists live (if not, write regression spec and close)
94
- - [ ] `get <key>` finds entry when `search <key>` finds it
95
- - [ ] `remove <key>` finds entry when `search <key>` finds it
96
- - [ ] Regression tests for key lookup consistency
97
- - [ ] Root cause documented in commit message
98
-
99
- ---
100
-
101
68
  ### B007 — Performance: Parallel git/S3 Status Checks
102
69
 
103
70
  **Context:** `dam list appydave` with 13 projects takes ~26s (sequential git+S3 check per project).
@@ -146,47 +113,6 @@ bin/jump.rb remove test-minimal --force # ❌ "No locations found."
146
113
 
147
114
  ---
148
115
 
149
- ### B015 — BUG-2: FileCollector FileUtils.cd Without ensure
150
-
151
- **Context:** `lib/appydave/tools/gpt_context/file_collector.rb` line 20 calls `FileUtils.cd(@working_directory)`. If an exception fires inside `build`, the process working directory is never restored to `Dir.home`. Affects any subsequent operation in the same process.
152
- **Fix:** Wrap in block form: `FileUtils.cd(@working_directory) { ... }` — Ruby handles restore automatically. Or add `ensure FileUtils.cd(Dir.home)`.
153
- **Blocker for:** FR-2 — fix this before adding more code paths to `file_collector.rb`.
154
- **Source:** Code quality audit 2026-03-19, MAJOR issue #2.
155
-
156
- ---
157
-
158
- ### B016 — BUG-3: ManifestGenerator vs SyncFromSsd Incompatible Range Strings
159
-
160
- **Context:** `ManifestGenerator.determine_range('b65')` returns `"b50-b99"`. `SyncFromSsd.determine_range('b65')` returns `"60-69"`. Both are used to construct SSD archive folder paths. Projects archived via SSD sync won't be found by the manifest generator, and vice versa. A `find_ssd_project_path` fallback scan may paper over this in practice.
161
- **Fix:** Standardise both methods on one format. Decide which format matches actual SSD folder structure on disk, then update the other method to match.
162
- **Source:** Code quality audit 2026-03-19, MAJOR issue #1.
163
-
164
- ---
165
-
166
- ### B017 — Security: ssl_verify_peer Disabled in S3Operations + ShareOperations
167
-
168
- **Context:** `lib/appydave/tools/dam/s3_operations.rb` lines 110-113 and `share_operations.rb` lines 97-100 set `ssl_verify_peer: false` unconditionally. Comment claims "safe for AWS S3" — this is incorrect. Disabling peer verification removes MITM protection on all S3 operations including AWS credential transmission.
169
- **Fix:** Remove the `ssl_verify_peer: false` override entirely. AWS SDK handles SSL correctly by default. If there was a historical reason (corporate proxy, dev cert issue), document it and scope to `ENV['AWS_SKIP_SSL'] == 'true'` only.
170
- **Source:** Code quality audit 2026-03-19, MAJOR issue #3.
171
-
172
- ---
173
-
174
- ### B018 — Tests: Jump Commands Layer Has No Dedicated Specs
175
-
176
- **Context:** `Commands::Remove`, `Commands::Add`, `Commands::Update` have zero unit specs. The CLI spec only tests auto-regenerate side effects. `--force` guard, error codes, suggestion-on-not-found logic, and key nil-handling in these commands are entirely untested.
177
- **Fix:** Add `spec/appydave/tools/jump/commands/remove_spec.rb`, `add_spec.rb`, `update_spec.rb`. Use `JumpTestLocations` factory + `with jump filesystem` context.
178
- **Source:** Test quality audit 2026-03-19, RISK-1.
179
-
180
- ---
181
-
182
- ### B019 — Fix: Remove Debug puts From file_collector.rb
183
-
184
- **Context:** `lib/appydave/tools/gpt_context/file_collector.rb` line 15: `puts @working_directory`. Prints working directory on every `gpt_context` invocation. Pollutes captured output. Must be removed before FR-2 adds help system output.
185
- **Fix:** Delete line 15.
186
- **Source:** Code quality audit 2026-03-19, MINOR issue #4.
187
-
188
- ---
189
-
190
116
  ### B020 — Arch: Split S3Operations (1,030 lines)
191
117
 
192
118
  **Context:** `S3Operations` handles upload, download, status, cleanup, archive to SSD, MD5 comparison, content type detection, file formatting, and time formatting — all in one class with direct `puts` throughout. No result objects returned from upload/download/cleanup (void methods with side effects).