@ccoalm/ccl-skills 0.13.0 → 0.15.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.
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/SKILL.md +19 -24
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/client-routing.md +32 -32
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/manual-invocation-and-prompts.md +16 -14
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/references/staged-review-contract.md +24 -26
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/AGENTS.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/claude_review.sh +60 -209
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/init_policy_matrix.py +114 -367
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/parse_probe_result.py +52 -672
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/review_gate.py +10 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/runtime-surface-verification-design.md +4 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_claude_review_probe.sh +77 -444
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_init_policy_matrix.sh +33 -98
- package/dist/assets/marketplace/plugins/ccl-skills/skills/code-review/scripts/test_parse_probe_result.sh +57 -173
- package/dist/assets/marketplace/plugins/ccl-skills/skills/defect-diagnosis/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/grill-me/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/miniapp-product-dev/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-observability/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/platform-release-engineering/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/SKILL.md +2 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/product-rd-workflow/references/rd-standards-doc-family-checklist.md +2 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-baseline/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-doc-writer/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/requirement-scope/SKILL.md +1 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/SKILL.md +14 -41
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/attention-budget-ratchet.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/correction-routing-map.md +22 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/coverage-exhaustion-traps.md +7 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/description-authoring.md +26 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/dual-track-review-gate.md +2 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/eval-routing.md +8 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/external-practice-controls.md +7 -1
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/extraction-quickstart.md +4 -2
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/harness-patterns-and-eval.md +8 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/incident-postmortem-extraction.md +8 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/rule-consolidation.md +1 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/source-register.md +73 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/uiux-judgment-extraction.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/references/validation-and-landing.md +11 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/entrypoint_form_census.py +169 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/eval-routing-bank.rb +62 -3
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/impact-chain-gate.rb +114 -10
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/reference-access-census.sh +157 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/review_ledger_binding.py +483 -109
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_impact_chain_refscripts.sh +188 -14
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_check_ccl_regressions.sh +10 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_entrypoint_form_census.sh +174 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_eval_routing_bank_resolution.sh +253 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_impact_chain_gate_verdict_differential.sh +49 -25
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_reference_access_census.sh +209 -0
- package/dist/assets/marketplace/plugins/ccl-skills/skills/skill-extraction-workflow/scripts/test_review_ledger_binding.sh +394 -5
- package/dist/assets/release.json +77 -47
- package/package.json +1 -1
|
@@ -492,14 +492,403 @@ out="$(run_part --base "$PART_BASE")"; rc=$?
|
|
|
492
492
|
check "the passing partition state still passes after the probes" \
|
|
493
493
|
'[ "$rc" = 0 ]'
|
|
494
494
|
|
|
495
|
+
# Chain: an integration branch accumulates several reviewed rounds, each merged
|
|
496
|
+
# with its own ledger bound at its own base, and is then promoted as one pull
|
|
497
|
+
# request. No single ledger binds the promotion candidate, and a path partition
|
|
498
|
+
# cannot either when two rounds append to the same file: that file's promotion
|
|
499
|
+
# diff is the sum of both appends and no round ever froze that sum. Every byte
|
|
500
|
+
# of the promotion reached the branch through a first-parent merge whose second
|
|
501
|
+
# parent is a reviewed head, so the gate walks that chain and rebinds each round
|
|
502
|
+
# in a detached checkout at the round's own base, requiring every merge to be
|
|
503
|
+
# exactly the automatic merge of its parents.
|
|
504
|
+
CHAIN="$WORK/chain-repo"
|
|
505
|
+
mkdir -p "$CHAIN/skills/code-review/scripts" "$CHAIN/skills/skill-extraction-workflow/scripts" "$CHAIN/specs"
|
|
506
|
+
cp "$CONTROLLER" "$CHAIN/skills/code-review/scripts/review_gate.py"
|
|
507
|
+
# This stub has a rule, unlike the accept-all stubs above, so a round can forge a
|
|
508
|
+
# ledger the real validator would reject and the suite can tell whose validator
|
|
509
|
+
# judged it.
|
|
510
|
+
STRICT_VALIDATOR='import json, sys
|
|
511
|
+
payload = json.load(open(sys.argv[1], encoding="utf-8"))
|
|
512
|
+
if payload.get("closeout_state") == "ready_for_human_decision":
|
|
513
|
+
print("extraction_review_state_ok: stub accepted")
|
|
514
|
+
sys.exit(0)
|
|
515
|
+
print("extraction_review_state_invalid: stub rejected")
|
|
516
|
+
sys.exit(1)
|
|
517
|
+
'
|
|
518
|
+
printf '%s' "$STRICT_VALIDATOR" >"$CHAIN/skills/skill-extraction-workflow/scripts/validate_extraction_review_state.py"
|
|
519
|
+
git -C "$CHAIN" init -q -b main .
|
|
520
|
+
git -C "$CHAIN" config user.email t@example.invalid
|
|
521
|
+
git -C "$CHAIN" config user.name tester
|
|
522
|
+
printf 'baseline\n' >"$CHAIN/skills/skill-extraction-workflow/SKILL.md"
|
|
523
|
+
printf '| row | owner |\n' >"$CHAIN/skills/skill-extraction-workflow/register.md"
|
|
524
|
+
printf 'baseline\n' >"$CHAIN/README.md"
|
|
525
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm baseline
|
|
526
|
+
CHAIN_BASE="$(git -C "$CHAIN" rev-parse HEAD)"
|
|
527
|
+
git -C "$CHAIN" checkout -q -b dev
|
|
528
|
+
|
|
529
|
+
run_chain() { python3 "$GATE" --repo-root "$CHAIN" "$@" 2>&1; }
|
|
530
|
+
|
|
531
|
+
# Land one reviewed round on the integration branch: branch, edit, ledger bound
|
|
532
|
+
# to the round's own candidate (its base is the integration tip it forked from),
|
|
533
|
+
# then a non-fast-forward merge so the round is one first-parent step.
|
|
534
|
+
land_round() {
|
|
535
|
+
local name="$1" ledger="$2"; shift 2
|
|
536
|
+
git -C "$CHAIN" checkout -q -b "round-$name" dev
|
|
537
|
+
"$@"
|
|
538
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round $name"
|
|
539
|
+
if [ "$ledger" = with-ledger ]; then
|
|
540
|
+
local digest
|
|
541
|
+
digest="$(run_chain --base dev --print-candidate)"
|
|
542
|
+
mkdir -p "$CHAIN/specs/$name/evidence"
|
|
543
|
+
write_closeout "$CHAIN/specs/$name/evidence/closeout.json" "$digest"
|
|
544
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round $name ledger"
|
|
545
|
+
fi
|
|
546
|
+
git -C "$CHAIN" checkout -q dev
|
|
547
|
+
git -C "$CHAIN" merge -q --no-ff -m "merge round $name" "round-$name"
|
|
548
|
+
}
|
|
549
|
+
edit_round_a() {
|
|
550
|
+
printf 'baseline\nround a\n' >"$CHAIN/skills/skill-extraction-workflow/SKILL.md"
|
|
551
|
+
printf '| round a | owner |\n' >>"$CHAIN/skills/skill-extraction-workflow/register.md"
|
|
552
|
+
}
|
|
553
|
+
edit_round_b() {
|
|
554
|
+
mkdir -p "$CHAIN/lane"
|
|
555
|
+
printf 'round b\n' >"$CHAIN/lane/file.txt"
|
|
556
|
+
printf '| round b | owner |\n' >>"$CHAIN/skills/skill-extraction-workflow/register.md"
|
|
557
|
+
}
|
|
558
|
+
land_round a with-ledger edit_round_a
|
|
559
|
+
land_round b with-ledger edit_round_b
|
|
560
|
+
CHAIN_TWO="$(git -C "$CHAIN" rev-parse HEAD)"
|
|
561
|
+
|
|
562
|
+
worktrees_before="$(git -C "$CHAIN" worktree list --porcelain)"
|
|
563
|
+
tree_before="$(git -C "$CHAIN" status --porcelain --ignored)"
|
|
564
|
+
out="$(run_chain --base "$CHAIN_BASE")"; rc=$?
|
|
565
|
+
check "two rounds appending to one file bind through the first-parent chain where no single ledger or path partition can" \
|
|
566
|
+
'[ "$rc" = 0 ] && case "$out" in *"first-parent chain"*"2 rounds"*"specs/b/evidence/closeout.json"*"specs/a/evidence/closeout.json"*) true;; *) false;; esac'
|
|
567
|
+
check "walking the chain leaves no detached checkout registered and the bound tree byte-identical" \
|
|
568
|
+
'[ "$(git -C "$CHAIN" worktree list --porcelain)" = "$worktrees_before" ] && [ "$(git -C "$CHAIN" status --porcelain --ignored)" = "$tree_before" ]'
|
|
569
|
+
|
|
570
|
+
out="$(run_chain --base "$CHAIN_BASE" --paths skills)"; rc=$?
|
|
571
|
+
check "a narrowed --paths scope does not evaluate the chain, because each round's ledger binds the whole round" \
|
|
572
|
+
'[ "$rc" = 1 ] && case "$out" in *"default path set"*) true;; *) false;; esac'
|
|
573
|
+
|
|
574
|
+
# The promotion pull request is brought up to date with its target: the target
|
|
575
|
+
# advanced, and the sync merge's second parent is already on the base. That step
|
|
576
|
+
# owes no evidence, but it must still be exactly the automatic merge.
|
|
577
|
+
git -C "$CHAIN" checkout -q main
|
|
578
|
+
printf 'baseline\nfixed on the target\n' >"$CHAIN/README.md"
|
|
579
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "target advances"
|
|
580
|
+
CHAIN_MAIN="$(git -C "$CHAIN" rev-parse HEAD)"
|
|
581
|
+
git -C "$CHAIN" checkout -q dev
|
|
582
|
+
git -C "$CHAIN" merge -q --no-ff -m "sync target into dev" main
|
|
583
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
584
|
+
check "a sync merge of the advanced target on top of the chain owes no evidence and still binds" \
|
|
585
|
+
'[ "$rc" = 0 ] && case "$out" in *"first-parent chain"*"2 rounds"*"sync"*) true;; *) false;; esac'
|
|
586
|
+
CHAIN_GOOD="$(git -C "$CHAIN" rev-parse HEAD)"
|
|
587
|
+
|
|
588
|
+
# A round the integration branch advanced past before it merged: its fork point
|
|
589
|
+
# is not the merge's first parent, the merge is still the automatic one, and the
|
|
590
|
+
# round's ledger was bound at its own fork point.
|
|
591
|
+
git -C "$CHAIN" checkout -q -b round-late dev
|
|
592
|
+
printf 'round late\n' >"$CHAIN/lane/late.txt"
|
|
593
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round late"
|
|
594
|
+
LATE_DIGEST="$(run_chain --base dev --print-candidate)"
|
|
595
|
+
mkdir -p "$CHAIN/specs/late/evidence"
|
|
596
|
+
write_closeout "$CHAIN/specs/late/evidence/closeout.json" "$LATE_DIGEST"
|
|
597
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round late ledger"
|
|
598
|
+
git -C "$CHAIN" checkout -q dev
|
|
599
|
+
edit_round_c() { printf 'round c\n' >"$CHAIN/lane/c.txt"; }
|
|
600
|
+
land_round c with-ledger edit_round_c
|
|
601
|
+
git -C "$CHAIN" merge -q --no-ff -m "merge round late" round-late
|
|
602
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
603
|
+
check "a round merged after the integration branch advanced still binds at its own fork point" \
|
|
604
|
+
'[ "$rc" = 0 ] && case "$out" in *"first-parent chain"*"4 rounds"*) true;; *) false;; esac'
|
|
605
|
+
CHAIN_ADVANCED="$(git -C "$CHAIN" rev-parse HEAD)"
|
|
606
|
+
|
|
607
|
+
# Every way a chain step can fail to be a reviewed round is refused for its own
|
|
608
|
+
# reason. Each probe branches from the passing state so the cases stay independent.
|
|
609
|
+
probe_chain() { git -C "$CHAIN" checkout -q -B dev "$CHAIN_GOOD"; }
|
|
610
|
+
|
|
611
|
+
probe_chain
|
|
612
|
+
edit_round_d() { printf 'round d\n' >"$CHAIN/lane/d.txt"; }
|
|
613
|
+
land_round d no-ledger edit_round_d
|
|
614
|
+
UNBOUND_MERGE="$(git -C "$CHAIN" rev-parse --short=12 HEAD)"
|
|
615
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
616
|
+
check "a round with no accepted ledger at its own base refuses the whole chain, naming that round" \
|
|
617
|
+
'[ "$rc" = 1 ] && case "$out" in *"round $UNBOUND_MERGE"*"does not bind at its own base"*) true;; *) false;; esac'
|
|
618
|
+
|
|
619
|
+
# Evidence is read from the LANDING tree, not from the round's own checkout. A
|
|
620
|
+
# round that merged without its ledger is still a set of bytes some later review
|
|
621
|
+
# can freeze and inspect; a validator-accepted closeout for exactly that candidate,
|
|
622
|
+
# committed on the integration branch afterwards, binds it. A closeout for any
|
|
623
|
+
# other digest does not, wherever it sits — the candidate hash, not the file's
|
|
624
|
+
# location, is what makes a ledger evidence. The retro ledger lands as a round of
|
|
625
|
+
# its own (a merge whose only change is receipt-shaped evidence), because a
|
|
626
|
+
# direct commit on the integration branch is refused for its own reason.
|
|
627
|
+
D_BASE="$(git -C "$CHAIN" rev-parse HEAD^1)"
|
|
628
|
+
git -C "$CHAIN" checkout -q round-d
|
|
629
|
+
D_DIGEST="$(run_chain --base "$D_BASE" --print-candidate)"
|
|
630
|
+
git -C "$CHAIN" checkout -q dev
|
|
631
|
+
edit_retro_wrong() {
|
|
632
|
+
mkdir -p "$CHAIN/specs/d-retro-wrong/evidence"
|
|
633
|
+
write_closeout "$CHAIN/specs/d-retro-wrong/evidence/closeout.json" "$(printf '%064d' 7)"
|
|
634
|
+
}
|
|
635
|
+
land_round d-retro-wrong no-ledger edit_retro_wrong
|
|
636
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
637
|
+
check "a later closeout for a different digest does not bind the unbound round" \
|
|
638
|
+
'[ "$rc" = 1 ] && case "$out" in *"round $UNBOUND_MERGE"*"does not bind at its own base"*) true;; *) false;; esac'
|
|
639
|
+
# The right digest in a closeout the validator rejects is still not evidence.
|
|
640
|
+
edit_retro_rejected() {
|
|
641
|
+
mkdir -p "$CHAIN/specs/d-retro-rejected/evidence"
|
|
642
|
+
python3 - "$CHAIN/specs/d-retro-rejected/evidence/closeout.json" "$D_DIGEST" <<'PY'
|
|
643
|
+
import json, sys
|
|
644
|
+
from pathlib import Path
|
|
645
|
+
Path(sys.argv[1]).write_text(json.dumps({"schema_version": 3, "closeout_state": "forged", "controller_receipts": [], "candidate_sha256": sys.argv[2]}))
|
|
646
|
+
PY
|
|
647
|
+
}
|
|
648
|
+
land_round d-retro-rejected no-ledger edit_retro_rejected
|
|
649
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
650
|
+
check "a later closeout for the right digest that the validator rejects does not bind the unbound round" \
|
|
651
|
+
'[ "$rc" = 1 ] && case "$out" in *"round $UNBOUND_MERGE"*"does not bind at its own base"*) true;; *) false;; esac'
|
|
652
|
+
# Evidence in the landing tree must be COMMITTED there, exactly as before: an
|
|
653
|
+
# untracked closeout for the right digest is refused outright, not read from disk.
|
|
654
|
+
mkdir -p "$CHAIN/specs/d-retro/evidence"
|
|
655
|
+
write_closeout "$CHAIN/specs/d-retro/evidence/closeout.json" "$D_DIGEST"
|
|
656
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
657
|
+
check "an uncommitted closeout in the landing tree is refused before any round is bound" \
|
|
658
|
+
'[ "$rc" != 0 ] && case "$out" in *"uncommitted changes"*) true;; *) false;; esac'
|
|
659
|
+
rm -r "$CHAIN/specs/d-retro"
|
|
660
|
+
edit_retro_right() {
|
|
661
|
+
mkdir -p "$CHAIN/specs/d-retro/evidence"
|
|
662
|
+
write_closeout "$CHAIN/specs/d-retro/evidence/closeout.json" "$D_DIGEST"
|
|
663
|
+
}
|
|
664
|
+
land_round d-retro no-ledger edit_retro_right
|
|
665
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
666
|
+
check "a validator-accepted closeout for the round's own candidate, committed on the integration branch after the merge, binds it through the chain" \
|
|
667
|
+
'[ "$rc" = 0 ] && case "$out" in *"first-parent chain"*"specs/d-retro/evidence/closeout.json"*) true;; *) false;; esac'
|
|
668
|
+
# Later evidence changes where a ledger may be found, never what the round is:
|
|
669
|
+
# the unbound round's candidate at its own base hashes exactly as it did before
|
|
670
|
+
# any retro ledger existed, so its packet, base and excludes are untouched.
|
|
671
|
+
git -C "$CHAIN" checkout -q round-d
|
|
672
|
+
D_DIGEST_AFTER="$(run_chain --base "$D_BASE" --print-candidate)"
|
|
673
|
+
git -C "$CHAIN" checkout -q dev
|
|
674
|
+
check "the round's candidate hash is unchanged by evidence committed later in the landing tree" \
|
|
675
|
+
'[ "$D_DIGEST_AFTER" = "$D_DIGEST" ]'
|
|
676
|
+
|
|
677
|
+
probe_chain
|
|
678
|
+
printf 'pushed straight to the integration branch\n' >"$CHAIN/lane/direct.txt"
|
|
679
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "direct commit on dev"
|
|
680
|
+
DIRECT="$(git -C "$CHAIN" rev-parse --short=12 HEAD)"
|
|
681
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
682
|
+
check "a non-merge commit on the integration branch is refused: nothing reviewed binds its content" \
|
|
683
|
+
'[ "$rc" = 1 ] && case "$out" in *"$DIRECT is not a merge commit"*) true;; *) false;; esac'
|
|
684
|
+
|
|
685
|
+
probe_chain
|
|
686
|
+
git -C "$CHAIN" checkout -q -b round-evil dev
|
|
687
|
+
printf 'round evil\n' >"$CHAIN/lane/evil.txt"
|
|
688
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round evil"
|
|
689
|
+
EVIL_DIGEST="$(run_chain --base dev --print-candidate)"
|
|
690
|
+
mkdir -p "$CHAIN/specs/evil/evidence"
|
|
691
|
+
write_closeout "$CHAIN/specs/evil/evidence/closeout.json" "$EVIL_DIGEST"
|
|
692
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round evil ledger"
|
|
693
|
+
git -C "$CHAIN" checkout -q dev
|
|
694
|
+
git -C "$CHAIN" merge -q --no-ff --no-commit round-evil
|
|
695
|
+
printf 'slipped into the merge commit itself\n' >"$CHAIN/lane/smuggled.txt"
|
|
696
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "merge round evil (with extra content)"
|
|
697
|
+
EVIL_MERGE="$(git -C "$CHAIN" rev-parse --short=12 HEAD)"
|
|
698
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
699
|
+
check "a merge whose tree is not the automatic merge of its parents is refused, naming the merge" \
|
|
700
|
+
'[ "$rc" = 1 ] && case "$out" in *"$EVIL_MERGE"*"automatic merge"*) true;; *) false;; esac'
|
|
701
|
+
|
|
702
|
+
probe_chain
|
|
703
|
+
git -C "$CHAIN" checkout -q -b round-conflict "$CHAIN_TWO"
|
|
704
|
+
printf 'baseline\nconflicting fix\n' >"$CHAIN/README.md"
|
|
705
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round conflict"
|
|
706
|
+
CONFLICT_DIGEST="$(run_chain --base "$CHAIN_TWO" --print-candidate)"
|
|
707
|
+
mkdir -p "$CHAIN/specs/conflict/evidence"
|
|
708
|
+
write_closeout "$CHAIN/specs/conflict/evidence/closeout.json" "$CONFLICT_DIGEST"
|
|
709
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round conflict ledger"
|
|
710
|
+
git -C "$CHAIN" checkout -q dev
|
|
711
|
+
git -C "$CHAIN" merge -q --no-ff --no-commit round-conflict >/dev/null 2>&1 || true
|
|
712
|
+
printf 'baseline\nresolved by hand\n' >"$CHAIN/README.md"
|
|
713
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "merge round conflict (resolved by hand)"
|
|
714
|
+
CONFLICT_MERGE="$(git -C "$CHAIN" rev-parse --short=12 HEAD)"
|
|
715
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
716
|
+
check "a merge that needed hand resolution is refused: the resolution is content no round reviewed" \
|
|
717
|
+
'[ "$rc" = 1 ] && case "$out" in *"$CONFLICT_MERGE"*"automatic merge"*) true;; *) false;; esac'
|
|
718
|
+
|
|
719
|
+
probe_chain
|
|
720
|
+
git -C "$CHAIN" checkout -q -b round-stale dev
|
|
721
|
+
printf 'round stale\n' >"$CHAIN/lane/stale.txt"
|
|
722
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round stale"
|
|
723
|
+
STALE_DIGEST="$(run_chain --base dev --print-candidate)"
|
|
724
|
+
mkdir -p "$CHAIN/specs/stale/evidence"
|
|
725
|
+
write_closeout "$CHAIN/specs/stale/evidence/closeout.json" "$STALE_DIGEST"
|
|
726
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round stale ledger"
|
|
727
|
+
printf 'edited after the review\n' >>"$CHAIN/lane/stale.txt"
|
|
728
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round stale moves after its ledger"
|
|
729
|
+
git -C "$CHAIN" checkout -q dev
|
|
730
|
+
git -C "$CHAIN" merge -q --no-ff -m "merge round stale" round-stale
|
|
731
|
+
STALE_MERGE="$(git -C "$CHAIN" rev-parse --short=12 HEAD)"
|
|
732
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
733
|
+
check "a round whose ledger binds a candidate it later moved away from is refused" \
|
|
734
|
+
'[ "$rc" = 1 ] && case "$out" in *"round $STALE_MERGE"*"does not bind at its own base"*) true;; *) false;; esac'
|
|
735
|
+
|
|
736
|
+
# A round is judged with the landing tree's controller and validator, never its
|
|
737
|
+
# own: a round that installs an accept-all validator in its own branch, forges a
|
|
738
|
+
# ledger the real validator rejects, and is later followed by a round restoring
|
|
739
|
+
# the real validator must not bind through history's tools.
|
|
740
|
+
probe_chain
|
|
741
|
+
git -C "$CHAIN" checkout -q -b round-forged dev
|
|
742
|
+
printf 'round forged\n' >"$CHAIN/lane/forged.txt"
|
|
743
|
+
printf 'import sys\nprint("extraction_review_state_ok: hollow validator accepts everything")\nsys.exit(0)\n' \
|
|
744
|
+
>"$CHAIN/skills/skill-extraction-workflow/scripts/validate_extraction_review_state.py"
|
|
745
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round forged"
|
|
746
|
+
FORGED_DIGEST="$(run_chain --base dev --print-candidate)"
|
|
747
|
+
mkdir -p "$CHAIN/specs/forged/evidence"
|
|
748
|
+
python3 - "$CHAIN/specs/forged/evidence/closeout.json" "$FORGED_DIGEST" <<'PY'
|
|
749
|
+
import json, sys
|
|
750
|
+
from pathlib import Path
|
|
751
|
+
Path(sys.argv[1]).write_text(json.dumps({"schema_version": 3, "closeout_state": "forged", "controller_receipts": [], "candidate_sha256": sys.argv[2]}))
|
|
752
|
+
PY
|
|
753
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "round forged ledger"
|
|
754
|
+
git -C "$CHAIN" checkout -q dev
|
|
755
|
+
git -C "$CHAIN" merge -q --no-ff -m "merge round forged" round-forged
|
|
756
|
+
FORGED_MERGE="$(git -C "$CHAIN" rev-parse --short=12 HEAD)"
|
|
757
|
+
edit_round_restore() { printf '%s' "$STRICT_VALIDATOR" >"$CHAIN/skills/skill-extraction-workflow/scripts/validate_extraction_review_state.py"; }
|
|
758
|
+
land_round restore with-ledger edit_round_restore
|
|
759
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
760
|
+
check "a round that forged a ledger under its own hollow validator is refused even after a later round restored the real one" \
|
|
761
|
+
'[ "$rc" = 1 ] && case "$out" in *"round $FORGED_MERGE"*"does not bind at its own base"*) true;; *) false;; esac'
|
|
762
|
+
|
|
763
|
+
# The walk is bounded at exactly 64 steps: a chain of 64 passes, 65 is refused.
|
|
764
|
+
# Receipt-only rounds keep the fixture fast, since a round whose only change is
|
|
765
|
+
# an excluded receipt binds as "no reviewed-path change" without a freeze.
|
|
766
|
+
probe_chain
|
|
767
|
+
fill_round() {
|
|
768
|
+
git -C "$CHAIN" checkout -q -b "round-fill-$1" dev
|
|
769
|
+
mkdir -p "$CHAIN/specs/fill-$1/evidence"
|
|
770
|
+
printf '{"schema_version": 3, "candidate_sha256": "%s"}\n' "$(printf '0%.0s' $(seq 64))" >"$CHAIN/specs/fill-$1/evidence/note.json"
|
|
771
|
+
git -C "$CHAIN" add -A && git -C "$CHAIN" commit -qm "fill $1"
|
|
772
|
+
git -C "$CHAIN" checkout -q dev
|
|
773
|
+
git -C "$CHAIN" merge -q --no-ff -m "merge fill $1" "round-fill-$1"
|
|
774
|
+
}
|
|
775
|
+
for index in $(seq 1 61); do fill_round "$index"; done
|
|
776
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
777
|
+
check "a chain of exactly 64 steps is still walked and binds" \
|
|
778
|
+
'[ "$rc" = 0 ] && case "$out" in *"first-parent chain"*"63 rounds"*) true;; *) false;; esac'
|
|
779
|
+
fill_round 62
|
|
780
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
781
|
+
check "a chain of 65 steps is refused as longer than the bound" \
|
|
782
|
+
'[ "$rc" = 1 ] && case "$out" in *"more than 64 steps"*) true;; *) false;; esac'
|
|
783
|
+
|
|
784
|
+
# A checkout this run cannot release is an error, never a pass: the removal's
|
|
785
|
+
# result is checked and the registry read back, and nothing prunes registrations
|
|
786
|
+
# the run did not create. A git shim refuses only `worktree remove`.
|
|
787
|
+
git -C "$CHAIN" checkout -q -B dev "$CHAIN_GOOD"
|
|
788
|
+
REAL_GIT="$(command -v git)"
|
|
789
|
+
mkdir -p "$WORK/fakegit" "$WORK/shim-tmp"
|
|
790
|
+
cat >"$WORK/fakegit/git" <<EOF
|
|
791
|
+
#!/usr/bin/env bash
|
|
792
|
+
if [ "\$1" = "-C" ] && [ "\$3" = "worktree" ] && [ "\$4" = "remove" ]; then
|
|
793
|
+
echo "shim: refusing to remove the worktree" >&2
|
|
794
|
+
exit 1
|
|
795
|
+
fi
|
|
796
|
+
exec "$REAL_GIT" "\$@"
|
|
797
|
+
EOF
|
|
798
|
+
chmod +x "$WORK/fakegit/git"
|
|
799
|
+
out="$(PATH="$WORK/fakegit:$PATH" TMPDIR="$WORK/shim-tmp" run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
800
|
+
check "a detached checkout that cannot be released turns the verdict into an error, never a pass" \
|
|
801
|
+
'[ "$rc" != 0 ] && case "$out" in *"cannot release the detached checkout"*) case "$out" in *review_ledger_binding_ok*) false;; *) true;; esac;; *) false;; esac'
|
|
802
|
+
git -C "$CHAIN" worktree prune
|
|
803
|
+
|
|
804
|
+
# `git worktree add` can register and populate the checkout and still return
|
|
805
|
+
# nonzero. The failure is an error either way, but the registration it left
|
|
806
|
+
# behind must be released and verified, not merely have its directory deleted.
|
|
807
|
+
mkdir -p "$WORK/fakegit-add" "$WORK/shim-add-tmp"
|
|
808
|
+
cat >"$WORK/fakegit-add/git" <<EOF
|
|
809
|
+
#!/usr/bin/env bash
|
|
810
|
+
if [ "\$1" = "-C" ] && [ "\$3" = "worktree" ] && [ "\$4" = "add" ]; then
|
|
811
|
+
"$REAL_GIT" "\$@"
|
|
812
|
+
echo "shim: worktree add failed after registering" >&2
|
|
813
|
+
exit 1
|
|
814
|
+
fi
|
|
815
|
+
exec "$REAL_GIT" "\$@"
|
|
816
|
+
EOF
|
|
817
|
+
chmod +x "$WORK/fakegit-add/git"
|
|
818
|
+
worktrees_before="$(git -C "$CHAIN" worktree list --porcelain)"
|
|
819
|
+
out="$(PATH="$WORK/fakegit-add:$PATH" TMPDIR="$WORK/shim-add-tmp" run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
820
|
+
check "a checkout creation that fails after registering is an error and leaves no registration or directory behind" \
|
|
821
|
+
'[ "$rc" != 0 ] && case "$out" in *"cannot check out round head"*) case "$out" in *review_ledger_binding_ok*) false;; *) true;; esac;; *) false;; esac && [ "$(git -C "$CHAIN" worktree list --porcelain)" = "$worktrees_before" ] && [ -z "$(ls -A "$WORK/shim-add-tmp")" ]'
|
|
822
|
+
git -C "$CHAIN" worktree prune
|
|
823
|
+
|
|
824
|
+
# The benign sibling: an add that fails before registering anything must error
|
|
825
|
+
# the same way, leave the registry untouched, and remove the directory this run
|
|
826
|
+
# created for it, without reporting a release problem it does not have.
|
|
827
|
+
mkdir -p "$WORK/fakegit-noadd" "$WORK/shim-noadd-tmp"
|
|
828
|
+
cat >"$WORK/fakegit-noadd/git" <<EOF
|
|
829
|
+
#!/usr/bin/env bash
|
|
830
|
+
if [ "\$1" = "-C" ] && [ "\$3" = "worktree" ] && [ "\$4" = "add" ]; then
|
|
831
|
+
echo "shim: worktree add refused before registering" >&2
|
|
832
|
+
exit 1
|
|
833
|
+
fi
|
|
834
|
+
exec "$REAL_GIT" "\$@"
|
|
835
|
+
EOF
|
|
836
|
+
chmod +x "$WORK/fakegit-noadd/git"
|
|
837
|
+
worktrees_before="$(git -C "$CHAIN" worktree list --porcelain)"
|
|
838
|
+
out="$(PATH="$WORK/fakegit-noadd:$PATH" TMPDIR="$WORK/shim-noadd-tmp" run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
839
|
+
check "a checkout creation that fails before registering errors cleanly with no registration, no directory, and no release complaint" \
|
|
840
|
+
'[ "$rc" != 0 ] && case "$out" in *"cannot check out round head"*) case "$out" in *"could not be released"*|*review_ledger_binding_ok*) false;; *) true;; esac;; *) false;; esac && [ "$(git -C "$CHAIN" worktree list --porcelain)" = "$worktrees_before" ] && [ -z "$(ls -A "$WORK/shim-noadd-tmp")" ]'
|
|
841
|
+
|
|
842
|
+
# The registry is read NUL-terminated: line-oriented porcelain cannot carry a
|
|
843
|
+
# path with a newline (the line splits; a tab is printed raw on the git in use,
|
|
844
|
+
# and quoting depends on version and core.quotePath), so a registration under
|
|
845
|
+
# such a temporary directory would match neither spelling and read as gone.
|
|
846
|
+
# Here the add registers and fails, the remove is refused, and the surviving
|
|
847
|
+
# registration must be reported.
|
|
848
|
+
TAB_TMP="$WORK/shim nl
|
|
849
|
+
dir"
|
|
850
|
+
mkdir -p "$WORK/fakegit-tab" "$TAB_TMP"
|
|
851
|
+
cat >"$WORK/fakegit-tab/git" <<EOF
|
|
852
|
+
#!/usr/bin/env bash
|
|
853
|
+
if [ "\$1" = "-C" ] && [ "\$3" = "worktree" ] && [ "\$4" = "add" ]; then
|
|
854
|
+
"$REAL_GIT" "\$@"
|
|
855
|
+
echo "shim: worktree add failed after registering" >&2
|
|
856
|
+
exit 1
|
|
857
|
+
fi
|
|
858
|
+
if [ "\$1" = "-C" ] && [ "\$3" = "worktree" ] && [ "\$4" = "remove" ]; then
|
|
859
|
+
echo "shim: refusing to remove the worktree" >&2
|
|
860
|
+
exit 1
|
|
861
|
+
fi
|
|
862
|
+
exec "$REAL_GIT" "\$@"
|
|
863
|
+
EOF
|
|
864
|
+
chmod +x "$WORK/fakegit-tab/git"
|
|
865
|
+
worktrees_before="$(git -C "$CHAIN" worktree list --porcelain)"
|
|
866
|
+
out="$(PATH="$WORK/fakegit-tab:$PATH" TMPDIR="$TAB_TMP" run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
867
|
+
check "a surviving registration under a newline-bearing temporary path is still reported, not read as gone through line-oriented porcelain" \
|
|
868
|
+
'[ "$rc" != 0 ] && case "$out" in *"cannot check out round head"*"could not be released"*"still registered"*) true;; *) false;; esac'
|
|
869
|
+
rm -rf "$TAB_TMP"
|
|
870
|
+
git -C "$CHAIN" worktree prune
|
|
871
|
+
# This case deliberately leaves a registration behind, so its own cleanup is
|
|
872
|
+
# what restores the fixture. Prune only drops registrations whose directory is
|
|
873
|
+
# already gone, so the directory must go first; asserting the restoration keeps
|
|
874
|
+
# a later reordering from silently handing every following case a mutated
|
|
875
|
+
# registry.
|
|
876
|
+
check "the newline-path case restores the fixture's worktree registry for the cases that follow" \
|
|
877
|
+
'[ "$(git -C "$CHAIN" worktree list --porcelain)" = "$worktrees_before" ]'
|
|
878
|
+
|
|
879
|
+
git -C "$CHAIN" checkout -q -B dev "$CHAIN_ADVANCED"
|
|
880
|
+
out="$(run_chain --base "$CHAIN_MAIN")"; rc=$?
|
|
881
|
+
check "the passing chain state still passes after the probes" \
|
|
882
|
+
'[ "$rc" = 0 ]'
|
|
883
|
+
|
|
495
884
|
# The suite above exercises a synthetic repository. The gate must also run against
|
|
496
885
|
# the real checkout it ships in, or a break in that path passes every test here.
|
|
497
886
|
REAL_ROOT="$(cd "$DIR/../../.." && pwd -P)"
|
|
498
887
|
real_out="$(env -u CCL_SKILL_BASE_REF python3 "$GATE" --repo-root "$REAL_ROOT" --base HEAD~1 --print-candidate 2>&1)"; real_rc=$?
|
|
499
|
-
#
|
|
500
|
-
# commit happened to touch: a candidate hash when a reviewed path moved,
|
|
501
|
-
# no-change signal when it did not
|
|
502
|
-
#
|
|
888
|
+
# Three outputs are legitimate and which one appears depends on what the parent
|
|
889
|
+
# commit happened to touch: a candidate hash when a bounded reviewed path moved,
|
|
890
|
+
# the no-change signal when it did not, or the packet-ceiling refusal when the
|
|
891
|
+
# parent diff is too large for one reviewer packet.
|
|
503
892
|
# Which answer is legitimate depends on the checkout, so decide that FIRST and then
|
|
504
893
|
# assert the one matching branch. Accepting every output would make this assertion a
|
|
505
894
|
# function of repository state; branching on the state keeps it an assertion about
|
|
@@ -511,7 +900,7 @@ if [ -n "$real_dirty" ]; then
|
|
|
511
900
|
'[ "$real_rc" != 0 ] && case "$real_out" in *"uncommitted changes"*) true;; *) false;; esac'
|
|
512
901
|
else
|
|
513
902
|
check "the gate answers for the clean real checkout it ships in, whichever legitimate answer applies" \
|
|
514
|
-
'[ "$real_rc" = 0 ] && { case "$real_out" in [0-9a-f]*) [ ${#real_out} = 64 ];; *) false;; esac || case "$real_out" in *review_ledger_binding_no_change*) true;; *) false;; esac; }'
|
|
903
|
+
'{ [ "$real_rc" = 0 ] && { case "$real_out" in [0-9a-f]*) [ ${#real_out} = 64 ];; *) false;; esac || case "$real_out" in *review_ledger_binding_no_change*) true;; *) false;; esac; }; } || { [ "$real_rc" = 1 ] && case "$real_out" in *"cannot freeze the candidate packet"*"review packet exceeds 200000 bytes"*) true;; *) false;; esac; }'
|
|
515
904
|
fi
|
|
516
905
|
|
|
517
906
|
if [ "$fails" -gt 0 ]; then
|