1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
/// Work subcommands for unified GitHub/YAML workflow
/// CRUD: Create (add), Read (list/status), Update (edit/start/complete), Delete (delete)
#[derive(Debug, Clone, Subcommand)]
pub enum WorkCommands {
/// Add a new work ticket (CREATE)
#[command(visible_aliases = &["new", "create", "a"])]
Add {
/// Ticket title (required)
title: String,
/// Description (optional)
#[arg(short, long)]
description: Option<String>,
/// Priority level
#[arg(short, long, value_enum, default_value = "medium")]
priority: WorkPriority,
/// Tags (comma-separated)
#[arg(short, long)]
tags: Option<String>,
/// Project path (default: current directory)
#[arg(long)]
path: Option<PathBuf>,
/// Also create GitHub issue
#[arg(long)]
github: bool,
},
/// List all work tickets (READ)
#[command(visible_aliases = &["ls", "l"])]
List {
/// Filter by status
#[arg(short, long)]
status: Option<String>,
/// Filter by priority
#[arg(long)]
priority: Option<WorkPriority>,
/// Show only count
#[arg(long)]
count: bool,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Edit an existing ticket (UPDATE)
#[command(visible_aliases = &["update", "e"])]
Edit {
/// Ticket ID to edit
id: String,
/// New title
#[arg(short, long)]
title: Option<String>,
/// New description
#[arg(short, long)]
description: Option<String>,
/// New priority
#[arg(long)]
priority: Option<WorkPriority>,
/// New status
#[arg(short, long)]
status: Option<String>,
/// New tags (comma-separated, replaces existing)
#[arg(long)]
tags: Option<String>,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Delete a work ticket (DELETE)
#[command(visible_aliases = &["rm", "remove", "del"])]
Delete {
/// Ticket ID to delete
id: String,
/// Skip confirmation prompt
#[arg(short, long)]
force: bool,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Show unified quality annotations for a ticket
#[command(visible_aliases = &["ann", "quality", "metrics"])]
Annotate {
/// Ticket ID to annotate
id: String,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Output format
#[arg(short, long, value_enum, default_value = "text")]
format: AnnotateOutputFormat,
/// Include churn analysis (slower)
#[arg(long)]
with_churn: bool,
/// Days for churn analysis
#[arg(long, default_value = "30")]
churn_days: u32,
},
/// Start work on a GitHub issue or YAML ticket
#[command(visible_aliases = &["begin", "s"])]
Start {
/// Issue number (e.g., "8", "42") or YAML ticket ID (e.g., "PERF-001")
id: String,
/// Agent provenance (declared; also read from PMAT_AGENT_* env)
#[command(flatten)]
agent: AgentFlags,
/// Create specification file (docs/specifications/NNN-name.md)
#[arg(long)]
with_spec: bool,
/// Create as epic with subtasks
#[arg(long)]
epic: bool,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Force create GitHub issue for YAML ticket
#[arg(long)]
create_github: bool,
/// DbC contract profile override (universal, rust, pmat)
#[arg(long)]
profile: Option<String>,
/// Exclude specific DbC claims (comma-separated, e.g. "ensure.coverage,ensure.supply_chain")
#[arg(long, value_delimiter = ',')]
without: Option<Vec<String>>,
/// Iteration number for subcontracting (inherits postconditions from prior iteration)
#[arg(long, default_value = "1")]
iteration: u32,
/// Bind this ticket to a provable-contracts equation (Component 27).
/// Format: `<contract>/<equation>`, e.g. `rope-kernel-v1/rope`.
/// Repeatable for cross-kernel work items.
#[arg(long, value_name = "CONTRACT/EQUATION")]
implements: Vec<String>,
},
/// Continue work on existing issue/ticket
#[command(visible_aliases = &["cont", "c", "resume"])]
Continue {
/// Issue number or ticket ID
id: String,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Run invariant checkpoint (DbC §4.2)
#[command(visible_aliases = &["ck", "cp"])]
Checkpoint {
/// Issue number or ticket ID
id: String,
/// Agent provenance (declared; also read from PMAT_AGENT_* env)
#[command(flatten)]
agent: AgentFlags,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Complete work on issue/ticket
#[command(visible_aliases = &["done", "finish", "f"])]
Complete {
/// Issue number or ticket ID
id: String,
/// Skip quality gates (not recommended, falsification still runs)
#[arg(long)]
skip_quality: bool,
/// Override specific falsification claims (requires --ticket)
/// Use claim names like: coverage, complexity, file-size, github-sync
#[arg(long, value_delimiter = ',')]
override_claims: Option<Vec<String>>,
/// Ticket ID for override accountability (MANDATORY with --override-claims)
/// Must reference a valid debt ticket (e.g., DEBT-COV-20240115)
#[arg(long)]
ticket: Option<String>,
/// Agent provenance (declared; also read from PMAT_AGENT_* env)
#[command(flatten)]
agent: AgentFlags,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Run falsification tests without completing the work item
#[command(visible_alias = "test-claims")]
Falsify {
/// Issue number or ticket ID
id: String,
/// Override specific falsification claims (requires --ticket)
#[arg(long, value_delimiter = ',')]
override_claims: Option<Vec<String>>,
/// Ticket ID for override accountability (MANDATORY with --override-claims)
#[arg(long)]
ticket: Option<String>,
/// Agent provenance (declared; also read from PMAT_AGENT_* env)
#[command(flatten)]
agent: AgentFlags,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Structured chain-of-thought tools: integrity check + derivation
/// (MACS F3 / Component 31)
Cot {
/// CoT subcommand
#[command(subcommand)]
command: WorkCotCommands,
},
/// Falsification-ledger tools: hash re-verification + provenance report
/// (MACS F1 / Component 32)
Ledger {
/// Ledger subcommand
#[command(subcommand)]
command: WorkLedgerCommands,
},
/// Record an agent interruption event (refusal, model switch, session
/// restart, workflow spawn) or acknowledge one (MACS F1/E5)
#[command(visible_alias = "ev")]
Event {
/// Ticket ID (defaults to the single in-progress ticket)
id: Option<String>,
/// Event type: refusal|model-switch|session-restart|workflow-spawn
#[arg(long = "type", value_name = "TYPE")]
event_type: Option<String>,
/// Optional note (refusal)
#[arg(long)]
note: Option<String>,
/// Model id before the switch (model-switch)
#[arg(long)]
from: Option<String>,
/// Model id after the switch (model-switch)
#[arg(long)]
to: Option<String>,
/// Workflow id (workflow-spawn)
#[arg(long)]
workflow_id: Option<String>,
/// Number of subagents spawned (workflow-spawn)
#[arg(long, default_value = "0")]
subagents: u32,
/// Acknowledge a prior event by record id (requires --reason)
#[arg(long)]
ack_event: Option<String>,
/// Reason for the acknowledgement (root cause + disposition)
#[arg(long)]
reason: Option<String>,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Show work status
#[command(visible_aliases = &["st", "stat"])]
Status {
/// Issue number or ticket ID (default: all)
id: Option<String>,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Show only active items
#[arg(long)]
active: bool,
},
/// Synchronize GitHub and YAML
#[command(visible_aliases = &["sy"])]
Sync {
/// Sync direction
#[arg(long, value_enum, default_value = "full")]
direction: SyncDirection,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Dry run (show what would be synced)
#[arg(long)]
dry_run: bool,
},
/// Initialize roadmap and hooks
#[command(visible_aliases = &["setup", "ini"])]
Init {
/// GitHub repository (owner/repo)
#[arg(long)]
github_repo: Option<String>,
/// Disable GitHub integration
#[arg(long)]
no_github: bool,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Validate roadmap.yaml syntax and content (Part B: UX Improvements)
#[command(visible_aliases = &["check", "lint", "v"])]
Validate {
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Show verbose output with suggestions
#[arg(long)]
verbose: bool,
/// Fix issues automatically where possible
#[arg(long)]
fix: bool,
},
/// Auto-fix common roadmap.yaml issues (Part B: UX Improvements)
#[command(visible_aliases = &["fix", "m"])]
Migrate {
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Dry run (show what would be changed)
#[arg(long)]
dry_run: bool,
/// Create backup before migration
#[arg(long, default_value = "true")]
backup: bool,
/// Rewrite legacy verification_level strings in .pmat-work contracts
/// to typed canonical form; invalid values become L0 + audit note
/// (MACS-004)
#[arg(long)]
levels: bool,
},
/// List all valid status values with descriptions
#[command(visible_aliases = &["values", "statuses"])]
ListStatuses,
/// Score a work contract (DBC spec 5-dimension quality + lint)
#[command(visible_aliases = &["sc", "quality-score"])]
Score {
/// Work item ID
id: String,
/// Minimum score threshold (0.0-1.0, default: 0.0)
#[arg(long, default_value = "0.0")]
min_score: f64,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Output format (text, json, or sarif)
#[arg(short, long, default_value = "text")]
format: String,
},
/// Aggregate quality score across all work contracts (DBC spec §14.6)
#[command(visible_aliases = &["cbs", "portfolio"])]
CodebaseScore {
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
/// Output format (text or json)
#[arg(short, long, default_value = "text")]
format: String,
},
}
/// Agent provenance flags shared by `pmat work start|checkpoint|complete|falsify`
/// (MACS F1). Values are also read from `PMAT_AGENT_*` env vars; explicit flags
/// win. Flags and env both count as *declared* provenance — advisory detection
/// (e.g. CLAUDE_CODE_EFFORT_LEVEL) happens in the handler and is labeled.
#[derive(Debug, Clone, Default, clap::Args)]
pub struct AgentFlags {
/// Agent model id, verbatim (e.g. "claude-fable-5")
#[arg(long, env = "PMAT_AGENT_MODEL", global = false)]
pub agent_model: Option<String>,
/// Model effort as sent to the model: low|medium|high|xhigh|max
#[arg(long, env = "PMAT_AGENT_EFFORT")]
pub agent_effort: Option<String>,
/// Runner kind: claude-code|claude-agent-sdk|ultracode-workflow|ci-pipeline|human|<other>
#[arg(long, env = "PMAT_AGENT_HARNESS")]
pub agent_harness: Option<String>,
/// Ultracode workflow id, if any
#[arg(long, env = "PMAT_AGENT_WORKFLOW_ID")]
pub agent_workflow_id: Option<String>,
/// Parent agent/session id for nested subagents
#[arg(long, env = "PMAT_AGENT_PARENT")]
pub agent_parent: Option<String>,
}
impl AgentFlags {
/// Convert to the handler-layer declared-provenance struct.
pub fn to_declared(&self) -> crate::cli::handlers::work_ledger::DeclaredAgent {
crate::cli::handlers::work_ledger::DeclaredAgent {
model: self.agent_model.clone(),
effort: self.agent_effort.clone(),
harness: self.agent_harness.clone(),
workflow_id: self.agent_workflow_id.clone(),
parent: self.agent_parent.clone(),
}
}
}
/// Chain-of-thought subcommands (MACS F3): `pmat work cot check|derive`.
#[derive(Debug, Clone, Subcommand)]
pub enum WorkCotCommands {
/// Verify chain integrity (CB-1640): every assumption discharged,
/// discharge graph a DAG rooted in evidence
Check {
/// Ticket ID
id: String,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
/// Derive one proof obligation + one falsifiable claim per step
/// (verbatim fields) into contracts/work/<ID>.cot.yaml and record the
/// canonical CoT digest (CB-1646/CB-1658)
Derive {
/// Ticket ID
id: String,
/// Also emit optional require/ensure clauses (C30 codegen)
#[arg(long)]
emit_clauses: bool,
/// Project path (default: current directory)
#[arg(short, long)]
path: Option<PathBuf>,
},
}
/// Falsification-ledger subcommands (MACS-016): `pmat work ledger verify`.
#[derive(Debug, Clone, Subcommand)]
pub enum WorkLedgerCommands {
/// Recompute every receipt hash (v1 + v2 rules), detect tampering,
/// report provenance, and check Rule R1 ascending order. Read-only.
Verify {
/// Show the provenance report (receipts grouped by model/effort/harness)
#[arg(long)]
report: bool,
/// Output format
#[arg(short = 'f', long = "format", value_enum, default_value = "text")]
format: QaOutputFormat,
/// Project path (default: current directory)
#[arg(short = 'p', long = "path")]
path: Option<PathBuf>,
},
}