@windyroad/itil 0.26.0 → 0.27.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.
@@ -507,3 +507,356 @@ EOF
507
507
  [ "$status" -eq 1 ]
508
508
  echo "$output" | grep -q "P099"
509
509
  }
510
+
511
+ # ── RFC-002 T4: dual-tolerant layout enumeration ────────────────────────────
512
+ #
513
+ # Contract: during the P170/RFC-002 migration window, problem tickets MAY
514
+ # live under either the flat layout (`docs/problems/<NNN>-<title>.<state>.md`)
515
+ # OR the per-state subdir layout (`docs/problems/<state>/<NNN>-<title>.md`).
516
+ # `reconcile-readme.sh` MUST enumerate ground-truth status from both,
517
+ # otherwise:
518
+ # - tickets in the un-migrated layout-half show as MISSING in WSJF Rankings,
519
+ # - or tickets in the migrated layout-half are not validated against
520
+ # README claims, masking drift.
521
+ #
522
+ # Behavioural contract: drift output (or exit 0) MUST be IDENTICAL regardless
523
+ # of which layout the source tickets reside in. The script's stdout is the
524
+ # observable signal; tests assert against stdout content + exit code, NOT
525
+ # against script source (P081 — no structural-grep on script content).
526
+ #
527
+ # T6 (post-T5 verification) drops the flat-layout half. These tests update
528
+ # at T6 to single-layout fixtures, NOT removed — the contract becomes
529
+ # "per-state layout enumerates correctly" but remains behavioural.
530
+ #
531
+ # @rfc RFC-002 T4
532
+ # @adr ADR-031 (per-state subdir is post-migration ground truth)
533
+ # @adr ADR-051 (load-bearing-from-the-start — T4 ships with bats coverage)
534
+ # @adr ADR-052 (behavioural-tests-default — fixture-driven not source-grep)
535
+
536
+ @test "reconcile-readme T4: per-state subdir .open ticket recognised, no drift when README matches" {
537
+ # Per-state layout — same Open ticket as the flat-only baseline test
538
+ # at line ~63 ("WSJF Rankings matches filesystem .open.md set"). The
539
+ # rendered drift output (exit 0) MUST be identical regardless of which
540
+ # layout the ticket resides in.
541
+ mkdir -p "$FIXTURE_DIR/open"
542
+ cat > "$FIXTURE_DIR/open/100-foo.md" <<EOF
543
+ # Problem 100: Foo
544
+ **Status**: Open
545
+ **WSJF**: 5.0
546
+ EOF
547
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
548
+ # Problem Backlog
549
+
550
+ ## WSJF Rankings
551
+
552
+ | WSJF | ID | Title | Severity | Status | Effort |
553
+ |------|-----|-------|----------|--------|--------|
554
+ | 5.0 | P100 | Foo | 12 High | Open | M |
555
+
556
+ ## Verification Queue
557
+
558
+ | ID | Title | Released | Likely verified? |
559
+ |----|-------|----------|------------------|
560
+
561
+ ## Closed
562
+
563
+ | ID | Title | Closed via |
564
+ |----|-------|-----------|
565
+ EOF
566
+ run "$SCRIPT" "$FIXTURE_DIR"
567
+ [ "$status" -eq 0 ]
568
+ }
569
+
570
+ @test "reconcile-readme T4: per-state subdir .closed ticket flagged when README ranks it Open (drift parity with flat)" {
571
+ # Mirrors the flat-layout P074 case at line ~94. Same drift, different
572
+ # source layout — drift output must surface P074 the same way.
573
+ mkdir -p "$FIXTURE_DIR/closed"
574
+ cat > "$FIXTURE_DIR/closed/074-foo.md" <<EOF
575
+ # Problem 074: Foo
576
+ **Status**: Closed
577
+ EOF
578
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
579
+ # Problem Backlog
580
+
581
+ ## WSJF Rankings
582
+
583
+ | WSJF | ID | Title | Severity | Status | Effort |
584
+ |------|-----|-------|----------|--------|--------|
585
+ | 6.0 | P074 | Foo | 12 High | Open | M |
586
+
587
+ ## Verification Queue
588
+
589
+ | ID | Title | Released | Likely verified? |
590
+ |----|-------|----------|------------------|
591
+
592
+ ## Closed
593
+
594
+ | ID | Title | Closed via |
595
+ |----|-------|-----------|
596
+ EOF
597
+ run "$SCRIPT" "$FIXTURE_DIR"
598
+ [ "$status" -eq 1 ]
599
+ echo "$output" | grep -q "P074"
600
+ echo "$output" | grep -q "actual=closed"
601
+ }
602
+
603
+ @test "reconcile-readme T4: per-state subdir .verifying ticket in WSJF Rankings flagged as drift (ADR-022)" {
604
+ # Mirrors the flat-layout P105 case at line ~317 — Verification Pending
605
+ # tickets must NOT appear in WSJF Rankings (ADR-022).
606
+ mkdir -p "$FIXTURE_DIR/verifying"
607
+ cat > "$FIXTURE_DIR/verifying/105-verify.md" <<EOF
608
+ **Status**: Verification Pending
609
+ EOF
610
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
611
+ ## WSJF Rankings
612
+
613
+ | WSJF | ID | Title | Severity | Status | Effort |
614
+ |------|-----|-------|----------|--------|--------|
615
+ | 8.0 | P105 | Verify | 12 High | Open | M |
616
+
617
+ ## Verification Queue
618
+
619
+ | ID | Title | Released | Likely verified? |
620
+ |----|-------|----------|------------------|
621
+
622
+ ## Closed
623
+
624
+ | ID | Title | Closed via |
625
+ |----|-------|-----------|
626
+ EOF
627
+ run "$SCRIPT" "$FIXTURE_DIR"
628
+ [ "$status" -eq 1 ]
629
+ echo "$output" | grep -q "P105"
630
+ }
631
+
632
+ @test "reconcile-readme T4: per-state subdir .open ticket missing from WSJF Rankings is flagged MISSING" {
633
+ # Mirrors the flat-layout P079 case at line ~127 — a ticket on disk
634
+ # but absent from README WSJF Rankings is drift.
635
+ mkdir -p "$FIXTURE_DIR/open"
636
+ cat > "$FIXTURE_DIR/open/079-bar.md" <<EOF
637
+ # Problem 079: Bar
638
+ **Status**: Open
639
+ **WSJF**: 3.0
640
+ EOF
641
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
642
+ ## WSJF Rankings
643
+
644
+ | WSJF | ID | Title | Severity | Status | Effort |
645
+ |------|-----|-------|----------|--------|--------|
646
+
647
+ ## Verification Queue
648
+
649
+ | ID | Title | Released | Likely verified? |
650
+ |----|-------|----------|------------------|
651
+
652
+ ## Closed
653
+
654
+ | ID | Title | Closed via |
655
+ |----|-------|-----------|
656
+ EOF
657
+ run "$SCRIPT" "$FIXTURE_DIR"
658
+ [ "$status" -eq 1 ]
659
+ echo "$output" | grep -q "P079"
660
+ }
661
+
662
+ @test "reconcile-readme T4: per-state subdir .verifying ticket listed in Verification Queue is clean (no drift)" {
663
+ # Verification Queue expects .verifying.md tickets — per-state
664
+ # equivalent is docs/problems/verifying/<NNN>-*.md.
665
+ mkdir -p "$FIXTURE_DIR/verifying"
666
+ cat > "$FIXTURE_DIR/verifying/056-qux.md" <<EOF
667
+ **Status**: Verification Pending
668
+ EOF
669
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
670
+ ## WSJF Rankings
671
+
672
+ | WSJF | ID | Title | Severity | Status | Effort |
673
+ |------|-----|-------|----------|--------|--------|
674
+
675
+ ## Verification Queue
676
+
677
+ | ID | Title | Released | Likely verified? |
678
+ |----|-------|----------|------------------|
679
+ | P056 | Qux | 2026-01-01 | yes |
680
+
681
+ ## Closed
682
+
683
+ | ID | Title | Closed via |
684
+ |----|-------|-----------|
685
+ EOF
686
+ run "$SCRIPT" "$FIXTURE_DIR"
687
+ [ "$status" -eq 0 ]
688
+ }
689
+
690
+ @test "reconcile-readme T4: mixed-layout fixture (flat + per-state) enumerates BOTH and stays clean" {
691
+ # Mid-migration race: some tickets already moved to per-state subdir,
692
+ # others still in flat layout. README accurately tracks both. Script
693
+ # must recognise both layout-halves as filesystem ground truth and
694
+ # report exit 0 (no drift) when README rows match.
695
+ cat > "$FIXTURE_DIR/100-foo.open.md" <<EOF
696
+ **Status**: Open
697
+ EOF
698
+ mkdir -p "$FIXTURE_DIR/open"
699
+ cat > "$FIXTURE_DIR/open/200-bar.md" <<EOF
700
+ **Status**: Open
701
+ EOF
702
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
703
+ ## WSJF Rankings
704
+
705
+ | WSJF | ID | Title | Severity | Status | Effort |
706
+ |------|-----|-------|----------|--------|--------|
707
+ | 5.0 | P100 | Foo | 12 High | Open | M |
708
+ | 4.0 | P200 | Bar | 12 High | Open | M |
709
+
710
+ ## Verification Queue
711
+
712
+ | ID | Title | Released | Likely verified? |
713
+ |----|-------|----------|------------------|
714
+
715
+ ## Closed
716
+
717
+ | ID | Title | Closed via |
718
+ |----|-------|-----------|
719
+ EOF
720
+ run "$SCRIPT" "$FIXTURE_DIR"
721
+ [ "$status" -eq 0 ]
722
+ }
723
+
724
+ @test "reconcile-readme T4: mixed-layout fixture surfaces drift from BOTH halves" {
725
+ # Both layout-halves contain a drifting ticket; both surfaces in
726
+ # output. Confirms the script enumerates both, not just one or the
727
+ # other.
728
+ cat > "$FIXTURE_DIR/100-foo.closed.md" <<EOF
729
+ **Status**: Closed
730
+ EOF
731
+ mkdir -p "$FIXTURE_DIR/closed"
732
+ cat > "$FIXTURE_DIR/closed/200-bar.md" <<EOF
733
+ **Status**: Closed
734
+ EOF
735
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
736
+ ## WSJF Rankings
737
+
738
+ | WSJF | ID | Title | Severity | Status | Effort |
739
+ |------|-----|-------|----------|--------|--------|
740
+ | 6.0 | P100 | Foo | 12 High | Open | M |
741
+ | 5.0 | P200 | Bar | 12 High | Open | M |
742
+
743
+ ## Verification Queue
744
+
745
+ | ID | Title | Released | Likely verified? |
746
+ |----|-------|----------|------------------|
747
+
748
+ ## Closed
749
+
750
+ | ID | Title | Closed via |
751
+ |----|-------|-----------|
752
+ EOF
753
+ run "$SCRIPT" "$FIXTURE_DIR"
754
+ [ "$status" -eq 1 ]
755
+ echo "$output" | grep -q "P100"
756
+ echo "$output" | grep -q "P200"
757
+ # Both surface as DRIFT (claims=open, actual=closed).
758
+ echo "$output" | grep -q "actual=closed"
759
+ }
760
+
761
+ @test "reconcile-readme T4: per-state subdir wins on cross-layout ID collision (post-migration is authoritative)" {
762
+ # Mid-migration race window: same ID may transiently appear in both
763
+ # layouts between the `git mv` and the README refresh in T5 bulk
764
+ # migration commit. Per-state subdir is the migration target —
765
+ # ADR-031 §"Authoritative state signal" treats subdirectory as
766
+ # authoritative. The script must therefore report per-state status,
767
+ # not flat-layout status, when both are present.
768
+ cat > "$FIXTURE_DIR/300-collision.open.md" <<EOF
769
+ **Status**: Open
770
+ EOF
771
+ mkdir -p "$FIXTURE_DIR/closed"
772
+ cat > "$FIXTURE_DIR/closed/300-collision.md" <<EOF
773
+ **Status**: Closed
774
+ EOF
775
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
776
+ ## WSJF Rankings
777
+
778
+ | WSJF | ID | Title | Severity | Status | Effort |
779
+ |------|-----|-------|----------|--------|--------|
780
+ | 5.0 | P300 | Collision | 12 High | Open | M |
781
+
782
+ ## Verification Queue
783
+
784
+ | ID | Title | Released | Likely verified? |
785
+ |----|-------|----------|------------------|
786
+
787
+ ## Closed
788
+
789
+ | ID | Title | Closed via |
790
+ |----|-------|-----------|
791
+ EOF
792
+ run "$SCRIPT" "$FIXTURE_DIR"
793
+ # Per-state subdir is authoritative → README's "Open" claim drifts
794
+ # against actual=closed. If flat-layout were preferred, the script
795
+ # would report exit 0 (no drift). Asserting actual=closed proves
796
+ # per-state-wins semantics.
797
+ [ "$status" -eq 1 ]
798
+ echo "$output" | grep -q "P300"
799
+ echo "$output" | grep -q "actual=closed"
800
+ }
801
+
802
+ @test "reconcile-readme T4: per-state subdir .parked ticket excluded from WSJF Rankings (ADR-022 multiplier 0)" {
803
+ # Mirrors the flat-layout P005 case at line ~375 — Parked tickets
804
+ # have their own section; absence from WSJF Rankings is correct.
805
+ mkdir -p "$FIXTURE_DIR/parked"
806
+ cat > "$FIXTURE_DIR/parked/005-parked.md" <<EOF
807
+ **Status**: Parked
808
+ EOF
809
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
810
+ ## WSJF Rankings
811
+
812
+ | WSJF | ID | Title | Severity | Status | Effort |
813
+ |------|-----|-------|----------|--------|--------|
814
+
815
+ ## Verification Queue
816
+
817
+ | ID | Title | Released | Likely verified? |
818
+ |----|-------|----------|------------------|
819
+
820
+ ## Closed
821
+
822
+ | ID | Title | Closed via |
823
+ |----|-------|-----------|
824
+
825
+ ## Parked
826
+
827
+ | ID | Title | Reason | Parked since |
828
+ |----|-------|--------|-------------|
829
+ | P005 | Parked | Upstream | 2026-04-16 |
830
+ EOF
831
+ run "$SCRIPT" "$FIXTURE_DIR"
832
+ [ "$status" -eq 0 ]
833
+ }
834
+
835
+ @test "reconcile-readme T4: per-state subdir .known-error ticket recognised in WSJF Rankings as Open-class" {
836
+ # Known-error tickets belong in WSJF Rankings (ADR-022 — open + known-error
837
+ # are the dev-work classes). Per-state subdir equivalent is
838
+ # docs/problems/known-error/<NNN>-*.md.
839
+ mkdir -p "$FIXTURE_DIR/known-error"
840
+ cat > "$FIXTURE_DIR/known-error/150-ke.md" <<EOF
841
+ **Status**: Known Error
842
+ EOF
843
+ cat > "$FIXTURE_DIR/README.md" <<'EOF'
844
+ ## WSJF Rankings
845
+
846
+ | WSJF | ID | Title | Severity | Status | Effort |
847
+ |------|-----|-------|----------|--------|--------|
848
+ | 4.0 | P150 | KE | 8 Med | Known Error | M |
849
+
850
+ ## Verification Queue
851
+
852
+ | ID | Title | Released | Likely verified? |
853
+ |----|-------|----------|------------------|
854
+
855
+ ## Closed
856
+
857
+ | ID | Title | Closed via |
858
+ |----|-------|-----------|
859
+ EOF
860
+ run "$SCRIPT" "$FIXTURE_DIR"
861
+ [ "$status" -eq 0 ]
862
+ }