@amsterdamdatalabs/adl-agent-control-linux-x64 0.1.35 → 0.1.46

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 (128) hide show
  1. package/bin/adl +2 -2
  2. package/bin/reconcile +3 -11
  3. package/bin/setup +15 -15
  4. package/package.json +1 -1
  5. package/packages/agent-hooks/deploy-profile.json +1 -1
  6. package/packages/agent-hooks/package.json +1 -1
  7. package/packages/agent-hooks/src/main.ts +23 -2
  8. package/packages/agent-hooks/src/pre-tool-use/handler.ts +2 -2
  9. package/packages/agent-hooks/src/rules/impl/adl-build-run-role.ts +116 -0
  10. package/packages/agent-hooks/src/rules/impl/adl-git-user-override-block.ts +159 -0
  11. package/packages/agent-hooks/src/rules/impl/adl-mcp-cli.ts +22 -12
  12. package/packages/agent-hooks/src/rules/impl/adl-pr-complete-pending.ts +9 -9
  13. package/packages/agent-hooks/src/rules/impl/adl-pr-role.ts +6 -5
  14. package/packages/agent-hooks/src/rules/impl/adl-run-required.ts +11 -5
  15. package/packages/agent-hooks/src/rules/impl/adl-workitem-role.ts +18 -5
  16. package/packages/agent-hooks/src/rules/impl/agent-tamper-protection.ts +30 -25
  17. package/packages/agent-hooks/src/rules/impl/git-core.ts +4 -8
  18. package/packages/agent-hooks/src/rules/impl/git-target.ts +5 -0
  19. package/packages/agent-hooks/src/rules/impl/mcp-tool.ts +4 -2
  20. package/packages/agent-hooks/src/rules/impl/tool-frontend.ts +230 -11
  21. package/packages/agent-hooks/src/rules/registry.ts +11 -2
  22. package/packages/agent-hooks/src/rules/shell/git-identity.ts +1 -1
  23. package/packages/agent-hooks/src/rules/shell/invocation.ts +14 -2
  24. package/packages/agent-hooks/src/rules/shell/protected-carriers.ts +10 -7
  25. package/packages/agent-settings/assets/TARUN-GLOBAL-AGENTS-INSTRUCTIONS.md +2 -2
  26. package/packages/agent-settings/package.json +1 -1
  27. package/packages/agent-settings/src/deploy/agents-deploy.ts +19 -1
  28. package/packages/agent-settings/src/deploy/index.ts +1 -0
  29. package/packages/agent-skills/assets/agent-search-tool-audit/SKILL.md +4 -6
  30. package/packages/agent-skills/assets/code-review/SKILL.md +84 -66
  31. package/packages/agent-skills/assets/diagnosing-bugs/SKILL.md +23 -2
  32. package/packages/agent-skills/assets/diagnosing-bugs/references/FEEDBACK-LOOP-TACTICS.md +1 -1
  33. package/packages/agent-skills/assets/explore-codebase/SKILL.md +3 -2
  34. package/packages/agent-skills/assets/finalize-feature/SKILL.md +63 -0
  35. package/packages/agent-skills/assets/fix-ci/SKILL.md +58 -0
  36. package/packages/agent-skills/assets/handoff/SKILL.md +1 -1
  37. package/packages/agent-skills/assets/implement-feature/SKILL.md +150 -0
  38. package/packages/agent-skills/assets/implement-feature/references/briefs.md +94 -0
  39. package/packages/agent-skills/assets/implement-item/SKILL.md +71 -0
  40. package/packages/agent-skills/assets/mechanics/SKILL.md +38 -0
  41. package/packages/agent-skills/assets/plan-feature/SKILL.md +141 -0
  42. package/packages/agent-skills/assets/prepare-promotion/SKILL.md +90 -0
  43. package/packages/agent-skills/assets/ralplan/SKILL.md +149 -0
  44. package/packages/agent-skills/assets/refactor-safely/SKILL.md +4 -3
  45. package/packages/agent-skills/assets/report-bug/SKILL.md +72 -0
  46. package/packages/agent-skills/assets/review-change/SKILL.md +82 -0
  47. package/packages/agent-skills/assets/review-plan/SKILL.md +124 -0
  48. package/packages/agent-skills/assets/triage-workitems/SKILL.md +99 -0
  49. package/packages/agent-skills/assets/ultragoal/SKILL.md +77 -0
  50. package/packages/agent-skills/assets/validate-design/SKILL.md +64 -0
  51. package/packages/agent-skills/assets/verify-item/SKILL.md +71 -0
  52. package/packages/agent-skills/assets/wayfinder/SKILL.md +1 -1
  53. package/packages/agent-skills/assets/workitems-process/SKILL.md +145 -0
  54. package/packages/agent-skills/assets/workitems-process/references/ado-and-git.md +227 -0
  55. package/packages/agent-skills/assets/workitems-process/references/evidence.md +74 -0
  56. package/packages/agent-skills/assets/workitems-process/references/workitem-states.md +92 -0
  57. package/packages/agent-skills/assets/write-feature/SKILL.md +94 -0
  58. package/packages/agent-skills/dist/deploy.d.ts +52 -0
  59. package/packages/agent-skills/dist/deploy.d.ts.map +1 -1
  60. package/packages/agent-skills/dist/deploy.js +218 -7
  61. package/packages/agent-skills/dist/deploy.js.map +1 -1
  62. package/packages/agent-skills/dist/index.d.ts +1 -1
  63. package/packages/agent-skills/dist/index.d.ts.map +1 -1
  64. package/packages/agent-skills/dist/index.js +1 -1
  65. package/packages/agent-skills/dist/index.js.map +1 -1
  66. package/packages/agent-skills/package.json +1 -1
  67. package/packages/agent-skills/src/deploy.ts +288 -6
  68. package/packages/agent-skills/src/index.ts +10 -1
  69. package/packages/azdo/README.md +13 -4
  70. package/packages/azdo/bunfig.toml +6 -0
  71. package/packages/azdo/package.json +1 -1
  72. package/packages/azdo/scripts/probe-ado-rules.ts +1 -1
  73. package/packages/azdo/src/activity-log.ts +118 -0
  74. package/packages/azdo/src/azdo-attachments.ts +109 -0
  75. package/packages/azdo/src/azdo-pl.ts +100 -3
  76. package/packages/azdo/src/azdo-pr.ts +376 -17
  77. package/packages/azdo/src/azdo-wit.ts +594 -34
  78. package/packages/azdo/src/cli.ts +119 -12
  79. package/packages/azdo/src/lib/client.ts +95 -17
  80. package/packages/azdo/src/lib/validate-pr-metadata.ts +14 -5
  81. package/packages/azdo/src/mcp-server.ts +121 -8
  82. package/packages/azdo/src/tool-dispatch.ts +107 -23
  83. package/packages/azdo/src/workflow-ladder.csv +125 -107
  84. package/packages/azdo/src/workflow-rules.ts +254 -97
  85. package/packages/fleet/src/install-adl-package.ts +4 -3
  86. package/packages/repo-controls/README.md +12 -4
  87. package/packages/repo-controls/assets/promote.ts +1 -0
  88. package/packages/repo-controls/assets/scaffold/docs/AGENTS.md +5 -5
  89. package/packages/repo-controls/assets/scaffold/plans/AGENTS.md +42 -13
  90. package/packages/repo-controls/assets/scaffold/root/CONTRIBUTING.md +5 -5
  91. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/closed_set/test_check.py +0 -11
  92. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/filename/test_check.py +4 -6
  93. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/ledger/test_check.py +15 -0
  94. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/docs-okf-profiles.yaml +1 -17
  95. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/no-type.md +1 -1
  96. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-experiment.md +1 -1
  97. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-profile-untyped/docs/research/typed-research.md +1 -1
  98. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-key.md +1 -1
  99. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/extra-keys.md +1 -1
  100. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-created.md +1 -1
  101. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-description.md +1 -1
  102. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-last-update.md +1 -1
  103. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-status.md +1 -1
  104. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/missing-title.md +1 -1
  105. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/optional-keys.md +1 -1
  106. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/fixtures/okf-research/docs/research/research-ok.md +1 -1
  107. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/docs/okf_profile/test_check.py +3 -22
  108. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/check.py +39 -182
  109. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/fixtures/open-work-cap-clean/plans/features/az601-clean/intent.md +17 -0
  110. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/open_work_cap/test_check.py +90 -321
  111. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plan_metadata.py +31 -5
  112. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/check.py +282 -54
  113. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/design.md +35 -0
  114. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/file-map-reference.md +19 -0
  115. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/intent.md +25 -0
  116. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/items/az351-restore-entrypoint.md +25 -0
  117. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-clean/plans/features/az347-test-coverage/requirements.md +44 -0
  118. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/fixtures/plans-layout-violation/plans/features/az347-test-coverage/requirements.md +44 -0
  119. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/checks/layout/plans_layout/test_check.py +646 -53
  120. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/cli.py +3 -3
  121. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/docs_shape.py +1 -12
  122. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.alt.yaml +1 -1
  123. package/packages/repo-controls/package/adl-compliance/src/adl_compliance/policy/gate-registry.yaml +1 -1
  124. package/packages/repo-controls/package.json +1 -1
  125. package/packages/repo-controls/src/config.ts +21 -2
  126. package/packages/repo-controls/src/doctor.ts +9 -14
  127. package/packages/repo-controls/src/findings-ratchet.ts +12 -0
  128. package/packages/repo-controls/src/hook.ts +61 -4
@@ -4,53 +4,58 @@
4
4
  // Custom.Reviewpassed, Custom.Testspassing, Custom.Docsupdated,
5
5
  // Custom.Mergedtointegration) with ordered item states; the flags were
6
6
  // removed from the process at the cutover and nothing here reads or writes
7
- // them. The routes below implement the owner's final state model (PBI and
8
- // Bug identical), carried as src/workflow-ladder.csv next to this file; the
7
+ // them. The routes below implement the owner's final state model: PBIs
8
+ // walk the item ladder; Bugs walk their own shorter ladder (F9 — never
9
+ // planned, reproducing before fixing); both are carried as
10
+ // src/workflow-ladder.csv next to this file; the
9
11
  // unit test tests/workflow-rules.test.ts asserts the embedded table agrees
10
12
  // with that CSV on every type × from × to triple, so the compiled binary
11
13
  // needs no file access at runtime. Features and Epics walk no item ladder
12
14
  // and are exempt: evaluateWorkflowTransition returns no violations for
13
- // them.
15
+ // them (the Feature ladder lives in evaluateFeatureTransition).
14
16
 
15
17
  /**
16
- * The thirteen recognized states: the twelve active states of the final
17
- * model, plus Committed — retired (UI-hidden, no route references it) but
18
- * still recognized so a transition touching it is refused with the retired
19
- * note instead of passing through silently.
18
+ * The fifteen recognized states: the twelve active states of the final
19
+ * model, plus In Reproduction and In Fixing (Bug-only ladder states, F9),
20
+ * plus Committed — retired (UI-hidden, no route references it) but still
21
+ * recognized so a transition touching it is refused with the retired note
22
+ * instead of passing through silently.
20
23
  */
21
24
  export const WORKFLOW_STATES = [
22
- 'New',
23
- 'In Planning',
24
- 'Awaiting Approval',
25
- 'Approved',
26
- 'Spec Validation',
27
- 'In Implementation',
28
- 'In Testing',
29
- 'In Review',
30
- 'Updating Docs',
31
- 'Done',
32
- 'Parked for Removal',
33
- 'Removed',
34
- 'Committed',
25
+ "New",
26
+ "In Planning",
27
+ "Awaiting Approval",
28
+ "Approved",
29
+ "Design Validation",
30
+ "In Implementation",
31
+ "In Reproduction",
32
+ "In Fixing",
33
+ "In Testing",
34
+ "In Review",
35
+ "Updating Docs",
36
+ "Done",
37
+ "Parked for Removal",
38
+ "Removed",
39
+ "Committed",
35
40
  ] as const;
36
41
  export type WorkflowState = (typeof WORKFLOW_STATES)[number];
37
42
 
38
- const GATED_TYPES = ['Product Backlog Item', 'Bug'] as const;
43
+ const GATED_TYPES = ["Product Backlog Item", "Bug"] as const;
39
44
 
40
45
  /**
41
46
  * The main line, in route order — forward only. PBI and Bug share it (no
42
47
  * type deltas in the final model).
43
48
  */
44
49
  const MAIN_LINE: readonly WorkflowState[] = [
45
- 'New',
46
- 'In Planning',
47
- 'Awaiting Approval',
48
- 'Approved',
49
- 'Spec Validation',
50
- 'In Implementation',
51
- 'In Testing',
52
- 'In Review',
53
- 'Updating Docs',
50
+ "New",
51
+ "In Planning",
52
+ "Awaiting Approval",
53
+ "Approved",
54
+ "Design Validation",
55
+ "In Implementation",
56
+ "In Testing",
57
+ "In Review",
58
+ "Updating Docs",
54
59
  ];
55
60
  const MAIN_LINE_INDEX = new Map<string, number>(MAIN_LINE.map((state, index) => [state, index]));
56
61
 
@@ -60,27 +65,82 @@ const LADDER_EDGES: readonly (readonly [WorkflowState, WorkflowState])[] = MAIN_
60
65
  );
61
66
 
62
67
  /**
63
- * The states that may move back to New — any active state (re-plan /
64
- * unpark), plus Removed (recovery). Done is not active: its one recovery is
65
- * In Planning (see RECOVERY_EDGES).
68
+ * The non-linear loop (F1): every ordered pair among these four states is
69
+ * allowed, in either direction and with skips — the implementation lead
70
+ * moves items around the loop freely. In Implementation → Design Validation
71
+ * (DRIFT_EDGE) is the one sanctioned exit backward out of the loop, on
72
+ * mid-loop drift.
66
73
  */
67
- const REPLAN_SOURCES: ReadonlySet<WorkflowState> = new Set([
68
- 'In Planning',
69
- 'Awaiting Approval',
70
- 'Approved',
71
- 'Spec Validation',
72
- 'In Implementation',
73
- 'In Testing',
74
- 'In Review',
75
- 'Updating Docs',
76
- 'Parked for Removal',
77
- 'Removed',
74
+ const LOOP_STATES: ReadonlySet<WorkflowState> = new Set([
75
+ "In Implementation",
76
+ "In Testing",
77
+ "In Review",
78
+ "Updating Docs",
79
+ ]);
80
+ /**
81
+ * The drift loop-back: mid-loop drift returns through Design Validation.
82
+ * (PBI only — Bugs have no Design Validation, F9.)
83
+ */
84
+ const DRIFT_EDGE: readonly [WorkflowState, WorkflowState] = ["In Implementation", "Design Validation"];
85
+
86
+ /**
87
+ * The Bug ladder (F9): Bugs no longer share the PBI ladder. A Bug is never
88
+ * planned — no In Planning, Awaiting Approval or Design Validation — and
89
+ * reproduces before it is fixed. Allowed agent moves: New → Parked for
90
+ * Removal; Approved → In Reproduction; In Reproduction → In Fixing;
91
+ * In Reproduction → Parked for Removal (won't reproduce); the non-linear
92
+ * loop over In Fixing ↔ In Testing ↔ In Review ↔ Updating Docs (every
93
+ * ordered pair); and parking from any non-terminal Bug state. Everything
94
+ * else is refused, including targets of Awaiting Approval, In Planning and
95
+ * Design Validation. The human-only targets (Approved, Done, Removed, the
96
+ * parked revive) and the terminals are handled by the shared front matter
97
+ * of evaluateWorkflowTransition.
98
+ */
99
+ const BUG_LOOP_STATES: ReadonlySet<WorkflowState> = new Set(["In Fixing", "In Testing", "In Review", "Updating Docs"]);
100
+ /** Any non-terminal Bug state may park (New and Approved included, to park a duplicate). */
101
+ const BUG_PARKING_SOURCES: ReadonlySet<WorkflowState> = new Set([
102
+ "New",
103
+ "Approved",
104
+ "In Reproduction",
105
+ "In Fixing",
106
+ "In Testing",
107
+ "In Review",
108
+ "Updating Docs",
78
109
  ]);
79
110
 
80
- /** The ONE sanctioned backward work-edge: review agent rejection. */
81
- const REJECTION_EDGE: readonly [WorkflowState, WorkflowState] = ['In Review', 'In Implementation'];
82
- /** The documented recovery out of the completed terminal. */
83
- const RECOVERY_EDGE: readonly [WorkflowState, WorkflowState] = ['Done', 'In Planning'];
111
+ /** The Bug transition table itself, after the shared human-only/terminal front matter. */
112
+ function evaluateBugTransition(from: WorkflowState, to: WorkflowState): WorkflowViolation[] {
113
+ if (from === "Parked for Removal") {
114
+ // to New (human-only revive) and to Removed (G3) were handled by the
115
+ // shared front matter; every other exit keeps the parked note.
116
+ return [{ kind: "no-transition", fromState: from, toState: to, note: PARKED_EXIT_NOTE }];
117
+ }
118
+ if (to === "Parked for Removal") {
119
+ return BUG_PARKING_SOURCES.has(from)
120
+ ? []
121
+ : [{ kind: "no-transition", fromState: from, toState: to, note: PARKED_EXIT_NOTE }];
122
+ }
123
+ if (from === "Approved" && to === "In Reproduction") return [];
124
+ if (from === "In Reproduction" && to === "In Fixing") return [];
125
+ if (BUG_LOOP_STATES.has(from) && BUG_LOOP_STATES.has(to)) return [];
126
+ return [{ kind: "no-transition", fromState: from, toState: to }];
127
+ }
128
+
129
+ /**
130
+ * The states that may move back to New for a re-plan — any active state.
131
+ * Parked for Removal is deliberately absent: its → New revive is human-only
132
+ * (F10). Done and Removed are terminal (F10) and absent too.
133
+ */
134
+ const REPLAN_SOURCES: ReadonlySet<WorkflowState> = new Set([
135
+ "In Planning",
136
+ "Awaiting Approval",
137
+ "Approved",
138
+ "Design Validation",
139
+ "In Implementation",
140
+ "In Testing",
141
+ "In Review",
142
+ "Updating Docs",
143
+ ]);
84
144
 
85
145
  /**
86
146
  * Targets no agent may set, with the owner named in the refusal: Approved is
@@ -88,46 +148,68 @@ const RECOVERY_EDGE: readonly [WorkflowState, WorkflowState] = ['Done', 'In Plan
88
148
  * removal, taken from Parked for Removal), Done is entered only by PR merge
89
149
  * automation into integration (from Updating Docs).
90
150
  */
91
- export const WORKFLOW_HUMAN_ONLY_TARGETS: Readonly<Record<'Approved' | 'Done' | 'Removed', string>> = {
92
- Approved: 'G1 — human approval only; agents cannot move items to Approved',
93
- Done: 'entered only by PR merge automation into integration',
94
- Removed: 'G3 — human removal only; agents cannot move items to Removed',
151
+ export const WORKFLOW_HUMAN_ONLY_TARGETS: Readonly<Record<"Approved" | "Done" | "Removed", string>> = {
152
+ Approved: "G1 — human approval only; agents cannot move items to Approved",
153
+ Done: "entered only by PR merge automation into integration",
154
+ Removed: "G3 — human removal only; agents cannot move items to Removed",
95
155
  };
96
156
 
97
- const RETIRED_COMMITTED_NOTE = 'Committed is a retired state (UI-hidden; no route references it)';
98
- const PARKED_EXIT_NOTE = 'Parked for Removal exits only to New (re-plan) or Removed (G3 human)';
157
+ const RETIRED_COMMITTED_NOTE = "Committed is a retired state (UI-hidden; no route references it)";
158
+ const PARKED_EXIT_NOTE = "Parked for Removal exits only to New (human-only revive) or Removed (G3 human)";
159
+ /** F10: the parked revive is Tarun's alone, like the G3 removal it precedes. */
160
+ export const PARKED_REVIVE_OWNER = "human revive only; agents cannot move items from Parked for Removal back to New";
99
161
 
100
162
  export type WorkflowViolation =
101
- | { kind: 'skipped-gate'; fromState: WorkflowState; toState: WorkflowState; skippedState: WorkflowState }
102
- | { kind: 'human-only'; fromState: WorkflowState; toState: WorkflowState; owner: string }
103
- | { kind: 'no-transition'; fromState: WorkflowState; toState: WorkflowState; note?: string };
163
+ | { kind: "skipped-gate"; fromState: WorkflowState; toState: WorkflowState; skippedState: WorkflowState }
164
+ | { kind: "human-only"; fromState: WorkflowState; toState: WorkflowState; owner: string }
165
+ | { kind: "no-transition"; fromState: WorkflowState; toState: WorkflowState; note?: string };
166
+
167
+ /**
168
+ * The Feature ladder's violation shape (F3). Mirrors WorkflowViolation but uses
169
+ * FeatureState literals so `evaluateFeatureTransition`'s output is honest about
170
+ * what states it carries, instead of casting every Feature-state literal to
171
+ * WorkflowState at the function boundary.
172
+ */
173
+ export type FeatureViolation =
174
+ | { kind: "skipped-gate"; fromState: FeatureState; toState: FeatureState; skippedState: FeatureState }
175
+ | { kind: "human-only"; fromState: FeatureState; toState: FeatureState; owner: string }
176
+ | { kind: "no-transition"; fromState: FeatureState; toState: FeatureState; note?: string };
104
177
 
105
178
  /**
106
179
  * Evaluate a state TRANSITION (from-state → to-state) against the final
107
180
  * state model. One violation per refusal class:
108
181
  *
109
182
  * - `human-only` — the target is owned by G1 approval, PR merge automation
110
- * or G3 human removal; agents never set it.
183
+ * or G3 human removal; agents never set it. Checked before the
184
+ * from-state recognition (F2), so an off-ladder from-state cannot smuggle
185
+ * an agent into a human-owned target. Parked for Removal → New is a
186
+ * human-only revive (F10) with its own owner text.
111
187
  * - `skipped-gate` — a forward jump over main-line states; one violation per
112
188
  * skipped state, in route order, so the refusal names every gate
113
189
  * bypassed. Approved is annotated "(G1: human approval)".
114
190
  * - `no-transition` — anything off the model. Committed is retired: any
115
- * transition touching it names the retired state. Parked for Removal is
116
- * enterable from anywhere but exits only to New or Removed. Everything
117
- * else backward is refused flat — including In Implementation → Spec
118
- * Validation and In Testing → In Implementation (no special-casing; the
119
- * owner decision is "no backward rule, enforce forward").
191
+ * transition touching it names the retired state. Done and Removed are
192
+ * terminal for agents (F10): every exit is refused with the terminal
193
+ * note. Parked for Removal is enterable from anywhere and exits only to
194
+ * New (human-only revive) or Removed (G3).
195
+ *
196
+ * The loop is non-linear (F1): every ordered pair among In Implementation,
197
+ * In Testing, In Review and Updating Docs is allowed, and In
198
+ * Implementation → Design Validation is the drift loop-back. Backward
199
+ * moves outside the loop are refused flat — no special-casing.
200
+ *
201
+ * F9: Bugs walk their own ladder — New → Approved (G1, human-only) →
202
+ * In Reproduction → In Fixing, then the same non-linear loop with
203
+ * In Fixing in place of In Implementation; parking from any non-terminal
204
+ * Bug state; never In Planning, Awaiting Approval or Design Validation.
120
205
  *
121
206
  * Allowed to writers: identity writes (from === to, never gated); the
122
207
  * adjacent main-line forward moves; parking to Parked for Removal from any
123
- * state; re-plan moves to New from any active state plus Removed; the
124
- * review-rejection edge In Review → In Implementation; and the Done →
125
- * In Planning recovery. Exits from Done other than In Planning and from
126
- * Removed other than New/Parked keep the terminal notes ("completed items
127
- * stay Done; a G2 rejection gets its own linked item" / "Removed is
128
- * terminal"). A state outside the thirteen recognized states yields none —
129
- * the ADO process template enforces server-side. Exempt types
130
- * (Feature/Epic) yield none.
208
+ * state; re-plan moves to New from any active state; the 12 loop pairs and
209
+ * the drift loop-back. A state outside the thirteen recognized states
210
+ * yields none — except the human-only targets, refused first (F2) — the
211
+ * ADO process template enforces server-side. Exempt types (Feature/Epic)
212
+ * yield none.
131
213
  */
132
214
  export function evaluateWorkflowTransition(
133
215
  workItemType: string,
@@ -135,60 +217,135 @@ export function evaluateWorkflowTransition(
135
217
  toState: string,
136
218
  ): WorkflowViolation[] {
137
219
  if (!(GATED_TYPES as readonly string[]).includes(workItemType)) return [];
220
+ if (fromState === toState) return [];
221
+ if (fromState === "Committed" || toState === "Committed") {
222
+ return [
223
+ {
224
+ kind: "no-transition",
225
+ fromState: fromState as WorkflowState,
226
+ toState: toState as WorkflowState,
227
+ note: RETIRED_COMMITTED_NOTE,
228
+ },
229
+ ];
230
+ }
231
+ // F2: the human-only targets are refused BEFORE the from-state
232
+ // recognition, so an off-ladder from-state cannot smuggle an agent into
233
+ // a human-owned target.
234
+ const owner = (WORKFLOW_HUMAN_ONLY_TARGETS as Partial<Record<string, string>>)[toState];
235
+ if (owner !== undefined) {
236
+ return [
237
+ { kind: "human-only", fromState: fromState as WorkflowState, toState: toState as WorkflowState, owner },
238
+ ];
239
+ }
138
240
  if (!(WORKFLOW_STATES as readonly string[]).includes(fromState)) return [];
139
241
  if (!(WORKFLOW_STATES as readonly string[]).includes(toState)) return [];
140
242
  const from = fromState as WorkflowState;
141
243
  const to = toState as WorkflowState;
142
- if (from === to) return [];
143
- if (from === 'Committed' || to === 'Committed') {
144
- return [{ kind: 'no-transition', fromState: from, toState: to, note: RETIRED_COMMITTED_NOTE }];
244
+ if (from === "Parked for Removal" && to === "New") {
245
+ return [{ kind: "human-only", fromState: from, toState: to, owner: PARKED_REVIVE_OWNER }];
145
246
  }
146
- const owner = (WORKFLOW_HUMAN_ONLY_TARGETS as Partial<Record<WorkflowState, string>>)[to];
147
- if (owner !== undefined) return [{ kind: 'human-only', fromState: from, toState: to, owner }];
148
- if (to === 'Parked for Removal') return [];
149
- if (to === 'New' && REPLAN_SOURCES.has(from)) return [];
150
- if (from === REJECTION_EDGE[0] && to === REJECTION_EDGE[1]) return [];
151
- if (from === RECOVERY_EDGE[0] && to === RECOVERY_EDGE[1]) return [];
152
- if (from === 'Done' || from === 'Removed') {
153
- return [{ kind: 'no-transition', fromState: from, toState: to, note: terminalSourceNote(from) }];
247
+ if (from === "Done" || from === "Removed") {
248
+ return [{ kind: "no-transition", fromState: from, toState: to, note: terminalSourceNote(from) }];
154
249
  }
155
- if (from === 'Parked for Removal') {
156
- return [{ kind: 'no-transition', fromState: from, toState: to, note: PARKED_EXIT_NOTE }];
250
+ // F9: Bugs walk their own ladder from here on.
251
+ if (workItemType === "Bug") return evaluateBugTransition(from, to);
252
+ if (to === "Parked for Removal") return [];
253
+ if (to === "New" && REPLAN_SOURCES.has(from)) return [];
254
+ if (LOOP_STATES.has(from) && LOOP_STATES.has(to)) return [];
255
+ if (from === DRIFT_EDGE[0] && to === DRIFT_EDGE[1]) return [];
256
+ if (from === "Parked for Removal") {
257
+ return [{ kind: "no-transition", fromState: from, toState: to, note: PARKED_EXIT_NOTE }];
157
258
  }
158
259
  if (LADDER_EDGES.some(([edgeFrom, edgeTo]) => edgeFrom === from && edgeTo === to)) return [];
159
260
  const fromIndex = MAIN_LINE_INDEX.get(from)!;
160
261
  const toIndex = MAIN_LINE_INDEX.get(to)!;
161
262
  if (toIndex > fromIndex) {
162
263
  return MAIN_LINE.slice(fromIndex + 1, toIndex).map((skippedState) => ({
163
- kind: 'skipped-gate',
264
+ kind: "skipped-gate",
164
265
  fromState: from,
165
266
  toState: to,
166
267
  skippedState,
167
268
  }));
168
269
  }
169
- return [{ kind: 'no-transition', fromState: from, toState: to }];
270
+ return [{ kind: "no-transition", fromState: from, toState: to }];
170
271
  }
171
272
 
172
- /** from is Done or Removed here; identity, parking and recoveries were handled by the caller. */
273
+ /** from is Done or Removed here; identity, parking and human-only targets were handled by the caller. */
173
274
  function terminalSourceNote(from: WorkflowState): string {
174
- return from === 'Done'
175
- ? 'completed items stay Done; a G2 rejection gets its own linked item'
176
- : 'Removed is terminal';
275
+ return from === "Done" ? "completed items stay Done; a G2 rejection gets its own linked item" : "Removed is terminal";
177
276
  }
178
277
 
179
- export function formatWorkflowViolation(violation: WorkflowViolation): string {
180
- if (violation.kind === 'skipped-gate') {
181
- const g1 = violation.skippedState === 'Approved' ? ' (G1: human approval)' : '';
278
+ /** A printable violation: either WorkflowViolation or FeatureViolation. Both shapes carry
279
+ * the same {kind, fromState, toState} skeleton so the formatter can render either. */
280
+ export type AnyWorkflowViolation = WorkflowViolation | FeatureViolation;
281
+
282
+ export function formatWorkflowViolation(violation: AnyWorkflowViolation): string {
283
+ if (violation.kind === "skipped-gate") {
284
+ const g1 = violation.skippedState === "Approved" ? " (G1: human approval)" : "";
182
285
  return `fenced by state ladder: '${violation.fromState}' → '${violation.toState}' skips '${violation.skippedState}'${g1}`;
183
286
  }
184
- if (violation.kind === 'human-only') {
287
+ if (violation.kind === "human-only") {
185
288
  return `fenced by state ladder: '${violation.fromState}' → '${violation.toState}' is ${violation.owner}`;
186
289
  }
187
- const note = violation.note === undefined ? '' : ` (${violation.note})`;
290
+ const note = violation.note === undefined ? "" : ` (${violation.note})`;
188
291
  return `fenced by state ladder: no ladder transition '${violation.fromState}' → '${violation.toState}'${note}`;
189
292
  }
190
293
 
191
294
  /** One refusal line per violation, joined for a loud multi-line error. */
192
- export function formatWorkflowRefusal(violations: WorkflowViolation[]): string {
193
- return violations.map(formatWorkflowViolation).join('\n');
295
+ export function formatWorkflowRefusal(violations: readonly AnyWorkflowViolation[]): string {
296
+ return violations.map(formatWorkflowViolation).join("\n");
297
+ }
298
+
299
+ /**
300
+ * The Feature ladder (F3): linear, one step at a time, never backward —
301
+ * New → In Progress → Awaiting Release → Done. Only a human moves a
302
+ * Feature to Removed (G3). 'Awaiting Release' exists only on Features, so
303
+ * this table is deliberately separate from evaluateWorkflowTransition,
304
+ * which stays pure on the item-ladder vocabulary; the Feature
305
+ * preconditions against children live in azdo-wit.ts (F4).
306
+ */
307
+ const FEATURE_STATES = ["New", "In Progress", "Awaiting Release", "Done", "Removed"] as const;
308
+ type FeatureState = (typeof FEATURE_STATES)[number];
309
+
310
+ const FEATURE_MAIN_LINE: readonly FeatureState[] = ["New", "In Progress", "Awaiting Release", "Done"];
311
+ const FEATURE_MAIN_LINE_INDEX = new Map<string, number>(FEATURE_MAIN_LINE.map((state, index) => [state, index]));
312
+ const FEATURE_LADDER_EDGES: readonly (readonly [FeatureState, FeatureState])[] = FEATURE_MAIN_LINE.slice(1).map(
313
+ (state, index) => [FEATURE_MAIN_LINE[index]!, state] as const,
314
+ );
315
+ const FEATURE_REMOVED_OWNER = "G3 — human removal only; agents cannot move Features to Removed";
316
+ const FEATURE_BACKWARD_NOTE = "the Feature ladder is linear: never backward";
317
+
318
+ /**
319
+ * Evaluate a Feature state TRANSITION against the Feature ladder. Like the
320
+ * item fence: identity writes are never gated; the human-only target
321
+ * (Removed) is refused before the from-state recognition; unknown states
322
+ * stay silent (the ADO process enforces server-side); forward skips name
323
+ * every skipped state; backward moves refuse flat.
324
+ */
325
+ export function evaluateFeatureTransition(fromState: string, toState: string): FeatureViolation[] {
326
+ if (fromState === toState) return [];
327
+ if (toState === "Removed") {
328
+ // An off-ladder fromState still trips the human-only refusal here (the
329
+ // Removed check fires before from-state recognition, see comment at
330
+ // the function head). We normalize fromState to "Removed" so the
331
+ // violation shape stays in FeatureState terms; the human-only owner
332
+ // note names Removed at the G3 boundary.
333
+ return [{ kind: "human-only", fromState: "Removed", toState: "Removed", owner: FEATURE_REMOVED_OWNER }];
334
+ }
335
+ if (!(FEATURE_STATES as readonly string[]).includes(fromState)) return [];
336
+ if (!(FEATURE_STATES as readonly string[]).includes(toState)) return [];
337
+ const from = fromState as FeatureState;
338
+ const to = toState as FeatureState;
339
+ if (FEATURE_LADDER_EDGES.some(([edgeFrom, edgeTo]) => edgeFrom === from && edgeTo === to)) return [];
340
+ const fromIndex = FEATURE_MAIN_LINE_INDEX.get(from)!;
341
+ const toIndex = FEATURE_MAIN_LINE_INDEX.get(to)!;
342
+ if (toIndex > fromIndex) {
343
+ return FEATURE_MAIN_LINE.slice(fromIndex + 1, toIndex).map((skippedState) => ({
344
+ kind: "skipped-gate",
345
+ fromState: from,
346
+ toState: to,
347
+ skippedState,
348
+ }));
349
+ }
350
+ return [{ kind: "no-transition", fromState: from, toState: to, note: FEATURE_BACKWARD_NOTE }];
194
351
  }
@@ -19,15 +19,16 @@ import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'
19
19
  // import cross-package by relative path — a package added to those imports
20
20
  // but not here breaks every managed repo's git hooks with "Cannot find module"
21
21
  // the next time reconcile projects this payload.
22
- // Every package apps/cli reads from /usr/local/libexec/adl (hooks.ts, skills.ts, settings.ts,
22
+ // Every package apps/cli reads from /usr/local/libexec/adl (hooks.ts, settings.ts,
23
23
  // repo-controls.ts: DEFAULT_LIBEXEC_DIR) plus azdo, which they import by relative path.
24
+ // skills.ts dropped its libexec fallback for agent-skills as part of az697
25
+ // (fleet does not install skills; every skill comes from `adl skills deploy`).
24
26
  // install-adl-package.test.ts pins both against the real sources.
25
- export const payloadDirectories = ['packages/agent-skills', 'packages/repo-controls', 'packages/agent-hooks', 'packages/agent-settings', 'packages/azdo']
27
+ export const payloadDirectories = ['packages/repo-controls', 'packages/agent-hooks', 'packages/agent-settings', 'packages/azdo']
26
28
  const payloadScripts = ['bin/git', 'bin/git-ado']
27
29
  const requiredFiles = [
28
30
  'bin/reconcile',
29
31
  'packages/fleet/manifest.json',
30
- 'packages/agent-skills/dist/index.js',
31
32
  'packages/repo-controls/bin/adl-repo-controls.ts',
32
33
  'packages/agent-hooks/src/log/writer.ts',
33
34
  'packages/agent-settings/deploy-profile.json',
@@ -538,7 +538,10 @@ doctor report and never repairs or stages the managed surface: run
538
538
  Armed from the first commit with NO ratchet baseline for existing violations, so an
539
539
  existing repository reports its violations as guidance. Measured on a fresh install
540
540
  (see "Fresh-install result" below), the one gate this package's own install leaves
541
- failing is `repository.license-declared` (REP-001: no `license` declared). An existing `enabled` key, even `[]`, is never rewritten, and
541
+ failing is `repository.license-declared` (REP-001: no `license` declared), and
542
+ `docs.okf-profile`, `docs.filename` and `docs.directory-size` are could-not-run until
543
+ the first real docs page lands — the fresh scaffold's `docs/` holds only
544
+ `AGENTS.md`/`CLAUDE.md`/`decisions/index.md`, all outside their scope. An existing `enabled` key, even `[]`, is never rewritten, and
542
545
  switching a gate off is the repository's own decision, made by removing its one line
543
546
  from `enabled`
544
547
  ([`#strict-activation-and-switching-a-gate-off`](../../docs/architecture/compliance-controls.md#strict-activation-and-switching-a-gate-off)).
@@ -598,7 +601,7 @@ truthful. A `uv`-less machine errors out of the grade step, after everything is
598
601
 
599
602
  Install bootstraps the minimal skeleton of `docs`, `plans` and `workflows` from the
600
603
  package's `assets/scaffold/<tree>/` (Bug 570, Tarun 2026-10-08):
601
- `docs/{AGENTS.md,CLAUDE.md,notes.md,decisions/index.md}`,
604
+ `docs/{AGENTS.md,CLAUDE.md,decisions/index.md}`,
602
605
  `plans/{AGENTS.md,CLAUDE.md,GAPS-AND-FINDINGS.md,LEDGER.md,features/.gitkeep}`, and
603
606
  `workflows/{AGENTS.md,CLAUDE.md,pipelines/.gitkeep,scripts/.gitkeep}`. Rules:
604
607
 
@@ -630,8 +633,13 @@ package's `assets/scaffold/<tree>/` (Bug 570, Tarun 2026-10-08):
630
633
 
631
634
  The scaffold gates (DOC-001, DOC-002, DOC-004 to DOC-012, LAY-002, LAY-004, LAY-009,
632
635
  LAY-011, LAY-014, LAY-016, LFS-001) pass on a fresh install
633
- (`tests/install-scaffold.test.ts`). Of the 29 enabled gates, the package-level result of a
634
- fresh install is exactly one failing gate, REP-001 `repository.license-declared`
636
+ (`tests/install-scaffold.test.ts`), except DOC-006, DOC-011 and DOC-012, which are
637
+ could-not-run there: the fresh scaffold's `docs/` holds only
638
+ `AGENTS.md`/`CLAUDE.md`/`decisions/index.md`, all outside their scope, and a scope
639
+ that selects nothing is could-not-run, never a clean pass (Bug 597). They start
640
+ grading with the first real docs page. Of the 29 enabled gates, the package-level
641
+ result of a fresh install is exactly one failing gate, REP-001
642
+ `repository.license-declared`, plus those three could-not-run
635
643
  (`tests/install-strict.test.ts`). `adl install` also deploys skills, hooks and plugins into
636
644
  the repository, and any of their files with consecutive comment lines fail REP-007
637
645
  `repository.no-multiline-comments`; that is a defect of the deployed assets, not an expected
@@ -1,5 +1,6 @@
1
1
  // Managed by adl-repo-controls, do not edit; regenerate with: adl-repo-controls install --repo . (README "Managed workflow scripts").
2
2
 
3
+
3
4
  /** Promote one branch to another through an Azure DevOps pull request; see README "Managed workflow scripts". */
4
5
 
5
6
  /** Azure DevOps' `mergeStrategy` by name; see README "Managed workflow scripts". */
@@ -10,16 +10,16 @@ the way it is.
10
10
  - Sub-directories group related pages (for example `decisions/` for
11
11
  architecture decision records, `research/` for dated investigations). Add one
12
12
  only when it has pages to hold.
13
- - `notes.md` is the repository's task ledger: one line when an agent starts a
14
- task and one when it finishes.
13
+ - The agent activity log lives at `.adl/agent-activity.sqlite` (gitignored,
14
+ local only): agents write with `adl activity add "<note>"` and read with
15
+ `adl activity list`.
15
16
 
16
17
  ## Conventions
17
18
 
18
19
  - Every page carries YAML frontmatter with at least `type`, `title`,
19
20
  `description`, `status` and `last_update` (ISO-8601 UTC,
20
21
  `YYYY-MM-DDTHH:MM:SSZ`).
21
- - `notes.md` is append-only: newest line at the bottom, earlier lines are never
22
- rewritten. Format `YYYY-MM-DD HH:MM <surface> <note>`, at most 100
23
- characters per line.
22
+ - Activity entries are append-only, oldest first, and the tool fills time
23
+ (UTC), surface, agent identity and repo — only the note is caller-supplied.
24
24
  - A page that is catalogued in an index stays listed there; add the entry in
25
25
  the same change that adds or renames the page.
@@ -5,19 +5,45 @@ board is the only place status lives; the files here describe the work.
5
5
 
6
6
  ## Layout
7
7
 
8
- - `plans/features/az<id>-<slug>/spec.md` — one Feature, one file, for its whole
9
- life. Frontmatter: `type: feature`, `title`, `status` (the board state),
10
- `epic:` (the parent Epic's board URL), `work_item:` (this Feature's own board
11
- URL), `last_update`. The Feature's own `## Items` table is the one place it
12
- may list its children.
13
- - `plans/features/az<id>-<slug>/items/az<item-id>-<slug>.md` — one PBI or Bug.
14
- Frontmatter: `type: pbi` or `type: bug`, `title`, `status`, `feature:` (the
15
- parent Feature's slug), `work_item:`, `last_update`.
16
- - `plans/GAPS-AND-FINDINGS.md` — a register of gaps found while planning or
17
- building something else. A row is deleted, not marked done, once its linked
18
- item closes.
19
- - `plans/LEDGER.md` — the plan-event ledger, a Markdown table, newest entry
20
- first.
8
+ ```text
9
+ plans/
10
+ LEDGER.md
11
+ features/
12
+ az<feature id>-<slug>/
13
+ intent.md # required — lands with the Feature
14
+ requirements.md # the planning run (approved at G1)
15
+ design.md # optional — the planning run
16
+ file-map-reference.md # optional — the planning run
17
+ items/
18
+ az<item id>-<slug>.md # one PBI or Bug
19
+ ```
20
+
21
+ - `plans/features/az<id>-<slug>/intent.md` — the WHY, written by the human
22
+ with the Feature. Frontmatter: `type: intent`, `title`, `status` (the
23
+ Feature's board state), `work_item:` (the Feature's full board URL; its id
24
+ equals the folder id), `last_update`. Sections: `## Why`, `## Outcome`,
25
+ `## Constraints`, `## Non-goals`, optional `## Open questions`.
26
+ - `plans/features/az<id>-<slug>/requirements.md` — the what and why, frozen
27
+ at G1. Frontmatter: `type: feature`, `title`, `status` (the Feature's
28
+ board state), `epic:` (the parent Epic's board URL), `work_item:` (the
29
+ Feature's full board URL), `last_update`, `sources:` listing `intent.md`
30
+ first. Sections: `## Problem`, `## Acceptance criteria` (`AC-1…`, EARS),
31
+ `## Scope`, `## Predecessors`, `## Items` (`Id | Title | Type | Delivers |
32
+ Verification`), `## Open questions for G1`, `## Revision log`.
33
+ - `plans/features/az<id>-<slug>/items/az<item-id>-<slug>.md` — one PBI or
34
+ Bug. Frontmatter: `type: pbi` or `type: bug`, `title`, `status` (the
35
+ item's board state), `work_item:` (the item's full board URL), `feature:`
36
+ (the Feature's full board URL), `last_update`. A PBI carries `## What it
37
+ delivers` and `## Verification` naming its `AC-n`; a Fixes Bug carries the
38
+ bugfix sections (`## Current behaviour`, `## Expected behaviour`,
39
+ `## Behaviour that must not change`, `## Responsible Feature`,
40
+ `## Predecessors`, `## Verification`).
41
+ - `plans/LEDGER.md` — the plan-event ledger: `Date | Id | Area | Event |
42
+ Refs`, newest first, Event ≤ 99 characters. There is no `Next` table;
43
+ Feature order comes from the board's predecessor links.
44
+
45
+ The templates ship with the `adl-workitems-process` skill
46
+ (`references/templates/`); there is no per-repo `plans/templates/`.
21
47
 
22
48
  ## Conventions
23
49
 
@@ -26,3 +52,6 @@ board is the only place status lives; the files here describe the work.
26
52
  - An item is allocated on the board first; the file is named `az<id>-<slug>`
27
53
  only once that id exists. Files never move between directories.
28
54
  - `epic:` and `feature:` are authored by hand, never tool-generated.
55
+ - An item names its `feature:` as the Feature's full board URL.
56
+ - A gap found along the way is filed through `report-bug`, never a register
57
+ file; findings enter only that way.
@@ -4,10 +4,10 @@ How to contribute to THIS repository. Orientation is in `AGENTS.md`; what must n
4
4
 
5
5
  ## Plans and work items
6
6
  - A plan is a Feature; a backlog item is a PBI or a Bug. One file each; the board is the only place their state lives.
7
- - Layout: `plans/features/az<feature id>-<slug>/spec.md`, items under `items/az<id>-<slug>.md`.
7
+ - Layout: `plans/features/az<feature id>-<slug>/` with `intent.md`, `requirements.md` (plan files `design.md`/`file-map-reference.md` optional), items under `items/az<id>-<slug>.md`.
8
8
  - The id is the identity: allocate the item on the board first, then name the file. Until then it is a row in the plan's `## Items` table.
9
- - Nothing moves between directories; the spec text is the item's fields.
10
- - A gap found along the way goes in `plans/GAPS-AND-FINDINGS.md` and becomes a Bug under the same Feature.
9
+ - Nothing moves between directories; the plan text is the work item's fields.
10
+ - An item names its `feature:` as the Feature's full board URL; a gap found along the way is filed through `report-bug`, never a register file.
11
11
 
12
12
  ## Commits and PRs
13
13
  - Each commit is independently green and on one topic. Never `git stash`. Green wins over one topic, and say so.
@@ -21,8 +21,8 @@ How to contribute to THIS repository. Orientation is in `AGENTS.md`; what must n
21
21
  - A repository that differs states it under "Release flow of this repository".
22
22
 
23
23
  ## Tasks ledger
24
- - At the start and the end of a task, append one line to `docs/notes.md` (create it if missing, with YAML frontmatter and a `## Lines` section).
25
- - Format `YYYY-MM-DD HH:MM <surface> <note>`, whole line ≤100 characters. Append-only, newest last, never rewrite earlier lines. One ledger per repository.
24
+ - At the start and the end of a task, log with `adl activity add "<note>"` and read the log with `adl activity list`. The MCP tools `activity_add`/`activity_list` are the same storage; the CLI is the documented fallback.
25
+ - The log is `.adl/agent-activity.sqlite` — gitignored, local only. One ledger per repository; the tool fills time, surface, agent and repo, and only the note is caller-supplied.
26
26
 
27
27
  ## Release flow of this repository
28
28
  - <!-- Owner: state any difference from the flow above; delete this section if none. -->