@event4u/agent-config 9.24.0 → 9.26.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.
Files changed (97) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +136 -0
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/conformance.md +182 -0
  5. package/dist/agent-src/commands/analyze/inbox.md +33 -2
  6. package/dist/agent-src/commands/review/changes.md +6 -5
  7. package/dist/agent-src/commands/roadmap/next.md +194 -0
  8. package/dist/agent-src/commands/roadmap.md +12 -4
  9. package/dist/agent-src/contexts/execution/subagent-routing.md +4 -1
  10. package/dist/agent-src/rules/decision-revisit-gate.md +2 -0
  11. package/dist/agent-src/rules/delegation-policy.md +3 -2
  12. package/dist/agent-src/rules/design-fidelity.md +17 -1
  13. package/dist/agent-src/rules/design-review-after-ui-write.md +116 -0
  14. package/dist/agent-src/rules/evaluator-independence.md +111 -0
  15. package/dist/agent-src/rules/session-canary.md +15 -1
  16. package/dist/agent-src/rules/settings-ask-protocol.md +176 -0
  17. package/dist/agent-src/rules/token-budget-discipline.md +6 -3
  18. package/dist/agent-src/rules/ui-audit-gate.md +3 -0
  19. package/dist/agent-src/rules/user-interaction.md +23 -0
  20. package/dist/agent-src/skills/finishing-a-development-branch/SKILL.md +1 -1
  21. package/dist/agent-src/skills/recursive-verification/SKILL.md +13 -0
  22. package/dist/agent-src/skills/rule-writing/SKILL.md +45 -0
  23. package/dist/agent-src/skills/skill-writing/SKILL.md +114 -0
  24. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  25. package/dist/cli/registry.js +1 -0
  26. package/dist/cli/registry.js.map +1 -1
  27. package/dist/cli-delegate/cmd_route_audit.js +4 -1
  28. package/dist/cli-delegate/cmd_route_explain.js +4 -1
  29. package/dist/discovery/deprecation-report.md +1 -1
  30. package/dist/discovery/discovery-manifest.json +146 -28
  31. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  32. package/dist/discovery/discovery-manifest.summary.md +5 -5
  33. package/dist/discovery/orphan-report.md +1 -1
  34. package/dist/discovery/packs.json +16 -11
  35. package/dist/discovery/trust-report.md +3 -3
  36. package/dist/discovery/workspaces.json +12 -7
  37. package/dist/hooks/dispatch.js +1501 -511
  38. package/dist/mcp/registry-manifest.json +3 -3
  39. package/dist/mcp/server.json +2 -2
  40. package/dist/router.json +1 -1
  41. package/dist/server/nicknameResolver.js +116 -0
  42. package/dist/server/nicknameResolver.js.map +1 -0
  43. package/dist/server/routes/ping.js +29 -11
  44. package/dist/server/routes/ping.js.map +1 -1
  45. package/dist/shared/interactiveContext.js +73 -0
  46. package/dist/shared/interactiveContext.js.map +1 -0
  47. package/dist/shared/nicknamePrefill.js +59 -0
  48. package/dist/shared/nicknamePrefill.js.map +1 -0
  49. package/dist/shared/settingsAsks.js +128 -0
  50. package/dist/shared/settingsAsks.js.map +1 -0
  51. package/dist/shared/settingsConsent.js +93 -0
  52. package/dist/shared/settingsConsent.js.map +1 -0
  53. package/package.json +1 -1
  54. package/src/config/agents-paths.yml +15 -0
  55. package/src/config/evaluator-budgets.json +68 -68
  56. package/src/config/gate-coverage.yml +131 -5
  57. package/src/config/gate-violation-baselines.json +11 -0
  58. package/src/scripts/_cli/cmd_route_audit.ts +4 -1
  59. package/src/scripts/_cli/cmd_route_explain.ts +9 -1
  60. package/src/scripts/_dispatch.bash +12 -0
  61. package/src/scripts/ai-video/stitch.sh +27 -9
  62. package/src/scripts/before_complete_hook.ts +146 -5
  63. package/src/scripts/bench_ab_v2_run.ts +272 -16
  64. package/src/scripts/bench_ab_v2_stats.ts +156 -3
  65. package/src/scripts/check_completion_review.ts +80 -3
  66. package/src/scripts/check_corpus_staleness.ts +692 -0
  67. package/src/scripts/check_depth_budget.ts +295 -0
  68. package/src/scripts/check_gate_coverage.ts +67 -0
  69. package/src/scripts/check_hook_bundle_freshness.ts +183 -0
  70. package/src/scripts/conformance_scan.ts +422 -0
  71. package/src/scripts/dispatch_r2_reviewer.ts +31 -2
  72. package/src/scripts/git_authorization_hook.ts +328 -0
  73. package/src/scripts/hook_manifest.yaml +69 -9
  74. package/src/scripts/hooks/block_no_verify.ts +3 -1
  75. package/src/scripts/hooks/block_unauthorized_git.ts +371 -0
  76. package/src/scripts/hooks/concern_registry.ts +8 -0
  77. package/src/scripts/hooks/design_slop_hook.ts +13 -1
  78. package/src/scripts/hooks/dispatch_hook.ts +97 -2
  79. package/src/scripts/hooks/evidence_independence.ts +368 -0
  80. package/src/scripts/language_mirror_hook.ts +456 -0
  81. package/src/scripts/lint_abstraction_thresholds.ts +41 -8
  82. package/src/scripts/lint_agents_layout.ts +2 -0
  83. package/src/scripts/lint_decision_impact.ts +246 -0
  84. package/src/scripts/lint_example_fences.ts +609 -0
  85. package/src/scripts/lint_hook_manifest.ts +29 -0
  86. package/src/scripts/lint_rule_interactions.ts +90 -0
  87. package/src/scripts/lint_rule_migration_ledger.ts +480 -0
  88. package/src/scripts/lint_skill_descriptions.ts +86 -2
  89. package/src/scripts/memory_learn_hook.ts +109 -6
  90. package/src/scripts/pr_url_reminder_hook.ts +17 -2
  91. package/src/scripts/release.ts +38 -1
  92. package/src/scripts/schemas/review-findings.schema.json +99 -0
  93. package/src/scripts/schemas/rule.schema.json +10 -0
  94. package/src/shared/interactiveContext.ts +98 -0
  95. package/src/shared/nicknamePrefill.ts +96 -0
  96. package/src/shared/settingsAsks.ts +176 -0
  97. package/src/shared/settingsConsent.ts +136 -0
@@ -42,11 +42,11 @@
42
42
  #
43
43
  # COVERAGE — THE HONEST DENOMINATOR (re-measured 2026-08-05)
44
44
  # ----------------------------------------------------------
45
- # 224 `lint_*` / `check_*` / `audit_*` scripts live under `src/scripts/`
45
+ # 240 `lint_*` / `check_*` / `audit_*` scripts live under `src/scripts/`
46
46
  # (the count is computed, not asserted — `check_gate_coverage.count_gate_scripts`).
47
- # **27 of them emit the machine-readable `scanned: <N>` line under their
48
- # CI-identical argv, and all 27 are listed below.** The manifest is therefore
49
- # complete with respect to its own contract, and covers ~12 % of the population.
47
+ # **32 of them emit the machine-readable `scanned: <N>` line under their
48
+ # CI-identical argv, and all 31 are listed below.** The manifest is therefore
49
+ # complete with respect to its own contract, and covers ~13 % of the population.
50
50
  #
51
51
  # Two revisions of this header have now gone stale the same way. It claimed
52
52
  # "8 of 211", then "22 of 223" while 26 entries were listed. Both halves drift
@@ -57,7 +57,7 @@
57
57
  # stays a manual count until something computes it too. If you add an entry,
58
58
  # the two numbers in the paragraph above are part of the diff.
59
59
  #
60
- # The other ~197 are NOT covered, for one reason: rule 1. They print their count
60
+ # The other ~209 are NOT covered, for one reason: rule 1. They print their count
61
61
  # in prose ("111 file(s) scanned", "0 declarer(s)") or not at all, and a guard
62
62
  # that parses prose is the fragile thing being replaced. Padding this list with
63
63
  # them would manufacture exactly the false green the file exists to prevent.
@@ -501,3 +501,129 @@ gates:
501
501
  create-only by design. Discrimination is proven instead by the gate's own
502
502
  `--self-test`, which drives the real binary through six rejecting cases
503
503
  including the dead-scan-root one.
504
+
505
+ - id: lint_example_fences
506
+ argv: ["--strict"]
507
+ min_scanned: 450
508
+ corpus: "authored markdown whose fenced blocks are code the reader copies — src/rules/*.md, src/skills/*/SKILL.md, docs/guidelines/**/*.md (503 at baseline)"
509
+ status: enforced
510
+ canary:
511
+ class: undetected-antipattern
512
+ path: docs/guidelines/zz-canary-example-fence.md
513
+ content: |
514
+ # Canary
515
+
516
+ Planted canary: a fenced example teaching the render sink the
517
+ `frontend-render-security` rule forbids three paragraphs away.
518
+
519
+ ```js
520
+ el.innerHTML = untrustedUserBio;
521
+ ```
522
+ note: >
523
+ Registered STRICT on day one, which is the opposite of the advisory
524
+ landing its roadmap step planned for — because the classification that
525
+ step demands came back **zero hits over all 503 files**, and an advisory
526
+ gate over an empty violation set is a gate that can only ever be ignored.
527
+ The zero is verified rather than assumed: every raw occurrence of the
528
+ eight registry tokens in the tree is prose forbidding the pattern, a table
529
+ row, or an `rg` search string inside a shell fence, and a liveness probe
530
+ that injected a violation INTO a real corpus file fired while the
531
+ untouched original stayed clean. Floor at 450 against a live 503 leaves
532
+ room for skill retirement without redding the change that retires one.
533
+
534
+ - id: check_depth_budget
535
+ argv: []
536
+ min_scanned: 140
537
+ corpus: "on-demand depth files — src/agent-src/contexts/**/*.md + docs/guidelines/**/*.md (161 at baseline)"
538
+ status: enforced
539
+ canary:
540
+ class: budget-blind
541
+ path: docs/guidelines/zz-canary-depth-budget.md
542
+ content: |
543
+ # Canary
544
+
545
+ Planted canary: a depth file over the 16,000-char ceiling, which must
546
+ make the shrink-only ratchet red as the fifth violation.
547
+
548
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
549
+ note: >
550
+ The ratchet baseline is 4, so this gate is green on the current tree and
551
+ reds on a FIFTH over-ceiling depth file. Both halves are proven rather
552
+ than assumed: planting a 16,100-char file took it to exit 1 and removing
553
+ the file took it back to exit 0. Floor at 140 against a live 161 leaves
554
+ room for consolidating reference documents — which is the direction this
555
+ ratchet is meant to push — without redding the change that consolidates.
556
+
557
+ - id: lint_rule_migration_ledger
558
+ argv: ["--quiet"]
559
+ min_scanned: 35
560
+ corpus: "rules whose body was migrated out to a skill, guideline, context or contract (44 at baseline)"
561
+ status: enforced
562
+ canary:
563
+ class: unledgered-migration
564
+ path: src/rules/zz-canary-migrated-rule.md
565
+ content: |
566
+ ---
567
+ type: auto
568
+ description: "Planted canary rule whose body was migrated out with no ledger behind it."
569
+ ---
570
+
571
+ # Canary
572
+
573
+ Body migrated to `skill:docker`.
574
+ note: >
575
+ The canary plants a rule carrying a migration pointer and no ledger, which
576
+ is the defect the gate exists for — a lossy transform with no record.
577
+ Floor at 35 against a live 44 leaves room for a rule un-migrating (its
578
+ body coming back) without redding the change that does it.
579
+
580
+ - id: lint_decision_impact
581
+ argv: ["--quiet"]
582
+ min_scanned: 90
583
+ corpus: "src/rules/*.md frontmatters (111 at baseline)"
584
+ status: enforced
585
+ canary:
586
+ class: unevidenced-removal-class
587
+ path: src/rules/zz-canary-decision-impact.md
588
+ content: |
589
+ ---
590
+ type: auto
591
+ description: "Planted canary claiming the removal-permitting class with no evidence behind it."
592
+ decision_impact: already-complied-with
593
+ ---
594
+
595
+ # Canary
596
+ note: >
597
+ Verified-empty by design: 111 rules read, 0 classified, because the field
598
+ is optional and backfill is opportunistic (a 111-rule batch trips
599
+ check_kernel_prefix_stability). The canary is what distinguishes that from
600
+ a gate scanning nothing — it plants the removal-permitting class with no
601
+ evidence and the gate reds.
602
+
603
+ - id: check_corpus_staleness
604
+ argv: ["--quiet", "--today", "2026-08-06"]
605
+ min_scanned: 5
606
+ corpus: "src/skills/*/data/manifest.json — grounding-corpus manifests (6 at baseline; brand, database, accessibility-auditor, api-design, design-intelligence, threat-modeling)"
607
+ status: enforced
608
+ canary:
609
+ class: missing-declared-csv
610
+ path: src/skills/zz-canary-corpus/data/manifest.json
611
+ content: |
612
+ {
613
+ "manifest_version": 1,
614
+ "refresh_cadence": "quarterly",
615
+ "upstream": { "last_checked": "2026-07-01" },
616
+ "domains": { "d": { "file": "nope.csv", "search_cols": ["a"], "output_cols": ["b"] } }
617
+ }
618
+ note: >
619
+ `--today` is PINNED in argv on purpose, and it is the whole reason this
620
+ gate is testable at all: the five upstream-vendored corpora share
621
+ `last_checked: 2026-06-07`, so an unpinned reference date makes this row
622
+ flip from green to red on 2026-09-15 with no diff behind it. The pinned
623
+ date keeps the coverage guard measuring COVERAGE; the real calendar check
624
+ is the workflow step, which runs unpinned and is meant to red when the
625
+ cadence is actually missed. Changing the pin is how you re-baseline after a
626
+ re-vendor, and it should be visible in a diff.
627
+ The canary plants a manifest whose declared CSV does not exist — the exact
628
+ gap `corpus-grounding/scripts/schema_validator.ts` leaves open, since it
629
+ computes the path and never opens the file.
@@ -26,6 +26,17 @@
26
26
  "landed": "2026-08-05",
27
27
  "note": "Ledger adoption ratchet. 217 of 221 CI-registered gates do not yet carry per-target completeness accounting (`_lib/gate_ledger.ts`) or a `// ledger-exempt:` marker. This is deliberately NOT a sweep: road-to-skill-ecosystem-gate-integrity Phase 1 adopts exactly three gates (lint_framework_leakage, check_references, lint_roadmap_complexity) plus the checker itself to prove the interface, and the remainder migrates as gates are touched. Shrink-only from here — the number may not grow, so a NEW gate must adopt or exempt.",
28
28
  "falsifier": "./scripts-run src/scripts/check_gate_completeness"
29
+ },
30
+ "check_depth_budget": {
31
+ "count": 4,
32
+ "landed": "2026-08-06",
33
+ "note": "Four depth files exceed the 16,000-char per-file ceiling: rule-body-migration-inventory.md (23,782), design-antipatterns.md (20,707), roadmap-process-loop.md (20,360), orchestration-telemetry.md (16,155). Recorded rather than fixed because splitting four large reference documents is unrelated to the change that introduced the ceiling, and a gate that lands as four instant blockers is the shape this repository has already recorded as a failure. Shrink-only from here: a FIFTH over-ceiling file reds. roadmap-process-loop.md is the file that motivated the gate — it states 'Size budget: <= 4,000 chars' in its own header and is 5x over it, which is what a declared budget with nothing measuring it decays into. The ceiling is a GROWTH RATCHET, not a measured quality threshold: the 7,308-trajectory study behind the 3,500-token skill ceiling (ADR-217) was taken on procedural always-co-loaded skills, and this layer is declarative and loaded one or two files at a time. Replace the number when someone measures comprehension on THIS layer."
34
+ },
35
+ "gate-self-test:registered-non-adopters": {
36
+ "count": 24,
37
+ "landed": "2026-08-06",
38
+ "note": "Self-test adoption ratchet, expressed as a shrink-only NON-adopter count. 24 of the 32 gates registered enforced in gate-coverage.yml carry neither a `--self-test` (`_lib/gate_self_test.ts`) nor a `// self-test-exempt: <reason>` marker, so nothing proves they DISCRIMINATE — an enforced `scanned:` floor proves a gate read something, only a self-test proves the reading changes the verdict. Deliberately NOT an adoption column ratcheted upward: check_gate_coverage.ts's own report_hardening_ratchet rejects that shape in this same file (\"grades the solution instead of the problem\"), and the sibling adoption ratchet (check_gate_completeness) is already a non-adopter count. Population is the manifest, not every script under src/scripts: padding the manifest to move this number would mean adding a floor per row. Shrink-only from here — a NEW registered gate must adopt or exempt. Migration mechanism, same as the ledger ratchet above: gates adopt as they are touched, not in a sweep — the eight current adopters were each added alongside a real change to that gate. The 56-day non-stagnation clause applies unchanged, so a count parked here fails on its own.",
39
+ "falsifier": "./scripts-run src/scripts/check_gate_coverage"
29
40
  }
30
41
  }
31
42
  }
@@ -36,8 +36,11 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
36
36
  import { match_prompt, type Router } from '../_lib/router_match.js';
37
37
  import { load_agent_settings } from '../_lib/agent_settings.js';
38
38
  import { read_entries } from '../chat_history.js';
39
+ import { resolvePackageRoot } from '../_lib/package_root.js';
39
40
 
40
- const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
41
+ // Marker-anchored, not hop-counted — see the sibling note in cmd_route_explain.ts.
42
+ // Both routing commands were the last two `_cli` entries still counting hops.
43
+ const REPO_ROOT = resolvePackageRoot(import.meta.url);
41
44
  const ROUTER_JSON = path.join(REPO_ROOT, 'dist', 'router.json');
42
45
 
43
46
  // cache-version: v1 — rebuildable audit log: delete-and-rerun rebuilds it from
@@ -31,8 +31,16 @@ import {
31
31
  } from '../_lib/router_match.js';
32
32
  import { measure, method_note } from '../_lib/token_count.js';
33
33
  import { load_agent_settings } from '../_lib/agent_settings.js';
34
+ import { resolvePackageRoot } from '../_lib/package_root.js';
34
35
 
35
- const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..');
36
+ // Marker-anchored, not hop-counted: this module runs from `src/scripts/_cli/`
37
+ // (three levels down) AND from the precompiled `dist/cli-delegate/` (two), and
38
+ // a fixed hop count is right in exactly one of them. Three hops from the bundle
39
+ // landed on `<pkg>/..` — `node_modules/@event4u` for a scoped install — so
40
+ // `route:explain` and `route:audit` reported dist/router.json as missing on
41
+ // every invocation through the shipped binary while both worked under `tsx`.
42
+ // The resolver exists precisely for this and 12 sibling commands already use it.
43
+ const REPO_ROOT = resolvePackageRoot(import.meta.url);
36
44
  const ROUTER_JSON = path.join(REPO_ROOT, 'dist', 'router.json');
37
45
  const RULES_DIST_DIR = path.join(REPO_ROOT, 'dist', 'agent-src', 'rules');
38
46
 
@@ -124,6 +124,7 @@ Tier 1 — power-user (release shape, audit, migration):
124
124
  user-authored files; persists standing consent
125
125
  (install.auto_converge) on first use.
126
126
  Flags: --dry-run | --yes
127
+ conformance:behavior Replay local transcripts through the mechanised conformance checks
127
128
  conformance Consumer conformance contract: doctor --ci +
128
129
  installed-and-firing checks. Exits non-zero on
129
130
  a failed check.
@@ -1219,6 +1220,16 @@ cmd_analyze_session() {
1219
1220
  exec_ts "$PACKAGE_ROOT/src/scripts/_cli/cmd_analyze_session.ts" "$@"
1220
1221
  }
1221
1222
 
1223
+ # `agent-config conformance:behavior` — replay the local transcript store
1224
+ # through the four MECHANISED conformance checks (language pin, git
1225
+ # authorization, vacuous evidence, evidence steering). Report, not gate:
1226
+ # exit 0 unless the store is unreadable. See src/scripts/conformance_scan.ts.
1227
+ cmd_conformance_behavior() {
1228
+ local script
1229
+ script="$(resolve_script "src/scripts/conformance_scan.ts" "dist/agent-src/scripts/conformance_scan.ts")"
1230
+ exec_ts "$script" "$@"
1231
+ }
1232
+
1222
1233
  # `agent-config handoff` — pick a recent session, generate a deterministic
1223
1234
  # handoff into agents/runtime/state/handoff-context.md, optionally --launch a
1224
1235
  # fresh host session. See scripts/_cli/cmd_handoff.ts.
@@ -1240,6 +1251,7 @@ main() {
1240
1251
  graph-explain) cmd_graph_explain "$@" ;;
1241
1252
  benchmark) cmd_benchmark "$@" ;;
1242
1253
  code-graph) cmd_code_graph "$@" ;;
1254
+ conformance:behavior) cmd_conformance_behavior "$@" ;;
1243
1255
  roadmap:progress) cmd_roadmap_progress "$@" ;;
1244
1256
  roadmap:progress-check) cmd_roadmap_progress_check "$@" ;;
1245
1257
  roadmap:archive) cmd_roadmap_archive "$@" ;;
@@ -10,7 +10,10 @@
10
10
  # stitch.sh <manifest.json> <output.mp4>
11
11
  # [--skip-scene <id> ...]
12
12
  # [--abort-on-missing | --continue]
13
- # [--crossfade <seconds>]
13
+ #
14
+ # NOT a flag: --crossfade. It is parsed and REFUSED (exit 2). See
15
+ # "Refused flags" below — it is listed so a caller who read the old
16
+ # usage line gets an error instead of a hard cut.
14
17
  #
15
18
  # Failure semantics:
16
19
  # - Missing clip → fail loud with scene_id and re-render hint
@@ -21,6 +24,22 @@
21
24
  # <project>/scenes/<id>/error.json; stitch.sh checks for that
22
25
  # file alongside the clip and surfaces it instead of an opaque
23
26
  # ffmpeg error.
27
+ #
28
+ # Refused flags:
29
+ # --crossfade <seconds> — accepted by the parser, then REFUSED with
30
+ # exit 2 before any work. It used to print "not yet implemented"
31
+ # to stderr and fall straight through to the plain concat, so the
32
+ # script reported success (exit 0, success JSON) while delivering a
33
+ # hard cut. Worse, the notice sat AFTER the dry-run exit, and
34
+ # AIV_DRYRUN defaults to true — so in the default mode the flag was
35
+ # accepted in total silence.
36
+ # A crossfade is not a small addition here: the output path is
37
+ # `-f concat -c copy`, and stream copy precludes any filtergraph, so
38
+ # xfade/acrossfade need a re-encode path that does not exist. It was
39
+ # also never reachable from a governed surface: /video:stitch passes
40
+ # only --skip-scene and --continue and rejects anything else. So the
41
+ # honest state is a refusal, not a silent downgrade and not a
42
+ # filtergraph shipped into a script with no test harness.
24
43
 
25
44
  set -euo pipefail
26
45
 
@@ -39,19 +58,23 @@ esac
39
58
  MANIFEST="${1:-}"
40
59
  OUTPUT="${2:-}"
41
60
  [ -n "${MANIFEST}" ] && [ -n "${OUTPUT}" ] \
42
- || aiv_die 2 "usage: stitch.sh <manifest.json> <output.mp4> [--skip-scene <id>] [--abort-on-missing|--continue] [--crossfade <s>]"
61
+ || aiv_die 2 "usage: stitch.sh <manifest.json> <output.mp4> [--skip-scene <id>] [--abort-on-missing|--continue]"
43
62
  [ -r "${MANIFEST}" ] || aiv_die 2 "manifest not readable: ${MANIFEST}"
44
63
  shift 2 || true
45
64
 
46
65
  SKIP_IDS=""
47
66
  MISSING_POLICY="abort"
48
- CROSSFADE=""
49
67
  while [ "$#" -gt 0 ]; do
50
68
  case "$1" in
51
69
  --skip-scene) SKIP_IDS="${SKIP_IDS} ${2:-}"; shift 2 ;;
52
70
  --abort-on-missing) MISSING_POLICY="abort"; shift ;;
53
71
  --continue) MISSING_POLICY="continue"; shift ;;
54
- --crossfade) CROSSFADE="${2:-}"; shift 2 ;;
72
+ --crossfade)
73
+ # Refused HERE — before the dry-run branch, before ffmpeg, before any
74
+ # output. The old code warned after the dry-run exit and then concatenated
75
+ # anyway, so a caller asking for a crossfade got a hard cut and exit 0.
76
+ aiv_die 2 "stitch.sh: --crossfade is not implemented and will not be silently downgraded. The output path is 'ffmpeg -f concat -c copy', and stream copy precludes any filtergraph, so xfade/acrossfade require a re-encode path this script does not have. Re-run without --crossfade for a hard-cut concat, or open a roadmap item for the re-encode path."
77
+ ;;
55
78
  *) aiv_die 2 "stitch.sh: unknown flag '$1'" ;;
56
79
  esac
57
80
  done
@@ -149,11 +172,6 @@ if [ "${DRYRUN_FLAG}" -eq 1 ]; then
149
172
  exit 0
150
173
  fi
151
174
 
152
- if [ -n "${CROSSFADE}" ]; then
153
- printf 'stitch: crossfade=%ss requested — passing through ffmpeg xfade filter not yet implemented (concat path used)\n' \
154
- "${CROSSFADE}" >&2
155
- fi
156
-
157
175
  ffmpeg -loglevel error -y -f concat -safe 0 -i "${CONCAT_LIST}" \
158
176
  -c copy "${OUTPUT}" >/dev/null \
159
177
  || aiv_die 8 "ffmpeg concat failed (manifest=${MANIFEST}, output=${OUTPUT})"
@@ -111,6 +111,8 @@ function _empty_state(): StateDict {
111
111
  verifications_this_session: 0,
112
112
  last_stop_at: null,
113
113
  verified_this_turn: false,
114
+ ci_saw_pending: false,
115
+ nonevidence_this_turn: 0,
114
116
  checked_at: _now(),
115
117
  };
116
118
  }
@@ -163,7 +165,113 @@ function _extract_command(payload: StateDict): [string | null, string | null] {
163
165
  }
164
166
 
165
167
  function _is_verification(command: string): boolean {
166
- return _VERIFICATION_RE.test(command);
168
+ // CI polls join the verification set here (they did not match the local
169
+ // runner pattern). A settled green CI run IS evidence — but only once the
170
+ // settle is genuine, which is what the FC-3b guard below decides. Before this
171
+ // change a CI poll counted for nothing at all, so nothing observed the
172
+ // difference between "settled" and "never started".
173
+ return _VERIFICATION_RE.test(command) || isCiPoll(command);
174
+ }
175
+
176
+ /**
177
+ * Non-vacuity guard (conformance audit 2026-08-06, failure class FC-3b).
178
+ *
179
+ * The measured failure: a CI poll landing in the gap between `git push` and
180
+ * GitHub registering the checks returned `0 pass / 0 fail`, so the agent's exit
181
+ * condition `pending == 0` was TRIVIALLY satisfied and "CI settled" was reported
182
+ * twice — on a run that had not started. The verification *command* ran, so the
183
+ * evidence gate felt satisfied. Nothing checked that its output said anything.
184
+ *
185
+ * A result set of size zero is not evidence. `∀x ∈ ∅` is vacuously true, and
186
+ * that is a logic error rather than a judgement call, which is why it is gated
187
+ * here rather than described in a rule.
188
+ */
189
+ const _VACUOUS_PATTERNS: readonly RegExp[] = [
190
+ // gh pr checks / gh run — no checks registered at all.
191
+ /\b0\s+(?:checks?|runs?)\b/i,
192
+ // Test runners reporting an empty run.
193
+ /\bno tests? (?:ran|found|to run|were run)\b/i,
194
+ /\bNo test files found\b/i,
195
+ /\b0\s+pass(?:ed|ing)?\b[\s,|·]*\b0\s+fail(?:ed|ing|ures)?\b/i,
196
+ /\bTests?\s+0\s+passed\b/i,
197
+ /\bRan 0 tests?\b/i,
198
+ // Linters / scanners with an empty target set.
199
+ /\bno files? (?:matched|to (?:lint|check|scan)|found)\b/i,
200
+ /\b0\s+files?\s+(?:checked|scanned|linted)\b/i,
201
+ /\bnothing to check\b/i,
202
+ ];
203
+
204
+ /** True when a verification command's output proves nothing because it covered nothing. */
205
+ export function isVacuousOutput(output: string): boolean {
206
+ const text = output.trim();
207
+ if (!text) {
208
+ // Silence is the Unix convention for success: a clean `tsc --noEmit`,
209
+ // `eslint`, or `phpstan` prints nothing. Round 2 caught this reading empty
210
+ // output as vacuity, which quietly stopped counting the most common green
211
+ // signal in this repo. Genuinely unreadable CI polls are handled separately
212
+ // (`pendingCount` returns null and the poll counts for nothing).
213
+ return false;
214
+ }
215
+ // Per RESULT LINE, not per blob: a composite run whose 812 tests passed and
216
+ // whose one empty sub-package printed "No test files found" is evidence.
217
+ const lines = text.split("\n").filter((l) => l.trim());
218
+ return lines.every((l) => _VACUOUS_PATTERNS.some((re) => re.test(l)));
219
+ }
220
+
221
+ /** Commands that poll CI state rather than produce a local result. */
222
+ const _CI_POLL_RE = /\bgh\s+(?:pr\s+checks|run\s+(?:watch|list|view))\b/i;
223
+
224
+ export function isCiPoll(command: string): boolean {
225
+ return _CI_POLL_RE.test(command);
226
+ }
227
+
228
+ /**
229
+ * Read a pending-check count out of a CI poll's output. Returns null when the
230
+ * shape is unrecognised — an unknown shape must not be read as "settled".
231
+ */
232
+ export function pendingCount(output: string): number | null {
233
+ const m = /(\d+)\s+(?:checks? )?pending\b/i.exec(output) ?? /\bpending[:=]\s*(\d+)/i.exec(output);
234
+ if (m?.[1] !== undefined) {
235
+ return Number(m[1]);
236
+ }
237
+ // `gh pr checks` prints one row per check; count the in-progress markers.
238
+ // `gh pr checks` prints one row per check (`name\tpass\t1m2s\t…`). Count the
239
+ // in-flight rows; a table with rows but none pending IS a settle, which the
240
+ // first version could not see because it returned null and never counted.
241
+ const rows = output.match(/^\S.*\b(pending|in_progress|queued)\b/gim);
242
+ if (rows) {
243
+ return rows.length;
244
+ }
245
+ if (/\bno checks reported\b/i.test(output)) {
246
+ return null; // the push→registration gap — not a settle
247
+ }
248
+ if (/^\S+\s+(pass|fail|skipping|successful|failing)\b/im.test(output)) {
249
+ return 0; // a real result table with no in-flight rows
250
+ }
251
+ return null;
252
+ }
253
+
254
+ /**
255
+ * Extract a tool's textual output from a post-tool payload.
256
+ *
257
+ * Returns `null` when the payload carries NO output field at all — which is not
258
+ * the same fact as "the command produced no output". Several platforms do not
259
+ * surface tool output on this event, and treating their silence as a vacuous
260
+ * result would turn the guard into a blanket regression that stops counting
261
+ * every verification everywhere. The guard only fires where it can actually
262
+ * read a result.
263
+ */
264
+ function _extract_output(payload: StateDict): string | null {
265
+ for (const key of ["tool_response", "toolResponse", "output", "stdout", "result"]) {
266
+ const v = payload[key];
267
+ if (typeof v === "string") {
268
+ return v;
269
+ }
270
+ if (v !== null && typeof v === "object") {
271
+ return JSON.stringify(v);
272
+ }
273
+ }
274
+ return null;
167
275
  }
168
276
 
169
277
  function _reset_turn(state: StateDict, session_id: string): StateDict {
@@ -171,6 +279,10 @@ function _reset_turn(state: StateDict, session_id: string): StateDict {
171
279
  state["turn_started_at"] = _now();
172
280
  state["verifications_this_turn"] = 0;
173
281
  state["verified_this_turn"] = false;
282
+ // FC-3b turn-scoped counters: a CI settle must be witnessed within the same
283
+ // turn that claims it, so the in-flight observation does not survive a turn.
284
+ state["ci_saw_pending"] = false;
285
+ state["nonevidence_this_turn"] = 0;
174
286
  return state;
175
287
  }
176
288
 
@@ -205,16 +317,45 @@ function _update(state: StateDict, event: string, envelope: StateDict): StateDic
205
317
  } else if (event === "post_tool_use") {
206
318
  const [tool, cmd] = _extract_command(pl);
207
319
  if (cmd && _is_verification(cmd)) {
320
+ const output = _extract_output(pl);
321
+ // No readable output → the guard has nothing to judge, so behaviour is
322
+ // exactly what it was before FC-3b landed.
323
+ const vacuous = output !== null && isVacuousOutput(output);
324
+
325
+ // A CI poll is evidence of a SETTLE only when this turn has already seen
326
+ // the run in flight. Polling once and reading `pending == 0` off a run
327
+ // that never registered is the measured FC-3b failure. With no readable
328
+ // output a poll counts for nothing — which is also its pre-FC-3b
329
+ // behaviour, since CI polls were not in the verification set at all.
330
+ let counts = !vacuous;
331
+ if (isCiPoll(cmd)) {
332
+ const pending = output === null ? null : pendingCount(output);
333
+ if (pending !== null && pending > 0) {
334
+ state["ci_saw_pending"] = true;
335
+ counts = false; // running, not settled
336
+ } else if (pending === 0) {
337
+ counts = !vacuous && state["ci_saw_pending"] === true;
338
+ } else {
339
+ counts = false; // unrecognised or unreadable — never read as settled
340
+ }
341
+ }
342
+
208
343
  state["last_verification"] = {
209
344
  command: cmd.slice(0, 512),
210
345
  tool,
211
346
  at: _now(),
212
347
  platform: (envelope["platform"] || "") as unknown,
348
+ vacuous,
349
+ counted: counts,
213
350
  };
214
- state["verifications_this_turn"] = _asInt(state["verifications_this_turn"]) + 1;
215
- state["verifications_this_session"] =
216
- _asInt(state["verifications_this_session"]) + 1;
217
- state["verified_this_turn"] = true;
351
+ if (counts) {
352
+ state["verifications_this_turn"] = _asInt(state["verifications_this_turn"]) + 1;
353
+ state["verifications_this_session"] =
354
+ _asInt(state["verifications_this_session"]) + 1;
355
+ state["verified_this_turn"] = true;
356
+ } else {
357
+ state["nonevidence_this_turn"] = _asInt(state["nonevidence_this_turn"]) + 1;
358
+ }
218
359
  }
219
360
  } else if (event === "stop") {
220
361
  state["last_stop_at"] = _now();