yam-flow 0.1.7 → 0.1.9

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.
@@ -5,6 +5,8 @@ export type EvidenceKind = 'command' | 'evidence' | 'visual' | 'runtime' | 'skip
5
5
  export type RuntimeSubsystem = 'real_runtime' | 'tmux_physical' | 'process_cleanup' | 'browser_visual' | 'db_safety';
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
+ export type LoopStageStatus = 'passed' | 'failed' | 'blocked' | 'skipped' | 'partial' | 'pending' | 'recorded';
9
+ export type ToolIntent = 'read_only' | 'write' | 'destructive' | 'runtime' | 'visual' | 'publish';
8
10
  export interface SafetyHit {
9
11
  level: SafetyLevel;
10
12
  reason: string;
@@ -124,6 +126,50 @@ export interface RuntimeBackendEvidence {
124
126
  note: string;
125
127
  truth_status: TruthStatus;
126
128
  }
129
+ export interface StudyNoteSection {
130
+ code: string;
131
+ role: string;
132
+ symptom?: string;
133
+ summary?: string;
134
+ truth_status: TruthStatus;
135
+ }
136
+ export interface StudyNote {
137
+ schema: 'yam.study-note.v1';
138
+ problem: StudyNoteSection;
139
+ change: StudyNoteSection;
140
+ why_it_matters: string;
141
+ learning_note: string;
142
+ limits: string[];
143
+ truth_status: TruthStatus;
144
+ }
145
+ export interface LoopStage {
146
+ id: string;
147
+ status: LoopStageStatus;
148
+ note: string;
149
+ truth_status: TruthStatus;
150
+ }
151
+ export interface LoopReport {
152
+ schema: 'yam.loop-report.v1';
153
+ generated_at: string;
154
+ route: string;
155
+ intent: string;
156
+ loop_kind: string;
157
+ stages: LoopStage[];
158
+ evidence: string[];
159
+ blockers: string[];
160
+ truth_status: TruthStatus;
161
+ intent_label: ToolIntent;
162
+ tool_intent: ToolIntent;
163
+ next_action: string;
164
+ fix_first_items: string[];
165
+ remaining_tasks: string[];
166
+ recommended_direction: string;
167
+ implementation_notes: string[];
168
+ why_this_next: string;
169
+ blocked_by: string[];
170
+ owner_route: string;
171
+ study_note: StudyNote;
172
+ }
127
173
  export interface UeyeRunReport {
128
174
  schema: 'yam.ueye-run-report.v1';
129
175
  reference_sources: UeyeVisualProvenance[];
@@ -230,6 +276,8 @@ export declare function buildUeyeDesignCompletionGate(input?: Partial<UeyeDesign
230
276
  export declare function buildRollbackHint(input?: Partial<RollbackHint>): RollbackHint;
231
277
  export declare function buildMissionPatchEnvelope(input?: Partial<MissionPatchEnvelope>): MissionPatchEnvelope;
232
278
  export declare function buildRuntimeBackendEvidence(input?: Partial<RuntimeBackendEvidence>): RuntimeBackendEvidence;
279
+ export declare function buildStudyNote(input?: Partial<StudyNote> & Record<string, unknown>): StudyNote;
280
+ export declare function buildLoopReport(input?: Partial<LoopReport> & Record<string, unknown>): LoopReport;
233
281
  export declare function buildUeyeRunReport(input?: UeyeRunReportInput): UeyeRunReport;
234
282
  export declare function buildMediaGenerationProof(input?: Partial<MediaGenerationProof>): MediaGenerationProof;
235
283
  export declare function isTruthStatus(value?: unknown): value is TruthStatus;
@@ -199,6 +199,76 @@ export function buildRuntimeBackendEvidence(input = {}) {
199
199
  })
200
200
  };
201
201
  }
202
+ export function buildStudyNote(input = {}) {
203
+ const problem = buildStudyNoteSection(input.problem, {
204
+ code: input.issue_code,
205
+ role: input.issue_role,
206
+ symptom: input.issue_symptom
207
+ }, 'problem');
208
+ const change = buildStudyNoteSection(input.change, {
209
+ code: input.changed_code,
210
+ role: input.changed_role,
211
+ summary: input.change_summary
212
+ }, 'change');
213
+ const whyItMatters = shortText(input.why_it_matters || input.why_important);
214
+ const learningNote = shortText(input.learning_note);
215
+ const limits = [
216
+ ...asList(input.limits),
217
+ ...missingStudyNoteLimits(problem, change, whyItMatters, learningNote)
218
+ ];
219
+ const hasProblem = Boolean(problem.code || problem.role || problem.symptom);
220
+ const hasChange = Boolean(change.code || change.role || change.summary);
221
+ const truth = isTruthStatus(input.truth_status) ? input.truth_status
222
+ : hasProblem || hasChange || whyItMatters || learningNote ? 'partial'
223
+ : 'assumed';
224
+ return {
225
+ schema: 'yam.study-note.v1',
226
+ problem,
227
+ change,
228
+ why_it_matters: whyItMatters,
229
+ learning_note: learningNote,
230
+ limits: [...new Set(limits)],
231
+ truth_status: truth
232
+ };
233
+ }
234
+ export function buildLoopReport(input = {}) {
235
+ const stages = Array.isArray(input.stages)
236
+ ? input.stages.map((stage) => buildLoopStage(stage))
237
+ : [];
238
+ const evidence = asList(input.evidence);
239
+ const blockers = asList(input.blockers || input.blocked);
240
+ const hasBlockedStage = stages.some((stage) => stage.status === 'blocked' || stage.status === 'failed');
241
+ const requestedTruth = isTruthStatus(input.truth_status) ? input.truth_status : '';
242
+ const derivedTruth = blockers.length || hasBlockedStage ? 'blocked'
243
+ : evidence.length && stages.some((stage) => stage.status === 'passed') ? 'verified'
244
+ : evidence.length || stages.length ? 'partial'
245
+ : 'assumed';
246
+ const truth = requestedTruth ? weakestTruth(requestedTruth, derivedTruth) : derivedTruth;
247
+ const studyNote = buildStudyNote(input.study_note && typeof input.study_note === 'object' ? input.study_note : input);
248
+ const intentLabel = normalizeToolIntentLabel(input.intent_label || input.tool_intent);
249
+ return {
250
+ schema: 'yam.loop-report.v1',
251
+ generated_at: String(input.generated_at || new Date().toISOString()),
252
+ route: String(input.route || ''),
253
+ intent: shortText(input.intent),
254
+ loop_kind: String(input.loop_kind || 'harness'),
255
+ stages,
256
+ evidence,
257
+ blockers,
258
+ truth_status: truth,
259
+ intent_label: intentLabel,
260
+ 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')),
262
+ fix_first_items: asList(input.fix_first_items || input.fix_first_item),
263
+ remaining_tasks: asList(input.remaining_tasks || input.remaining_task),
264
+ recommended_direction: shortText(input.recommended_direction || input.direction),
265
+ implementation_notes: asList(input.implementation_notes || input.implementation_note),
266
+ why_this_next: shortText(input.why_this_next),
267
+ blocked_by: asList(input.blocked_by),
268
+ owner_route: normalizeOwnerRoute(input.owner_route || input.route),
269
+ study_note: studyNote
270
+ };
271
+ }
202
272
  export function buildUeyeRunReport(input = {}) {
203
273
  const references = Array.isArray(input.reference_sources)
204
274
  ? input.reference_sources.map((item) => buildUeyeVisualProvenance(item))
@@ -240,6 +310,102 @@ export function buildUeyeRunReport(input = {}) {
240
310
  truth_status: isTruthStatus(input.truth_status) ? input.truth_status : finalTruth
241
311
  };
242
312
  }
313
+ function buildStudyNoteSection(section, fallback, kind) {
314
+ const source = section && typeof section === 'object' ? section : fallback;
315
+ const code = shortText(source.code);
316
+ const role = shortText(source.role);
317
+ const symptom = kind === 'problem' ? shortText(source.symptom) : undefined;
318
+ const summary = kind === 'change' ? shortText(source.summary) : undefined;
319
+ return {
320
+ code,
321
+ role,
322
+ ...(symptom !== undefined ? { symptom } : {}),
323
+ ...(summary !== undefined ? { summary } : {}),
324
+ truth_status: code || role || symptom || summary ? 'partial' : 'assumed'
325
+ };
326
+ }
327
+ function missingStudyNoteLimits(problem, change, whyItMatters = '', learningNote = '') {
328
+ const limits = [];
329
+ if (!problem.code)
330
+ limits.push('issue_code not provided');
331
+ if (!problem.role)
332
+ limits.push('issue_role not provided');
333
+ if (!problem.symptom)
334
+ limits.push('issue_symptom not provided');
335
+ if (!change.code)
336
+ limits.push('changed_code not provided');
337
+ if (!change.role)
338
+ limits.push('changed_role not provided');
339
+ if (!change.summary)
340
+ limits.push('change_summary not provided');
341
+ if (!whyItMatters)
342
+ limits.push('why_it_matters not provided');
343
+ if (!learningNote)
344
+ limits.push('learning_note not provided');
345
+ return limits;
346
+ }
347
+ function buildLoopStage(value = '') {
348
+ if (value && typeof value === 'object') {
349
+ const item = value;
350
+ return loopStage(String(item.id || ''), item.status, String(item.note || ''));
351
+ }
352
+ const [id = '', rawStatus = '', ...noteParts] = String(value || '').split(':');
353
+ return loopStage(id, rawStatus, noteParts.join(':'));
354
+ }
355
+ function loopStage(id = '', rawStatus = '', note = '') {
356
+ const status = normalizeLoopStageStatus(rawStatus);
357
+ return {
358
+ id: shortText(id || 'stage'),
359
+ status,
360
+ note: shortText(note),
361
+ truth_status: stageTruth(status)
362
+ };
363
+ }
364
+ function normalizeLoopStageStatus(value = '') {
365
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
366
+ if (text === 'pass' || text === 'passed' || text === 'ok')
367
+ return 'passed';
368
+ if (text === 'fail' || text === 'failed' || text === 'error')
369
+ return 'failed';
370
+ if (text === 'block' || text === 'blocked')
371
+ return 'blocked';
372
+ if (text === 'skip' || text === 'skipped')
373
+ return 'skipped';
374
+ if (text === 'partial')
375
+ return 'partial';
376
+ if (text === 'pending')
377
+ return 'pending';
378
+ return 'recorded';
379
+ }
380
+ function stageTruth(status) {
381
+ if (status === 'passed')
382
+ return 'verified';
383
+ if (status === 'failed' || status === 'blocked')
384
+ return 'blocked';
385
+ if (status === 'skipped')
386
+ return 'skipped';
387
+ if (status === 'pending')
388
+ return 'assumed';
389
+ return 'partial';
390
+ }
391
+ function normalizeToolIntentLabel(value = '') {
392
+ const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
393
+ if (['read_only', 'write', 'destructive', 'runtime', 'visual', 'publish'].includes(text))
394
+ return text;
395
+ return 'read_only';
396
+ }
397
+ function normalizeOwnerRoute(value = '') {
398
+ const text = String(value || '').trim().replace(/^\$/, '').replace(/^yam-/, '');
399
+ if (['quick', 'ueye', 'question', 'scout', 'deep', 'mission'].includes(text))
400
+ return `$${text}`;
401
+ return text ? shortText(text, 80) : '';
402
+ }
403
+ function shortText(value = '', limit = 240) {
404
+ const text = String(value || '').trim().replace(/\s+/g, ' ');
405
+ if (text.length <= limit)
406
+ return text;
407
+ return `${text.slice(0, limit - 3)}...`;
408
+ }
243
409
  export function buildMediaGenerationProof(input = {}) {
244
410
  const requested = Boolean(input.generation_requested);
245
411
  const attempted = Boolean(input.generation_attempted);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yam-flow",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
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,30 @@ 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
+
81
+ `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`, and `owner_route`.
82
+
57
83
  ## Route Weight
58
84
 
59
85
  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, and why that next step matters.
@@ -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, and why that next step matters.
@@ -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, and why that next step matters.
@@ -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, and why that next step matters.