yam-flow 0.1.8 → 1.9.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/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  All notable changes to yam-flow are documented here.
4
4
 
5
+ ## v1.9.1 - 2026-06-19
6
+
7
+ ### Added
8
+
9
+ - Extended `yam loop report --json` with guided stage conventions, `evidence_level`, `evidence_stamp`/`source_digest`, `blocked_kind`, `safe_retry`, `owner_scope`, `scope_owner`, and `side_effects` so the report can act as a clearer handoff artifact without adding a new command.
10
+ - Updated loop report smoke coverage to assert the new handoff fields.
11
+
12
+ ### Improved
13
+
14
+ - Updated README, COMMANDS, final-report guidance, implementation skill final-response rules, and manifest principles to prefer fix-first handoff with evidence level, blocker kind, safe retry, and owner/scope clarity.
15
+
16
+ ## v0.1.9 - 2026-06-18
17
+
18
+ ### Added
19
+
20
+ - Expanded `yam loop report --json` into a read-only handoff artifact with `fix_first_items`, `recommended_direction`, `implementation_notes`, `why_this_next`, `blocked_by`, and `owner_route`.
21
+ - Added loop report smoke coverage for the new handoff fields while keeping the existing minimal and blocked report paths.
22
+
23
+ ### Improved
24
+
25
+ - Updated `$quick`, `$deep`, `$mission`, and `$ueye` final response guidance so implementation work can include Study Note and handoff habits without forcing a CLI artifact for ordinary work.
26
+ - Updated `references/final-report.md`, README, COMMANDS, and manifest principles to treat Study Note and handoff direction as final-report practices.
27
+
28
+ ### Verification
29
+
30
+ - `npm run typecheck`
31
+ - `npm run build`
32
+ - `node ./dist/bin/yam.js loop report --json` with handoff fields
33
+ - `npm run cli-smoke`
34
+ - `npm run verify:self`
35
+ - `npm run forbidden-names:check`
36
+ - `npm run package-boundary:check`
37
+ - `npm run dist:freshness`
38
+
5
39
  ## v0.1.8 - 2026-06-16
6
40
 
7
41
  ### Added
package/COMMANDS.md CHANGED
@@ -148,7 +148,7 @@ 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" --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 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" --blocked-kind auth_blocked --safe-retry "retry after npm whoami succeeds" --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" --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
152
  yam proof /path/to/project
153
153
  yam proof --route deep --truth verified --command "npm run build: pass"
154
154
  yam proof --route ueye --truth verified --visual "reference image only"
@@ -195,7 +195,7 @@ Supported report shapes:
195
195
 
196
196
  - Runtime evidence mini: command/process, observation, cleanup, truth status, next action.
197
197
  - Patch queue lite: mission lane status, changed files, verification hint, rollback hint, truth status.
198
- - Loop report: intent, stage outcomes, evidence, blockers, next action, remaining tasks, and study note.
198
+ - 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.
199
199
  - Study note: short non-specialist explanation of the failing code, its role, observed symptom, changed code, and why it matters.
200
200
  - Benchmark optimization loop lite: baseline, one change, rerun, keep/revert decision.
201
201
  - Structured diagnostic next action: severity, evidence, owner route, next action, truth status.
package/README.md CHANGED
@@ -142,7 +142,7 @@ yam ueye report --reference ./reference.png --actual .yam/screens/home.png --pre
142
142
  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"}'
143
143
  yam media proof --requested --attempted --output ./generated.png --wait-loop --json
144
144
  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"}'
145
- yam loop report --route quick --intent "fix release readiness" --stage "inspect:passed:read release report" --evidence "typecheck passed" --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
145
+ 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" --blocked-kind auth_blocked --safe-retry "retry after npm whoami succeeds" --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" --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
146
146
  yam release report --json
147
147
  yam safety "supabase db reset"
148
148
  yam detect /path/to/project
@@ -216,7 +216,7 @@ These shapes keep reports machine-readable without turning normal work into a he
216
216
  - Runtime evidence mini: compact route, command/process, observation, cleanup, truth status, and next action fields for `$deep` or `$mission` runtime claims.
217
217
  - Patch queue lite: `$mission` lane records with pending/applied/verified/reverted/blocked state, changed files, verification hint, rollback hint, truth status, and next action.
218
218
  - Release report JSON: `yam release report --json` summarizes typecheck, forbidden-name scan, package boundary, registry status, CLI smoke, dist freshness, diagnostics, and final truth status.
219
- - Loop report JSON: `yam loop report --json` records a read-only loop artifact: intent, stages, evidence, blockers, next action, remaining tasks, tool intent, truth status, and study note.
219
+ - Loop report JSON: `yam loop report --json` records a read-only handoff artifact: guided stages, evidence level/stamp, blocker kind, safe retry, owner route/scope, side effects, next action, fix-first items, remaining tasks, recommended direction, implementation notes, blocked-by notes, tool intent, truth status, and study note.
220
220
  - Study note: `yam.study-note.v1` keeps short non-specialist explanations for what code was failing, what role it plays, how the symptom showed up, what changed, and why it matters. Missing details stay in `limits` instead of being guessed.
221
221
  - Publish blocker evidence: release reports classify common npm auth, permission, OTP, immutable-version, cache, registry, and tarball failures into safe next actions.
222
222
  - Publish readiness evidence: release reports run read-only registry/auth/version probes, redact account/token details, and keep npm publish outside the report.
package/dist/bin/yam.js CHANGED
@@ -524,6 +524,12 @@ function normalizeToolIntent(value = '') {
524
524
  return text;
525
525
  return 'read_only';
526
526
  }
527
+ function normalizeLoopEvidenceLevelFlag(value = '') {
528
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
529
+ if (['fixture', 'smoke', 'local', 'real'].includes(text))
530
+ return text;
531
+ return 'none';
532
+ }
527
533
  function uniqueNextActionDetails(actions = []) {
528
534
  const seen = new Set();
529
535
  const unique = [];
@@ -1970,28 +1976,43 @@ async function loop(args = []) {
1970
1976
  function loopUsage() {
1971
1977
  console.log(`yam loop
1972
1978
 
1973
- Read-only loop artifact helpers. A loop report records intent, stages, evidence, blockers, next action, and a short study note. It does not run agents, start processes, publish packages, or write files.
1979
+ 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.
1974
1980
 
1975
1981
  Usage:
1976
- yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--blocked text] [--remaining-task 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]
1982
+ 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] [--blocked text] [--blocked-kind text] [--safe-retry 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] [--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]
1977
1983
  `);
1978
1984
  }
1979
1985
  async function loopReport(args = []) {
1980
1986
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
1981
1987
  return loopUsage();
1982
- const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'evidence', 'blocked', 'blocker', 'next-action', 'remaining-task', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
1988
+ const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'stage-convention', 'evidence', 'evidence-level', 'evidence-stamp', 'source-digest', 'blocked', 'blocker', 'blocked-kind', 'next-action', 'safe-retry', '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', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
1983
1989
  const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
1984
1990
  const report = buildLoopReport({
1985
1991
  route: normalizeRoute(flags.route) || String(flags.route || ''),
1986
1992
  intent: String(flags.intent || ''),
1987
1993
  loop_kind: String(flags.loop_kind || flags.route || 'harness'),
1994
+ stage_conventions: arrayFlag(flags.stage_convention),
1988
1995
  stages: arrayFlag(flags.stage),
1989
1996
  evidence: arrayFlag(flags.evidence),
1997
+ evidence_level: normalizeLoopEvidenceLevelFlag(flags.evidence_level),
1998
+ evidence_stamp: String(flags.evidence_stamp || ''),
1999
+ source_digest: String(flags.source_digest || ''),
1990
2000
  blockers,
2001
+ blocked_kind: String(flags.blocked_kind || ''),
1991
2002
  truth_status: isTruthStatus(flags.truth) ? flags.truth : undefined,
1992
2003
  intent_label: normalizeToolIntent(flags.intent_label || flags.tool_intent || 'read_only'),
1993
2004
  next_action: String(flags.next_action || ''),
2005
+ safe_retry: String(flags.safe_retry || ''),
2006
+ fix_first_items: arrayFlag(flags.fix_first_item),
1994
2007
  remaining_tasks: arrayFlag(flags.remaining_task),
2008
+ recommended_direction: String(flags.recommended_direction || flags.direction || ''),
2009
+ implementation_notes: arrayFlag(flags.implementation_note),
2010
+ why_this_next: String(flags.why_this_next || ''),
2011
+ blocked_by: arrayFlag(flags.blocked_by),
2012
+ owner_route: String(flags.owner_route || flags.route || ''),
2013
+ owner_scope: [...arrayFlag(flags.owner_scope), ...arrayFlag(flags.scope)],
2014
+ scope_owner: String(flags.scope_owner || flags.owner || ''),
2015
+ side_effects: arrayFlag(flags.side_effect),
1995
2016
  issue_code: String(flags.issue_code || ''),
1996
2017
  issue_role: String(flags.issue_role || ''),
1997
2018
  issue_symptom: String(flags.issue_symptom || ''),
@@ -6,6 +6,7 @@ export type RuntimeSubsystem = 'real_runtime' | 'tmux_physical' | 'process_clean
6
6
  export type RuntimeBackend = 'none' | 'in_app_browser' | 'playwright' | 'terminal' | 'tmux' | 'zellij' | 'unknown';
7
7
  export type RuntimeClaim = 'not_started' | 'started' | 'observed' | 'stopped' | 'cleanup_verified' | 'blocked' | 'unknown';
8
8
  export type LoopStageStatus = 'passed' | 'failed' | 'blocked' | 'skipped' | 'partial' | 'pending' | 'recorded';
9
+ export type LoopEvidenceLevel = 'none' | 'fixture' | 'smoke' | 'local' | 'real';
9
10
  export type ToolIntent = 'read_only' | 'write' | 'destructive' | 'runtime' | 'visual' | 'publish';
10
11
  export interface SafetyHit {
11
12
  level: SafetyLevel;
@@ -154,14 +155,29 @@ export interface LoopReport {
154
155
  route: string;
155
156
  intent: string;
156
157
  loop_kind: string;
158
+ stage_conventions: string[];
157
159
  stages: LoopStage[];
158
160
  evidence: string[];
161
+ evidence_level: LoopEvidenceLevel;
162
+ evidence_stamp: string;
163
+ source_digest: string;
159
164
  blockers: string[];
165
+ blocked_kind: string;
160
166
  truth_status: TruthStatus;
161
167
  intent_label: ToolIntent;
162
168
  tool_intent: ToolIntent;
163
169
  next_action: string;
170
+ safe_retry: string;
171
+ fix_first_items: string[];
164
172
  remaining_tasks: string[];
173
+ recommended_direction: string;
174
+ implementation_notes: string[];
175
+ why_this_next: string;
176
+ blocked_by: string[];
177
+ owner_route: string;
178
+ owner_scope: string[];
179
+ scope_owner: string;
180
+ side_effects: string[];
165
181
  study_note: StudyNote;
166
182
  }
167
183
  export interface UeyeRunReport {
@@ -237,9 +237,14 @@ export function buildLoopReport(input = {}) {
237
237
  : [];
238
238
  const evidence = asList(input.evidence);
239
239
  const blockers = asList(input.blockers || input.blocked);
240
+ const blockedBy = asList(input.blocked_by);
241
+ const blockedKind = shortText(input.blocked_kind || (blockers.length || blockedBy.length ? 'evidence_missing' : ''));
242
+ const evidenceStamp = shortText(input.evidence_stamp || input.source_digest, 320);
243
+ const sourceDigest = shortText(input.source_digest || input.evidence_stamp, 320);
240
244
  const hasBlockedStage = stages.some((stage) => stage.status === 'blocked' || stage.status === 'failed');
245
+ const hasBlockerSignal = Boolean(blockers.length || blockedBy.length || blockedKind);
241
246
  const requestedTruth = isTruthStatus(input.truth_status) ? input.truth_status : '';
242
- const derivedTruth = blockers.length || hasBlockedStage ? 'blocked'
247
+ const derivedTruth = hasBlockerSignal || hasBlockedStage ? 'blocked'
243
248
  : evidence.length && stages.some((stage) => stage.status === 'passed') ? 'verified'
244
249
  : evidence.length || stages.length ? 'partial'
245
250
  : 'assumed';
@@ -252,14 +257,31 @@ export function buildLoopReport(input = {}) {
252
257
  route: String(input.route || ''),
253
258
  intent: shortText(input.intent),
254
259
  loop_kind: String(input.loop_kind || 'harness'),
260
+ stage_conventions: asList(input.stage_conventions || input.stage_convention).length
261
+ ? asList(input.stage_conventions || input.stage_convention)
262
+ : ['brief', 'plan', 'implement', 'critique', 'verify', 'handoff'],
255
263
  stages,
256
264
  evidence,
265
+ evidence_level: normalizeLoopEvidenceLevel(input.evidence_level),
266
+ evidence_stamp: evidenceStamp,
267
+ source_digest: sourceDigest,
257
268
  blockers,
269
+ blocked_kind: blockedKind,
258
270
  truth_status: truth,
259
271
  intent_label: intentLabel,
260
272
  tool_intent: intentLabel,
261
- next_action: shortText(input.next_action || (blockers[0] ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
273
+ next_action: shortText(input.next_action || (hasBlockerSignal ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
274
+ safe_retry: shortText(input.safe_retry || (hasBlockerSignal ? 'retry only after the blocker is resolved and new evidence is recorded' : 'not required')),
275
+ fix_first_items: asList(input.fix_first_items || input.fix_first_item),
262
276
  remaining_tasks: asList(input.remaining_tasks || input.remaining_task),
277
+ recommended_direction: shortText(input.recommended_direction || input.direction),
278
+ implementation_notes: asList(input.implementation_notes || input.implementation_note),
279
+ why_this_next: shortText(input.why_this_next),
280
+ blocked_by: blockedBy,
281
+ owner_route: normalizeOwnerRoute(input.owner_route || input.route),
282
+ owner_scope: asList(input.owner_scope || input.scope),
283
+ scope_owner: normalizeOwnerRoute(input.scope_owner || input.owner),
284
+ side_effects: asList(input.side_effects || input.side_effect),
263
285
  study_note: studyNote
264
286
  };
265
287
  }
@@ -388,6 +410,18 @@ function normalizeToolIntentLabel(value = '') {
388
410
  return text;
389
411
  return 'read_only';
390
412
  }
413
+ function normalizeOwnerRoute(value = '') {
414
+ const text = String(value || '').trim().replace(/^\$/, '').replace(/^yam-/, '');
415
+ if (['quick', 'ueye', 'question', 'scout', 'deep', 'mission'].includes(text))
416
+ return `$${text}`;
417
+ return text ? shortText(text, 80) : '';
418
+ }
419
+ function normalizeLoopEvidenceLevel(value = '') {
420
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
421
+ if (['fixture', 'smoke', 'local', 'real'].includes(text))
422
+ return text;
423
+ return 'none';
424
+ }
391
425
  function shortText(value = '', limit = 240) {
392
426
  const text = String(value || '').trim().replace(/\s+/g, ' ');
393
427
  if (text.length <= limit)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yam-flow",
3
- "version": "0.1.8",
3
+ "version": "1.9.1",
4
4
  "description": "Progressive proof-first agent flow: start fast, deepen deliberately, stay honest by design.",
5
5
  "type": "module",
6
6
  "author": "0kim0bos",
@@ -16,8 +16,10 @@ Include these when they are useful and keep them short:
16
16
  - Context pressure or cleanup findings when they could affect the next run.
17
17
  - Publish blocker evidence when npm/release work fails.
18
18
  - Structured diagnostic next action, when a check found a concrete next step.
19
+ - Study Note for implementation work: what code was wrong, what role it has, how the symptom showed up, what changed, and why it matters in short non-specialist language.
19
20
  - Remaining tasks.
20
21
  - Fix-first items before planned tasks.
22
+ - Recommended direction and why that next step matters when the handoff would otherwise be ambiguous.
21
23
 
22
24
  ## Anti-False-Completion Check
23
25
 
@@ -54,6 +56,33 @@ Examples:
54
56
  - Active hooks or instruction files that conflict with the route.
55
57
  - Warnings that keep obscuring real problems.
56
58
 
59
+ ## Study Note
60
+
61
+ Use this when implementation changed code or fixed an error and the user would benefit from learning:
62
+
63
+ - What code had the issue.
64
+ - What role that code plays.
65
+ - How the issue showed up.
66
+ - What changed.
67
+ - Why the change matters.
68
+
69
+ Keep it short. If the information is not known, say so instead of inventing it.
70
+
71
+ ## Handoff Direction
72
+
73
+ Use this when the next run needs a clear starting point:
74
+
75
+ - Fix-first items before planned work.
76
+ - Remaining tasks that still belong to the request or roadmap.
77
+ - Recommended direction.
78
+ - Why this next step matters.
79
+ - What is blocked, and by what.
80
+ - Evidence level or stamp when the handoff relies on a specific command, file, or report.
81
+ - Blocker kind and safe retry when the next run should not blindly repeat the same action.
82
+ - Owner route, scope owner, and side effects when more than one person or route may continue the work.
83
+
84
+ `yam loop report` can record this as a handoff artifact with `fix_first_items`, `remaining_tasks`, `recommended_direction`, `implementation_notes`, `why_this_next`, `blocked_by`, `blocked_kind`, `safe_retry`, `evidence_level`, `evidence_stamp`, `owner_route`, `owner_scope`, `scope_owner`, and `side_effects`.
85
+
57
86
  ## Route Weight
58
87
 
59
88
  For `$quick`, one short paragraph or a compact verification matrix is enough.
@@ -70,8 +70,8 @@ Deep verification may include:
70
70
  Include:
71
71
 
72
72
  - What was changed or reviewed.
73
+ - Study Note for implementation work: what code was wrong, what role it has, how the symptom showed up, what changed, and why it matters in short non-specialist language.
73
74
  - Evidence gathered.
74
75
  - Truth status.
75
76
  - Blockers or remaining risk.
76
- - Remaining tasks.
77
- - Fix-first items before planned tasks.
77
+ - Handoff: fix-first items, remaining tasks, recommended direction, why that next step matters, blocker kind, safe retry, evidence level/stamp, side effects, and owner scope when another route or person may continue.
@@ -102,8 +102,8 @@ Report:
102
102
 
103
103
  - What the mission changed.
104
104
  - Role/cross-verification summary.
105
+ - Study Note for implementation lanes: what code was wrong, what role it has, how the symptom showed up, what changed, and why it matters in short non-specialist language.
105
106
  - Evidence gathered.
106
107
  - Truth status.
107
108
  - Cleanup status.
108
- - Remaining tasks.
109
- - Fix-first items before planned tasks.
109
+ - Handoff: fix-first items, remaining tasks, recommended direction, why that next step matters, blocker kind, safe retry, evidence level/stamp, side effects, and owner scope when another route or person may continue.
@@ -76,6 +76,7 @@ Use `references/token-budget-reporter.md` when a run needs measured budget feedb
76
76
  Keep it compact:
77
77
 
78
78
  - What changed or what the scan found.
79
+ - Study Note when useful: what code was wrong, what role it has, how the symptom showed up, what changed, and why it matters in short non-specialist language.
79
80
  - What was checked.
80
81
  - What was skipped, blocked, or still risky.
81
- - Remaining tasks and fix-first items, only when useful.
82
+ - Handoff when useful: fix-first items, remaining tasks, recommended direction, why that next step matters, blocker kind, safe retry, evidence level/stamp, and owner scope when another route or person may continue.
@@ -170,5 +170,6 @@ Report:
170
170
  - Review continuity/comparison result when this continues a prior Ueye run.
171
171
  - P0-P3 issues or confirmation that no blockers were found.
172
172
  - States/viewports checked.
173
+ - Study Note when UI implementation changed code: what UI code changed, what role it has, how the visible symptom appeared, and why the change matters in short non-specialist language.
173
174
  - Truth status and visual verification cap.
174
- - Remaining tasks and fix-first items before planned tasks when useful.
175
+ - Handoff when useful: fix-first visual issues, remaining tasks, recommended direction, why that next step matters, blocker kind, safe retry, evidence level/stamp, and owner scope when another route or person may continue.
package/src/bin/yam.ts CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  detectDbSafetyText as detectTrustDbSafetyText,
25
25
  isTruthStatus
26
26
  } from '../lib/trust-kernel.js';
27
- import type { ToolIntent } from '../lib/trust-kernel.js';
27
+ import type { LoopEvidenceLevel, ToolIntent } from '../lib/trust-kernel.js';
28
28
 
29
29
  type AnyRecord = Record<string, any>;
30
30
 
@@ -525,6 +525,12 @@ function normalizeToolIntent(value = ''): ToolIntent {
525
525
  return 'read_only';
526
526
  }
527
527
 
528
+ function normalizeLoopEvidenceLevelFlag(value = ''): LoopEvidenceLevel {
529
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
530
+ if (['fixture', 'smoke', 'local', 'real'].includes(text)) return text as LoopEvidenceLevel;
531
+ return 'none';
532
+ }
533
+
528
534
  function uniqueNextActionDetails(actions = []) {
529
535
  const seen = new Set<string>();
530
536
  const unique = [];
@@ -1968,28 +1974,43 @@ async function loop(args = []) {
1968
1974
  function loopUsage() {
1969
1975
  console.log(`yam loop
1970
1976
 
1971
- Read-only loop artifact helpers. A loop report records intent, stages, evidence, blockers, next action, and a short study note. It does not run agents, start processes, publish packages, or write files.
1977
+ 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.
1972
1978
 
1973
1979
  Usage:
1974
- yam loop report [--route route] [--intent text] [--loop-kind harness|release|ueye|scout|deep|mission] [--stage id:status:note] [--evidence text] [--blocked text] [--remaining-task 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]
1980
+ 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] [--blocked text] [--blocked-kind text] [--safe-retry 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] [--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]
1975
1981
  `);
1976
1982
  }
1977
1983
 
1978
1984
  async function loopReport(args = []) {
1979
1985
  if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h') return loopUsage();
1980
- const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'evidence', 'blocked', 'blocker', 'next-action', 'remaining-task', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
1986
+ const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'stage-convention', 'evidence', 'evidence-level', 'evidence-stamp', 'source-digest', 'blocked', 'blocker', 'blocked-kind', 'next-action', 'safe-retry', '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', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
1981
1987
  const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
1982
1988
  const report = buildLoopReport({
1983
1989
  route: normalizeRoute(flags.route) || String(flags.route || ''),
1984
1990
  intent: String(flags.intent || ''),
1985
1991
  loop_kind: String(flags.loop_kind || flags.route || 'harness'),
1992
+ stage_conventions: arrayFlag(flags.stage_convention),
1986
1993
  stages: arrayFlag(flags.stage),
1987
1994
  evidence: arrayFlag(flags.evidence),
1995
+ evidence_level: normalizeLoopEvidenceLevelFlag(flags.evidence_level),
1996
+ evidence_stamp: String(flags.evidence_stamp || ''),
1997
+ source_digest: String(flags.source_digest || ''),
1988
1998
  blockers,
1999
+ blocked_kind: String(flags.blocked_kind || ''),
1989
2000
  truth_status: isTruthStatus(flags.truth) ? flags.truth : undefined,
1990
2001
  intent_label: normalizeToolIntent(flags.intent_label || flags.tool_intent || 'read_only'),
1991
2002
  next_action: String(flags.next_action || ''),
2003
+ safe_retry: String(flags.safe_retry || ''),
2004
+ fix_first_items: arrayFlag(flags.fix_first_item),
1992
2005
  remaining_tasks: arrayFlag(flags.remaining_task),
2006
+ recommended_direction: String(flags.recommended_direction || flags.direction || ''),
2007
+ implementation_notes: arrayFlag(flags.implementation_note),
2008
+ why_this_next: String(flags.why_this_next || ''),
2009
+ blocked_by: arrayFlag(flags.blocked_by),
2010
+ owner_route: String(flags.owner_route || flags.route || ''),
2011
+ owner_scope: [...arrayFlag(flags.owner_scope), ...arrayFlag(flags.scope)],
2012
+ scope_owner: String(flags.scope_owner || flags.owner || ''),
2013
+ side_effects: arrayFlag(flags.side_effect),
1993
2014
  issue_code: String(flags.issue_code || ''),
1994
2015
  issue_role: String(flags.issue_role || ''),
1995
2016
  issue_symptom: String(flags.issue_symptom || ''),
@@ -18,6 +18,7 @@ export type RuntimeSubsystem = 'real_runtime' | 'tmux_physical' | 'process_clean
18
18
  export type RuntimeBackend = 'none' | 'in_app_browser' | 'playwright' | 'terminal' | 'tmux' | 'zellij' | 'unknown';
19
19
  export type RuntimeClaim = 'not_started' | 'started' | 'observed' | 'stopped' | 'cleanup_verified' | 'blocked' | 'unknown';
20
20
  export type LoopStageStatus = 'passed' | 'failed' | 'blocked' | 'skipped' | 'partial' | 'pending' | 'recorded';
21
+ export type LoopEvidenceLevel = 'none' | 'fixture' | 'smoke' | 'local' | 'real';
21
22
  export type ToolIntent = 'read_only' | 'write' | 'destructive' | 'runtime' | 'visual' | 'publish';
22
23
 
23
24
  export interface SafetyHit {
@@ -182,14 +183,29 @@ export interface LoopReport {
182
183
  route: string;
183
184
  intent: string;
184
185
  loop_kind: string;
186
+ stage_conventions: string[];
185
187
  stages: LoopStage[];
186
188
  evidence: string[];
189
+ evidence_level: LoopEvidenceLevel;
190
+ evidence_stamp: string;
191
+ source_digest: string;
187
192
  blockers: string[];
193
+ blocked_kind: string;
188
194
  truth_status: TruthStatus;
189
195
  intent_label: ToolIntent;
190
196
  tool_intent: ToolIntent;
191
197
  next_action: string;
198
+ safe_retry: string;
199
+ fix_first_items: string[];
192
200
  remaining_tasks: string[];
201
+ recommended_direction: string;
202
+ implementation_notes: string[];
203
+ why_this_next: string;
204
+ blocked_by: string[];
205
+ owner_route: string;
206
+ owner_scope: string[];
207
+ scope_owner: string;
208
+ side_effects: string[];
193
209
  study_note: StudyNote;
194
210
  }
195
211
 
@@ -535,9 +551,14 @@ export function buildLoopReport(input: Partial<LoopReport> & Record<string, unkn
535
551
  : [];
536
552
  const evidence = asList(input.evidence);
537
553
  const blockers = asList(input.blockers || input.blocked);
554
+ const blockedBy = asList(input.blocked_by);
555
+ const blockedKind = shortText(input.blocked_kind || (blockers.length || blockedBy.length ? 'evidence_missing' : ''));
556
+ const evidenceStamp = shortText(input.evidence_stamp || input.source_digest, 320);
557
+ const sourceDigest = shortText(input.source_digest || input.evidence_stamp, 320);
538
558
  const hasBlockedStage = stages.some((stage) => stage.status === 'blocked' || stage.status === 'failed');
559
+ const hasBlockerSignal = Boolean(blockers.length || blockedBy.length || blockedKind);
539
560
  const requestedTruth = isTruthStatus(input.truth_status) ? input.truth_status : '';
540
- const derivedTruth: TruthStatus = blockers.length || hasBlockedStage ? 'blocked'
561
+ const derivedTruth: TruthStatus = hasBlockerSignal || hasBlockedStage ? 'blocked'
541
562
  : evidence.length && stages.some((stage) => stage.status === 'passed') ? 'verified'
542
563
  : evidence.length || stages.length ? 'partial'
543
564
  : 'assumed';
@@ -550,14 +571,31 @@ export function buildLoopReport(input: Partial<LoopReport> & Record<string, unkn
550
571
  route: String(input.route || ''),
551
572
  intent: shortText(input.intent),
552
573
  loop_kind: String(input.loop_kind || 'harness'),
574
+ stage_conventions: asList(input.stage_conventions || input.stage_convention).length
575
+ ? asList(input.stage_conventions || input.stage_convention)
576
+ : ['brief', 'plan', 'implement', 'critique', 'verify', 'handoff'],
553
577
  stages,
554
578
  evidence,
579
+ evidence_level: normalizeLoopEvidenceLevel(input.evidence_level),
580
+ evidence_stamp: evidenceStamp,
581
+ source_digest: sourceDigest,
555
582
  blockers,
583
+ blocked_kind: blockedKind,
556
584
  truth_status: truth,
557
585
  intent_label: intentLabel,
558
586
  tool_intent: intentLabel,
559
- next_action: shortText(input.next_action || (blockers[0] ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
587
+ next_action: shortText(input.next_action || (hasBlockerSignal ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
588
+ safe_retry: shortText(input.safe_retry || (hasBlockerSignal ? 'retry only after the blocker is resolved and new evidence is recorded' : 'not required')),
589
+ fix_first_items: asList(input.fix_first_items || input.fix_first_item),
560
590
  remaining_tasks: asList(input.remaining_tasks || input.remaining_task),
591
+ recommended_direction: shortText(input.recommended_direction || input.direction),
592
+ implementation_notes: asList(input.implementation_notes || input.implementation_note),
593
+ why_this_next: shortText(input.why_this_next),
594
+ blocked_by: blockedBy,
595
+ owner_route: normalizeOwnerRoute(input.owner_route || input.route),
596
+ owner_scope: asList(input.owner_scope || input.scope),
597
+ scope_owner: normalizeOwnerRoute(input.scope_owner || input.owner),
598
+ side_effects: asList(input.side_effects || input.side_effect),
561
599
  study_note: studyNote
562
600
  };
563
601
  }
@@ -676,6 +714,18 @@ function normalizeToolIntentLabel(value: unknown = ''): ToolIntent {
676
714
  return 'read_only';
677
715
  }
678
716
 
717
+ function normalizeOwnerRoute(value: unknown = ''): string {
718
+ const text = String(value || '').trim().replace(/^\$/, '').replace(/^yam-/, '');
719
+ if (['quick', 'ueye', 'question', 'scout', 'deep', 'mission'].includes(text)) return `$${text}`;
720
+ return text ? shortText(text, 80) : '';
721
+ }
722
+
723
+ function normalizeLoopEvidenceLevel(value: unknown = ''): LoopEvidenceLevel {
724
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
725
+ if (['fixture', 'smoke', 'local', 'real'].includes(text)) return text as LoopEvidenceLevel;
726
+ return 'none';
727
+ }
728
+
679
729
  function shortText(value: unknown = '', limit = 240): string {
680
730
  const text = String(value || '').trim().replace(/\s+/g, ' ');
681
731
  if (text.length <= limit) return text;
package/yam.manifest.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yam",
3
- "version": "0.1.8",
3
+ "version": "1.9.1",
4
4
  "principles": [
5
5
  "Direction before execution.",
6
6
  "Start fast.",
@@ -11,7 +11,8 @@
11
11
  "Token-aware by default.",
12
12
  "Context-reuse first.",
13
13
  "End with remaining tasks and fix-first items.",
14
- "Explain what failed, what changed, and why it matters in short non-specialist language when useful."
14
+ "Explain what failed, what changed, and why it matters in short non-specialist language when useful.",
15
+ "Use handoff notes for fix-first items, remaining tasks, recommended next direction, blocker kind, safe retry, evidence level, and owner scope when useful."
15
16
  ],
16
17
  "defaultHooks": false,
17
18
  "routes": [