yam-flow 2.1.0 → 2.2.1

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.
package/AGENTS.md CHANGED
@@ -16,7 +16,8 @@
16
16
  14. For UI work, inspect real states and responsive behavior when feasible.
17
17
  15. For long-running processes, do not claim cleanup unless process exit is checked.
18
18
  16. When code, config, release metadata, documentation, or project artifacts changed, include a Study Note even if no yam skill was explicitly invoked.
19
- 17. Explain useful change insight for non-specialists: what the touched code or artifact does, what role it has, what was wrong or missing, what changed, what behavior is expected, one useful syntax/structure insight, what was verified, and what remains uncertain.
19
+ 17. Explain useful change insight for non-specialists: what the touched code or artifact does, what role it has, where it runs or is read, what was wrong or missing, what changed before/after, what behavior is expected, one useful syntax/structure insight, what was verified, and what remains uncertain.
20
20
  18. Use external references deliberately, preserve source clarity in research/proof notes, and rework good ideas into yam style.
21
21
  19. Treat security as the first project lens: identify sensitive surfaces early and guide safer defaults before convenience.
22
22
  20. Keep final reports short and concrete, but always include remaining tasks or state that none are meaningful.
23
+ 21. When relevant, include architecture hygiene in the Study Note: avoid dumping unrelated logic into `page.tsx`, one-off component CSS into `global.css`, or structured product data into broad DB `jsonb` blobs when existing project boundaries, scoped styles, typed tables, constraints, or indexes fit better.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,29 @@
2
2
 
3
3
  All notable changes to yam-flow are documented here.
4
4
 
5
+ ## v2.2.1 - 2026-07-09
6
+
7
+ ### Improved
8
+
9
+ - Strengthened `$scout` into a wider research harness with source mapping, evidence ledger, opposition pass, and blocked-source fallback guidance.
10
+ - Added `references/scout-wide-scan.md` for broad searches across tools, agent systems, protocols, harnesses, markets, and third-party ecosystems.
11
+ - Clarified that `insane-search` should be used as blocked-source acquisition for high-signal sources, not as Scout's default search path.
12
+ - Clarified that real subagent or parallel research lanes are explicit-only and should not turn ordinary scouting into `$mission`.
13
+
14
+ ## v2.2.0 - 2026-07-07
15
+
16
+ ### Added
17
+
18
+ - Added `yam study-note check` as a read-only Study Note Guard Lite for changed files and supplied final-report text.
19
+ - Added an opt-in `study-note` hook profile via `yam hook enable study-note --global` for prompt-time Study Note reminders without auto-generating or editing reports.
20
+ - Extended `yam loop report --json` with resume-ready handoff fields: touched/read/verified files, skipped checks, stop condition, resume hint, and readiness state.
21
+ - Added Ueye deep visual review fields for acceptance criteria, touched/read/verified files, skipped checks, residual risks, stop condition, resume hint, design-system evidence, implementation evidence, and state matrix.
22
+
23
+ ### Improved
24
+
25
+ - Strengthened Study Note v3 guidance for non-developer learning with execution point, before/after behavior, expected behavior, and architecture hygiene checks for `page.tsx`, `global.css`, and DB `jsonb` boundaries.
26
+ - Strengthened Ueye guidance so serious UI work can carry Deep-grade verification inside the Ueye route without requiring a separate Deep route.
27
+
5
28
  ## v2.1.0 - 2026-06-30
6
29
 
7
30
  ### Added
package/COMMANDS.md CHANGED
@@ -45,7 +45,7 @@ Opt-in visual evidence helpers:
45
45
  yam ueye preflight /path/to/project --json
46
46
  yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
47
47
  yam ueye compare --reference ./reference.png --actual .yam/screens/home.png
48
- yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --brief-dimension "primary CTA clarity" --constraint "mobile first" --review-session-id pricing-card-v1 --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --similar "overall hierarchy" --different "button glow intensity" --missing "mobile state" --design-quality needs-polish --json
48
+ yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --brief-dimension "primary CTA clarity" --constraint "mobile first" --acceptance-criterion "primary CTA remains visible on mobile" --design-system-evidence "uses existing button token" --implementation-evidence "browser screenshot reviewed" --state-check default:pass --state-check mobile:partial --skipped-check "hover state not checked on touch viewport" --residual-risk "tablet breakpoint still needs visual pass" --stop-condition "stop after primary states are checked and residual risk is recorded" --resume-hint "capture tablet screenshot next" --review-session-id pricing-card-v1 --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --similar "overall hierarchy" --different "button glow intensity" --missing "mobile state" --design-quality needs-polish --json
49
49
  yam ueye report --reference ./reference.png --actual .yam/screens/home.png --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --json
50
50
  yam media proof --requested --attempted --output ./generated.png --wait-loop --json
51
51
  yam proof --route ueye --truth partial --visual "browser/local screenshot comparison executed" --require-visual
@@ -148,7 +148,8 @@ yam tools doctor /path/to/project
148
148
  yam tools doctor /path/to/project --json
149
149
  yam context pressure /path/to/project --json
150
150
  yam cleanup scan /path/to/project --json
151
- yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
151
+ yam study-note check /path/to/project --text "Study Note: Touched code role before/after verification limits." --json
152
+ yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --touched-file src/bin/yam.ts --read-file README.md --verified-file scripts/cli-smoke.mjs --skipped-check "npm publish skipped by design" --stop-condition "stop after readiness evidence is recorded" --resume-hint "rerun release report after npm auth refresh" --readiness-state blocked --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
152
153
  yam proof /path/to/project
153
154
  yam proof --route deep --truth verified --command "npm run build: pass"
154
155
  yam proof --route ueye --truth verified --visual "reference image only"
@@ -196,12 +197,14 @@ Supported report shapes:
196
197
  - Runtime evidence mini: command/process, observation, cleanup, truth status, next action.
197
198
  - Patch queue lite: mission lane status, changed files, verification hint, rollback hint, truth status.
198
199
  - Verification Ladder: L0 stated, L1 inspected, L2 local check, L3 integrated, L4 release/runtime/visual proof, L5 bounded deep with stop condition and skipped/remaining work.
199
- - Loop report: intent, guided stage outcomes, evidence level/stamp, blockers, blocker kind, safe retry, next action, fix-first items, remaining tasks, recommended direction, blocked-by notes, owner route/scope, side effects, and study note.
200
- - Study note: short non-specialist explanation of the changed code/artifact, its role, what was wrong or missing, expected behavior, one syntax/structure insight, verification, and uncertainty.
200
+ - Loop report: intent, guided stage outcomes, touched/read/verified files, skipped checks, stop condition, resume hint, readiness state, evidence level/stamp, blockers, blocker kind, safe retry, next action, fix-first items, remaining tasks, recommended direction, blocked-by notes, owner route/scope, side effects, and study note.
201
+ - Study note: non-specialist explanation of the changed code/artifact, its role, execution point, before/after behavior, expected behavior, one syntax/structure insight, verification, uncertainty, and architecture hygiene around `page.tsx`, `global.css`, and DB `jsonb`.
202
+ - Study Note guard: read-only check for changed files and supplied final-report text; opt into prompt-time reminders with `yam hook enable study-note --global`.
201
203
  - Benchmark optimization loop lite: baseline, one change, rerun, keep/revert decision.
202
204
  - Structured diagnostic next action: severity, evidence, owner route, next action, truth status.
203
205
  - Ueye continuity/comparison: previous report, current report, comparison delta, design quality, next action.
204
206
  - Ueye design brief/anti-slop: brief dimensions, constraints, invented metrics, placeholder copy, generic visuals, and custom P0 blockers.
207
+ - Ueye deep visual review: acceptance criteria, touched/read/verified files, skipped checks, residual risks, stop condition, resume hint, design-system evidence, implementation evidence, and state matrix.
205
208
  - Context pressure: project pack age/size, memory summary, dirty scope, scripts, instruction surfaces, and route hint.
206
209
  - Cleanup scan: advisory-only list of confusing surfaces with destructive=false.
207
210
 
@@ -212,5 +215,7 @@ Advisory-only hook. It does not run checks or force routes.
212
215
  ```bash
213
216
  yam hook status --global
214
217
  yam hook enable lite --global
218
+ yam hook enable study-note --global
215
219
  yam hook disable lite --global
220
+ yam hook disable study-note --global
216
221
  ```
package/README.md CHANGED
@@ -134,6 +134,7 @@ yam tools doctor /path/to/project
134
134
  yam tools doctor /path/to/project --json
135
135
  yam context pressure /path/to/project --json
136
136
  yam cleanup scan /path/to/project --json
137
+ yam study-note check /path/to/project --text "Study Note: ..." --json
137
138
  yam proof /path/to/project
138
139
  yam proof write /path/to/project --route quick --truth verified --command "npm run verify:self: pass"
139
140
  yam proof --route ueye --truth verified --visual "reference image only"
@@ -141,17 +142,18 @@ yam proof --route ueye --truth partial --visual-provenance '{"source_kind":"refe
141
142
  yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
142
143
  yam ueye compare --reference ./reference.png --actual .yam/screens/home.png
143
144
  yam ueye preflight /path/to/project --json
144
- yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --app-surface codex-app --browser-surface in-app-browser --preserved-state --json
145
+ yam ueye report --reference ./reference.png --actual .yam/screens/home.png --preflight-id ueye-preflight-123 --p0-risk "mobile CTA may clip" --quality-gate-note "check CTA contrast before done" --acceptance-criterion "primary CTA remains visible on mobile" --state-check default:pass --state-check mobile:partial --implementation-evidence "browser screenshot reviewed" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --app-surface codex-app --browser-surface in-app-browser --preserved-state --json
145
146
  yam proof --route ueye --truth verified --visual "implementation screenshot evidence recorded" --design-completion '{"completion_claim":"done","has_implementation_screenshot":true,"design_quality":"pass","states_checked":true,"mobile_checked":true,"contrast_checked":true,"cta_checked":true,"direction_locked":true,"truth_status":"verified"}'
146
147
  yam media proof --requested --attempted --output ./generated.png --wait-loop --json
147
148
  yam proof --route mission --mission-envelope '{"agent_id":"implementer","assigned_scope":"target component","changed_files":["src/file.ts"],"verification_hint":"npm run typecheck","truth_status":"partial"}'
148
- yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
149
+ yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --evidence-level local --evidence-stamp "sha256:release-report" --touched-file src/bin/yam.ts --read-file README.md --verified-file scripts/cli-smoke.mjs --skipped-check "npm publish skipped by design" --stop-condition "stop after readiness evidence is recorded" --resume-hint "rerun release report after npm auth refresh" --readiness-state blocked --covered-requirement "release report is read-only" --uncovered-requirement "npm auth verified" --blocked-kind auth_blocked --failure-cause auth_token_invalid --safe-retry "retry after npm whoami succeeds" --recovery-hint "refresh npm auth, then rerun readiness checks" --fix-first-item "npm auth must be verified before publish" --remaining-task "rerun release report after auth refresh" --recommended-direction "fix npm auth first, then publish manually" --implementation-note "keep loop report read-only" --why-this-next "auth blocks public release claims" --blocked-by "npm whoami E401" --owner-route deep --owner-scope "release readiness only" --scope-owner deep --side-effect "no publish attempted" --avoidance-note "do not retry publish before npm auth is proven" --issue-code "src/bin/yam.ts release report" --issue-role "summarizes release readiness without publishing" --issue-symptom "npm auth failure needs clearer next action" --changed-code "yam loop report" --changed-role "records loop evidence and learning note" --change-summary "added a read-only loop artifact" --why-important "it helps users learn what changed without overclaiming verification" --learning-note "fix blockers before claiming done" --json
149
150
  yam release report --json
150
151
  yam safety "supabase db reset"
151
152
  yam detect /path/to/project
152
153
  yam pack /path/to/project
153
154
  yam hook status --global
154
155
  yam hook enable lite --global
156
+ yam hook enable study-note --global
155
157
  yam hook disable lite --global
156
158
  yam budget ueye
157
159
  yam measure ueye --files 5 --commands 2 --report-lines 12 --seconds 180
@@ -220,8 +222,9 @@ These shapes keep reports machine-readable without turning normal work into a he
220
222
  - Patch queue lite: `$mission` lane records with pending/applied/verified/reverted/blocked state, changed files, verification hint, rollback hint, truth status, and next action.
221
223
  - Verification Ladder: L0 stated, L1 inspected, L2 local check, L3 integrated, L4 release/runtime/visual proof, and L5 bounded deep. Heavier claims require heavier evidence, but stop conditions prevent endless proof loops.
222
224
  - Release report JSON: `yam release report --json` summarizes typecheck, forbidden-name scan, package boundary, registry status, CLI smoke, dist freshness, diagnostics, readiness receipt, and final truth status.
223
- - Loop report JSON: `yam loop report --json` records a read-only handoff artifact: guided stages, requirement coverage, evidence level/stamp, blocker kind, failure cause, safe retry, recovery hint, owner route/scope, side effects, next action, fix-first items, remaining tasks, recommended direction, implementation notes, blocked-by notes, avoidance note, tool intent, truth status, and study note.
224
- - Study note: `yam.study-note.v1` and `references/study-note.md` keep non-specialist explanations for what code/artifact changed, what role it plays, what was wrong or missing, what behavior is expected, one syntax/structure insight, what was verified, and what remains uncertain. Missing details stay in `limits` instead of being guessed.
225
+ - Loop report JSON: `yam loop report --json` records a read-only handoff artifact: guided stages, touched/read/verified files, skipped checks, stop condition, resume hint, readiness state, requirement coverage, evidence level/stamp, blocker kind, failure cause, safe retry, recovery hint, owner route/scope, side effects, next action, fix-first items, remaining tasks, recommended direction, implementation notes, blocked-by notes, avoidance note, tool intent, truth status, and study note.
226
+ - Study note: `yam.study-note.v1` and `references/study-note.md` keep non-specialist explanations for what code/artifact changed, what role it plays, where it runs, what changed from before to after, what behavior is expected, one syntax/structure insight, what was verified, and what remains uncertain. Missing details stay in `limits` instead of being guessed. Study Note v3 also asks whether work was dumped into `page.tsx`, `global.css`, or broad DB `jsonb` when a smaller component, style module/token, typed column, relation, or validation schema would teach and scale better.
227
+ - Study Note guard: `yam study-note check` is a read-only missing-note guard. It checks changed files against supplied final-report text and can be used directly or through the opt-in `yam hook enable study-note --global` advisory hook.
225
228
  - Avoidance note: loop reports may include one short mistake-to-avoid note, but durable memory stays explicit through `yam memory add`; `yam loop report` does not write `.yam/memory`.
226
229
  - Publish blocker evidence: release reports classify common npm auth, permission, OTP, immutable-version, cache, registry, and tarball failures into safe next actions.
227
230
  - Publish readiness evidence: release reports run read-only registry/auth/version probes, redact account/token details, keep npm publish outside the report, and include a `yam.release-readiness-receipt.v1` basis for the readiness judgment.
@@ -233,6 +236,7 @@ These shapes keep reports machine-readable without turning normal work into a he
233
236
  - Ueye surface context: `$ueye` run reports can record provider context, provider badge, execution surface, app surface, browser surface, control mode, preserved URL/state, and evidence id.
234
237
  - Ueye design completion gate: `$ueye` can stay fast for draft work, but a `done` claim is capped until implementation evidence, comparison/design-quality status, P0/P1 status, key states, mobile/responsive behavior, contrast/accessibility visuals, CTA affordance, and direction/reference-read proof are recorded when relevant.
235
238
  - Ueye design brief and anti-slop review: `$ueye` reports can record operator-provided brief dimensions, constraints, invented metrics, placeholder copy, generic visuals, and custom anti-slop blockers. P0 anti-slop findings block `done` claims.
239
+ - Ueye deep visual review: `$ueye` can record acceptance criteria, touched/read/verified files, skipped checks, residual risks, stop condition, resume hint, design-system evidence, implementation evidence, and a state matrix so serious UI work can carry Deep-grade verification without leaving the Ueye route.
236
240
 
237
241
  ## Ueye Capture And Compare
238
242
 
@@ -242,14 +246,14 @@ These shapes keep reports machine-readable without turning normal work into a he
242
246
  yam ueye capture --url http://localhost:3000 --out .yam/screens/home.png
243
247
  yam ueye compare --reference ./reference.png --actual .yam/screens/home.png --json
244
248
  yam ueye preflight . --json
245
- yam ueye report --reference ./reference.png --actual .yam/screens/home.png --brief-dimension "primary CTA clarity" --constraint "mobile first" --anti-slop "placeholder copy remains" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --preserved-state --json
249
+ yam ueye report --reference ./reference.png --actual .yam/screens/home.png --brief-dimension "primary CTA clarity" --constraint "mobile first" --anti-slop "placeholder copy remains" --acceptance-criterion "pricing card CTA remains visible on mobile" --design-system-evidence "uses existing button token" --implementation-evidence "browser screenshot reviewed" --state-check default:pass --state-check mobile:partial --skipped-check "hover state not checked on touch viewport" --residual-risk "tablet breakpoint still needs visual pass" --stop-condition "stop after primary states are checked and residual risk is recorded" --resume-hint "capture tablet screenshot next" --completion-claim done --design-quality pass --direction-locked --reference-read --states-checked --mobile-checked --contrast-checked --cta-checked --provider-context local --execution-surface in-app-browser --browser-surface in-app-browser --preserved-state --json
246
250
  ```
247
251
 
248
252
  `capture` uses a Playwright install from the current project when present, then falls back to the package context. It does not install browsers or add runtime dependencies by itself. If capture is unavailable, the visual claim stays `partial` or `blocked` until a real screenshot is supplied.
249
253
 
250
254
  `compare` is local-only and dependency-free. It records file hashes, dimensions, comparison result, and proof-ready visual provenance. Exact image matches can be `verified`; different screenshots stay `partial` so visual parity is not overclaimed.
251
255
 
252
- `report` gathers reference sources, implementation screenshots, comparison result, continuity fields, design quality judgment, design completion gate, surface context, and next action into one compact proof-ready JSON object. Draft and needs-polish work can stay fast; `--completion-claim done` turns on the stricter design gate.
256
+ `report` gathers reference sources, implementation screenshots, comparison result, continuity fields, design quality judgment, design completion gate, deep visual review, surface context, and next action into one compact proof-ready JSON object. Draft and needs-polish work can stay fast; `--completion-claim done` turns on the stricter design gate.
253
257
 
254
258
  `preflight` does not claim visual verification. It is a pre-work checklist for reference source, target states, mobile/responsive needs, CTA/contrast/accessibility risk, screenshot availability, and likely P0/P1 candidates.
255
259
 
package/dist/bin/yam.js CHANGED
@@ -50,6 +50,7 @@ const PROJECT_PACK = 'yam.project.md';
50
50
  const LEGACY_PROJECT_PACK = 'timeto.project.md';
51
51
  const PACK_STALE_DAYS = 30;
52
52
  const YAM_LITE_HOOK_COMMAND = `node ${path.join(ROOT, 'dist', 'bin', 'yam.js')} hook run lite`;
53
+ const YAM_STUDY_NOTE_HOOK_COMMAND = `node ${path.join(ROOT, 'dist', 'bin', 'yam.js')} hook run study-note`;
53
54
  const REQUIRED_PACK_SECTIONS = [
54
55
  'Product Direction',
55
56
  'UI Direction',
@@ -122,6 +123,7 @@ Usage:
122
123
  yam tools doctor [dir]
123
124
  yam proof [dir|--from file] [--route route] [--truth status] [--command text] [--evidence text]
124
125
  yam proof write [dir] [--format json|md] [--out file] [--route route] [--truth status] [--command text]
126
+ yam study-note check [dir] [--report file|--text text] [--json]
125
127
  yam loop report [--route route] [--intent text] [--stage id:status:note] [--evidence text] [--json]
126
128
  yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
127
129
  yam ueye compare --reference ref.png --actual screenshot.png [--json]
@@ -134,7 +136,7 @@ Usage:
134
136
  yam release report [--json]
135
137
  yam safety [text...]
136
138
  yam memory <init|add|list|summary|resolve> [dir] [options]
137
- yam hook <status|enable|disable|run> [lite] [--global|--project dir]
139
+ yam hook <status|enable|disable|run> [lite|study-note] [--global|--project dir]
138
140
  yam template <project|ueye|mission|proof|tuning>
139
141
  yam tune-log [dir]
140
142
  yam install
@@ -531,6 +533,12 @@ function normalizeLoopEvidenceLevelFlag(value = '') {
531
533
  return text;
532
534
  return 'none';
533
535
  }
536
+ function normalizeReadinessStateFlag(value = '') {
537
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
538
+ if (['usable', 'degraded', 'blocked', 'unknown'].includes(text))
539
+ return text;
540
+ return 'unknown';
541
+ }
534
542
  function uniqueNextActionDetails(actions = []) {
535
543
  const seen = new Set();
536
544
  const unique = [];
@@ -708,6 +716,124 @@ async function cleanup(args = []) {
708
716
  console.error(`unknown cleanup command: ${subcommand}`);
709
717
  return cleanupUsage();
710
718
  }
719
+ async function studyNote(args = []) {
720
+ const subcommand = args[0] || 'help';
721
+ if (subcommand === 'help' || subcommand === '--help' || subcommand === '-h')
722
+ return studyNoteUsage();
723
+ if (subcommand === 'check')
724
+ return studyNoteCheck(args.slice(1));
725
+ console.error(`unknown study-note command: ${subcommand}`);
726
+ return studyNoteUsage();
727
+ }
728
+ function studyNoteUsage() {
729
+ console.log(`yam study-note
730
+
731
+ Usage:
732
+ yam study-note check [dir] [--report file|--text text] [--json]
733
+
734
+ Notes:
735
+ Read-only guard. It checks whether changed work has a Study Note and whether relevant UI/CSS/DB hygiene was reported.
736
+ It does not generate, edit, or infer the Study Note for you.
737
+ `);
738
+ }
739
+ async function studyNoteCheck(args = []) {
740
+ const flags = parseSimpleFlags(args, new Set(['report', 'text', 'json']));
741
+ const dir = path.resolve(firstPositional(args) || process.cwd());
742
+ const changedFiles = await gitChangedFiles(dir);
743
+ const reportText = await readStudyNoteReportText(flags, dir);
744
+ const needsStudyNote = changedFiles.length > 0;
745
+ const hygieneRequirements = studyNoteHygieneRequirements(changedFiles);
746
+ const checks = [
747
+ studyNoteGuardCheck('changed_files', needsStudyNote ? 'pass' : 'skipped', needsStudyNote ? 'changed files detected; Study Note is required before final completion' : 'no changed files detected'),
748
+ studyNoteGuardCheck('study_note_present', !needsStudyNote || hasStudyNoteMarker(reportText) ? 'pass' : 'fail', 'final report should include a Study Note when project artifacts changed'),
749
+ studyNoteGuardCheck('role_or_responsibility', !needsStudyNote || /(\brole\b|\bresponsib|\bdoes\b|역할|기능)/i.test(reportText) ? 'pass' : 'fail', 'Study Note should explain what the touched code/artifact does'),
750
+ studyNoteGuardCheck('before_after_or_change', !needsStudyNote || /(\bbefore\b|\bafter\b|before\/after|changed|change meaning|바뀌|변경|수정)/i.test(reportText) ? 'pass' : 'fail', 'Study Note should explain what changed from before to after'),
751
+ studyNoteGuardCheck('verification_or_limits', !needsStudyNote || /(verification|verified|checked|limits|uncertain|검증|확인|한계|모르는)/i.test(reportText) ? 'pass' : 'fail', 'Study Note should say what was checked and what remains uncertain')
752
+ ];
753
+ for (const requirement of hygieneRequirements) {
754
+ checks.push(studyNoteGuardCheck(requirement.id, requirementSatisfied(reportText, requirement), requirement.note));
755
+ }
756
+ const blockers = checks.filter((check) => check.status === 'fail').map((check) => `${check.id}: ${check.next_action}`);
757
+ const result = {
758
+ schema: 'yam.study-note-guard.v1',
759
+ generated_at: new Date().toISOString(),
760
+ project: dir,
761
+ changed_files: changedFiles,
762
+ changed_file_count: changedFiles.length,
763
+ report_source: flags.report ? path.resolve(dir, String(flags.report)) : flags.text ? 'inline_text' : 'not_provided',
764
+ checks,
765
+ blockers,
766
+ next_action: blockers[0] || (needsStudyNote ? 'Study Note guard passed for the supplied report text' : 'no Study Note required because no changed files were detected'),
767
+ truth_status: blockers.length ? 'blocked' : needsStudyNote ? 'verified' : 'skipped'
768
+ };
769
+ printJsonOrHuman(result, Boolean(flags.json), 'Study Note guard');
770
+ if (blockers.length)
771
+ process.exitCode = 1;
772
+ }
773
+ function firstPositional(args = []) {
774
+ for (let index = 0; index < args.length; index += 1) {
775
+ const arg = String(args[index] || '');
776
+ if (arg.startsWith('--')) {
777
+ if (!arg.includes('=') && !['--json'].includes(arg))
778
+ index += 1;
779
+ continue;
780
+ }
781
+ if (arg === 'check')
782
+ continue;
783
+ return arg;
784
+ }
785
+ return '';
786
+ }
787
+ async function gitChangedFiles(dir) {
788
+ const output = runReadOnlyCommandIn(dir, 'git', ['status', '--short']);
789
+ return output
790
+ .split(/\r?\n/)
791
+ .filter(Boolean)
792
+ .map((line) => line.replace(/^..\s+/, '').replace(/^.* -> /, ''))
793
+ .map((line) => line.trim())
794
+ .filter((file) => file && !file.startsWith('dist/') && !file.endsWith('.tgz'));
795
+ }
796
+ async function readStudyNoteReportText(flags, dir) {
797
+ if (flags.text)
798
+ return String(flags.text || '');
799
+ if (!flags.report)
800
+ return '';
801
+ const file = path.resolve(dir, String(flags.report));
802
+ try {
803
+ return await fsp.readFile(file, 'utf8');
804
+ }
805
+ catch {
806
+ return '';
807
+ }
808
+ }
809
+ function hasStudyNoteMarker(text = '') {
810
+ return /(study note|study-note|학습\s*노트|스터디\s*노트)/i.test(text);
811
+ }
812
+ function studyNoteGuardCheck(id, status, nextAction) {
813
+ return {
814
+ id,
815
+ status,
816
+ next_action: nextAction,
817
+ truth_status: status === 'pass' ? 'verified' : status === 'fail' ? 'blocked' : status === 'skipped' ? 'skipped' : 'partial'
818
+ };
819
+ }
820
+ function studyNoteHygieneRequirements(files = []) {
821
+ const requirements = [];
822
+ if (files.some((file) => /(^|\/)page\.tsx$/i.test(file))) {
823
+ requirements.push({ id: 'page_tsx_hygiene', terms: ['page.tsx', 'component', 'hook', 'helper', 'server action', 'route'], note: 'Study Note should say whether page.tsx stayed focused or needs component/hook/helper/server-action separation' });
824
+ }
825
+ if (files.some((file) => /(^|\/)global\.css$/i.test(file))) {
826
+ requirements.push({ id: 'global_css_hygiene', terms: ['global.css', 'token', 'component', 'scoped', 'module', 'utility'], note: 'Study Note should say whether CSS belongs globally or should move to tokens/scoped/component styles' });
827
+ }
828
+ if (files.some((file) => /(migration|schema|db|database|sql|prisma|drizzle|supabase)/i.test(file))) {
829
+ requirements.push({ id: 'jsonb_hygiene', terms: ['jsonb', 'column', 'table', 'constraint', 'index', 'schema', 'relation'], note: 'Study Note should say whether structured product data belongs in typed columns/tables/constraints/indexes instead of broad DB jsonb' });
830
+ }
831
+ return requirements;
832
+ }
833
+ function requirementSatisfied(text = '', requirement) {
834
+ const normalized = String(text || '').toLowerCase();
835
+ return requirement.terms.some((term) => normalized.includes(term.toLowerCase())) ? 'pass' : 'fail';
836
+ }
711
837
  function cleanupUsage() {
712
838
  console.log(`yam cleanup
713
839
 
@@ -1271,20 +1397,20 @@ function hookUsage() {
1271
1397
 
1272
1398
  Usage:
1273
1399
  yam hook status [--global|--project dir]
1274
- yam hook enable lite [--global|--project dir]
1275
- yam hook disable [lite] [--global|--project dir]
1276
- yam hook run lite
1400
+ yam hook enable <lite|study-note> [--global|--project dir]
1401
+ yam hook disable [lite|study-note] [--global|--project dir]
1402
+ yam hook run <lite|study-note>
1277
1403
 
1278
1404
  Notes:
1279
- yam-lite is opt-in and advisory-only. It does not run checks, tmux, subagents, or proof gates.
1405
+ hooks are opt-in and advisory-only. They do not run tmux, subagents, or proof gates.
1280
1406
  `);
1281
1407
  }
1282
1408
  function parseHookArgs(args = []) {
1283
1409
  const result = { mode: 'project', projectDir: process.cwd(), profile: 'lite' };
1284
1410
  for (let index = 0; index < args.length; index += 1) {
1285
1411
  const arg = args[index];
1286
- if (arg === 'lite') {
1287
- result.profile = 'lite';
1412
+ if (arg === 'lite' || arg === 'study-note') {
1413
+ result.profile = arg;
1288
1414
  }
1289
1415
  else if (arg === '--global') {
1290
1416
  result.mode = 'global';
@@ -1309,13 +1435,19 @@ function hookPathFor(parsed) {
1309
1435
  function isYamLiteHook(handler = {}) {
1310
1436
  return handler?.type === 'command' && String(handler.command || '').includes('yam.js hook run lite');
1311
1437
  }
1312
- function stripYamLiteHooks(config = {}) {
1438
+ function isYamStudyNoteHook(handler = {}) {
1439
+ return handler?.type === 'command' && String(handler.command || '').includes('yam.js hook run study-note');
1440
+ }
1441
+ function isYamHookProfile(handler = {}, profile = 'lite') {
1442
+ return profile === 'study-note' ? isYamStudyNoteHook(handler) : isYamLiteHook(handler);
1443
+ }
1444
+ function stripYamHooks(config = {}, profile = 'lite') {
1313
1445
  const next = { ...config };
1314
1446
  for (const event of Object.keys(next)) {
1315
1447
  const entries = Array.isArray(next[event]) ? next[event] : [];
1316
1448
  const keptEntries = [];
1317
1449
  for (const entry of entries) {
1318
- const hooks = Array.isArray(entry?.hooks) ? entry.hooks.filter((handler) => !isYamLiteHook(handler)) : [];
1450
+ const hooks = Array.isArray(entry?.hooks) ? entry.hooks.filter((handler) => !isYamHookProfile(handler, profile)) : [];
1319
1451
  const rest = { ...entry, hooks };
1320
1452
  if (hooks.length > 0)
1321
1453
  keptEntries.push(rest);
@@ -1327,14 +1459,14 @@ function stripYamLiteHooks(config = {}) {
1327
1459
  }
1328
1460
  return next;
1329
1461
  }
1330
- function withYamLiteHook(config = {}) {
1331
- const next = stripYamLiteHooks(config);
1462
+ function withYamHook(config = {}, profile = 'lite') {
1463
+ const next = stripYamHooks(config, profile);
1332
1464
  const event = 'UserPromptSubmit';
1333
1465
  const entry = {
1334
1466
  hooks: [
1335
1467
  {
1336
1468
  type: 'command',
1337
- command: YAM_LITE_HOOK_COMMAND,
1469
+ command: profile === 'study-note' ? YAM_STUDY_NOTE_HOOK_COMMAND : YAM_LITE_HOOK_COMMAND,
1338
1470
  timeout: 5
1339
1471
  }
1340
1472
  ]
@@ -1346,26 +1478,29 @@ async function hookStatus(args = []) {
1346
1478
  const parsed = parseHookArgs(args);
1347
1479
  const target = hookPathFor(parsed);
1348
1480
  const config = await readJsonOrDefault(target, {});
1349
- const enabled = hookConfigHasYamLite(config);
1350
- console.log(`yam-lite hook: ${enabled ? 'enabled' : 'disabled'}`);
1481
+ console.log(`yam-lite hook: ${hookConfigHasProfile(config, 'lite') ? 'enabled' : 'disabled'}`);
1482
+ console.log(`yam-study-note hook: ${hookConfigHasProfile(config, 'study-note') ? 'enabled' : 'disabled'}`);
1351
1483
  console.log(`scope: ${parsed.mode}`);
1352
1484
  console.log(`file: ${target}`);
1353
1485
  }
1354
1486
  function hookConfigHasYamLite(config = {}) {
1487
+ return hookConfigHasProfile(config, 'lite');
1488
+ }
1489
+ function hookConfigHasProfile(config = {}, profile = 'lite') {
1355
1490
  return Object.values(config).some((entries) => Array.isArray(entries) && entries.some((entry) => {
1356
- return Array.isArray(entry?.hooks) && entry.hooks.some(isYamLiteHook);
1491
+ return Array.isArray(entry?.hooks) && entry.hooks.some((handler) => isYamHookProfile(handler, profile));
1357
1492
  }));
1358
1493
  }
1359
1494
  async function hookEnable(args = []) {
1360
1495
  const parsed = parseHookArgs(args);
1361
- if (parsed.profile !== 'lite') {
1362
- console.error('Only yam-lite hook is supported: yam hook enable lite');
1496
+ if (!['lite', 'study-note'].includes(parsed.profile)) {
1497
+ console.error('Only lite and study-note hooks are supported: yam hook enable <lite|study-note>');
1363
1498
  process.exitCode = 1;
1364
1499
  return;
1365
1500
  }
1366
1501
  const target = hookPathFor(parsed);
1367
1502
  const current = await readJsonOrDefault(target, {});
1368
- const next = withYamLiteHook(current);
1503
+ const next = withYamHook(current, parsed.profile);
1369
1504
  await fsp.mkdir(path.dirname(target), { recursive: true });
1370
1505
  if (await exists(target)) {
1371
1506
  const backup = `${target}.yam-backup-${timestampId()}`;
@@ -1373,29 +1508,29 @@ async function hookEnable(args = []) {
1373
1508
  console.log(`backup: ${backup}`);
1374
1509
  }
1375
1510
  await fsp.writeFile(target, `${JSON.stringify(next, null, 2)}\n`);
1376
- console.log(`yam-lite hook enabled (${parsed.mode}): ${target}`);
1511
+ console.log(`yam-${parsed.profile} hook enabled (${parsed.mode}): ${target}`);
1377
1512
  console.log('Restart Codex or start a new thread if the app does not pick up hook changes immediately.');
1378
1513
  }
1379
1514
  async function hookDisable(args = []) {
1380
1515
  const parsed = parseHookArgs(args);
1381
1516
  const target = hookPathFor(parsed);
1382
1517
  const current = await readJsonOrDefault(target, {});
1383
- if (!hookConfigHasYamLite(current)) {
1384
- console.log(`yam-lite hook already disabled (${parsed.mode}): ${target}`);
1518
+ if (!hookConfigHasProfile(current, parsed.profile)) {
1519
+ console.log(`yam-${parsed.profile} hook already disabled (${parsed.mode}): ${target}`);
1385
1520
  return;
1386
1521
  }
1387
- const next = stripYamLiteHooks(current);
1522
+ const next = stripYamHooks(current, parsed.profile);
1388
1523
  if (Object.keys(next).length === 0) {
1389
1524
  await rmrf(target);
1390
1525
  }
1391
1526
  else {
1392
1527
  await fsp.writeFile(target, `${JSON.stringify(next, null, 2)}\n`);
1393
1528
  }
1394
- console.log(`yam-lite hook disabled (${parsed.mode}): ${target}`);
1529
+ console.log(`yam-${parsed.profile} hook disabled (${parsed.mode}): ${target}`);
1395
1530
  }
1396
1531
  async function hookRun(args = []) {
1397
1532
  const profile = args[0] || 'lite';
1398
- if (profile !== 'lite') {
1533
+ if (!['lite', 'study-note'].includes(profile)) {
1399
1534
  console.log(JSON.stringify({ continue: true }));
1400
1535
  return;
1401
1536
  }
@@ -1403,7 +1538,9 @@ async function hookRun(args = []) {
1403
1538
  const event = input?.hook_event_name || input?.hookEventName || input?.event || 'UserPromptSubmit';
1404
1539
  const cwd = String(input?.cwd || process.cwd());
1405
1540
  const prompt = extractPrompt(input);
1406
- const additionalContext = await buildYamLiteContext({ cwd, prompt });
1541
+ const additionalContext = profile === 'study-note'
1542
+ ? await buildStudyNoteHookContext({ cwd })
1543
+ : await buildYamLiteContext({ cwd, prompt });
1407
1544
  const output = {
1408
1545
  continue: true,
1409
1546
  hookSpecificOutput: {
@@ -1461,6 +1598,26 @@ async function buildYamLiteContext({ cwd, prompt }) {
1461
1598
  lines.push(routeHint);
1462
1599
  return lines.join('\n');
1463
1600
  }
1601
+ async function buildStudyNoteHookContext({ cwd }) {
1602
+ const dir = path.resolve(cwd || process.cwd());
1603
+ const changedFiles = await gitChangedFiles(dir);
1604
+ const lines = [
1605
+ 'yam Study Note guard active: if this turn changes code, config, release metadata, docs, or project artifacts, include a Study Note in the final response.'
1606
+ ];
1607
+ if (!changedFiles.length) {
1608
+ lines.push('No changed files were detected at prompt time; if you change artifacts during this turn, add the Study Note before final.');
1609
+ return lines.join('\n');
1610
+ }
1611
+ lines.push(`Changed files detected (${Math.min(changedFiles.length, 8)} shown): ${changedFiles.slice(0, 8).join(', ')}`);
1612
+ lines.push('Study Note minimum: touched code/artifact, role, execution point, before/after change, expected behavior, one syntax/structure insight, verification, and limits.');
1613
+ const hygiene = studyNoteHygieneRequirements(changedFiles);
1614
+ if (hygiene.length) {
1615
+ lines.push(`Architecture hygiene required: ${hygiene.map((item) => item.id).join(', ')}.`);
1616
+ lines.push('Report whether the change avoided dumping unrelated logic into page.tsx, one-off CSS into global.css, or structured product data into broad DB jsonb.');
1617
+ }
1618
+ lines.push('This hook is advisory; it does not generate or edit the Study Note.');
1619
+ return lines.join('\n');
1620
+ }
1464
1621
  function yamLiteRouteHint(prompt = '') {
1465
1622
  const text = String(prompt || '').toLowerCase();
1466
1623
  if (!text)
@@ -2023,13 +2180,13 @@ function loopUsage() {
2023
2180
  Read-only loop artifact helpers. A loop report records intent, stages, evidence, blockers, next action, handoff fields, and a short study note. It does not run agents, start processes, publish packages, or write files.
2024
2181
 
2025
2182
  Usage:
2026
- yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--evidence-level none|fixture|smoke|local|real] [--evidence-stamp text] [--source-digest text] [--covered-requirement text] [--uncovered-requirement text] [--blocked text] [--blocked-kind text] [--failure-cause text] [--safe-retry text] [--recovery-hint text] [--fix-first-item text] [--remaining-task text] [--recommended-direction text] [--implementation-note text] [--why-this-next text] [--blocked-by text] [--owner-route route] [--owner-scope text] [--scope-owner text] [--side-effect text] [--avoidance-note text] [--truth status] [--intent-label read_only|write|destructive|runtime|visual|publish] [--issue-code text] [--issue-role text] [--issue-symptom text] [--changed-code text] [--changed-role text] [--change-summary text] [--why-important text] [--learning-note text] [--json]
2183
+ yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--evidence-level none|fixture|smoke|local|real] [--evidence-stamp text] [--source-digest text] [--touched-file file] [--read-file file] [--verified-file file] [--skipped-check text] [--stop-condition text] [--resume-hint text] [--readiness-state usable|degraded|blocked|unknown] [--covered-requirement text] [--uncovered-requirement text] [--blocked text] [--blocked-kind text] [--failure-cause text] [--safe-retry text] [--recovery-hint text] [--fix-first-item text] [--remaining-task text] [--recommended-direction text] [--implementation-note text] [--why-this-next text] [--blocked-by text] [--owner-route route] [--owner-scope text] [--scope-owner text] [--side-effect text] [--avoidance-note text] [--truth status] [--intent-label read_only|write|destructive|runtime|visual|publish] [--issue-code text] [--issue-role text] [--issue-symptom text] [--changed-code text] [--changed-role text] [--change-summary text] [--why-important text] [--learning-note text] [--json]
2027
2184
  `);
2028
2185
  }
2029
2186
  async function loopReport(args = []) {
2030
2187
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
2031
2188
  return loopUsage();
2032
- const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'stage-convention', 'evidence', 'evidence-level', 'evidence-stamp', 'source-digest', 'covered-requirement', 'uncovered-requirement', 'blocked', 'blocker', 'blocked-kind', 'failure-cause', 'next-action', 'safe-retry', 'recovery-hint', 'fix-first-item', 'remaining-task', 'recommended-direction', 'direction', 'implementation-note', 'why-this-next', 'blocked-by', 'owner-route', 'owner-scope', 'scope-owner', 'owner', 'scope', 'side-effect', 'avoidance-note', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
2189
+ const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'stage-convention', 'evidence', 'evidence-level', 'evidence-stamp', 'source-digest', 'touched-file', 'read-file', 'verified-file', 'skipped-check', 'stop-condition', 'resume-hint', 'readiness-state', 'covered-requirement', 'uncovered-requirement', 'blocked', 'blocker', 'blocked-kind', 'failure-cause', 'next-action', 'safe-retry', 'recovery-hint', 'fix-first-item', 'remaining-task', 'recommended-direction', 'direction', 'implementation-note', 'why-this-next', 'blocked-by', 'owner-route', 'owner-scope', 'scope-owner', 'owner', 'scope', 'side-effect', 'avoidance-note', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
2033
2190
  const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
2034
2191
  const report = buildLoopReport({
2035
2192
  route: normalizeRoute(flags.route) || String(flags.route || ''),
@@ -2041,6 +2198,13 @@ async function loopReport(args = []) {
2041
2198
  evidence_level: normalizeLoopEvidenceLevelFlag(flags.evidence_level),
2042
2199
  evidence_stamp: String(flags.evidence_stamp || ''),
2043
2200
  source_digest: String(flags.source_digest || ''),
2201
+ touched_files: arrayFlag(flags.touched_file),
2202
+ read_files: arrayFlag(flags.read_file),
2203
+ verified_files: arrayFlag(flags.verified_file),
2204
+ skipped_checks: arrayFlag(flags.skipped_check),
2205
+ stop_condition: String(flags.stop_condition || ''),
2206
+ resume_hint: String(flags.resume_hint || ''),
2207
+ readiness_state: normalizeReadinessStateFlag(flags.readiness_state),
2044
2208
  covered_requirements: arrayFlag(flags.covered_requirement),
2045
2209
  uncovered_requirements: arrayFlag(flags.uncovered_requirement),
2046
2210
  blockers,
@@ -2099,7 +2263,7 @@ Usage:
2099
2263
  yam ueye capture --url URL --out screenshot.png [--viewport 1440x900] [--full-page] [--json]
2100
2264
  yam ueye compare --reference ref.png --actual screenshot.png [--json]
2101
2265
  yam ueye preflight [dir] [--json]
2102
- yam ueye report [--reference ref.png] [--actual screenshot.png] [--preflight-id id] [--p0-risk text] [--quality-gate-note text] [--brief-dimension text] [--constraint text] [--anti-slop text] [--invented-metric] [--placeholder-copy] [--generic-visual] [--review-session-id id] [--provider-context local] [--execution-surface in-app-browser] [--app-surface codex-app] [--browser-surface in-app-browser] [--control-mode manual|automated] [--preserved-state] [--preserved-url URL] [--completion-claim draft|needs-polish|done] [--strict] [--design-score n] [--p0 text] [--p1 text] [--states-checked] [--mobile-checked] [--contrast-checked] [--similar text] [--different text] [--missing text] [--resolved text] [--new-finding text] [--still-open text] [--regression text] [--viewport 1440x900] [--state default] [--design-quality pass|needs-polish|fails|not-checked] [--json]
2266
+ yam ueye report [--reference ref.png] [--actual screenshot.png] [--preflight-id id] [--p0-risk text] [--quality-gate-note text] [--brief-dimension text] [--constraint text] [--anti-slop text] [--invented-metric] [--placeholder-copy] [--generic-visual] [--acceptance-criterion text] [--touched-file file] [--read-file file] [--verified-file file] [--skipped-check text] [--residual-risk text] [--stop-condition text] [--resume-hint text] [--deep-visual-check text] [--design-system-evidence text] [--implementation-evidence text] [--state-check default:pass] [--review-session-id id] [--provider-context local] [--execution-surface in-app-browser] [--app-surface codex-app] [--browser-surface in-app-browser] [--control-mode manual|automated] [--preserved-state] [--preserved-url URL] [--completion-claim draft|needs-polish|done] [--strict] [--design-score n] [--p0 text] [--p1 text] [--states-checked] [--mobile-checked] [--contrast-checked] [--similar text] [--different text] [--missing text] [--resolved text] [--new-finding text] [--still-open text] [--regression text] [--viewport 1440x900] [--state default] [--design-quality pass|needs-polish|fails|not-checked] [--json]
2103
2267
 
2104
2268
  Notes:
2105
2269
  capture uses a locally available Playwright install when present. It does not download browsers or install dependencies.
@@ -2340,7 +2504,7 @@ async function ueyeCompare(args = []) {
2340
2504
  async function ueyeReport(args = []) {
2341
2505
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
2342
2506
  return ueyeUsage();
2343
- const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'capture-backend', 'compare-backend', 'design-quality', 'blocked-reason', 'next-action', 'next-visual-action', 'review-session-id', 'preflight-id', 'p0-risk', 'quality-gate-note', 'brief-dimension', 'constraint', 'anti-slop', 'invented-metric', 'placeholder-copy', 'generic-visual', 'reference-id', 'screenshot-id', 'previous-screenshot-id', 'current-screenshot-id', 'previous-report', 'comparison-notes', 'similar', 'different', 'missing', 'resolved', 'new-finding', 'still-open', 'regression', 'viewport', 'state', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'url', 'evidence-id', 'completion-claim', 'completion-status', 'gate-mode', 'strict', 'design-score', 'min-design-score', 'p0', 'p1', 'open-p0', 'open-p1', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read', 'comparison-result', 'json']));
2507
+ const flags = parseSimpleFlags(args, new Set(['reference', 'ref', 'actual', 'screenshot', 'capture-backend', 'compare-backend', 'design-quality', 'blocked-reason', 'next-action', 'next-visual-action', 'review-session-id', 'preflight-id', 'p0-risk', 'quality-gate-note', 'brief-dimension', 'constraint', 'anti-slop', 'invented-metric', 'placeholder-copy', 'generic-visual', 'acceptance-criterion', 'touched-file', 'read-file', 'verified-file', 'skipped-check', 'residual-risk', 'stop-condition', 'resume-hint', 'deep-visual-check', 'design-system-evidence', 'implementation-evidence', 'state-check', 'reference-id', 'screenshot-id', 'previous-screenshot-id', 'current-screenshot-id', 'previous-report', 'comparison-notes', 'similar', 'different', 'missing', 'resolved', 'new-finding', 'still-open', 'regression', 'viewport', 'state', 'provider-context', 'provider-badge', 'execution-surface', 'app-surface', 'browser-surface', 'control-mode', 'preserved-state', 'preserved-url', 'url', 'evidence-id', 'completion-claim', 'completion-status', 'gate-mode', 'strict', 'design-score', 'min-design-score', 'p0', 'p1', 'open-p0', 'open-p1', 'states-checked', 'mobile-checked', 'responsive-checked', 'contrast-checked', 'accessibility-checked', 'cta-checked', 'direction-locked', 'reference-read', 'comparison-result', 'json']));
2344
2508
  const reference = String(flags.reference || flags.ref || '');
2345
2509
  const actual = String(flags.actual || flags.screenshot || '');
2346
2510
  const referenceSources = [];
@@ -2446,6 +2610,20 @@ async function ueyeReport(args = []) {
2446
2610
  direction_locked: Boolean(flags.direction_locked),
2447
2611
  reference_read: Boolean(flags.reference_read)
2448
2612
  },
2613
+ deep_visual_review: {
2614
+ acceptance_criteria: arrayFlag(flags.acceptance_criterion),
2615
+ touched_files: arrayFlag(flags.touched_file),
2616
+ read_files: arrayFlag(flags.read_file),
2617
+ verified_files: arrayFlag(flags.verified_file),
2618
+ skipped_checks: arrayFlag(flags.skipped_check),
2619
+ residual_risks: arrayFlag(flags.residual_risk),
2620
+ stop_condition: String(flags.stop_condition || ''),
2621
+ resume_hint: String(flags.resume_hint || ''),
2622
+ deep_visual_checks: arrayFlag(flags.deep_visual_check),
2623
+ design_system_evidence: arrayFlag(flags.design_system_evidence),
2624
+ implementation_evidence: arrayFlag(flags.implementation_evidence),
2625
+ state_check: arrayFlag(flags.state_check)
2626
+ },
2449
2627
  blocked_reason: blockedReason,
2450
2628
  next_action: String(flags.next_visual_action || flags.next_action || '')
2451
2629
  });
@@ -4200,6 +4378,8 @@ async function main() {
4200
4378
  return tools(process.argv.slice(3));
4201
4379
  if (command === 'proof')
4202
4380
  return proof(process.argv.slice(3));
4381
+ if (command === 'study-note')
4382
+ return studyNote(process.argv.slice(3));
4203
4383
  if (command === 'loop')
4204
4384
  return loop(process.argv.slice(3));
4205
4385
  if (command === 'ueye')