changeledger 0.7.0 → 0.9.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.
Files changed (35) hide show
  1. package/AGENTS.md +11 -5
  2. package/README.md +5 -1
  3. package/bin/changeledger.mjs +82 -6
  4. package/package.json +1 -1
  5. package/src/check.mjs +37 -1
  6. package/src/commands/agent-context.mjs +64 -0
  7. package/src/commands/agent-prompt.mjs +22 -0
  8. package/src/commands/agent.mjs +50 -7
  9. package/src/commands/context.mjs +8 -9
  10. package/src/commands/graduate.mjs +20 -8
  11. package/src/commands/view.mjs +6 -2
  12. package/src/contract.mjs +11 -5
  13. package/src/framing.mjs +22 -0
  14. package/src/lifecycle.mjs +4 -3
  15. package/src/metrics.mjs +3 -3
  16. package/src/viewer/domain.mjs +17 -7
  17. package/src/viewer/public/app-state.js +77 -6
  18. package/src/viewer/public/app.js +193 -42
  19. package/src/viewer/public/index.html +2 -2
  20. package/src/viewer/public/state.js +6 -2
  21. package/src/viewer/public/styles.css +205 -14
  22. package/src/viewer/public/view-parts.js +52 -0
  23. package/templates/contract/agent-contexts/implementation.md +18 -0
  24. package/templates/contract/agent-contexts/investigation.md +14 -0
  25. package/templates/contract/agent-contexts/review.md +22 -0
  26. package/templates/contract/agent-prompts/implementation.md +38 -0
  27. package/templates/contract/agent-prompts/investigation.md +41 -0
  28. package/templates/contract/agent-prompts/review.md +36 -0
  29. package/templates/contract/budgets.yml +16 -0
  30. package/templates/contract/close.md +25 -14
  31. package/templates/contract/core.md +43 -35
  32. package/templates/contract/delegation.md +2 -1
  33. package/templates/contract/implement.md +27 -11
  34. package/templates/contract/review.md +12 -9
  35. package/templates/contract/validation.md +16 -2
@@ -23,12 +23,34 @@
23
23
  --status-discarded: #9aa0aa;
24
24
  --status-muted: #8b929e;
25
25
  font-family: "Avenir Next", Avenir, ui-sans-serif, sans-serif;
26
+ color-scheme: dark;
26
27
  }
27
28
 
28
29
  * {
29
30
  box-sizing: border-box;
30
31
  }
31
32
 
33
+ html,
34
+ body {
35
+ scrollbar-width: thin;
36
+ scrollbar-color: #3a414e transparent;
37
+ }
38
+ html::-webkit-scrollbar,
39
+ body::-webkit-scrollbar {
40
+ width: 8px;
41
+ height: 8px;
42
+ }
43
+ html::-webkit-scrollbar-track,
44
+ body::-webkit-scrollbar-track {
45
+ background: transparent;
46
+ }
47
+ html::-webkit-scrollbar-thumb,
48
+ body::-webkit-scrollbar-thumb {
49
+ background: #3a414e;
50
+ border: 2px solid var(--bg);
51
+ border-radius: 999px;
52
+ }
53
+
32
54
  body {
33
55
  margin: 0;
34
56
  background: var(--bg);
@@ -527,16 +549,31 @@ body {
527
549
  padding: 16px;
528
550
  overflow-x: auto;
529
551
  align-items: flex-start;
552
+ }
553
+ .board,
554
+ .detail,
555
+ .detail pre,
556
+ .detail table {
530
557
  scrollbar-width: thin;
531
558
  scrollbar-color: #3a414e transparent;
532
559
  }
533
- .board::-webkit-scrollbar {
560
+ .board::-webkit-scrollbar,
561
+ .detail::-webkit-scrollbar,
562
+ .detail pre::-webkit-scrollbar,
563
+ .detail table::-webkit-scrollbar {
564
+ width: 8px;
534
565
  height: 8px;
535
566
  }
536
- .board::-webkit-scrollbar-track {
567
+ .board::-webkit-scrollbar-track,
568
+ .detail::-webkit-scrollbar-track,
569
+ .detail pre::-webkit-scrollbar-track,
570
+ .detail table::-webkit-scrollbar-track {
537
571
  background: transparent;
538
572
  }
539
- .board::-webkit-scrollbar-thumb {
573
+ .board::-webkit-scrollbar-thumb,
574
+ .detail::-webkit-scrollbar-thumb,
575
+ .detail pre::-webkit-scrollbar-thumb,
576
+ .detail table::-webkit-scrollbar-thumb {
540
577
  background: #3a414e;
541
578
  border: 2px solid var(--bg);
542
579
  border-radius: 999px;
@@ -545,10 +582,10 @@ body {
545
582
  background: var(--panel);
546
583
  border: 1px solid var(--line);
547
584
  border-radius: 12px;
548
- width: clamp(238px, calc((100vw - 116px) / 7), 320px);
549
- min-width: 238px;
550
- max-width: 320px;
551
- flex: 0 0 clamp(238px, calc((100vw - 116px) / 7), 320px);
585
+ width: clamp(190px, calc((100vw - 140px) / 6), 400px);
586
+ min-width: 190px;
587
+ max-width: 400px;
588
+ flex: 0 0 clamp(190px, calc((100vw - 140px) / 6), 400px);
552
589
  }
553
590
  .column-head {
554
591
  display: flex;
@@ -593,6 +630,8 @@ body {
593
630
  font-family: ui-monospace, monospace;
594
631
  color: var(--muted);
595
632
  font-size: 12px;
633
+ min-width: 0;
634
+ overflow-wrap: anywhere;
596
635
  }
597
636
  .type-tag {
598
637
  font-size: 10px;
@@ -625,6 +664,7 @@ body {
625
664
  .card-title {
626
665
  font-weight: 600;
627
666
  line-height: 1.3;
667
+ overflow-wrap: anywhere;
628
668
  }
629
669
  .progress {
630
670
  margin-top: 9px;
@@ -640,6 +680,7 @@ body {
640
680
  }
641
681
  .card-meta {
642
682
  display: flex;
683
+ flex-wrap: wrap;
643
684
  gap: 10px;
644
685
  margin-top: 7px;
645
686
  font-size: 11px;
@@ -689,6 +730,13 @@ body {
689
730
  gap: 10px;
690
731
  margin-top: 15px;
691
732
  }
733
+ .reopen-controls {
734
+ display: grid;
735
+ grid-template-columns: minmax(190px, 1fr) auto;
736
+ align-items: end;
737
+ gap: 10px;
738
+ margin-top: 15px;
739
+ }
692
740
  .rejection-field {
693
741
  display: flex;
694
742
  flex-direction: column;
@@ -750,6 +798,7 @@ body {
750
798
  }
751
799
  .owner {
752
800
  font-weight: 600;
801
+ overflow-wrap: anywhere;
753
802
  }
754
803
  .card.archived {
755
804
  opacity: 0.55;
@@ -847,21 +896,107 @@ body {
847
896
  }
848
897
 
849
898
  /* Overlay + detail */
899
+ .detail-open {
900
+ overflow: hidden;
901
+ }
850
902
  .overlay {
851
903
  position: fixed;
852
904
  inset: 0;
853
905
  background: rgba(0, 0, 0, 0.55);
854
906
  display: flex;
855
907
  justify-content: flex-end;
908
+ align-items: stretch;
856
909
  z-index: 20;
857
910
  }
858
911
  .detail {
859
- width: min(720px, 92vw);
912
+ --detail-width: 960px;
913
+ container-type: inline-size;
914
+ position: relative;
915
+ width: min(var(--detail-width), calc(100vw - 48px));
860
916
  height: 100%;
861
917
  background: var(--bg);
862
918
  border-left: 1px solid var(--line);
863
919
  overflow-y: auto;
920
+ overflow-anchor: none;
864
921
  padding: 22px 26px 60px;
922
+ box-shadow: -24px 0 70px rgba(0, 0, 0, 0.28);
923
+ }
924
+ .detail[data-detail-size="compact"] {
925
+ --detail-width: 720px;
926
+ }
927
+ .detail[data-detail-size="wide"] {
928
+ --detail-width: 960px;
929
+ }
930
+ .detail[data-detail-size="full"] {
931
+ --detail-width: 1280px;
932
+ }
933
+ .overlay[data-detail-mode="floating"] {
934
+ align-items: center;
935
+ justify-content: center;
936
+ padding: 28px;
937
+ }
938
+ .overlay[data-detail-mode="floating"] .detail {
939
+ width: min(var(--detail-width), calc(100vw - 56px));
940
+ height: min(92vh, calc(100vh - 56px));
941
+ border: 1px solid var(--line);
942
+ border-radius: 16px;
943
+ box-shadow: 0 28px 90px rgba(0, 0, 0, 0.48);
944
+ }
945
+ .detail-toolbar {
946
+ position: sticky;
947
+ top: -22px;
948
+ z-index: 3;
949
+ display: grid;
950
+ grid-template-columns: auto minmax(0, 1fr) auto;
951
+ align-items: center;
952
+ gap: 12px;
953
+ margin: -22px -26px 20px;
954
+ padding: 14px 26px 10px;
955
+ border-bottom: 1px solid color-mix(in srgb, var(--line) 72%, transparent);
956
+ background: color-mix(in srgb, var(--bg) 92%, transparent);
957
+ backdrop-filter: blur(14px);
958
+ }
959
+ .detail-presentation {
960
+ display: flex;
961
+ flex-wrap: wrap;
962
+ gap: 8px;
963
+ width: fit-content;
964
+ }
965
+ .detail-choice {
966
+ display: inline-flex;
967
+ padding: 3px;
968
+ border: 1px solid var(--line);
969
+ border-radius: 9px;
970
+ background: var(--panel);
971
+ }
972
+ .detail-option {
973
+ min-height: 28px;
974
+ padding: 4px 9px;
975
+ border: 0;
976
+ border-radius: 6px;
977
+ background: transparent;
978
+ color: var(--muted);
979
+ font: inherit;
980
+ font-size: 11px;
981
+ cursor: pointer;
982
+ }
983
+ .detail-option[aria-pressed="true"] {
984
+ background: var(--panel-2);
985
+ color: var(--text);
986
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 42%, var(--line));
987
+ }
988
+ .detail-option:focus-visible {
989
+ outline: 2px solid var(--accent);
990
+ outline-offset: 2px;
991
+ }
992
+ .detail pre {
993
+ max-width: 100%;
994
+ overflow-x: auto;
995
+ }
996
+ .detail table {
997
+ display: block;
998
+ max-width: 100%;
999
+ overflow-x: auto;
865
1000
  }
866
1001
  .detail h1 {
867
1002
  font-size: 22px;
@@ -909,19 +1044,27 @@ body {
909
1044
  outline-offset: 3px;
910
1045
  }
911
1046
  .close {
912
- position: absolute;
913
- top: 16px;
914
- right: 22px;
1047
+ justify-self: end;
1048
+ }
1049
+ .detail-toolbar-close {
1050
+ grid-column: 3;
915
1051
  }
916
1052
 
917
1053
  .pipeline {
918
1054
  display: flex;
919
- flex-wrap: wrap;
1055
+ min-width: 0;
1056
+ flex-wrap: nowrap;
920
1057
  gap: 6px;
921
- margin: 16px 0;
1058
+ margin: 0;
1059
+ padding: 3px 2px;
1060
+ overflow-x: auto;
1061
+ overscroll-behavior-x: contain;
1062
+ scrollbar-width: thin;
922
1063
  }
923
1064
  .stage-chip {
1065
+ flex: 0 0 auto;
924
1066
  font-size: 12px;
1067
+ font-family: inherit;
925
1068
  padding: 5px 11px;
926
1069
  border-radius: 999px;
927
1070
  background: var(--panel);
@@ -937,6 +1080,7 @@ body {
937
1080
  .stage {
938
1081
  border-top: 1px solid var(--line);
939
1082
  padding-top: 14px;
1083
+ scroll-margin-top: 72px;
940
1084
  margin-top: 18px;
941
1085
  }
942
1086
  .stage h2 {
@@ -1235,7 +1379,8 @@ body {
1235
1379
  width: 100%;
1236
1380
  flex: 0 0 auto;
1237
1381
  }
1238
- .validation-controls {
1382
+ .validation-controls,
1383
+ .reopen-controls {
1239
1384
  grid-template-columns: 1fr;
1240
1385
  align-items: stretch;
1241
1386
  }
@@ -1255,7 +1400,32 @@ body {
1255
1400
  }
1256
1401
  .detail {
1257
1402
  width: 100vw;
1403
+ max-width: none;
1404
+ height: 100vh;
1405
+ max-height: none;
1258
1406
  padding: 18px 16px 60px;
1407
+ border: 0;
1408
+ border-radius: 0;
1409
+ }
1410
+ .overlay[data-detail-mode] {
1411
+ align-items: stretch;
1412
+ justify-content: stretch;
1413
+ padding: 0;
1414
+ }
1415
+ .overlay[data-detail-mode] .detail {
1416
+ width: 100vw;
1417
+ height: 100vh;
1418
+ max-height: none;
1419
+ border: 0;
1420
+ border-radius: 0;
1421
+ }
1422
+ .detail-toolbar {
1423
+ top: -18px;
1424
+ margin: -18px -16px 16px;
1425
+ padding: 10px 16px 8px;
1426
+ }
1427
+ .detail-option {
1428
+ padding-inline: 7px;
1259
1429
  }
1260
1430
  .grid th,
1261
1431
  .grid td {
@@ -1263,6 +1433,27 @@ body {
1263
1433
  }
1264
1434
  }
1265
1435
 
1436
+ /* Detail toolbar stacks its stage navigation onto its own row whenever the
1437
+ detail panel itself lacks room, independent of the surrounding viewport —
1438
+ this also covers the "Compact" width preset, not just narrow screens. */
1439
+ @container (max-width: 680px) {
1440
+ .detail-toolbar {
1441
+ grid-template-columns: minmax(0, 1fr) auto;
1442
+ gap: 8px;
1443
+ }
1444
+ .detail-toolbar-close {
1445
+ grid-column: 2;
1446
+ grid-row: 1;
1447
+ }
1448
+ .pipeline {
1449
+ grid-column: 1 / -1;
1450
+ grid-row: 2;
1451
+ }
1452
+ .stage {
1453
+ scroll-margin-top: 126px;
1454
+ }
1455
+ }
1456
+
1266
1457
  /* config editor tabs and form (113924) */
1267
1458
  .config-section {
1268
1459
  border-bottom: 1px solid var(--line);
@@ -36,6 +36,58 @@ export function closeButton(label = 'Close detail', extraClass = '') {
36
36
  </button>`;
37
37
  }
38
38
 
39
+ export function detailPresentationControls(mode = 'side', size = 'wide') {
40
+ const options = (values, selected, attr) =>
41
+ values.map(
42
+ ([value, label]) => html`<button
43
+ type="button"
44
+ class="detail-option"
45
+ data-detail-setting=${attr}
46
+ data-detail-value=${value}
47
+ aria-pressed=${String(selected === value)}
48
+ >${label}</button>`,
49
+ );
50
+ return html`<div class="detail-presentation" aria-label="Detail presentation">
51
+ <div class="detail-choice" role="group" aria-label="Layout">
52
+ ${options(
53
+ [
54
+ ['side', 'Side panel'],
55
+ ['floating', 'Floating modal'],
56
+ ],
57
+ mode,
58
+ 'mode',
59
+ )}
60
+ </div>
61
+ <div class="detail-choice" role="group" aria-label="Width">
62
+ ${options(
63
+ [
64
+ ['compact', 'Compact'],
65
+ ['wide', 'Wide'],
66
+ ['full', 'Full'],
67
+ ],
68
+ size,
69
+ 'size',
70
+ )}
71
+ </div>
72
+ </div>`;
73
+ }
74
+
75
+ export function detailToolbar(mode = 'side', size = 'wide', stages = []) {
76
+ const navigation = stages.length
77
+ ? html`<nav class="pipeline" aria-label="Change sections">
78
+ ${stages.map(
79
+ (stage) =>
80
+ html`<button type="button" class="stage-chip" data-go=${`stage-${stage.key}`}>${stage.heading}</button>`,
81
+ )}
82
+ </nav>`
83
+ : nothing;
84
+ return html`<div class="detail-toolbar" aria-label="Detail tools">
85
+ ${detailPresentationControls(mode, size)}
86
+ ${navigation}
87
+ ${closeButton('Close detail', 'detail-toolbar-close')}
88
+ </div>`;
89
+ }
90
+
39
91
  export function validationPanel() {
40
92
  return html`<section class="validation-actions" aria-labelledby="validation-title">
41
93
  <div class="validation-copy">
@@ -0,0 +1,18 @@
1
+ # Implementation Delegate
2
+
3
+ This is a self-contained delegated context. It replaces the ChangeLedger core
4
+ for this role; do not run `changeledger context` or load another ChangeLedger
5
+ context.
6
+
7
+ Implement only the bounded assignment in the delegation prompt and follow the
8
+ selected change's Specification and Plan exactly. With `tdd=on`, write the
9
+ failing test for each assigned criterion, make it pass, then refactor.
10
+
11
+ Modify only the files assigned in the delegation prompt. You share the worktree:
12
+ do not revert or overwrite others' work; stop and report any overlap instead of
13
+ resolving it silently. Do not change Git state, mutate the ledger or delegate
14
+ any part of the work. Lifecycle, tasks, Log, review and integration remain the
15
+ orchestrator's responsibility.
16
+
17
+ Return the files changed, criteria covered, tests run and their results, plus
18
+ any overlap or uncertainty. The orchestrator integrates and records the work.
@@ -0,0 +1,14 @@
1
+ # Investigation Delegate
2
+
3
+ This is a self-contained delegated context. It replaces the ChangeLedger core
4
+ for this role; do not run `changeledger context` or load another ChangeLedger
5
+ context.
6
+
7
+ Answer only the investigation question and ownership boundary in the delegation
8
+ prompt. This role is read-only: do not modify files, Git state or the ledger, and
9
+ do not delegate any part of the work.
10
+
11
+ Inspect the smallest useful surface. Return concrete findings and evidence such
12
+ as file:line references, constraints, risks and a root-cause statement when
13
+ applicable. State what could not be determined. Do not implement fixes or create
14
+ ChangeLedger artifacts.
@@ -0,0 +1,22 @@
1
+ # Independent Review Delegate
2
+
3
+ This is a self-contained delegated context. It replaces the ChangeLedger core
4
+ for this role; do not run `changeledger context` or load another ChangeLedger
5
+ context.
6
+
7
+ Review with clean context and do not trust the implementer's summary. This role
8
+ is read-only: do not modify files, Git state or the ledger, do not record the
9
+ verdict, and do not delegate any part of the work.
10
+
11
+ Inspect the selected change, every `CRn`, every Plan task, tests, the actual diff
12
+ and absence of TODO/FIXME, dead code or unrelated residue. Confirm tasks are
13
+ true rather than merely checked off and that implementation did not drift from
14
+ the authorized document.
15
+
16
+ Deep security, SAST and lint belong to dedicated tools. You may run them
17
+ read-only and report their evidence; ChangeLedger does not reimplement them.
18
+
19
+ Return per-criterion PASS/FAIL evidence and one recommended outcome: pass,
20
+ fail-retry with a reason for a fixable defect inside scope, or fail-block with a
21
+ reason when correction needs scope or product judgment. The orchestrator alone
22
+ records the verdict.
@@ -0,0 +1,38 @@
1
+ # Delegation skeleton — role: implementation
2
+
3
+ Fill every `{{placeholder}}` before handing this prompt to the subagent. Delete
4
+ guidance in parentheses. The delegate writes code within a bounded ownership; the
5
+ orchestrator keeps the ledger and integration.
6
+
7
+ ---
8
+
9
+ You are an IMPLEMENTATION delegate. Do not delegate any part of this to another
10
+ agent; execute it yourself.
11
+
12
+ Why this is delegated: {{reason}} (why a separate agent, e.g. a disjoint write
13
+ set that parallelizes safely, a sufficient cheaper model for well-specified
14
+ execution).
15
+
16
+ Your prompt identifies you as a ChangeLedger delegate. As your only ChangeLedger
17
+ load, run `changeledger agent-context implementation {{change_id}}` and read it
18
+ through its END sentinel; do not load the orchestrator core. It supplies the
19
+ selected change with its acceptance criteria and Plan.
20
+
21
+ Files you own: {{files}} (the only paths you may modify).
22
+
23
+ Boundaries — expressed by effect, not by tool name: modify only the files under
24
+ your ownership above; do not revert or overwrite anyone else's work; if you find
25
+ your change overlaps another change's surface, stop and report it instead of
26
+ resolving it silently. Do not mutate the ledger — status, task, log, review and
27
+ graduation transitions are the orchestrator's; you implement and report.
28
+
29
+ Expected output: {{expected_output}} (the code plus the tests that prove the
30
+ cited criteria, red-green; state which criteria you covered).
31
+
32
+ Difficulty or risk that set the model choice: {{difficulty_or_risk}}.
33
+
34
+ Return to the orchestrator only what changed and how it was verified — the files
35
+ touched, the tests run and their result, and any overlap you hit.
36
+
37
+ Integration criterion: {{integration}} (how the orchestrator merges/verifies your
38
+ work, e.g. it re-runs the full gate and records the ledger transitions).
@@ -0,0 +1,41 @@
1
+ # Delegation skeleton — role: investigation
2
+
3
+ Fill every `{{placeholder}}` before handing this prompt to the subagent. Delete
4
+ guidance in parentheses. This is a read-only inquiry: the delegate answers a
5
+ question, it does not change anything.
6
+
7
+ ---
8
+
9
+ You are an INVESTIGATION delegate. Do not delegate any part of this to another
10
+ agent; execute it yourself.
11
+
12
+ Why this is delegated: {{reason}} (why a separate agent, e.g. protect main
13
+ context, parallelize an independent question, bring a stronger model to hard
14
+ analysis).
15
+
16
+ Question you own: {{question}} (the single question or area to investigate;
17
+ state it concretely).
18
+
19
+ Your prompt identifies you as a ChangeLedger delegate. As your only ChangeLedger
20
+ load, run `changeledger agent-context investigation {{change_id}}` and read it
21
+ through its END sentinel; do not load the orchestrator core. There may be no
22
+ change yet: work without a change id. If the optional id below is empty, omit it
23
+ from the command.
24
+
25
+ Optional selected change: {{change_id}} (leave empty when investigating before a
26
+ change exists).
27
+
28
+ Boundaries — expressed by effect, not by tool name: do not modify any file, do
29
+ not change Git state, and do not mutate the ledger (no status, task, log, review
30
+ or graduation). Inspect and read only.
31
+
32
+ Expected output: {{expected_output}} (what the answer must contain, e.g. a
33
+ file:line map, a root-cause statement, a constraints/risks list).
34
+
35
+ Difficulty or risk that set the model choice: {{difficulty_or_risk}}.
36
+
37
+ Return to the orchestrator only findings/data — no narrative, no fixes. State
38
+ clearly what you could not determine.
39
+
40
+ Integration criterion: {{integration}} (how the orchestrator will use the answer,
41
+ e.g. it feeds the Investigation stage of the change).
@@ -0,0 +1,36 @@
1
+ # Delegation skeleton — role: review
2
+
3
+ Fill every `{{placeholder}}` before handing this prompt to the subagent. Delete
4
+ guidance in parentheses. The reviewer is a fresh, clean-context, read-only check;
5
+ the orchestrator alone records the verdict.
6
+
7
+ ---
8
+
9
+ You are an INDEPENDENT REVIEW delegate with clean context. Do not delegate any
10
+ part of this to another agent; execute it yourself.
11
+
12
+ Why this is delegated: {{reason}} (independence is a correctness requirement, not
13
+ an optimization — a fresh reviewer that does not trust the implementer's summary).
14
+
15
+ Your prompt identifies you as a ChangeLedger delegate. As your only ChangeLedger
16
+ load, run `changeledger agent-context review {{change_id}}` and read it through
17
+ its END sentinel; do not load the orchestrator core. Use the inspection
18
+ checklist that agent-context gives you.
19
+
20
+ Change under review: {{change_id}}.
21
+
22
+ Boundaries — expressed by effect, not by tool name: do not modify any file, do
23
+ not change Git state, and do not mutate the ledger. You inspect and report only;
24
+ you never record the verdict — the orchestrator does that.
25
+
26
+ Expected output: {{expected_output}} (per-criterion PASS/FAIL with concrete
27
+ evidence, plus any drift or residue found).
28
+
29
+ Difficulty or risk that set the model choice: {{difficulty_or_risk}}.
30
+
31
+ Return to the orchestrator a single recommended verdict — one of pass, fail-retry
32
+ with a reason, or fail-block with a reason — with the evidence behind it. The
33
+ orchestrator records it.
34
+
35
+ Integration criterion: {{integration}} (how the orchestrator acts on the verdict,
36
+ e.g. it records pass and moves the change to in-validation).
@@ -0,0 +1,16 @@
1
+ {
2
+ "base": {
3
+ "core": { "target": { "lines": 125, "bytes": 7500 }, "hard": { "lines": 140, "bytes": 9000 } },
4
+ "spec": { "target": { "lines": 280, "bytes": 12000 }, "hard": { "lines": 310, "bytes": 13500 } },
5
+ "implement": { "target": { "lines": 185, "bytes": 8500 }, "hard": { "lines": 205, "bytes": 10000 } },
6
+ "review": { "target": { "lines": 70, "bytes": 3500 }, "hard": { "lines": 85, "bytes": 4500 } },
7
+ "release": { "target": { "lines": 45, "bytes": 2500 }, "hard": { "lines": 60, "bytes": 3500 } }
8
+ },
9
+ "agent": { "target": { "lines": 45, "bytes": 2000 }, "hard": { "lines": 60, "bytes": 3000 } }
10
+ ,"overlays": {
11
+ "blocked": { "target": { "lines": 70, "bytes": 3000 }, "hard": { "lines": 84, "bytes": 3600 } },
12
+ "in-validation": { "target": { "lines": 45, "bytes": 1700 }, "hard": { "lines": 54, "bytes": 2040 } },
13
+ "done": { "target": { "lines": 90, "bytes": 3500 }, "hard": { "lines": 108, "bytes": 4200 } },
14
+ "discarded": { "target": { "lines": 40, "bytes": 1300 }, "hard": { "lines": 48, "bytes": 1560 } }
15
+ }
16
+ }
@@ -20,24 +20,35 @@ tags: []
20
20
  Choose exactly one explicit graduation mode. A positional slug without a mode
21
21
  is an error, so words such as `skip` or `skip-*` can never silently become specs.
22
22
 
23
- - For a new spec, run `changeledger graduate <id> <spec-slug> --new`. This creates
24
- a seed from the change's Specification or Proposal but leaves graduation
25
- pending. Rewrite it as concise durable current truth and remove the explicit
26
- scaffold marker. Then run `changeledger graduate <id> <spec-slug> --into` to
27
- finalize it. `--into` refuses an unrefined marked scaffold.
28
- - For an existing spec, the agent edits its body first, then runs
23
+ For a new spec, follow this ordered recipe `--new` alone does not finish it:
24
+
25
+ 1. `changeledger graduate <id> <spec-slug> --new` creates a seed from the
26
+ change's Specification or Proposal but leaves graduation pending; it does not
27
+ set `reviewed: true`.
28
+ 2. Rewrite the seed as concise durable current truth and remove the explicit
29
+ scaffold marker.
30
+ 3. `changeledger graduate <id> <spec-slug> --into` finalizes it; `--into`
31
+ refuses an unrefined marked scaffold and sets `reviewed: true`.
32
+
33
+ Alternatives to the two-step:
34
+
35
+ - For an existing spec, edit its body first, then run
29
36
  `changeledger graduate <id> <spec-slug> --into`. It refreshes `updated`, records
30
- the link and does not overwrite the body.
37
+ the link, does not overwrite the body and sets `reviewed: true`.
31
38
  - `changeledger graduate <id> --skip [reason]` records that no persistent truth
32
- changed.
39
+ changed and sets `reviewed: true`.
33
40
  - `changeledger graduate --pending` lists accepted changes whose decision is
34
41
  unresolved.
35
42
 
36
- Finalization with `--into` and skip both set `reviewed: true` on the change;
37
- `--new` does not. The boolean means the persistent-truth question was settled,
38
- not necessarily that a spec was created.
39
- The graduation link remains derivable from the Log marker `graduado a spec`,
40
- which carries the spec link, rather than from the boolean flag.
43
+ `reviewed: true` means the persistent-truth question was settled, not necessarily
44
+ that a spec was created. The graduation link remains derivable from the Log
45
+ marker `graduado a spec`, which carries the spec link, rather than from the flag.
46
+
47
+ After `--into` or `--skip`, create one final closure commit that coalesces any
48
+ pending `in-review → in-validation → done` ledger updates with the graduation
49
+ decision and durable spec edit. Do not create separate commits whose only
50
+ content is one of those transitions. If no lifecycle state is pending, the
51
+ graduation or skip itself remains the meaningful closure evidence.
41
52
 
42
53
  Operational inspection and visibility:
43
54
 
@@ -47,4 +58,4 @@ Operational inspection and visibility:
47
58
 
48
59
  Use Mermaid where it communicates persistent relationships better than prose.
49
60
  After closure, share a brief retrospective. New work needs a newly authorized
50
- change; `done` never reopens.
61
+ change; graduated, skipped, archived or released work never reopens.