yam-flow 0.1.9 → 2.0.0
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 +32 -0
- package/COMMANDS.md +2 -2
- package/README.md +5 -4
- package/dist/bin/yam.js +65 -2
- package/dist/lib/trust-kernel.d.ts +15 -0
- package/dist/lib/trust-kernel.js +35 -3
- package/package.json +1 -1
- package/references/final-report.md +6 -1
- package/skills/deep/SKILL.md +1 -1
- package/skills/mission/SKILL.md +1 -1
- package/skills/quick/SKILL.md +1 -1
- package/skills/ueye/SKILL.md +1 -1
- package/src/bin/yam.ts +67 -3
- package/src/lib/trust-kernel.ts +50 -3
- package/yam.manifest.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to yam-flow are documented here.
|
|
4
4
|
|
|
5
|
+
## v2.0.0 - 2026-06-24
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Extended `yam loop report --json` with lightweight requirement coverage, `failure_cause`, `recovery_hint`, and `avoidance_note` so handoff artifacts can show what must still be covered before a completion claim.
|
|
10
|
+
- Added `readiness_receipt` to `yam release report --json` to summarize the read-only evidence basis for package/version, registry, auth, git, dist, tarball, and release-check readiness.
|
|
11
|
+
|
|
12
|
+
### Improved
|
|
13
|
+
|
|
14
|
+
- Uncovered loop requirements now block verified truth, default `blocked_kind` to `requirement_uncovered`, and point the default next action at the first uncovered requirement.
|
|
15
|
+
- Documented that loop avoidance notes are report-only; durable learning remains explicit through `yam memory add`.
|
|
16
|
+
|
|
17
|
+
### Verification
|
|
18
|
+
|
|
19
|
+
- `npm run typecheck`
|
|
20
|
+
- `npm run build`
|
|
21
|
+
- `npm run cli-smoke`
|
|
22
|
+
- `npm run verify:self`
|
|
23
|
+
- `node ./dist/bin/yam.js loop report --json` with uncovered requirement truth blocking
|
|
24
|
+
- `node ./dist/bin/yam.js release report --json` (blocked as expected by npm auth readiness and dirty git, with `readiness_receipt`)
|
|
25
|
+
|
|
26
|
+
## v1.9.1 - 2026-06-19
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- 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.
|
|
31
|
+
- Updated loop report smoke coverage to assert the new handoff fields.
|
|
32
|
+
|
|
33
|
+
### Improved
|
|
34
|
+
|
|
35
|
+
- 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.
|
|
36
|
+
|
|
5
37
|
## v0.1.9 - 2026-06-18
|
|
6
38
|
|
|
7
39
|
### 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" --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 --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" --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
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, fix-first items, remaining tasks, recommended direction, blocked-by notes, owner route, 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" --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 --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" --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
|
|
146
146
|
yam release report --json
|
|
147
147
|
yam safety "supabase db reset"
|
|
148
148
|
yam detect /path/to/project
|
|
@@ -215,11 +215,12 @@ These shapes keep reports machine-readable without turning normal work into a he
|
|
|
215
215
|
|
|
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
|
-
- 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 handoff artifact:
|
|
218
|
+
- 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.
|
|
219
|
+
- 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.
|
|
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
|
+
- 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`.
|
|
221
222
|
- Publish blocker evidence: release reports classify common npm auth, permission, OTP, immutable-version, cache, registry, and tarball failures into safe next actions.
|
|
222
|
-
- Publish readiness evidence: release reports run read-only registry/auth/version probes, redact account/token details,
|
|
223
|
+
- 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.
|
|
223
224
|
- Context pressure: `yam context pressure` explains when project context is getting stale, broad, or confusing enough to summarize, refresh, narrow scope, or deepen route.
|
|
224
225
|
- Cleanup scan: `yam cleanup scan` is read-only and advisory; it reports confusing hooks, local skill folders, stale traces, or old proof artifacts without deleting anything.
|
|
225
226
|
- Benchmark optimization loop lite: use `yam measure <route>` and `yam template tuning` to record baseline, one route wording change, rerun result, keep/revert decision, and stop condition.
|
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 = [];
|
|
@@ -1580,6 +1586,7 @@ function runReleaseReport() {
|
|
|
1580
1586
|
const publishReadiness = releasePublishReadiness(checks, provenance, tarball, publishBlockerEvidence);
|
|
1581
1587
|
const nextActions = releaseNextActions(checks, provenance, tarball, publishBlockerEvidence, publishReadiness);
|
|
1582
1588
|
const ok = failed.length === 0 && publishReadiness.status === 'ready';
|
|
1589
|
+
const readinessReceipt = releaseReadinessReceipt(provenance, freshness, tarball, publishReadiness, ok);
|
|
1583
1590
|
return {
|
|
1584
1591
|
schema: 'yam.release-report.v1',
|
|
1585
1592
|
generated_at: startedAt,
|
|
@@ -1593,11 +1600,53 @@ function runReleaseReport() {
|
|
|
1593
1600
|
tarball,
|
|
1594
1601
|
freshness,
|
|
1595
1602
|
publish_readiness: publishReadiness,
|
|
1603
|
+
readiness_receipt: readinessReceipt,
|
|
1596
1604
|
study_note: releaseStudyNote(publishReadiness, publishBlockerEvidence),
|
|
1597
1605
|
publishBlockerEvidence,
|
|
1598
1606
|
next_actions: nextActions
|
|
1599
1607
|
};
|
|
1600
1608
|
}
|
|
1609
|
+
function releaseReadinessReceipt(provenance = {}, freshness = {}, tarball = {}, publishReadiness = {}, ok = false) {
|
|
1610
|
+
return {
|
|
1611
|
+
schema: 'yam.release-readiness-receipt.v1',
|
|
1612
|
+
generated_at: new Date().toISOString(),
|
|
1613
|
+
package_name: PACKAGE_JSON.name,
|
|
1614
|
+
local_version: VERSION,
|
|
1615
|
+
registry: {
|
|
1616
|
+
url: String(publishReadiness.registry?.url || ''),
|
|
1617
|
+
latest_version: String(publishReadiness.registry?.latest_version || ''),
|
|
1618
|
+
version_status: String(publishReadiness.registry?.version_status || 'not_verified'),
|
|
1619
|
+
truth_status: publishReadiness.registry?.truth_status || 'partial'
|
|
1620
|
+
},
|
|
1621
|
+
auth: {
|
|
1622
|
+
command: 'npm whoami',
|
|
1623
|
+
status: String(publishReadiness.auth?.status || 'not_verified'),
|
|
1624
|
+
account: publishReadiness.auth?.status === 'authenticated' ? 'observed_redacted' : '',
|
|
1625
|
+
truth_status: publishReadiness.auth?.truth_status || 'partial'
|
|
1626
|
+
},
|
|
1627
|
+
git: {
|
|
1628
|
+
commit: String(provenance.git_commit || ''),
|
|
1629
|
+
dirty: Boolean(provenance.git_dirty),
|
|
1630
|
+
dirty_lines_observed: Array.isArray(provenance.git_status_lines) ? provenance.git_status_lines.length : 0,
|
|
1631
|
+
truth_status: provenance.truth_status || 'partial'
|
|
1632
|
+
},
|
|
1633
|
+
checks: {
|
|
1634
|
+
dist: freshness.dist || 'not-verified',
|
|
1635
|
+
package_boundary: freshness.package_boundary || 'not-verified',
|
|
1636
|
+
cli_smoke: freshness.cli_smoke || 'not-verified',
|
|
1637
|
+
tarball: tarball.status === 'checked' ? 'checked' : 'not-verified'
|
|
1638
|
+
},
|
|
1639
|
+
tarball: {
|
|
1640
|
+
status: String(tarball.status || 'not-verified'),
|
|
1641
|
+
name: String(tarball.tarball_name || ''),
|
|
1642
|
+
integrity_present: Boolean(tarball.integrity),
|
|
1643
|
+
shasum_present: Boolean(tarball.shasum),
|
|
1644
|
+
truth_status: tarball.truth_status || 'partial'
|
|
1645
|
+
},
|
|
1646
|
+
publish_attempted: false,
|
|
1647
|
+
truth_status: ok ? 'verified' : 'blocked'
|
|
1648
|
+
};
|
|
1649
|
+
}
|
|
1601
1650
|
function releaseProvenance(checks = []) {
|
|
1602
1651
|
const gitCommit = runReadOnlyCommand('git', ['rev-parse', '--short', 'HEAD']);
|
|
1603
1652
|
const gitStatus = runReadOnlyCommand('git', ['status', '--short']);
|
|
@@ -1973,24 +2022,34 @@ function loopUsage() {
|
|
|
1973
2022
|
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
2023
|
|
|
1975
2024
|
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] [--fix-first-item text] [--remaining-task text] [--recommended-direction text] [--implementation-note text] [--why-this-next text] [--blocked-by text] [--owner-route route] [--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]
|
|
2025
|
+
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]
|
|
1977
2026
|
`);
|
|
1978
2027
|
}
|
|
1979
2028
|
async function loopReport(args = []) {
|
|
1980
2029
|
if (args[0] === 'help' || args[0] === '--help' || args[0] === '-h')
|
|
1981
2030
|
return loopUsage();
|
|
1982
|
-
const flags = parseSimpleFlags(args, new Set(['route', 'intent', 'loop-kind', 'stage', 'evidence', 'blocked', 'blocker', 'next-action', 'fix-first-item', 'remaining-task', 'recommended-direction', 'direction', 'implementation-note', 'why-this-next', 'blocked-by', 'owner-route', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
|
|
2031
|
+
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']));
|
|
1983
2032
|
const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
|
|
1984
2033
|
const report = buildLoopReport({
|
|
1985
2034
|
route: normalizeRoute(flags.route) || String(flags.route || ''),
|
|
1986
2035
|
intent: String(flags.intent || ''),
|
|
1987
2036
|
loop_kind: String(flags.loop_kind || flags.route || 'harness'),
|
|
2037
|
+
stage_conventions: arrayFlag(flags.stage_convention),
|
|
1988
2038
|
stages: arrayFlag(flags.stage),
|
|
1989
2039
|
evidence: arrayFlag(flags.evidence),
|
|
2040
|
+
evidence_level: normalizeLoopEvidenceLevelFlag(flags.evidence_level),
|
|
2041
|
+
evidence_stamp: String(flags.evidence_stamp || ''),
|
|
2042
|
+
source_digest: String(flags.source_digest || ''),
|
|
2043
|
+
covered_requirements: arrayFlag(flags.covered_requirement),
|
|
2044
|
+
uncovered_requirements: arrayFlag(flags.uncovered_requirement),
|
|
1990
2045
|
blockers,
|
|
2046
|
+
blocked_kind: String(flags.blocked_kind || ''),
|
|
2047
|
+
failure_cause: String(flags.failure_cause || ''),
|
|
1991
2048
|
truth_status: isTruthStatus(flags.truth) ? flags.truth : undefined,
|
|
1992
2049
|
intent_label: normalizeToolIntent(flags.intent_label || flags.tool_intent || 'read_only'),
|
|
1993
2050
|
next_action: String(flags.next_action || ''),
|
|
2051
|
+
safe_retry: String(flags.safe_retry || ''),
|
|
2052
|
+
recovery_hint: String(flags.recovery_hint || ''),
|
|
1994
2053
|
fix_first_items: arrayFlag(flags.fix_first_item),
|
|
1995
2054
|
remaining_tasks: arrayFlag(flags.remaining_task),
|
|
1996
2055
|
recommended_direction: String(flags.recommended_direction || flags.direction || ''),
|
|
@@ -1998,6 +2057,10 @@ async function loopReport(args = []) {
|
|
|
1998
2057
|
why_this_next: String(flags.why_this_next || ''),
|
|
1999
2058
|
blocked_by: arrayFlag(flags.blocked_by),
|
|
2000
2059
|
owner_route: String(flags.owner_route || flags.route || ''),
|
|
2060
|
+
owner_scope: [...arrayFlag(flags.owner_scope), ...arrayFlag(flags.scope)],
|
|
2061
|
+
scope_owner: String(flags.scope_owner || flags.owner || ''),
|
|
2062
|
+
side_effects: arrayFlag(flags.side_effect),
|
|
2063
|
+
avoidance_note: String(flags.avoidance_note || ''),
|
|
2001
2064
|
issue_code: String(flags.issue_code || ''),
|
|
2002
2065
|
issue_role: String(flags.issue_role || ''),
|
|
2003
2066
|
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,13 +155,23 @@ 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;
|
|
164
|
+
covered_requirements: string[];
|
|
165
|
+
uncovered_requirements: string[];
|
|
159
166
|
blockers: string[];
|
|
167
|
+
blocked_kind: string;
|
|
168
|
+
failure_cause: string;
|
|
160
169
|
truth_status: TruthStatus;
|
|
161
170
|
intent_label: ToolIntent;
|
|
162
171
|
tool_intent: ToolIntent;
|
|
163
172
|
next_action: string;
|
|
173
|
+
safe_retry: string;
|
|
174
|
+
recovery_hint: string;
|
|
164
175
|
fix_first_items: string[];
|
|
165
176
|
remaining_tasks: string[];
|
|
166
177
|
recommended_direction: string;
|
|
@@ -168,6 +179,10 @@ export interface LoopReport {
|
|
|
168
179
|
why_this_next: string;
|
|
169
180
|
blocked_by: string[];
|
|
170
181
|
owner_route: string;
|
|
182
|
+
owner_scope: string[];
|
|
183
|
+
scope_owner: string;
|
|
184
|
+
side_effects: string[];
|
|
185
|
+
avoidance_note: string;
|
|
171
186
|
study_note: StudyNote;
|
|
172
187
|
}
|
|
173
188
|
export interface UeyeRunReport {
|
package/dist/lib/trust-kernel.js
CHANGED
|
@@ -236,10 +236,20 @@ export function buildLoopReport(input = {}) {
|
|
|
236
236
|
? input.stages.map((stage) => buildLoopStage(stage))
|
|
237
237
|
: [];
|
|
238
238
|
const evidence = asList(input.evidence);
|
|
239
|
+
const coveredRequirements = asList(input.covered_requirements || input.covered_requirement);
|
|
240
|
+
const uncoveredRequirements = asList(input.uncovered_requirements || input.uncovered_requirement);
|
|
239
241
|
const blockers = asList(input.blockers || input.blocked);
|
|
242
|
+
const blockedBy = asList(input.blocked_by);
|
|
243
|
+
const blockedKind = shortText(input.blocked_kind || (uncoveredRequirements.length ? 'requirement_uncovered' : blockers.length || blockedBy.length ? 'evidence_missing' : ''));
|
|
244
|
+
const failureCause = shortText(input.failure_cause);
|
|
245
|
+
const recoveryHint = shortText(input.recovery_hint);
|
|
246
|
+
const avoidanceNote = shortText(input.avoidance_note);
|
|
247
|
+
const evidenceStamp = shortText(input.evidence_stamp || input.source_digest, 320);
|
|
248
|
+
const sourceDigest = shortText(input.source_digest || input.evidence_stamp, 320);
|
|
240
249
|
const hasBlockedStage = stages.some((stage) => stage.status === 'blocked' || stage.status === 'failed');
|
|
250
|
+
const hasBlockerSignal = Boolean(blockers.length || blockedBy.length || blockedKind || uncoveredRequirements.length);
|
|
241
251
|
const requestedTruth = isTruthStatus(input.truth_status) ? input.truth_status : '';
|
|
242
|
-
const derivedTruth =
|
|
252
|
+
const derivedTruth = hasBlockerSignal || hasBlockedStage ? 'blocked'
|
|
243
253
|
: evidence.length && stages.some((stage) => stage.status === 'passed') ? 'verified'
|
|
244
254
|
: evidence.length || stages.length ? 'partial'
|
|
245
255
|
: 'assumed';
|
|
@@ -252,20 +262,36 @@ export function buildLoopReport(input = {}) {
|
|
|
252
262
|
route: String(input.route || ''),
|
|
253
263
|
intent: shortText(input.intent),
|
|
254
264
|
loop_kind: String(input.loop_kind || 'harness'),
|
|
265
|
+
stage_conventions: asList(input.stage_conventions || input.stage_convention).length
|
|
266
|
+
? asList(input.stage_conventions || input.stage_convention)
|
|
267
|
+
: ['brief', 'plan', 'implement', 'critique', 'verify', 'handoff'],
|
|
255
268
|
stages,
|
|
256
269
|
evidence,
|
|
270
|
+
evidence_level: normalizeLoopEvidenceLevel(input.evidence_level),
|
|
271
|
+
evidence_stamp: evidenceStamp,
|
|
272
|
+
source_digest: sourceDigest,
|
|
273
|
+
covered_requirements: coveredRequirements,
|
|
274
|
+
uncovered_requirements: uncoveredRequirements,
|
|
257
275
|
blockers,
|
|
276
|
+
blocked_kind: blockedKind,
|
|
277
|
+
failure_cause: failureCause,
|
|
258
278
|
truth_status: truth,
|
|
259
279
|
intent_label: intentLabel,
|
|
260
280
|
tool_intent: intentLabel,
|
|
261
|
-
next_action: shortText(input.next_action || (
|
|
281
|
+
next_action: shortText(input.next_action || (uncoveredRequirements.length ? `cover requirement before claiming complete: ${uncoveredRequirements[0]}` : hasBlockerSignal ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
|
|
282
|
+
safe_retry: shortText(input.safe_retry || (hasBlockerSignal ? 'retry only after the blocker is resolved and new evidence is recorded' : 'not required')),
|
|
283
|
+
recovery_hint: recoveryHint,
|
|
262
284
|
fix_first_items: asList(input.fix_first_items || input.fix_first_item),
|
|
263
285
|
remaining_tasks: asList(input.remaining_tasks || input.remaining_task),
|
|
264
286
|
recommended_direction: shortText(input.recommended_direction || input.direction),
|
|
265
287
|
implementation_notes: asList(input.implementation_notes || input.implementation_note),
|
|
266
288
|
why_this_next: shortText(input.why_this_next),
|
|
267
|
-
blocked_by:
|
|
289
|
+
blocked_by: blockedBy,
|
|
268
290
|
owner_route: normalizeOwnerRoute(input.owner_route || input.route),
|
|
291
|
+
owner_scope: asList(input.owner_scope || input.scope),
|
|
292
|
+
scope_owner: normalizeOwnerRoute(input.scope_owner || input.owner),
|
|
293
|
+
side_effects: asList(input.side_effects || input.side_effect),
|
|
294
|
+
avoidance_note: avoidanceNote,
|
|
269
295
|
study_note: studyNote
|
|
270
296
|
};
|
|
271
297
|
}
|
|
@@ -400,6 +426,12 @@ function normalizeOwnerRoute(value = '') {
|
|
|
400
426
|
return `$${text}`;
|
|
401
427
|
return text ? shortText(text, 80) : '';
|
|
402
428
|
}
|
|
429
|
+
function normalizeLoopEvidenceLevel(value = '') {
|
|
430
|
+
const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
|
|
431
|
+
if (['fixture', 'smoke', 'local', 'real'].includes(text))
|
|
432
|
+
return text;
|
|
433
|
+
return 'none';
|
|
434
|
+
}
|
|
403
435
|
function shortText(value = '', limit = 240) {
|
|
404
436
|
const text = String(value || '').trim().replace(/\s+/g, ' ');
|
|
405
437
|
if (text.length <= limit)
|
package/package.json
CHANGED
|
@@ -77,8 +77,13 @@ Use this when the next run needs a clear starting point:
|
|
|
77
77
|
- Recommended direction.
|
|
78
78
|
- Why this next step matters.
|
|
79
79
|
- What is blocked, and by what.
|
|
80
|
+
- Covered and uncovered requirements when the next run could otherwise overclaim completion.
|
|
81
|
+
- Evidence level or stamp when the handoff relies on a specific command, file, or report.
|
|
82
|
+
- Blocker kind, failure cause, recovery hint, and safe retry when the next run should not blindly repeat the same action.
|
|
83
|
+
- Avoidance note when a repeated mistake should be easy to spot; durable memory still uses explicit `yam memory add`.
|
|
84
|
+
- Owner route, scope owner, and side effects when more than one person or route may continue the work.
|
|
80
85
|
|
|
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 `
|
|
86
|
+
`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`, `covered_requirements`, `uncovered_requirements`, `blocked_kind`, `failure_cause`, `recovery_hint`, `safe_retry`, `evidence_level`, `evidence_stamp`, `owner_route`, `owner_scope`, `scope_owner`, `side_effects`, and `avoidance_note`.
|
|
82
87
|
|
|
83
88
|
## Route Weight
|
|
84
89
|
|
package/skills/deep/SKILL.md
CHANGED
|
@@ -74,4 +74,4 @@ Include:
|
|
|
74
74
|
- Evidence gathered.
|
|
75
75
|
- Truth status.
|
|
76
76
|
- Blockers or remaining risk.
|
|
77
|
-
- Handoff: fix-first items, remaining tasks, recommended direction,
|
|
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.
|
package/skills/mission/SKILL.md
CHANGED
|
@@ -106,4 +106,4 @@ Report:
|
|
|
106
106
|
- Evidence gathered.
|
|
107
107
|
- Truth status.
|
|
108
108
|
- Cleanup status.
|
|
109
|
-
- Handoff: fix-first items, remaining tasks, recommended direction,
|
|
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.
|
package/skills/quick/SKILL.md
CHANGED
|
@@ -79,4 +79,4 @@ Keep it compact:
|
|
|
79
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.
|
|
80
80
|
- What was checked.
|
|
81
81
|
- What was skipped, blocked, or still risky.
|
|
82
|
-
- Handoff when useful: fix-first items, remaining tasks, recommended direction,
|
|
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.
|
package/skills/ueye/SKILL.md
CHANGED
|
@@ -172,4 +172,4 @@ Report:
|
|
|
172
172
|
- States/viewports checked.
|
|
173
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.
|
|
174
174
|
- Truth status and visual verification cap.
|
|
175
|
-
- Handoff when useful: fix-first visual issues, remaining tasks, recommended direction,
|
|
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 = [];
|
|
@@ -1569,6 +1575,7 @@ function runReleaseReport() {
|
|
|
1569
1575
|
const publishReadiness = releasePublishReadiness(checks, provenance, tarball, publishBlockerEvidence);
|
|
1570
1576
|
const nextActions = releaseNextActions(checks, provenance, tarball, publishBlockerEvidence, publishReadiness);
|
|
1571
1577
|
const ok = failed.length === 0 && publishReadiness.status === 'ready';
|
|
1578
|
+
const readinessReceipt = releaseReadinessReceipt(provenance, freshness, tarball, publishReadiness, ok);
|
|
1572
1579
|
return {
|
|
1573
1580
|
schema: 'yam.release-report.v1',
|
|
1574
1581
|
generated_at: startedAt,
|
|
@@ -1582,12 +1589,55 @@ function runReleaseReport() {
|
|
|
1582
1589
|
tarball,
|
|
1583
1590
|
freshness,
|
|
1584
1591
|
publish_readiness: publishReadiness,
|
|
1592
|
+
readiness_receipt: readinessReceipt,
|
|
1585
1593
|
study_note: releaseStudyNote(publishReadiness, publishBlockerEvidence),
|
|
1586
1594
|
publishBlockerEvidence,
|
|
1587
1595
|
next_actions: nextActions
|
|
1588
1596
|
};
|
|
1589
1597
|
}
|
|
1590
1598
|
|
|
1599
|
+
function releaseReadinessReceipt(provenance: AnyRecord = {}, freshness: AnyRecord = {}, tarball: AnyRecord = {}, publishReadiness: AnyRecord = {}, ok = false) {
|
|
1600
|
+
return {
|
|
1601
|
+
schema: 'yam.release-readiness-receipt.v1',
|
|
1602
|
+
generated_at: new Date().toISOString(),
|
|
1603
|
+
package_name: PACKAGE_JSON.name,
|
|
1604
|
+
local_version: VERSION,
|
|
1605
|
+
registry: {
|
|
1606
|
+
url: String(publishReadiness.registry?.url || ''),
|
|
1607
|
+
latest_version: String(publishReadiness.registry?.latest_version || ''),
|
|
1608
|
+
version_status: String(publishReadiness.registry?.version_status || 'not_verified'),
|
|
1609
|
+
truth_status: publishReadiness.registry?.truth_status || 'partial'
|
|
1610
|
+
},
|
|
1611
|
+
auth: {
|
|
1612
|
+
command: 'npm whoami',
|
|
1613
|
+
status: String(publishReadiness.auth?.status || 'not_verified'),
|
|
1614
|
+
account: publishReadiness.auth?.status === 'authenticated' ? 'observed_redacted' : '',
|
|
1615
|
+
truth_status: publishReadiness.auth?.truth_status || 'partial'
|
|
1616
|
+
},
|
|
1617
|
+
git: {
|
|
1618
|
+
commit: String(provenance.git_commit || ''),
|
|
1619
|
+
dirty: Boolean(provenance.git_dirty),
|
|
1620
|
+
dirty_lines_observed: Array.isArray(provenance.git_status_lines) ? provenance.git_status_lines.length : 0,
|
|
1621
|
+
truth_status: provenance.truth_status || 'partial'
|
|
1622
|
+
},
|
|
1623
|
+
checks: {
|
|
1624
|
+
dist: freshness.dist || 'not-verified',
|
|
1625
|
+
package_boundary: freshness.package_boundary || 'not-verified',
|
|
1626
|
+
cli_smoke: freshness.cli_smoke || 'not-verified',
|
|
1627
|
+
tarball: tarball.status === 'checked' ? 'checked' : 'not-verified'
|
|
1628
|
+
},
|
|
1629
|
+
tarball: {
|
|
1630
|
+
status: String(tarball.status || 'not-verified'),
|
|
1631
|
+
name: String(tarball.tarball_name || ''),
|
|
1632
|
+
integrity_present: Boolean(tarball.integrity),
|
|
1633
|
+
shasum_present: Boolean(tarball.shasum),
|
|
1634
|
+
truth_status: tarball.truth_status || 'partial'
|
|
1635
|
+
},
|
|
1636
|
+
publish_attempted: false,
|
|
1637
|
+
truth_status: ok ? 'verified' : 'blocked'
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1591
1641
|
function releaseProvenance(checks = []) {
|
|
1592
1642
|
const gitCommit = runReadOnlyCommand('git', ['rev-parse', '--short', 'HEAD']);
|
|
1593
1643
|
const gitStatus = runReadOnlyCommand('git', ['status', '--short']);
|
|
@@ -1971,24 +2021,34 @@ function loopUsage() {
|
|
|
1971
2021
|
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
2022
|
|
|
1973
2023
|
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] [--fix-first-item text] [--remaining-task text] [--recommended-direction text] [--implementation-note text] [--why-this-next text] [--blocked-by text] [--owner-route route] [--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]
|
|
2024
|
+
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]
|
|
1975
2025
|
`);
|
|
1976
2026
|
}
|
|
1977
2027
|
|
|
1978
2028
|
async function loopReport(args = []) {
|
|
1979
2029
|
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', 'fix-first-item', 'remaining-task', 'recommended-direction', 'direction', 'implementation-note', 'why-this-next', 'blocked-by', 'owner-route', 'truth', 'intent-label', 'tool-intent', 'issue-code', 'issue-role', 'issue-symptom', 'changed-code', 'changed-role', 'change-summary', 'why-important', 'learning-note', 'json']));
|
|
2030
|
+
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']));
|
|
1981
2031
|
const blockers = [...arrayFlag(flags.blocked), ...arrayFlag(flags.blocker)];
|
|
1982
2032
|
const report = buildLoopReport({
|
|
1983
2033
|
route: normalizeRoute(flags.route) || String(flags.route || ''),
|
|
1984
2034
|
intent: String(flags.intent || ''),
|
|
1985
2035
|
loop_kind: String(flags.loop_kind || flags.route || 'harness'),
|
|
2036
|
+
stage_conventions: arrayFlag(flags.stage_convention),
|
|
1986
2037
|
stages: arrayFlag(flags.stage),
|
|
1987
2038
|
evidence: arrayFlag(flags.evidence),
|
|
2039
|
+
evidence_level: normalizeLoopEvidenceLevelFlag(flags.evidence_level),
|
|
2040
|
+
evidence_stamp: String(flags.evidence_stamp || ''),
|
|
2041
|
+
source_digest: String(flags.source_digest || ''),
|
|
2042
|
+
covered_requirements: arrayFlag(flags.covered_requirement),
|
|
2043
|
+
uncovered_requirements: arrayFlag(flags.uncovered_requirement),
|
|
1988
2044
|
blockers,
|
|
2045
|
+
blocked_kind: String(flags.blocked_kind || ''),
|
|
2046
|
+
failure_cause: String(flags.failure_cause || ''),
|
|
1989
2047
|
truth_status: isTruthStatus(flags.truth) ? flags.truth : undefined,
|
|
1990
2048
|
intent_label: normalizeToolIntent(flags.intent_label || flags.tool_intent || 'read_only'),
|
|
1991
2049
|
next_action: String(flags.next_action || ''),
|
|
2050
|
+
safe_retry: String(flags.safe_retry || ''),
|
|
2051
|
+
recovery_hint: String(flags.recovery_hint || ''),
|
|
1992
2052
|
fix_first_items: arrayFlag(flags.fix_first_item),
|
|
1993
2053
|
remaining_tasks: arrayFlag(flags.remaining_task),
|
|
1994
2054
|
recommended_direction: String(flags.recommended_direction || flags.direction || ''),
|
|
@@ -1996,6 +2056,10 @@ async function loopReport(args = []) {
|
|
|
1996
2056
|
why_this_next: String(flags.why_this_next || ''),
|
|
1997
2057
|
blocked_by: arrayFlag(flags.blocked_by),
|
|
1998
2058
|
owner_route: String(flags.owner_route || flags.route || ''),
|
|
2059
|
+
owner_scope: [...arrayFlag(flags.owner_scope), ...arrayFlag(flags.scope)],
|
|
2060
|
+
scope_owner: String(flags.scope_owner || flags.owner || ''),
|
|
2061
|
+
side_effects: arrayFlag(flags.side_effect),
|
|
2062
|
+
avoidance_note: String(flags.avoidance_note || ''),
|
|
1999
2063
|
issue_code: String(flags.issue_code || ''),
|
|
2000
2064
|
issue_role: String(flags.issue_role || ''),
|
|
2001
2065
|
issue_symptom: String(flags.issue_symptom || ''),
|
package/src/lib/trust-kernel.ts
CHANGED
|
@@ -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,13 +183,23 @@ 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;
|
|
192
|
+
covered_requirements: string[];
|
|
193
|
+
uncovered_requirements: string[];
|
|
187
194
|
blockers: string[];
|
|
195
|
+
blocked_kind: string;
|
|
196
|
+
failure_cause: string;
|
|
188
197
|
truth_status: TruthStatus;
|
|
189
198
|
intent_label: ToolIntent;
|
|
190
199
|
tool_intent: ToolIntent;
|
|
191
200
|
next_action: string;
|
|
201
|
+
safe_retry: string;
|
|
202
|
+
recovery_hint: string;
|
|
192
203
|
fix_first_items: string[];
|
|
193
204
|
remaining_tasks: string[];
|
|
194
205
|
recommended_direction: string;
|
|
@@ -196,6 +207,10 @@ export interface LoopReport {
|
|
|
196
207
|
why_this_next: string;
|
|
197
208
|
blocked_by: string[];
|
|
198
209
|
owner_route: string;
|
|
210
|
+
owner_scope: string[];
|
|
211
|
+
scope_owner: string;
|
|
212
|
+
side_effects: string[];
|
|
213
|
+
avoidance_note: string;
|
|
199
214
|
study_note: StudyNote;
|
|
200
215
|
}
|
|
201
216
|
|
|
@@ -540,10 +555,20 @@ export function buildLoopReport(input: Partial<LoopReport> & Record<string, unkn
|
|
|
540
555
|
? input.stages.map((stage) => buildLoopStage(stage))
|
|
541
556
|
: [];
|
|
542
557
|
const evidence = asList(input.evidence);
|
|
558
|
+
const coveredRequirements = asList(input.covered_requirements || input.covered_requirement);
|
|
559
|
+
const uncoveredRequirements = asList(input.uncovered_requirements || input.uncovered_requirement);
|
|
543
560
|
const blockers = asList(input.blockers || input.blocked);
|
|
561
|
+
const blockedBy = asList(input.blocked_by);
|
|
562
|
+
const blockedKind = shortText(input.blocked_kind || (uncoveredRequirements.length ? 'requirement_uncovered' : blockers.length || blockedBy.length ? 'evidence_missing' : ''));
|
|
563
|
+
const failureCause = shortText(input.failure_cause);
|
|
564
|
+
const recoveryHint = shortText(input.recovery_hint);
|
|
565
|
+
const avoidanceNote = shortText(input.avoidance_note);
|
|
566
|
+
const evidenceStamp = shortText(input.evidence_stamp || input.source_digest, 320);
|
|
567
|
+
const sourceDigest = shortText(input.source_digest || input.evidence_stamp, 320);
|
|
544
568
|
const hasBlockedStage = stages.some((stage) => stage.status === 'blocked' || stage.status === 'failed');
|
|
569
|
+
const hasBlockerSignal = Boolean(blockers.length || blockedBy.length || blockedKind || uncoveredRequirements.length);
|
|
545
570
|
const requestedTruth = isTruthStatus(input.truth_status) ? input.truth_status : '';
|
|
546
|
-
const derivedTruth: TruthStatus =
|
|
571
|
+
const derivedTruth: TruthStatus = hasBlockerSignal || hasBlockedStage ? 'blocked'
|
|
547
572
|
: evidence.length && stages.some((stage) => stage.status === 'passed') ? 'verified'
|
|
548
573
|
: evidence.length || stages.length ? 'partial'
|
|
549
574
|
: 'assumed';
|
|
@@ -556,20 +581,36 @@ export function buildLoopReport(input: Partial<LoopReport> & Record<string, unkn
|
|
|
556
581
|
route: String(input.route || ''),
|
|
557
582
|
intent: shortText(input.intent),
|
|
558
583
|
loop_kind: String(input.loop_kind || 'harness'),
|
|
584
|
+
stage_conventions: asList(input.stage_conventions || input.stage_convention).length
|
|
585
|
+
? asList(input.stage_conventions || input.stage_convention)
|
|
586
|
+
: ['brief', 'plan', 'implement', 'critique', 'verify', 'handoff'],
|
|
559
587
|
stages,
|
|
560
588
|
evidence,
|
|
589
|
+
evidence_level: normalizeLoopEvidenceLevel(input.evidence_level),
|
|
590
|
+
evidence_stamp: evidenceStamp,
|
|
591
|
+
source_digest: sourceDigest,
|
|
592
|
+
covered_requirements: coveredRequirements,
|
|
593
|
+
uncovered_requirements: uncoveredRequirements,
|
|
561
594
|
blockers,
|
|
595
|
+
blocked_kind: blockedKind,
|
|
596
|
+
failure_cause: failureCause,
|
|
562
597
|
truth_status: truth,
|
|
563
598
|
intent_label: intentLabel,
|
|
564
599
|
tool_intent: intentLabel,
|
|
565
|
-
next_action: shortText(input.next_action || (
|
|
600
|
+
next_action: shortText(input.next_action || (uncoveredRequirements.length ? `cover requirement before claiming complete: ${uncoveredRequirements[0]}` : hasBlockerSignal ? 'resolve the blocker before claiming this loop complete' : 'record the next smallest useful action')),
|
|
601
|
+
safe_retry: shortText(input.safe_retry || (hasBlockerSignal ? 'retry only after the blocker is resolved and new evidence is recorded' : 'not required')),
|
|
602
|
+
recovery_hint: recoveryHint,
|
|
566
603
|
fix_first_items: asList(input.fix_first_items || input.fix_first_item),
|
|
567
604
|
remaining_tasks: asList(input.remaining_tasks || input.remaining_task),
|
|
568
605
|
recommended_direction: shortText(input.recommended_direction || input.direction),
|
|
569
606
|
implementation_notes: asList(input.implementation_notes || input.implementation_note),
|
|
570
607
|
why_this_next: shortText(input.why_this_next),
|
|
571
|
-
blocked_by:
|
|
608
|
+
blocked_by: blockedBy,
|
|
572
609
|
owner_route: normalizeOwnerRoute(input.owner_route || input.route),
|
|
610
|
+
owner_scope: asList(input.owner_scope || input.scope),
|
|
611
|
+
scope_owner: normalizeOwnerRoute(input.scope_owner || input.owner),
|
|
612
|
+
side_effects: asList(input.side_effects || input.side_effect),
|
|
613
|
+
avoidance_note: avoidanceNote,
|
|
573
614
|
study_note: studyNote
|
|
574
615
|
};
|
|
575
616
|
}
|
|
@@ -694,6 +735,12 @@ function normalizeOwnerRoute(value: unknown = ''): string {
|
|
|
694
735
|
return text ? shortText(text, 80) : '';
|
|
695
736
|
}
|
|
696
737
|
|
|
738
|
+
function normalizeLoopEvidenceLevel(value: unknown = ''): LoopEvidenceLevel {
|
|
739
|
+
const text = String(value || '').toLowerCase().replace(/[-\s]/g, '_');
|
|
740
|
+
if (['fixture', 'smoke', 'local', 'real'].includes(text)) return text as LoopEvidenceLevel;
|
|
741
|
+
return 'none';
|
|
742
|
+
}
|
|
743
|
+
|
|
697
744
|
function shortText(value: unknown = '', limit = 240): string {
|
|
698
745
|
const text = String(value || '').trim().replace(/\s+/g, ' ');
|
|
699
746
|
if (text.length <= limit) return text;
|
package/yam.manifest.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yam",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"principles": [
|
|
5
5
|
"Direction before execution.",
|
|
6
6
|
"Start fast.",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"Context-reuse first.",
|
|
13
13
|
"End with remaining tasks and fix-first items.",
|
|
14
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,
|
|
15
|
+
"Use handoff notes for fix-first items, remaining tasks, recommended next direction, requirement coverage, blocker kind, failure cause, recovery hint, safe retry, evidence level, and owner scope when useful."
|
|
16
16
|
],
|
|
17
17
|
"defaultHooks": false,
|
|
18
18
|
"routes": [
|