devrites 7.3.4 → 7.3.5

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 (64) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +1 -1
  3. package/docs/adr/0039-autocomplete-structural-admission.md +87 -0
  4. package/docs/adr/README.md +1 -0
  5. package/docs/cli.md +103 -5
  6. package/docs/engine/commands.md +46 -1
  7. package/engine/internal/lib/claims.go +65 -8
  8. package/engine/internal/lib/continuation.go +6 -1
  9. package/engine/internal/lib/dispatch.go +78 -32
  10. package/engine/internal/lib/frontier.go +103 -47
  11. package/engine/internal/lib/frontier_controller.go +652 -0
  12. package/engine/internal/lib/frontier_roadmap.go +168 -0
  13. package/engine/internal/lib/next.go +9 -0
  14. package/engine/internal/parallel/repository.go +10 -0
  15. package/pack/.claude/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  16. package/pack/.claude/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  17. package/pack/.claude/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  18. package/pack/.claude/skills/rite-autocomplete/SKILL.md +33 -38
  19. package/pack/.claude/skills/rite-autocomplete/reference/loop.md +46 -52
  20. package/pack/.claude/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  21. package/pack/.claude/skills/rite-build/reference/parallel-batch.md +17 -15
  22. package/pack/generated/claude/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  23. package/pack/generated/claude/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  24. package/pack/generated/claude/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  25. package/pack/generated/claude/skills/rite-autocomplete/SKILL.md +33 -38
  26. package/pack/generated/claude/skills/rite-autocomplete/reference/loop.md +46 -52
  27. package/pack/generated/claude/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  28. package/pack/generated/claude/skills/rite-build/reference/parallel-batch.md +17 -15
  29. package/pack/generated/codex/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  30. package/pack/generated/codex/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  31. package/pack/generated/codex/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  32. package/pack/generated/codex/skills/rite-autocomplete/SKILL.md +33 -38
  33. package/pack/generated/codex/skills/rite-autocomplete/reference/loop.md +46 -52
  34. package/pack/generated/codex/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  35. package/pack/generated/codex/skills/rite-build/reference/parallel-batch.md +17 -15
  36. package/pack/generated/devin/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  37. package/pack/generated/devin/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  38. package/pack/generated/devin/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  39. package/pack/generated/devin/skills/rite-autocomplete/SKILL.md +33 -38
  40. package/pack/generated/devin/skills/rite-autocomplete/reference/loop.md +46 -52
  41. package/pack/generated/devin/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  42. package/pack/generated/devin/skills/rite-build/reference/parallel-batch.md +17 -15
  43. package/pack/generated/dsh/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  44. package/pack/generated/dsh/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  45. package/pack/generated/dsh/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  46. package/pack/generated/dsh/skills/rite-autocomplete/SKILL.md +33 -38
  47. package/pack/generated/dsh/skills/rite-autocomplete/reference/loop.md +46 -52
  48. package/pack/generated/dsh/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  49. package/pack/generated/dsh/skills/rite-build/reference/parallel-batch.md +17 -15
  50. package/pack/generated/omp/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  51. package/pack/generated/omp/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  52. package/pack/generated/omp/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  53. package/pack/generated/omp/skills/rite-autocomplete/SKILL.md +33 -38
  54. package/pack/generated/omp/skills/rite-autocomplete/reference/loop.md +46 -52
  55. package/pack/generated/omp/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  56. package/pack/generated/omp/skills/rite-build/reference/parallel-batch.md +17 -15
  57. package/pack/generated/pi/skills/devrites-lib/reference/parallel-workspaces.md +106 -115
  58. package/pack/generated/pi/skills/devrites-lib/reference/standards/afk-hitl.md +18 -17
  59. package/pack/generated/pi/skills/devrites-lib/reference/workspace-artifact-schema.md +41 -38
  60. package/pack/generated/pi/skills/rite-autocomplete/SKILL.md +33 -38
  61. package/pack/generated/pi/skills/rite-autocomplete/reference/loop.md +46 -52
  62. package/pack/generated/pi/skills/rite-autocomplete/reference/stop-conditions.md +28 -28
  63. package/pack/generated/pi/skills/rite-build/reference/parallel-batch.md +17 -15
  64. package/package.json +1 -1
@@ -5,7 +5,6 @@ import (
5
5
  "io"
6
6
  "os"
7
7
  "path/filepath"
8
- "sort"
9
8
  "strconv"
10
9
  "strings"
11
10
 
@@ -241,6 +240,10 @@ func frontierQuote(s string) string { return "'" + strings.ReplaceAll(s, "'", "'
241
240
 
242
241
  // FrontierLines reports structural obligations, never semantic authorization or Ship approval.
243
242
  func FrontierLines(root, slug string) ([]string, error) {
243
+ mode, err := autocompleteMode(root)
244
+ if err != nil {
245
+ return nil, err
246
+ }
244
247
  if slug == "" {
245
248
  var err error
246
249
  slug, err = devritespaths.ActiveSlug(root)
@@ -248,11 +251,13 @@ func FrontierLines(root, slug string) ([]string, error) {
248
251
  return nil, err
249
252
  }
250
253
  }
254
+ workspaceOverride := ""
251
255
  if slug != "" {
252
256
  if !devritespaths.ValidSlug(slug) {
253
257
  return nil, fmt.Errorf("invalid source slug")
254
258
  }
255
- if _, err := devritespaths.WorkspaceOverrideChecked(root, slug); err != nil {
259
+ workspaceOverride, err = devritespaths.WorkspaceOverrideChecked(root, slug)
260
+ if err != nil {
256
261
  return nil, err
257
262
  }
258
263
  }
@@ -288,44 +293,21 @@ func FrontierLines(root, slug string) ([]string, error) {
288
293
  }
289
294
  chain, chainErr := frontierChain(nodes, slug)
290
295
  if chainErr != nil {
291
- return []string{"frontier: blocked", "frontier-source: " + slug, fmt.Sprintf("frontier-workspace: %s location=%s action=repair reason=%s", slug, source.location, chainErr)}, nil
292
- }
293
- anchor := chain[len(chain)-1]
294
- related := map[string]bool{anchor: true}
295
- for range maxSequenceChain {
296
- changed := false
297
- for name, n := range nodes {
298
- if related[n.parent] && !related[name] {
299
- related[name] = true
300
- changed = true
301
- }
302
- }
303
- if !changed {
304
- break
305
- }
306
- }
296
+ location := "work"
297
+ if source.location == "archive" {
298
+ location = "archive"
299
+ }
300
+ artifact := filepath.Join(root, location, slug, "state.md")
301
+ return []string{
302
+ "frontier: blocked", "frontier-source: " + slug,
303
+ fmt.Sprintf("frontier-workspace: %s location=%s action=repair reason=%s", slug, source.location, chainErr),
304
+ "frontier-review-sequence: " + artifact + " reason=native authority-normalization required: " + chainErr.Error(),
305
+ }, nil
306
+ }
307
+ ordered, related := frontierRelated(nodes, chain)
307
308
  if len(related) == 1 && source.parent == "" && !source.hasPosition && !source.hasRemaining && frontierSpecTarget(source) == "" {
308
309
  return []string{"frontier: none"}, nil
309
310
  }
310
- ordered := make([]string, 0, len(related))
311
- for name := range related {
312
- ordered = append(ordered, name)
313
- }
314
- depth := make(map[string]int, len(ordered))
315
- for _, name := range ordered {
316
- chain, _ := frontierChain(nodes, name)
317
- depth[name] = len(chain)
318
- }
319
- sort.Slice(ordered, func(i, j int) bool {
320
- a, b := nodes[ordered[i]], nodes[ordered[j]]
321
- if depth[a.slug] != depth[b.slug] {
322
- return depth[a.slug] < depth[b.slug]
323
- }
324
- if a.position != b.position {
325
- return a.position < b.position
326
- }
327
- return a.slug < b.slug
328
- })
329
311
  controller := ""
330
312
  for _, name := range ordered {
331
313
  if nodes[name].location == "live" {
@@ -350,6 +332,9 @@ func FrontierLines(root, slug string) ([]string, error) {
350
332
  if err != nil {
351
333
  return nil, err
352
334
  }
335
+ if workspaceOverride != "" {
336
+ allowFuture = false
337
+ }
353
338
  if lease != nil && lease.Capacity > 0 && capN > lease.Capacity {
354
339
  capN = lease.Capacity
355
340
  }
@@ -364,11 +349,30 @@ func FrontierLines(root, slug string) ([]string, error) {
364
349
  if source.hasRemaining && source.remaining == 0 {
365
350
  allowFuture = false
366
351
  }
367
- maps, artifacts, mapProblem := frontierRoadmap(nodes, ordered)
352
+ maps, artifacts, mapProblem, invalidCanonical := frontierRoadmap(nodes, ordered)
353
+ if invalidCanonical {
354
+ return []string{"frontier: blocked", "frontier-source: " + slug, "frontier-review-sequence: " + strings.Join(artifacts, ",") + " reason=native authority-normalization required: invalid canonical authority: " + mapProblem}, nil
355
+ }
356
+ if len(maps) > 0 && mapProblem == "" {
357
+ lines = append(lines, "frontier-authority: "+strings.Join(artifacts, ","))
358
+ }
359
+ records := frontierRecords{}
360
+ if mode {
361
+ records, err = frontierEvidence(root, slug)
362
+ if err != nil {
363
+ return nil, err
364
+ }
365
+ }
366
+ sequenceDeferred := mode && records.blocked["sequence"] != ""
368
367
  if mapProblem != "" {
369
- lines = append(lines, "frontier-review-sequence: "+strings.Join(artifacts, ",")+" reason=native authority-normalization required: "+mapProblem)
370
- blocked = true
368
+ if sequenceDeferred {
369
+ lines = append(lines, "frontier-blocked: sequence — "+records.blocked["sequence"]+"; scheduling deferred, not normalized")
370
+ } else {
371
+ lines = append(lines, "frontier-review-sequence: "+strings.Join(artifacts, ",")+" reason=native authority-normalization required: "+mapProblem)
372
+ blocked = true
373
+ }
371
374
  }
375
+ deferred := map[string]string{}
372
376
  prepared := map[string]bool{}
373
377
  for _, name := range ordered {
374
378
  n := nodes[name]
@@ -386,15 +390,21 @@ func FrontierLines(root, slug string) ([]string, error) {
386
390
  if err != nil {
387
391
  action, reason, n.selectionHeld = "repair", err.Error(), true
388
392
  }
393
+ if mode && action == "prepare" && deferred[name] != "" {
394
+ action, reason, n.selectionHeld = "wait", "frontier-blocked: "+name+" — "+deferred[name], true
395
+ }
389
396
  if !n.selectionHeld {
390
397
  live = append(live, name)
391
398
  }
392
- held = action == "blocked" || err != nil
399
+ held = action == "blocked" || err != nil || mode && action == "wait" && deferred[name] != ""
393
400
  switch action {
394
401
  case "inspect", "prepare", "repair":
395
402
  actionable = true
396
403
  case "wait":
397
404
  waiting = true
405
+ case "no-cursor":
406
+ blocked = true
407
+ action = "wait"
398
408
  case "blocked":
399
409
  blocked = true
400
410
  action = "wait"
@@ -409,7 +419,7 @@ func FrontierLines(root, slug string) ([]string, error) {
409
419
  target = maps[n.position+1]
410
420
  }
411
421
  if mapProblem != "" {
412
- if target != "" || n.hasRemaining && n.remaining > 0 {
422
+ if !sequenceDeferred && (target != "" || n.hasRemaining && n.remaining > 0) {
413
423
  actionable = true
414
424
  }
415
425
  continue
@@ -429,6 +439,20 @@ func FrontierLines(root, slug string) ([]string, error) {
429
439
  actionable, blocked = true, true
430
440
  continue
431
441
  }
442
+ if mode && target != "" {
443
+ sourceRecords := records
444
+ if name != slug {
445
+ sourceRecords, err = frontierEvidence(root, name)
446
+ if err != nil {
447
+ return nil, err
448
+ }
449
+ }
450
+ if reason := sourceRecords.blocked[target]; reason != "" {
451
+ deferred[target] = reason
452
+ lines = append(lines, "frontier-blocked: "+target+" source="+name+" — "+reason+"; preparation deferred, not approved")
453
+ continue
454
+ }
455
+ }
432
456
  if target != "" && nodes[target] == nil && !prepared[target] {
433
457
  prepared[target] = true
434
458
  // A table identifies a preparation obligation, not approval to implement it.
@@ -439,6 +463,23 @@ func FrontierLines(root, slug string) ([]string, error) {
439
463
  actionable, blocked = true, true
440
464
  }
441
465
  }
466
+ if mode {
467
+ filtered := candidates[:0]
468
+ for _, candidate := range candidates {
469
+ workspace := candidate.Workspace
470
+ if workspace == "" {
471
+ workspace = controller
472
+ }
473
+ if workspace != slug {
474
+ if reason := frontierSerialReason(records, slug, workspace, candidate.ID); reason != "" {
475
+ lines = append(lines, "frontier-serial: "+workspace+"/"+candidate.ID+" — "+reason+"; ordered handoff retained")
476
+ continue
477
+ }
478
+ }
479
+ filtered = append(filtered, candidate)
480
+ }
481
+ candidates = filtered
482
+ }
442
483
  if controller != "" && controllerProblem == "" && len(live) > 0 {
443
484
  lines = append(lines, fmt.Sprintf("frontier-select-command: devrites-engine parallel select --root %s --slug %s --from-plan --workspaces %s --cap %d", frontierQuote(filepath.Dir(root)), frontierQuote(controller), frontierQuote(strings.Join(live, ",")), capN))
444
485
  if len(candidates) > 0 {
@@ -638,12 +679,22 @@ func frontierLocal(root, controller string, n *frontierWorkspace, candidates *[]
638
679
  n.selectionHeld = true
639
680
  return "wait", "Ship requires existing native authority; controller invocation is not approval", nil
640
681
  }
682
+ if n.next == "" {
683
+ // Missing local work is not a hold on independently recorded preparation.
684
+ n.selectionHeld = true
685
+ return "no-cursor", "no actionable native internal cursor; review state without inventing authority", nil
686
+ }
641
687
  return "blocked", "no actionable native internal cursor; review state without inventing authority", nil
642
688
  }
643
689
 
644
- // Only exact position/slug or position/workspace tables are structural authority.
645
- // Different maps require native normalization, even if prose claims one supersedes another.
646
- func frontierRoadmap(nodes map[string]*frontierWorkspace, ordered []string) (map[int]string, []string, string) {
690
+ // Current canonical authority supersedes historical tables without rewriting them.
691
+ // Without it, differing exact legacy maps require native normalization.
692
+ func frontierRoadmap(nodes map[string]*frontierWorkspace, ordered []string) (map[int]string, []string, string, bool) {
693
+ if mapping, artifacts, err := frontierCanonicalRoadmap(nodes, ordered); err != nil {
694
+ return nil, artifacts, err.Error(), true
695
+ } else if mapping != nil {
696
+ return mapping, artifacts, "", false
697
+ }
647
698
  result := map[int]string{}
648
699
  var artifacts []string
649
700
  problem := ""
@@ -743,7 +794,7 @@ func frontierRoadmap(nodes map[string]*frontierWorkspace, ordered []string) (map
743
794
  artifacts = append(artifacts, filepath.Join(nodes[slug].dir, "state.md"))
744
795
  }
745
796
  }
746
- return result, artifacts, problem
797
+ return result, artifacts, problem, false
747
798
  }
748
799
 
749
800
  func frontierCells(line string) []string {
@@ -782,6 +833,12 @@ func frontierBoundSpec(root, slug, action string) bool {
782
833
  if err != nil {
783
834
  return false
784
835
  }
836
+ ordered, _ := frontierRelated(nodes, chain)
837
+ mapping, _, problem, invalidCanonical := frontierRoadmap(nodes, ordered)
838
+ if invalidCanonical {
839
+ return false
840
+ }
841
+ // Existing checked children remain resumable under ambiguous historical maps.
785
842
  if child := nodes[target]; child != nil {
786
843
  if child.parent != slug {
787
844
  return false
@@ -791,7 +848,6 @@ func frontierBoundSpec(root, slug, action string) bool {
791
848
  }
792
849
  return true
793
850
  }
794
- mapping, _, problem := frontierRoadmap(nodes, chain)
795
851
  if problem != "" || n.hasPosition && mapping[n.position+1] != "" && mapping[n.position+1] != target {
796
852
  return false
797
853
  }