appydave-tools 0.76.11 → 0.76.12

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: 6557cf7bec5e564e6541cd1c65236f67888241cead0d9038be5bc57191c6dac4
4
- data.tar.gz: 9e8b2ec379d9fb6d22a0437b980893ce031683da6ca2b2281b54b553f32323b8
3
+ metadata.gz: 9252ea22ead22d967de9096d645777ce4b65bc66e633fbf391e385e2719a839e
4
+ data.tar.gz: 4ea18017243a9d10dd8d0daedf060d91cf7a85fd95c3093d8e5fbeebbd7d82eb
5
5
  SHA512:
6
- metadata.gz: 6aa1fd27da7b10e94594d0056fd001943bdce7b29b53d87173d6b0655880a58f2324f32f166719589f6b0585a1697a6c876a7335c197686feeaa07841b0f09a5
7
- data.tar.gz: 8449913492bc836620632662c167de675488f10999af39e7f68b2d1b96fd4ddce4d52021ce60185ffc4e337656392bd92b46d579b7bbf443d40bec4c7f3600a6
6
+ metadata.gz: 863eb25208061bef821717a4b6fbf73159e299f7fc6e1fda7e79fc646ea849fe587574ed395b5d1c441238eb2bed781dd9154a5e69b4d0d27ae3c18f29fd7703
7
+ data.tar.gz: da1c86a72f91fa4bf8686e8c5ffb90916d84841cfc8b63189e2d7adafdb019a2c98223da79e0d1cab646c3da6a8e19182215eb2bcde23b4f517a0f1200e04db9
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [0.76.11](https://github.com/appydave/appydave-tools/compare/v0.76.10...v0.76.11) (2026-03-19)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * use full BrandsConfig constant in s3_scan_command_spec to prevent CI verification failure ([3bd417d](https://github.com/appydave/appydave-tools/commit/3bd417d5d58dff89af736567ba7f85fd1d786fb6))
7
+
1
8
  ## [0.76.10](https://github.com/appydave/appydave-tools/compare/v0.76.9...v0.76.10) (2026-03-19)
2
9
 
3
10
 
data/bin/dam CHANGED
@@ -155,7 +155,6 @@ class VatCLI
155
155
  # S3 Upload
156
156
  def s3_up_command(args)
157
157
  options = Appydave::Tools::Dam::S3ArgParser.parse_s3(args, 's3-up')
158
- ENV['BRAND_PATH'] = options[:brand_path]
159
158
  s3_ops = Appydave::Tools::Dam::S3Operations.new(options[:brand], options[:project])
160
159
  s3_ops.upload(dry_run: options[:dry_run])
161
160
  rescue StandardError => e
@@ -166,7 +165,6 @@ class VatCLI
166
165
  # S3 Download
167
166
  def s3_down_command(args)
168
167
  options = Appydave::Tools::Dam::S3ArgParser.parse_s3(args, 's3-down')
169
- ENV['BRAND_PATH'] = options[:brand_path]
170
168
  s3_ops = Appydave::Tools::Dam::S3Operations.new(options[:brand], options[:project])
171
169
  s3_ops.download(dry_run: options[:dry_run])
172
170
  rescue StandardError => e
@@ -177,7 +175,6 @@ class VatCLI
177
175
  # S3 Status
178
176
  def s3_status_command(args)
179
177
  options = Appydave::Tools::Dam::S3ArgParser.parse_s3(args, 's3-status')
180
- ENV['BRAND_PATH'] = options[:brand_path]
181
178
  s3_ops = Appydave::Tools::Dam::S3Operations.new(options[:brand], options[:project])
182
179
  s3_ops.status
183
180
  rescue StandardError => e
@@ -188,7 +185,6 @@ class VatCLI
188
185
  # S3 Cleanup Remote
189
186
  def s3_cleanup_remote_command(args)
190
187
  options = Appydave::Tools::Dam::S3ArgParser.parse_s3(args, 's3-cleanup-remote')
191
- ENV['BRAND_PATH'] = options[:brand_path]
192
188
  s3_ops = Appydave::Tools::Dam::S3Operations.new(options[:brand], options[:project])
193
189
  s3_ops.cleanup(force: options[:force], dry_run: options[:dry_run])
194
190
  rescue StandardError => e
@@ -199,7 +195,6 @@ class VatCLI
199
195
  # S3 Cleanup Local
200
196
  def s3_cleanup_local_command(args)
201
197
  options = Appydave::Tools::Dam::S3ArgParser.parse_s3(args, 's3-cleanup-local')
202
- ENV['BRAND_PATH'] = options[:brand_path]
203
198
  s3_ops = Appydave::Tools::Dam::S3Operations.new(options[:brand], options[:project])
204
199
  s3_ops.cleanup_local(force: options[:force], dry_run: options[:dry_run])
205
200
  rescue StandardError => e
@@ -210,7 +205,6 @@ class VatCLI
210
205
  # Share file via pre-signed URL
211
206
  def s3_share_command(args)
212
207
  options = Appydave::Tools::Dam::S3ArgParser.parse_share(args)
213
- ENV['BRAND_PATH'] = options[:brand_path]
214
208
  share_ops = Appydave::Tools::Dam::ShareOperations.new(options[:brand], options[:project])
215
209
  share_ops.generate_links(files: options[:file], expires: options[:expires], download: options[:download])
216
210
  rescue StandardError => e
@@ -221,7 +215,6 @@ class VatCLI
221
215
  # Discover files in S3 for a project
222
216
  def s3_discover_command(args)
223
217
  options = Appydave::Tools::Dam::S3ArgParser.parse_discover(args)
224
- ENV['BRAND_PATH'] = options[:brand_path]
225
218
  files = fetch_s3_files(options[:brand_key], options[:project_id])
226
219
 
227
220
  return if handle_empty_files?(files, options[:brand_key], options[:project_id])
@@ -235,7 +228,6 @@ class VatCLI
235
228
  # Archive project to SSD
236
229
  def archive_command(args)
237
230
  options = Appydave::Tools::Dam::S3ArgParser.parse_s3(args, 'archive')
238
- ENV['BRAND_PATH'] = options[:brand_path]
239
231
  s3_ops = Appydave::Tools::Dam::S3Operations.new(options[:brand], options[:project])
240
232
  s3_ops.archive(force: options[:force], dry_run: options[:dry_run])
241
233
  rescue StandardError => e
@@ -282,7 +274,6 @@ class VatCLI
282
274
 
283
275
  def generate_single_manifest(brand_arg, verbose: false)
284
276
  Appydave::Tools::Dam::Config.expand_brand(brand_arg)
285
- ENV['BRAND_PATH'] = Appydave::Tools::Dam::Config.brand_path(brand_arg)
286
277
 
287
278
  generator = Appydave::Tools::Dam::ManifestGenerator.new(brand_arg)
288
279
  generator.generate(verbose: verbose)
@@ -329,7 +320,6 @@ class VatCLI
329
320
  if brand_arg
330
321
  # Sync specific brand
331
322
  Appydave::Tools::Dam::Config.expand_brand(brand_arg)
332
- ENV['BRAND_PATH'] = Appydave::Tools::Dam::Config.brand_path(brand_arg)
333
323
 
334
324
  syncer = Appydave::Tools::Dam::SyncFromSsd.new(brand_arg)
335
325
  syncer.sync(dry_run: dry_run)
@@ -1,7 +1,7 @@
1
1
  # Project Backlog — AppyDave Tools
2
2
 
3
- **Last updated**: 2026-03-19 (extract-vat-cli campaign complete)
4
- **Total**: 37 | Pending: 11 | Done: 26 | Deferred: 0 | Rejected: 0
3
+ **Last updated**: 2026-03-19 (library-boundary-cleanup campaign complete)
4
+ **Total**: 40 | Pending: 9 | Done: 30 | Deferred: 0 | Rejected: 0
5
5
 
6
6
  ---
7
7
 
@@ -10,16 +10,13 @@
10
10
  ### Medium Priority
11
11
  - [ ] B001 — FR-1: GPT Context token counting | Priority: medium
12
12
  - [ ] B012 — Arch: add integration tests for brand resolution end-to-end | Priority: medium
13
- - [ ] B007 — Performance: parallel git/S3 status checks for dam list | Priority: low
13
+ - [ ] B007 — Performance: parallel git/S3 status checks for dam list | Priority: low (now unblocked)
14
14
  - [ ] B008 — Performance: cache git/S3 status with 5-min TTL | Priority: low
15
15
  - [ ] B009 — UX: progress indicators for dam operations > 5s | Priority: low
16
16
  - [ ] B010 — UX: auto-adjust dam table column widths to terminal width | Priority: low
17
- - [x] B011 — Arch: extract VatCLI business logic from bin/dam (1,600-line God class) | Completed: extract-vat-cli (2026-03-19)
18
- - [ ] B020Arch: split S3Operations (1,030 lines, mixed I/O + logic) | Priority: low
19
- - [ ] B034Fix: replace exit 1 with typed exceptions in S3ScanCommand + S3ArgParser | Priority: high (blocks B007 + test coverage)
20
- - [ ] B035 — Fix: remove ENV['BRAND_PATH'] side effect from S3ArgParser | Priority: high (blocks B007 parallelism)
21
- - [ ] B036 — Tests: improve S3ScanCommand spec from D to B (depends on B034) | Priority: medium
22
- - [ ] B037 — Tests: LocalSyncStatus :partial case, local_file_count assertion, Zone.Identifier exclusion | Priority: medium
17
+ - [ ] B020 — Arch: split S3Operations (1,030 lines, mixed I/O + logic) | Priority: low (now unblocked)
18
+ - [ ] B038Cleanup: remove ENV['BRAND_PATH'] dead code from bin/dam (10 assignments, never read in lib/) | Priority: low
19
+ - [ ] B039Tests: strengthen s3_scan_command_spec data-value assertions + remove LocalSyncStatus stub | Priority: low
23
20
 
24
21
  ---
25
22
 
@@ -50,6 +47,11 @@
50
47
  - [x] B031 — Tests: add_spec `type` field assertion | Completed: already in commit 8eec40c; closed micro-cleanup (2026-03-19)
51
48
  - [x] B032 — Tests: cli_spec `-f json` subprocess test | Completed: micro-cleanup (2026-03-19), v0.76.4
52
49
  - [x] B033 — Fix: file_collector.rb return `''` when working_directory missing | Completed: already in commit 13d5f87; closed micro-cleanup (2026-03-19)
50
+ - [x] B011 — Arch: extract VatCLI business logic from bin/dam (1,600-line God class) | Completed: extract-vat-cli (2026-03-19)
51
+ - [x] B034 — Fix: replace exit 1 with typed exceptions in S3ScanCommand + S3ArgParser; add UsageError | Completed: library-boundary-cleanup (2026-03-19), v0.76.8
52
+ - [x] B035 — Fix: remove ENV['BRAND_PATH'] side effect from S3ArgParser; return brand_path: in result hash | Completed: library-boundary-cleanup (2026-03-19), v0.76.9
53
+ - [x] B036 — Tests: rebuild S3ScanCommand spec from D to B (10 behaviour examples) | Completed: library-boundary-cleanup (2026-03-19), v0.76.10
54
+ - [x] B037 — Tests: LocalSyncStatus :partial, local_file_count, Zone.Identifier exclusion, unknown format | Completed: library-boundary-cleanup (2026-03-19), v0.76.11
53
55
 
54
56
  ---
55
57
 
@@ -0,0 +1,234 @@
1
+ # AGENTS.md — AppyDave Tools / env-dead-code-cleanup campaign
2
+
3
+ > Operational knowledge for every background agent. Self-contained — you receive only this file + your work unit prompt.
4
+ > Inherited from: library-boundary-cleanup campaign (2026-03-20)
5
+ > Updated for: env-dead-code-cleanup campaign (2026-03-20)
6
+
7
+ ---
8
+
9
+ ## Project Overview
10
+
11
+ **What:** Ruby gem providing CLI productivity tools for AppyDave's YouTube content creation workflow.
12
+ **Stack:** Ruby 3.4.2, Bundler 2.6.2, RSpec, RuboCop, semantic-release CI/CD.
13
+ **Active campaign:** env-dead-code-cleanup — remove confirmed dead ENV code and strengthen one test assertion.
14
+ **Commits:** Always use `kfeat`/`kfix` — never `git commit` directly.
15
+
16
+ ---
17
+
18
+ ## ⚠️ Pre-Commit Check (Mandatory Every Commit)
19
+
20
+ ```bash
21
+ git status
22
+ ```
23
+
24
+ Confirm ONLY the files you intentionally changed are staged. **Stage by file name — never `git add .` or `git add -A`.**
25
+
26
+ ```bash
27
+ # Correct:
28
+ git add bin/dam
29
+ kfix "..."
30
+
31
+ # Wrong — stages everything including planning files:
32
+ git add .
33
+ ```
34
+
35
+ **Why:** Three prior campaigns have had accidental staging from `git add .`. It is the single most common failure mode in this repo.
36
+
37
+ ---
38
+
39
+ ## Build & Run Commands
40
+
41
+ ```bash
42
+ eval "$(rbenv init -)"
43
+
44
+ RUBYOPT="-W0" bundle exec rspec # Full suite
45
+ bundle exec rspec spec/appydave/tools/dam/s3_scan_command_spec.rb # Single file
46
+ bundle exec rubocop --format clang # Lint (matches CI)
47
+
48
+ kfeat "description" # Minor version bump
49
+ kfix "description" # Patch version bump
50
+ ```
51
+
52
+ **Baseline (start of env-dead-code-cleanup):** 861 examples, 0 failures, 86.43% line coverage
53
+
54
+ ---
55
+
56
+ ## Directory Structure
57
+
58
+ ```
59
+ bin/
60
+ dam Main DAM CLI — target of B038 (10 ENV removals)
61
+ lib/appydave/tools/dam/
62
+ errors.rb UsageError, ConfigurationError, etc.
63
+ s3_scan_command.rb S3 scan orchestration
64
+ s3_arg_parser.rb CLI arg parsing — ENV side-effect already removed
65
+ local_sync_status.rb Local s3-staging sync status
66
+ manifest_generator.rb ManifestGenerator — confirmed does NOT read ENV['BRAND_PATH']
67
+ sync_from_ssd.rb SyncFromSsd — confirmed does NOT read ENV['BRAND_PATH']
68
+ spec/
69
+ appydave/tools/dam/
70
+ s3_scan_command_spec.rb Target of B039 (strengthen assertions)
71
+ local_sync_status_spec.rb Already updated in library-boundary-cleanup
72
+ ```
73
+
74
+ ---
75
+
76
+ ## This Campaign
77
+
78
+ ### B038 — remove-env-dead-code
79
+
80
+ **File:** `bin/dam` only.
81
+
82
+ Remove all 10 `ENV['BRAND_PATH'] =` lines. Confirmed dead:
83
+ - `grep -rn "BRAND_PATH" lib/ spec/` → 0 results
84
+ - ManifestGenerator, SyncFromSsd: grep confirmed no reads
85
+
86
+ **10 lines to delete** (line numbers approximate after prior edits — grep to find exact):
87
+
88
+ | Method | Pattern to remove |
89
+ |--------|------------------|
90
+ | s3_up_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
91
+ | s3_down_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
92
+ | s3_status_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
93
+ | s3_cleanup_remote_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
94
+ | s3_cleanup_local_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
95
+ | s3_archive_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
96
+ | s3_share_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
97
+ | s3_discover_command | `ENV['BRAND_PATH'] = options[:brand_path]` |
98
+ | generate_single_manifest | `ENV['BRAND_PATH'] = Appydave::Tools::Dam::Config.brand_path(brand_arg)` |
99
+ | sync_ssd_command | `ENV['BRAND_PATH'] = Appydave::Tools::Dam::Config.brand_path(brand_arg)` |
100
+
101
+ After removing, also check if `options[:brand_path]` was the ONLY use of `options` in any method. If so, the `options =` assignment itself may now be unused. Grep the method body before removing.
102
+
103
+ **Done when:**
104
+ - `grep -n "BRAND_PATH" bin/dam` → 0 results
105
+ - `RUBYOPT="-W0" bundle exec rspec` → 861 examples, 0 failures
106
+ - `bundle exec rubocop --format clang` → 0 offenses
107
+ - `git status` clean (only bin/dam staged)
108
+
109
+ **Commit:** `kfix "remove ENV BRAND_PATH dead code from bin/dam (10 assignments, never read in lib)"`
110
+
111
+ ---
112
+
113
+ ### B039 — strengthen-s3-scan-spec
114
+
115
+ **File:** `spec/appydave/tools/dam/s3_scan_command_spec.rb` only.
116
+
117
+ **Read the current spec file in full before making any changes.**
118
+
119
+ Two specific improvements:
120
+
121
+ **1. Replace `not_to be_empty` with field-value assertion**
122
+
123
+ Find the test that checks `project[:storage][:s3]` and replace the weak emptiness check:
124
+ ```ruby
125
+ # Before (weak):
126
+ expect(project[:storage][:s3]).not_to be_empty
127
+
128
+ # After (catches wrong values):
129
+ expect(project[:storage][:s3]).to include(
130
+ file_count: 3,
131
+ total_bytes: 1_500_000,
132
+ last_modified: '2025-01-01T00:00:00Z'
133
+ )
134
+ ```
135
+
136
+ Match the values to whatever the mock `scan_all_projects` returns in that context.
137
+
138
+ **2. Remove LocalSyncStatus stub, let integration run**
139
+
140
+ Find:
141
+ ```ruby
142
+ allow(Appydave::Tools::Dam::LocalSyncStatus).to receive(:enrich!)
143
+ ```
144
+
145
+ Remove this line. `LocalSyncStatus.enrich!` uses the filesystem — it needs the s3-staging directory to exist (or it sets `:no_project`/:no_files`). The test doesn't need to assert on `:local_status` — just ensure it doesn't raise.
146
+
147
+ If removing the stub causes failures because LocalSyncStatus can't find the brand path, add an `s3-staging` folder to the fixture:
148
+ ```ruby
149
+ FileUtils.mkdir_p(File.join(appydave_path, 'b65-test-project', 's3-staging'))
150
+ ```
151
+
152
+ **Done when:**
153
+ - `bundle exec rspec spec/appydave/tools/dam/s3_scan_command_spec.rb` → all pass
154
+ - `RUBYOPT="-W0" bundle exec rspec` → 861 examples, 0 failures (count unchanged — no new specs)
155
+ - `bundle exec rubocop --format clang` → 0 offenses
156
+ - `git status` clean (only spec file staged)
157
+
158
+ **Commit:** `kfix "strengthen s3_scan_command_spec field assertions; remove LocalSyncStatus stub"`
159
+
160
+ ---
161
+
162
+ ## Success Criteria (Every Work Unit)
163
+
164
+ - [ ] `RUBYOPT="-W0" bundle exec rspec` — 861+ examples, 0 failures
165
+ - [ ] `bundle exec rubocop --format clang` — 0 offenses
166
+ - [ ] Line coverage ≥ 86.43%
167
+ - [ ] `git status` clean, specific files staged (NOT `git add .`)
168
+
169
+ ---
170
+
171
+ ## Reference Patterns
172
+
173
+ ### Shared Context for DAM Specs
174
+
175
+ ```ruby
176
+ RSpec.describe Appydave::Tools::Dam::SomeClass do
177
+ include_context 'with vat filesystem and brands', brands: %w[appydave voz]
178
+ # Provides: temp_folder, projects_root, appydave_path, voz_path
179
+ # SettingsConfig#video_projects_root mocked to return projects_root
180
+ end
181
+ ```
182
+
183
+ ### instance_double — Always Use Full Constant
184
+
185
+ ```ruby
186
+ # Correct:
187
+ instance_double(Appydave::Tools::Configuration::Models::BrandsConfig)
188
+
189
+ # Wrong — fails CI on Ubuntu:
190
+ instance_double('BrandsConfig')
191
+ ```
192
+
193
+ ### Typed Exception Pattern
194
+
195
+ ```ruby
196
+ raise Appydave::Tools::Dam::ConfigurationError, 'Manifest not found: /path'
197
+ raise Appydave::Tools::Dam::UsageError, 'Usage: dam s3-up <brand> <project>'
198
+ ```
199
+
200
+ ---
201
+
202
+ ## Anti-Patterns to Avoid
203
+
204
+ - ❌ `git add .` or `git add -A` — always stage specific files by name
205
+ - ❌ `exit 1` in library code — use typed exceptions (already fixed in library-boundary-cleanup)
206
+ - ❌ `ENV['BRAND_PATH'] =` in any file — confirmed dead, being removed in B038
207
+ - ❌ `instance_double('StringForm')` — use full constant always
208
+ - ❌ Inline brand transformations — use BrandResolver
209
+ - ❌ Multiple `before` blocks in same RSpec context — merge them (RSpec/ScatteredSetup)
210
+ - ❌ `$?` for subprocess status — use `$CHILD_STATUS`
211
+
212
+ ---
213
+
214
+ ## Learnings
215
+
216
+ ### From library-boundary-cleanup (2026-03-20)
217
+
218
+ - **`instance_double` string form fails CI on Ubuntu.** Always use full constant: `instance_double(Fully::Qualified::ClassName)`.
219
+ - **`git add .` is the recurring staging bug.** Stage specific files by name. Always. Every commit.
220
+ - **`ENV['BRAND_PATH']` in bin/dam is dead code.** 10 assignments, 0 reads. Being removed in B038.
221
+ - **VatCLI rescue blocks catch DamError correctly.** `UsageError < DamError < StandardError` — all 17 rescue blocks catch it without modification.
222
+
223
+ ### From extract-vat-cli (2026-03-19)
224
+
225
+ - **Dirty working tree + kfix = accidental staging.** Run `git status` before every commit.
226
+ - **rubocop-disable directives become redundant when methods move.** Check for orphaned disable/enable pairs after extraction.
227
+ - **valid_brand? needs Config.brands mock.** Shared filesystem context only mocks SettingsConfig; Config.brands needs a separate mock.
228
+ - **S3ScanCommand#scan_all already rescues per-brand.** Per-brand exceptions are isolated by design.
229
+
230
+ ### From DAM Enhancement Sprint (Jan 2025)
231
+
232
+ - **BrandResolver is the critical path.** All dam commands flow through it.
233
+ - **`Config.configure` is memoized but called redundantly.** Don't add new calls.
234
+ - **Table format() pattern is non-obvious.** Headers misaligned 3× in UAT. Always verify with real data.
@@ -0,0 +1,51 @@
1
+ # IMPLEMENTATION_PLAN.md — env-dead-code-cleanup
2
+
3
+ **Goal**: Remove confirmed dead code (10× `ENV['BRAND_PATH']` in bin/dam) and strengthen s3_scan_command_spec data-value assertions. Closes B038 + B039 from the library-boundary-cleanup audit.
4
+ **Started**: 2026-03-20
5
+ **Target**: Both items complete; 861+ examples passing; rubocop 0 offenses; no regressions
6
+
7
+ ## Summary
8
+ - Total: 2 | Complete: 0 | In Progress: 2 | Pending: 0 | Failed: 0
9
+
10
+ ## Pending
11
+
12
+ ## In Progress
13
+ - [~] B038 — remove-env-dead-code — Remove all 10 `ENV['BRAND_PATH'] =` assignments from bin/dam
14
+ - [~] B039 — strengthen-s3-scan-spec — Replace `not_to be_empty` with field-value assertions; remove LocalSyncStatus stub
15
+
16
+ ## Complete
17
+
18
+ ## Failed / Needs Retry
19
+
20
+ ## Notes & Decisions
21
+
22
+ ### Wave Plan
23
+
24
+ **Wave 1 — B038 + B039 in parallel**
25
+ - B038 touches `bin/dam` only
26
+ - B039 touches `spec/appydave/tools/dam/s3_scan_command_spec.rb` only
27
+ - No shared files — safe to run in parallel
28
+
29
+ ### B038: All 10 ENV assignments confirmed dead (2026-03-20)
30
+
31
+ | Line | Method | Form |
32
+ |------|--------|------|
33
+ | 158 | s3_up_command | `options[:brand_path]` |
34
+ | 169 | s3_down_command | `options[:brand_path]` |
35
+ | 180 | s3_status_command | `options[:brand_path]` |
36
+ | 191 | s3_cleanup_remote_command | `options[:brand_path]` |
37
+ | 202 | s3_cleanup_local_command | `options[:brand_path]` |
38
+ | 213 | s3_archive_command | `options[:brand_path]` |
39
+ | 224 | s3_share_command | `options[:brand_path]` |
40
+ | 238 | s3_discover_command | `options[:brand_path]` |
41
+ | 285 | generate_single_manifest | `Config.brand_path(brand_arg)` |
42
+ | 332 | sync_ssd_command | `Config.brand_path(brand_arg)` |
43
+
44
+ - `grep -rn "BRAND_PATH" lib/ spec/` → 0 results (confirmed 2026-03-20)
45
+ - ManifestGenerator and SyncFromSsd do not read ENV['BRAND_PATH'] (confirmed 2026-03-20)
46
+
47
+ ### B039: What to strengthen in s3_scan_command_spec
48
+
49
+ - Replace `expect(project[:storage][:s3]).not_to be_empty` with `include(file_count: 3, total_bytes: 1_500_000)`
50
+ - Remove `allow(Appydave::Tools::Dam::LocalSyncStatus).to receive(:enrich!)` stub — let it run for real
51
+ - If LocalSyncStatus.enrich! needs the s3-staging path to exist, create it in the fixture setup
@@ -645,6 +645,12 @@ end
645
645
  - **`ENV['BRAND_PATH']` is set in 5 places in bin/dam.** Three are in parse methods (being extracted to B035). Two remain in `generate_single_manifest` and `sync_ssd_command` — out of scope for this campaign.
646
646
  - **Do NOT attempt B020 (split S3Operations) in this campaign.** Different class, different risk profile.
647
647
 
648
+ ### From library-boundary-cleanup (2026-03-20)
649
+
650
+ - **`instance_double` string form fails CI on Ubuntu.** Always use full constant: `instance_double(Fully::Qualified::ClassName)`. String form passes locally but Ubuntu CI enforces constant lookup. A CI failure after a green local run is almost always this.
651
+ - **`git add .` is the recurring staging bug.** Three campaigns have had accidental staging from `git add .`. Stage specific files by name: `git add lib/appydave/tools/dam/local_sync_status.rb spec/...`. Never `git add .` or `git add -A` in this repo.
652
+ - **`ENV['BRAND_PATH']` in bin/dam is dead code.** 10 assignments in bin/dam, 0 reads in lib/. S3Operations receives brand_path as a constructor parameter. Tracked as B038 for cleanup.
653
+
648
654
  ### From extract-vat-cli (2026-03-19)
649
655
 
650
656
  - **valid_brand? needs Config.brands mock.** The shared filesystem context only mocks `SettingsConfig`. When testing code that calls `Config.brands`, mock it separately: `allow(Appydave::Tools::Configuration::Config).to receive(:brands).and_return(...)`.
@@ -5,13 +5,13 @@
5
5
  **Target**: 4 items complete; 847+ examples passing; rubocop 0 offenses; no regressions
6
6
 
7
7
  ## Summary
8
- - Total: 4 | Complete: 3 | In Progress: 1 | Pending: 0 | Failed: 0
8
+ - Total: 4 | Complete: 4 | In Progress: 0 | Pending: 0 | Failed: 0
9
9
 
10
10
  ## Pending
11
11
 
12
12
  ## In Progress
13
13
  - [x] B036 — tests-s3-scan-command — 10 behaviour examples replacing 2 smoke tests (happy path, manifest missing, empty results, orphaned projects, scan_all partial). 861 examples, 0 failures. 86.43% coverage. v0.76.10. Commit: de9d118.
14
- - [~] B037 — tests-local-sync-status — Add :partial case, local_file_count assertion, Zone.Identifier exclusion, unknown format guard
14
+ - [x] B037 — tests-local-sync-status — 6 new examples: :partial (2), local_file_count in :synced (1), Zone.Identifier exclusion (2), unknown format guard (1). Source already had both features — tests only. CI fix: replaced string instance_double with full constant. v0.76.11. Commits: 3fddeff, 3bd417d.
15
15
 
16
16
  ## Complete
17
17
  - [x] B034 — extract-exit-calls — UsageError added to errors.rb; exit 1 replaced in s3_scan_command.rb (1) and s3_arg_parser.rb (4); show_share_usage_and_exit renamed. 847 examples, 0 failures. v0.76.8. Commit: 87bb43a.
@@ -0,0 +1,109 @@
1
+ # Assessment: library-boundary-cleanup
2
+
3
+ **Campaign**: library-boundary-cleanup
4
+ **Date**: 2026-03-19 → 2026-03-19
5
+ **Results**: 4 complete, 0 failed
6
+ **Final version**: v0.76.11 (from v0.76.7 baseline)
7
+ **Quality audits**: code-quality-audit ✅ | test-quality-audit ✅
8
+
9
+ ---
10
+
11
+ ## Results Summary
12
+
13
+ | Work Unit | Description | Result | Version |
14
+ |-----------|-------------|--------|---------|
15
+ | B034 | extract-exit-calls | ✅ Complete | v0.76.8 |
16
+ | B035 | extract-env-side-effect | ✅ Complete | v0.76.9 |
17
+ | B036 | tests-s3-scan-command | ✅ Complete | v0.76.10 |
18
+ | B037 | tests-local-sync-status | ✅ Complete | v0.76.11 |
19
+
20
+ **Test baseline:** 847 → 861+ examples (net +14), 0 failures, 86.43% line coverage
21
+
22
+ ---
23
+
24
+ ## What Worked Well
25
+
26
+ 1. **Wave plan held perfectly.** B034 → B035 → B036+B037 (parallel) ran with zero merge conflicts. Pre-reading the files before planning meant the sequencing constraints were exact.
27
+
28
+ 2. **B035 rubocop self-corrected.** Agent caught a `Lint/UselessAssignment` for the now-redundant `brand =` local variable that was only there to support the ENV assignment. Removed cleanly in the same commit.
29
+
30
+ 3. **LocalSyncStatus source already had the hard bits.** Zone.Identifier exclusion and `format` else-branch were already implemented — B037 only needed tests. Pre-reading confirmed this before writing any spec code.
31
+
32
+ 4. **VatCLI rescue chain worked exactly as predicted.** No rescue changes needed in bin/dam — `UsageError < DamError < StandardError` was caught by all 17 existing `rescue StandardError` blocks.
33
+
34
+ 5. **Code quality audit grade: HIGH.** 0 rubocop offenses, exception messages are actionable, ENV pattern in bin/dam is consistent across all 8 sites.
35
+
36
+ ---
37
+
38
+ ## What Didn't Work
39
+
40
+ 1. **B037 agent used `git add .` instead of staging specific files.** Accidentally included the B036 spec and IMPLEMENTATION_PLAN.md in its commit. Required a follow-up fix commit. (Recurring issue — pre-commit check needs to be more prominent in AGENTS.md.)
41
+
42
+ 2. **B036 CI failure on Ubuntu.** `instance_double('BrandsConfig')` (string form) failed double verification in CI but passed locally. Required a second `kfix` commit to replace with full constant `instance_double(Appydave::Tools::Configuration::Models::BrandsConfig)`. Ubuntu CI is stricter about constant resolution in instance_doubles.
43
+
44
+ 3. **ENV['BRAND_PATH'] is dead code.** The 10 `ENV['BRAND_PATH'] =` assignments in bin/dam (8 new from B035, 2 pre-existing) are never read anywhere in `lib/`. S3Operations receives `brand_path` as a constructor parameter. The ENV assignments preserved the original behaviour faithfully but the env var itself appears unused. Should be investigated and removed in a future cleanup.
45
+
46
+ ---
47
+
48
+ ## Key Learnings — Application
49
+
50
+ 1. **`instance_double` string form fails CI on Ubuntu.** Always use full constant form: `instance_double(Fully::Qualified::ClassName)`. The string form passes locally (RSpec doesn't resolve it) but Ubuntu CI enforces constant lookup.
51
+
52
+ 2. **`git add .` is the recurring staging bug.** Three campaigns now have had accidental staging from `git add .`. The AGENTS.md pre-commit rule needs to be in a more prominent position — not buried at the top, but repeated immediately before the commit step.
53
+
54
+ 3. **`ENV['BRAND_PATH']` may be vestigial.** Check whether any external consumers (config_loader, shell scripts, `.video-tools.env` loading) depend on it before removing. If confirmed unused: clean up the 10 assignments in bin/dam.
55
+
56
+ 4. **Read source before writing tests.** B037 avoided writing a Zone.Identifier exclusion to the source (it was already there) because AGENTS.md said to read the source first. Saved one unnecessary commit.
57
+
58
+ ---
59
+
60
+ ## Key Learnings — Ralph Loop
61
+
62
+ 1. **Extend mode is fast when the brief is complete.** The next-round-brief had exact file line numbers, precise changes, and confirmed dependency order. Planning took minutes, not a full session.
63
+
64
+ 2. **Wave 3 parallel worked cleanly.** B036 and B037 touched different spec files with no shared state. Both committed independently with no conflicts. The wave 3 parallel pattern is reliable for spec-only work.
65
+
66
+ 3. **Quality audit found real things.** ENV dead code finding and the B-grade test gaps (data-value assertions, LocalSyncStatus integration stub) are both actionable. Running audits before assessment is the right order.
67
+
68
+ ---
69
+
70
+ ## Code Quality Audit Findings
71
+
72
+ **Grade: HIGH / Production-ready**
73
+
74
+ - Exception hierarchy correct (`UsageError < DamError < StandardError`)
75
+ - Exception messages user-friendly and actionable with recovery steps
76
+ - ENV['BRAND_PATH'] pattern in VatCLI is consistent across all 8 call sites
77
+ - 0 rubocop offenses
78
+ - **One finding:** `ENV['BRAND_PATH']` set in 10 locations in bin/dam but never read in lib/ — dead code, low risk, cleanup candidate
79
+
80
+ ---
81
+
82
+ ## Test Quality Audit Findings
83
+
84
+ **Grade: B (80% regression catch rate)**
85
+
86
+ **s3_scan_command_spec — Grade B-:**
87
+ - Manifest file write verified via real I/O ✅
88
+ - Missing manifest raises ConfigurationError ✅
89
+ - Empty S3 results handled gracefully ✅
90
+ - Weakness: data-value assertions only check non-empty, not specific field values
91
+ - Weakness: LocalSyncStatus mocked in scan_single tests — integration gap
92
+
93
+ **local_sync_status_spec — Grade A-:**
94
+ - Zone.Identifier exclusion test is strong (real files, would catch regression) ✅
95
+ - All 4 status transitions tested ✅
96
+ - format method covers all branches ✅
97
+ - Weakness: nested directory traversal not tested; local_file_count = 0 edge case
98
+
99
+ ---
100
+
101
+ ## Suggestions for Next Campaign
102
+
103
+ 1. **Promote to BACKLOG:** `ENV['BRAND_PATH']` dead code cleanup — verify no consumers, then remove 10 assignments from bin/dam (1 work unit, low risk)
104
+
105
+ 2. **Promote to BACKLOG:** Strengthen s3_scan_command_spec data-value assertions + remove LocalSyncStatus stub to test integration (could fold into B020 S3Operations split campaign)
106
+
107
+ 3. **AGENTS.md update for next campaign:** Add `instance_double` rule ("always use full constant, never string form"). Move pre-commit `git status` check to a repeated callout immediately before commit instructions.
108
+
109
+ 4. **Next logical work:** B007 (parallel git/S3 status checks) and B020 (split S3Operations) are now unblocked — library boundaries are clean.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.76.11'
5
+ VERSION = '0.76.12'
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.76.11",
3
+ "version": "0.76.12",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.76.11
4
+ version: 0.76.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys
@@ -300,6 +300,8 @@ files:
300
300
  - docs/planning/bugfix-and-security/AGENTS.md
301
301
  - docs/planning/bugfix-and-security/IMPLEMENTATION_PLAN.md
302
302
  - docs/planning/bugfix-and-security/assessment.md
303
+ - docs/planning/env-dead-code-cleanup/AGENTS.md
304
+ - docs/planning/env-dead-code-cleanup/IMPLEMENTATION_PLAN.md
303
305
  - docs/planning/extract-vat-cli/AGENTS.md
304
306
  - docs/planning/extract-vat-cli/IMPLEMENTATION_PLAN.md
305
307
  - docs/planning/extract-vat-cli/assessment.md
@@ -312,6 +314,7 @@ files:
312
314
  - docs/planning/fr2-gpt-context-help/assessment.md
313
315
  - docs/planning/library-boundary-cleanup/AGENTS.md
314
316
  - docs/planning/library-boundary-cleanup/IMPLEMENTATION_PLAN.md
317
+ - docs/planning/library-boundary-cleanup/assessment.md
315
318
  - docs/planning/micro-cleanup/AGENTS.md
316
319
  - docs/planning/micro-cleanup/IMPLEMENTATION_PLAN.md
317
320
  - docs/planning/micro-cleanup/assessment.md