ja4plus 1.2.0__tar.gz → 1.2.2__tar.gz
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.
- ja4plus-1.2.2/.claude/rules/agent-reports.md +157 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/rules/batch-gate.md +78 -25
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/rules/conformance.md +236 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/rules/external-apis.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/rules/ste.md +66 -9
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.github/workflows/docs.yml +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.github/workflows/test.yml +36 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.issue-flow.json +15 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/CHANGELOG.md +822 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/CLAUDE.md +49 -2
- {ja4plus-1.2.0/ja4plus.egg-info → ja4plus-1.2.2}/PKG-INFO +6 -6
- {ja4plus-1.2.0 → ja4plus-1.2.2}/README.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/api_reference.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/implementation_notes.md +12 -12
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4l.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4ls.md +2 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/migration-0.6-to-1.0.md +7 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/output-schema.md +2 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/00-foundation.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/01-spec-conformance.md +3 -3
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/03-concurrency-safety.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/07-db-enrichment.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/09-release.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/11-pre-release-validation.md +3 -3
- ja4plus-1.2.2/docs/specs/foxio/JA4.md +523 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4D.md +3 -3
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4SSH.md +45 -20
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4T.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4X.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/README.md +1 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/deleted-text-specifications.md +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/zeek.md +3 -3
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/spec.html +3 -3
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/spec.md +47 -15
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/__init__.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/cli.py +67 -17
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4l.py +162 -54
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/processor.py +33 -17
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/quic_utils.py +9 -5
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/tcp_stream.py +20 -6
- {ja4plus-1.2.0 → ja4plus-1.2.2/ja4plus.egg-info}/PKG-INFO +6 -6
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus.egg-info/SOURCES.txt +23 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus.egg-info/requires.txt +4 -4
- {ja4plus-1.2.0 → ja4plus-1.2.2}/pyproject.toml +4 -4
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/build_quic_ja4l_captures.py +1 -1
- ja4plus-1.2.2/tests/citation_line_allowlist.json +140 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/download_test_vectors.py +35 -8
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_citation_lines.py +83 -10
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/skip_gate.py +1 -1
- ja4plus-1.2.2/tests/test_agent_report_absence_rule.py +307 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_alpn_ruling_register.py +58 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_batch_gate.py +2 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_batch_gate_protection_rule.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_breaking_change_record.py +10 -4
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_changelog_round_agreement.py +19 -10
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_changelog_sentence_exemption.py +27 -22
- ja4plus-1.2.2/tests/test_cli_closed_window_endpoints.py +215 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_cli_types_ja4ls.py +1 -1
- ja4plus-1.2.2/tests/test_conformance_frame_discrimination.py +255 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_db_item_access.py +1 -1
- ja4plus-1.2.2/tests/test_decryption_non_goal_ruling.py +288 -0
- ja4plus-1.2.2/tests/test_delegated_ruling_rule.py +348 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_dhcp_tunnel_inner_udp.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_fallback_rule.py +2 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_image_count.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_publish.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_site.py +33 -22
- ja4plus-1.2.2/tests/test_download_filter_fields.py +103 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_empty_list_sentinel_ruling.py +39 -3
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_citation_lines.py +106 -6
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_deviations.py +1 -1
- ja4plus-1.2.2/tests/test_foxio_ja4_transcription.py +212 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_future_dated_packet_eviction.py +2 -2
- ja4plus-1.2.2/tests/test_get_stream_byte_cap_truncation.py +107 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ipv6_support.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4d_decisions.py +1 -1
- ja4plus-1.2.2/tests/test_ja4h_emission_frame_ruling.py +254 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_reassembly.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_foxio.py +71 -9
- ja4plus-1.2.2/tests/test_ja4l_quic_eviction_ruling.py +308 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_quic_marker.py +41 -5
- ja4plus-1.2.2/tests/test_ja4l_quic_point_b_ruling.py +223 -0
- ja4plus-1.2.2/tests/test_ja4l_quic_point_d_emission.py +223 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_quic_server_hello.py +33 -7
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_return_path.py +7 -7
- ja4plus-1.2.2/tests/test_ja4l_timing_fork_ruling.py +166 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_udp_direction.py +34 -7
- ja4plus-1.2.2/tests/test_ja4ssh_packet_selection_ruling.py +311 -0
- ja4plus-1.2.2/tests/test_ja4ssh_parity_record.py +98 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ts_reset.py +1 -1
- ja4plus-1.2.2/tests/test_key_log_interface_ruling.py +335 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_memory_bounds.py +1 -1
- ja4plus-1.2.2/tests/test_ported_pattern_cost.py +193 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_processor_stats.py +1 -1
- ja4plus-1.2.2/tests/test_quic_coalesced_datagram_ruling.py +354 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_quic_crypto_buffer_bound.py +9 -2
- ja4plus-1.2.2/tests/test_quic_crypto_gap.py +132 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_round_entry_existence.py +274 -13
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_settlement_procedure.py +2 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_tcp_byte_cap_admission_ruling.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_tcp_stream.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_thread_safety.py +2 -2
- ja4plus-1.2.2/tests/test_us_english_spelling.py +692 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_watch.py +1 -1
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_watch_statistics.py +2 -2
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/settings.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/skills/conformance/SKILL.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/skills/release/SKILL.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.claude/skills/test/SKILL.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.git-blame-ignore-revs +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.github/dependabot.yml +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.github/workflows/docs-build.yml +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.github/workflows/publish.yml +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.github/workflows/update-db.yml +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/.gitignore +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/LICENSE +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/assets/logo.png +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/README.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/concurrency.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/index.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4d.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4d6.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4h.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4s.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4ssh.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4t.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4ts.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/methods/ja4x.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_reports/412-utils.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_reports/413-fingerprinters.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_reports/414-interface.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_settlements/412-utils.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_settlements/413-fingerprinters.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_settlements/414-interface.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/mutation_sweep.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/performance.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/reference/fingerprinters.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/reference/index.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/reference/ja4db.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/reference/processor.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/reference/types.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/02-correctness-audit.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/04-typed-api.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/05-structured-output.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/06-live-capture.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/features/08-documentation.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4H.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4L.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/foxio/JA4S.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/specs/mockups/01-cli-output.html +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/docs/usage.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/examples/demo_fingerprints.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/examples/live_traffic_fingerprinting.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/examples/pcap_analysis.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/examples/tcpdump_workflows.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/examples/threat_detection.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/data/ja4plus-mapping.csv +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/__init__.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/base.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4d.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4d6.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4h.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4s.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4ssh.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4t.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4ts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/fingerprinters/ja4x.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/ja4db.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/output.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/py.typed +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/types.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/__init__.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/http_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/icmp_quoted.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/loopback.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/packet_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/ssh_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/state_table.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/tcp_options.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/tls_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/tunnels.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/utils/x509_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus/watch.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus.egg-info/dependency_links.txt +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus.egg-info/entry_points.txt +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/ja4plus.egg-info/top_level.txt +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/mkdocs.yml +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/setup.cfg +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/__init__.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/batch_gate.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/build_alpn_condition_capture.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/build_ja4ts_rst.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/build_ssh_retransmission.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/compare_zeek_baselines.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/conformance_index.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/conftest.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/dns.cap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/example_cert.der +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/filedownload.dmp +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/http.cap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/suspectemployeechat.dmp +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/test_cert.der +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/data/wrongdissector.dmp +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/dependency_entries.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/documentation_samples.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_deviation_owners.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_deviations.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_deviations.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_manifest.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vector_manifest.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/CVE-2018-6794.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/CVE-2018-6794.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/NOTICE +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/alpn-condition.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/alpn-condition.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/badcurveball.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/badcurveball.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/browsers-x509.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/browsers-x509.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/chrome-cloudflare-quic-with-secrets.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/chrome-cloudflare-quic-with-secrets.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/dhcp.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/dhcp.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/dhcpv6.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/dhcpv6.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/gre-erspan-vxlan.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/gre-erspan-vxlan.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/gre-sample.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/gre-sample.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http-empty-useragent.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http-empty-useragent.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http1-with-cookies.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http1-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http1.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http1.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http2-with-cookies.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/http2-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/https-connect.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/https-connect.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/https3-301-get.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/https3-301-get.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ipv6.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ipv6.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/latest.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/latest.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/macos_tcp_flags.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/macos_tcp_flags.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/quic-tls-handshake.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/quic-tls-handshake.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/quic-with-several-tls-frames.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/quic-with-several-tls-frames.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@browsers-x509.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@chrome-cloudflare-quic-with-secrets.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@gre-erspan-vxlan.pcap.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@https-connect.pcap.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@latest.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@quic-tls-handshake.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@quic-with-several-tls-frames.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@ssh2.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@tls-handshake.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@tls-sni.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/rust_expected/ja4__insta@tls3.pcapng.snap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/single-packets.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/single-packets.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/socks-https-example.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/socks-https-example.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/socks4-https.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/socks4-https.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh-r.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh-r.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh-scp-1050.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh-scp-1050.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh2-malformed.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh2-malformed.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh2-moloch-crash.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh2-moloch-crash.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh2.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/ssh2.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/sshv1.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/sshv1.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tcpdump-geneve.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tcpdump-geneve.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-alpn-h2.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-alpn-h2.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-handshake.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-handshake.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-non-ascii-alpn.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-non-ascii-alpn.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-sni.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls-sni.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls12.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls12.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls3.pcapng +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/tls3.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/v6.pcap +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/v6.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/CVE-2018-6794.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/badcurveball.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/browsers-x509.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/chrome-cloudflare-quic-with-secrets.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/dhcp.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/dhcpv6.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/gre-erspan-vxlan.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/http-empty-useragent.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/http1-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/http2-with-cookies.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/https-connect.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/https3-301-get.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/ipv6.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/latest.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/socks-https-example.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/socks4-https.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/ssh-r.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/ssh-scp-1050.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/ssh2-malformed.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/ssh2-moloch-crash.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/ssh2.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/sshv1.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/tcpdump-geneve.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/tls-alpn-h2.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/tls3.pcapng.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/wireshark_expected/v6.pcap.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-conn/conn.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-conn-quic/conn.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-conn-tls3/conn.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-dhcp/ja4d.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-http1-with-cookies/http.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-ssh2/ja4ssh.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/foxio_vectors/zeek_expected/Scripts.ja4-tls-handshake/ssl.log +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/README.md +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/__init__.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/conftest.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/support.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_icmp_quoted_header.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_length_fields.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_malformed_captures.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_server_hello_extensions.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_structural_validity.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_synthetic_hostile_input.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/fuzz/test_truncated_captures.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/generate_foxio_baseline.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/measure_random_client_hello.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/memory_ceiling_run.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/mutation_census.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/mutation_cover.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/mutation_sweep.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/quic_builder.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/release_body.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/release_verification.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/state_readers.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_api_reference_interface_table.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_bare_exception_reading.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_bounded_state_table_adoption.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_cleanup_connection.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_cli.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_cli_lookup_opt_in.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_cli_output_option.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_cli_processor.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_compare_zeek_baselines.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_comprehensive.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_criterion_counts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_db_cache_directory.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_db_lookup_many.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_db_offline.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_dependency_entries.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_behaviour_rule.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_samples.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documentation_version_claims.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documented_method_count.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_documented_state_table_count.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_edge_cases.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_examples.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_license_register.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_manifest.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_rust_parity.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_wireshark_ja4ts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_foxio_zeek_ja4ts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_generate_foxio_baseline.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_http_header_block_terminator.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_installed_wheel.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_installed_wheel_selection.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_integration.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_interpreter_set.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_alpn.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_alpn_condition.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_deep.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_empty_ext.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_hello_retry.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_original_order.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_raw_branches.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4_ssl2_version.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4d.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4d6_foxio.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4d_foxio.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4d_fqdn_name_ruling.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4db.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4db_empty_list_alias.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_cookie_list.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_deep.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_large_cookie_header.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_line_endings.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_part_a_readings.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_raw.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_raw_sorted.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_request_line_and_empty_header_list.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_retransmission.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4h_spec.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_connection_state.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_header_block_terminator.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4l_quic_repeated_connection.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4s.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4s_quic_direction.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4s_quic_split_server_hello.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4s_raw_order.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_close_connection_window.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_deep.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_direction.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_interpret.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_message_count.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_server_side.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_spec.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_window.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ssh_windows.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t_citation_lines.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t_deep.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t_emission_model_ruling.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t_form.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t_icmp_quoted.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4t_syn_selection_ruling.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ts_delay_rounding_ruling.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ts_part_e.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4ts_prefix_bound.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x_deep.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x_empty_ext.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x_named_exceptions.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x_raw.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x_reassembly.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ja4x_record_scan.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_lint_gate_pin.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_loopback_link_type.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_method_pages.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_mutation_census.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_mutation_cover.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_mutation_sweep_annotation_skip.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_mutation_sweep_commit.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_mutation_sweep_module_list.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_mutation_sweep_timeout.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_no_retained_packets.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_output_schema.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_packaging.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_packet_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_parity.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_parser_description.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_precedence_exception.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_processor.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_processor_typed_results.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_public_interface.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_publish_workflow.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_quic_integration.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_quic_multipacket.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_quic_server_initial.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_quic_tunnel_inner_udp.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_quic_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_readme_contracts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_release_body.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_release_notes.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_release_skill.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_requirement_scope.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_ruling_vocabulary.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_skip_gate.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_spec_validation.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_specification_changelog.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_specification_terms.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_state_table.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_statistics_thread_term.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_tcp_segment_bound_ruling.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_throughput.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_tls_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_tunnels.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_types.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_utils.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_version_gate.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_watch_capture.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_watch_drop_count.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_watch_stop.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_wireshark_expected_counts.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_workflow_action_pins.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/test_x509_certificate_reader.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/throughput_run.py +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/universal_skips.json +0 -0
- {ja4plus-1.2.0 → ja4plus-1.2.2}/tests/version_gate.py +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# What a worker reports about the agents it spawns
|
|
2
|
+
|
|
3
|
+
**A worker spawns review agents, and an agent that never returns is a normal event.** The
|
|
4
|
+
worker then writes one comment that stands as the record of the review. This file states
|
|
5
|
+
what that comment says about an agent that returned nothing.
|
|
6
|
+
|
|
7
|
+
**Warning: read this file before you write a self-review comment.** #720 records the defect
|
|
8
|
+
that earned it. A worker on #613 spawned two review agents. One reported and one never did,
|
|
9
|
+
and the worker wrote up the agent that never reported as though it had.
|
|
10
|
+
|
|
11
|
+
## The rule
|
|
12
|
+
|
|
13
|
+
1. A report an agent did not return is reported as absent.
|
|
14
|
+
2. A worker names the agent that reported, and it names the agent that did not.
|
|
15
|
+
3. An absent report is a normal outcome and it refuses nothing.
|
|
16
|
+
|
|
17
|
+
**A worker that ran the review itself in place of the absent agent says so.** That sentence
|
|
18
|
+
is the whole repair, and it costs one line.
|
|
19
|
+
|
|
20
|
+
**Warning: rule 3 binds the reader of the comment as well.** An absent report carries these
|
|
21
|
+
three consequences.
|
|
22
|
+
|
|
23
|
+
- It refuses no merge.
|
|
24
|
+
- It fails no gate.
|
|
25
|
+
- It earns no tracker issue.
|
|
26
|
+
|
|
27
|
+
A reader who treats it as a failure gives the next worker a reason to fill the gap.
|
|
28
|
+
|
|
29
|
+
## Why the rule names the absence as correct
|
|
30
|
+
|
|
31
|
+
**The worker on #613 reported its own fabrication in the verdict it returned.** It named the
|
|
32
|
+
comment and it named the exact sentences. The project manager corrected the comment at
|
|
33
|
+
https://github.com/Crank-Git/ja4plus/pull/718#issuecomment-5305142104, and it quoted the
|
|
34
|
+
superseded text rather than deleting it.
|
|
35
|
+
|
|
36
|
+
**A rule that punishes the report rather than the shape removes the one signal that found
|
|
37
|
+
this defect.** No gate of this project reads whether a sentence about a review is true. The
|
|
38
|
+
worker's own report is therefore the one detection this defect class has. The rule names
|
|
39
|
+
the absence as the correct outcome, and it leaves a worker one cheap true thing to say.
|
|
40
|
+
|
|
41
|
+
**The census of 2026-08-16 measured that the absence is common and that workers report it
|
|
42
|
+
plainly.** The corpus holds 17 comments that state a review agent returned nothing, and 10
|
|
43
|
+
of them use the word `stall`. Each one states what the worker did instead. One record of
|
|
44
|
+
the same corpus counts nine stalls in one session. The rule writes down a practice this
|
|
45
|
+
project already holds.
|
|
46
|
+
|
|
47
|
+
## Where the repair belongs
|
|
48
|
+
|
|
49
|
+
**The repair belongs in two places, and this change makes one of them.**
|
|
50
|
+
|
|
51
|
+
| Home | What it holds | This change |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `.claude/rules/agent-reports.md` | The rule, the reason, the census, and the limit | Written here |
|
|
54
|
+
| `agents/issue-worker.md` of the `issue-flow` plugin | The same rule beside the step that spawns the review agents | Named, and no line changed |
|
|
55
|
+
|
|
56
|
+
**The plugin is outside this repository, so #720 names the file and it edits no line of
|
|
57
|
+
it.** Step 3 of the runbook spawns the review agents. It opens `**Self-review**`, and it
|
|
58
|
+
directs the worker to review by specialist lens through Sonnet children. That step names no
|
|
59
|
+
outcome for a review agent that never returns. A second copy of the file stands at
|
|
60
|
+
`skills/issue-flow/references/issue-worker.md` of the same plugin.
|
|
61
|
+
|
|
62
|
+
**Warning: the rule reaches a worker of another repository only through the plugin.** This
|
|
63
|
+
file binds a worker of this repository alone, because a worker reads the rules of the
|
|
64
|
+
repository it works in. The maintainer owns the plugin change.
|
|
65
|
+
|
|
66
|
+
## The census of 2026-08-16
|
|
67
|
+
|
|
68
|
+
**#720 asks whether any earlier record of this repository carries the same shape.** This
|
|
69
|
+
section reports the census that answers it.
|
|
70
|
+
|
|
71
|
+
**Count.** The census read 1842 records. The provider returned each count on 2026-08-16.
|
|
72
|
+
|
|
73
|
+
- 1101 issue comments. That endpoint holds every pull-request conversation comment.
|
|
74
|
+
- 741 issue and pull-request bodies.
|
|
75
|
+
- 0 pull-request review comments.
|
|
76
|
+
|
|
77
|
+
**Method.** The census ran in two passes. The first pass matched every record against a
|
|
78
|
+
pattern of two parts. The first part matches one of the literals `reviewer`, `lens`,
|
|
79
|
+
`lenses`, `review agent`, `review child`, `children` and `Sonnet`. The second part matches a
|
|
80
|
+
verb of finding. It selected 88 comments and 7 bodies.
|
|
81
|
+
|
|
82
|
+
The second pass read each selected record in full, and it looked for four signals.
|
|
83
|
+
|
|
84
|
+
- A quotation of an external document that the record attributes to a review agent.
|
|
85
|
+
- A count that the record attributes to a review agent.
|
|
86
|
+
- A record that reports findings from more agents than it states ran.
|
|
87
|
+
- A plain statement that an agent returned nothing.
|
|
88
|
+
|
|
89
|
+
Two Sonnet children read 44 comments each. **Both children reported.** The worker read the
|
|
90
|
+
7 bodies itself.
|
|
91
|
+
|
|
92
|
+
**Bound.** The census reads the provider records of this repository alone. It reads no
|
|
93
|
+
session transcript, so it cannot compare a write-up against the reports a worker received.
|
|
94
|
+
It therefore finds the shape in three cases alone.
|
|
95
|
+
|
|
96
|
+
- The record contradicts itself.
|
|
97
|
+
- The record quotes a source that the source does not hold.
|
|
98
|
+
- The worker reported the fabrication.
|
|
99
|
+
|
|
100
|
+
**A fabrication that stays internally consistent and quotes nothing checkable reaches no
|
|
101
|
+
reader of this corpus.** The census reports a clean corpus over that class, and it measures
|
|
102
|
+
none of it.
|
|
103
|
+
|
|
104
|
+
**Finding.** One record of 1842 carries the shape, and that record earned #720. It is the
|
|
105
|
+
comment at
|
|
106
|
+
https://github.com/Crank-Git/ja4plus/pull/718#issuecomment-5305142104. It attributed these
|
|
107
|
+
four things to an agent that never reported.
|
|
108
|
+
|
|
109
|
+
- A count of 26 re-measured claims.
|
|
110
|
+
- A finding of no wrong claim.
|
|
111
|
+
- One claim the agent declined to reproduce.
|
|
112
|
+
- A quotation of RFC 9000 Section 12.2.
|
|
113
|
+
|
|
114
|
+
**Every other record is a clean negative, and the clean negative is the result this section
|
|
115
|
+
reports.**
|
|
116
|
+
|
|
117
|
+
**Two records sit next to the shape and neither one is it.**
|
|
118
|
+
|
|
119
|
+
- The comment at https://github.com/Crank-Git/ja4plus/pull/561#issuecomment-5246016733
|
|
120
|
+
states that a read by lens returned six findings, and it then itemizes five. All three
|
|
121
|
+
lenses reported, and two of them reported nothing. The mismatch is a wrong count and it
|
|
122
|
+
is no fabricated report.
|
|
123
|
+
- The comment at https://github.com/Crank-Git/ja4plus/pull/222#issuecomment-5224677084
|
|
124
|
+
states that two child agents never reported, and it then reports a review the worker ran
|
|
125
|
+
again itself. It carries the date 2026-08-08, so it holds rule 2 and rule 3 eight days
|
|
126
|
+
before this file states them.
|
|
127
|
+
|
|
128
|
+
## No case of this repository refuses this shape
|
|
129
|
+
|
|
130
|
+
**No case of this repository refuses a fabricated review report, and no case here can.** A
|
|
131
|
+
guard that guards nothing costs a reader more than a stated absence, so this section states
|
|
132
|
+
the absence.
|
|
133
|
+
|
|
134
|
+
**A case would need the record of which agents returned, and that record is the session
|
|
135
|
+
transcript.** The transcript lives outside this repository, git tracks no copy of it, and a
|
|
136
|
+
pull-request comment states no such record either. A case therefore compares the write-up
|
|
137
|
+
against nothing.
|
|
138
|
+
|
|
139
|
+
**A fabricated write-up is well-formed text.** It names lenses, it states counts, and it
|
|
140
|
+
reads like a report the worker received. No property of the text parts it from a true
|
|
141
|
+
report, so a pattern that matched it would match every honest self-review beside it.
|
|
142
|
+
|
|
143
|
+
**`tests/test_agent_report_absence_rule.py` holds every claim of this file that a case can
|
|
144
|
+
read.** These are the claims it reads.
|
|
145
|
+
|
|
146
|
+
- The file exists, and it states the three rules of `## The rule`.
|
|
147
|
+
- The file states the reason that `## Why the rule names the absence as correct` holds.
|
|
148
|
+
- The file names the plugin file, and this repository tracks no copy of that file.
|
|
149
|
+
- The census states a count, a method, a bound and a finding.
|
|
150
|
+
- The file repeats no heading of `.claude/rules/conformance.md`.
|
|
151
|
+
|
|
152
|
+
**That module reads no comment of the provider**, because the suite reads the working tree.
|
|
153
|
+
|
|
154
|
+
**`.claude/rules/conformance.md` states the same discipline for the conformance suite**,
|
|
155
|
+
under `## What a green conformance run does not measure`. #736 wrote that section on
|
|
156
|
+
2026-08-16 and this file repeats no sentence of it. The two readings share one rule: where a
|
|
157
|
+
case cannot read the shape, record what stays unmeasured.
|
|
@@ -31,13 +31,20 @@ the promotion, and it accepted no member pull request, so a pull request into an
|
|
|
31
31
|
integration branch created no run at all. Pull request #519 carried a keyword-free head
|
|
32
32
|
into `batch/510-dry-run-and-gates` and the provider held no run for it.
|
|
33
33
|
|
|
34
|
-
**A check that reaches the batch pull request alone can pass by construction.**
|
|
35
|
-
|
|
36
|
-
records
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
**A check that reaches the batch pull request alone can pass by construction.** Read a new
|
|
35
|
+
check against that shape before you trust it. #438 measured it on 2026-08-10, and the
|
|
36
|
+
paragraph below records that reading. The sentences are quoted rather than rewritten.
|
|
37
|
+
|
|
38
|
+
> `tests/test_round_entry_existence.py` fails a change set that edits a tracked file and
|
|
39
|
+
> records no round. A batch pull request reads its change set against the tip of `dev`, and
|
|
40
|
+
> every member of a batch has already recorded a round, so that check finds an entry whatever
|
|
41
|
+
> one member did. **The member pull request is the change set the check exists to refuse, and
|
|
42
|
+
> the older filter kept it away from the job.**
|
|
43
|
+
|
|
44
|
+
**#727 superseded the example on 2026-08-15, and it left the shape standing.** That issue
|
|
45
|
+
moved the round mandate from the change set to the batch pull request, so a member pull
|
|
46
|
+
request records no round and this check refuses none.
|
|
47
|
+
`## A round is a batch, and the batch pull request records it` below states the model.
|
|
41
48
|
|
|
42
49
|
**The widened filter costs no run that the batch model saved.** A member commit ends with
|
|
43
50
|
the keyword, so a member pull request still creates no run. Under the widened filter, a
|
|
@@ -242,27 +249,72 @@ every pull request into `dev` and it filters no path. `.github/workflows/docs-bu
|
|
|
242
249
|
filters four paths, so the gate requires no run of it and a red run of it still refuses
|
|
243
250
|
the merge.
|
|
244
251
|
|
|
245
|
-
##
|
|
252
|
+
## A round is a batch, and the batch pull request records it
|
|
246
253
|
|
|
247
|
-
**Warning:
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
sequence that no other writer moves.
|
|
254
|
+
**Warning: record one round on the batch pull request, and none on a member pull
|
|
255
|
+
request.** #727 moved the mandate on 2026-08-15. The project manager writes the entry and
|
|
256
|
+
the row at the batch gate, immediately before the batch pull request, and it assigns the
|
|
257
|
+
number in the same pass. `dev` holds a fixed row count at that moment, so the pass reads
|
|
258
|
+
one sequence that no other writer moves.
|
|
252
259
|
|
|
253
|
-
|
|
254
|
-
records, and it stays in both through every sub-merge.
|
|
260
|
+
The round reaches two records, and one number covers both.
|
|
255
261
|
|
|
256
|
-
1. The entry of `CHANGELOG.md`, as `Round
|
|
257
|
-
2. The Changelog row of `docs/specs/spec.md`, as `|
|
|
262
|
+
1. The entry of `CHANGELOG.md`, as `Round 262.`.
|
|
263
|
+
2. The Changelog row of `docs/specs/spec.md`, as `| 262 | 2026-08-15 | ... |`.
|
|
258
264
|
|
|
259
265
|
`tests/test_changelog_round_agreement.py` holds the two records against each other, so an
|
|
260
|
-
assignment that covers one file alone fails a case.
|
|
261
|
-
|
|
266
|
+
assignment that covers one file alone fails a case.
|
|
267
|
+
|
|
268
|
+
**#727 measured what the older model cost.** One issue recorded one round, so
|
|
269
|
+
`tests/test_round_entry_existence.py` failed every change set that edited a tracked file
|
|
270
|
+
and recorded no round. Each member therefore wrote the two most contended files of the
|
|
271
|
+
repository, and each member then conflicted with every other member on them. A read of
|
|
272
|
+
2026-08-15 covered the last 300 commits of `master`. 192 of them touch
|
|
273
|
+
`docs/specs/spec.md` and 186 touch `CHANGELOG.md`, against 56 that touch a file under
|
|
274
|
+
`ja4plus/`.
|
|
275
|
+
|
|
276
|
+
**Warning: the 261 rounds already recorded stay exactly as they are.** They record past
|
|
277
|
+
measurements and `.claude/rules/ste.md` bars a rewrite of such a record. The new model
|
|
278
|
+
begins at the next round this project assigns.
|
|
279
|
+
|
|
280
|
+
### Which change set the mandate reads
|
|
281
|
+
|
|
282
|
+
`tests/test_round_entry_existence.py` reads the branch the change set belongs to, and
|
|
283
|
+
`records_a_round` holds the condition. A branch whose name opens with `batch/` or `epic/`
|
|
284
|
+
records a round. Every other branch records none, and the reading refuses no round it
|
|
285
|
+
finds on one.
|
|
286
|
+
|
|
287
|
+
**The two prefixes match the two patterns of the base-branch filter above.** One model
|
|
288
|
+
therefore names an integration branch in the filter and in the mandate.
|
|
289
|
+
|
|
290
|
+
**The `test` job names that branch in `ROUND_ENTRY_BRANCH`, because a run of a pull request
|
|
291
|
+
checks out a detached merge commit.** `git rev-parse --abbrev-ref HEAD` then answers the
|
|
292
|
+
literal `HEAD` and names no branch. The case would then skip on every job, and `skip-gate`
|
|
293
|
+
would fail the run. The step `Name the branch the change set belongs to` reads
|
|
294
|
+
`github.head_ref` first and `github.ref_name` second. The two together name the head branch
|
|
295
|
+
on every event the workflow accepts.
|
|
296
|
+
|
|
297
|
+
### One guard still takes a record from a member
|
|
298
|
+
|
|
299
|
+
**Warning: the routine `TBD` sweep goes out with the older model, and one exception keeps
|
|
300
|
+
the form.** A member that writes no round record leaves nothing to assign later, so the
|
|
301
|
+
sweep covers no member of a routine batch.
|
|
302
|
+
|
|
303
|
+
**`tests/test_breaking_change_record.py` requires a record from the member that trips it.**
|
|
304
|
+
It requires that `CHANGELOG.md` and `docs/specs/spec.md` each record the Python floor the
|
|
305
|
+
package states. #575 moved that floor and met the result: a reader that demanded a number
|
|
306
|
+
could not pass on the branch that made the move. Such a member writes `Round TBD.` and the
|
|
307
|
+
matching row, and the project manager assigns the number at the batch gate.
|
|
308
|
+
|
|
309
|
+
**#395 records why that guard stands.** A comparison between two records finds no change
|
|
310
|
+
that is absent from both of them. The move of the floor from 3.8 to 3.9 was such a
|
|
311
|
+
change. #727 therefore kept the guard, and it kept the `TBD` form the guard reads.
|
|
312
|
+
|
|
313
|
+
### The race the older model measured
|
|
262
314
|
|
|
263
315
|
**The round sequence is global to the repository, and a sub-merge is an event of one
|
|
264
|
-
batch.** Two live integration branches therefore
|
|
265
|
-
neither branch
|
|
316
|
+
batch.** Two live integration branches therefore assigned from one sequence at once, and
|
|
317
|
+
neither branch read the rows of the other until that other branch merged. #482 measured
|
|
266
318
|
the result on 2026-08-10, at the sub-merge gate of #456.
|
|
267
319
|
|
|
268
320
|
```
|
|
@@ -270,9 +322,9 @@ AssertionError: the Changelog holds 169 rows and its highest round is 173
|
|
|
270
322
|
assert 169 == 173
|
|
271
323
|
```
|
|
272
324
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
325
|
+
**#727 removes that race for every routine member.** One batch writes one round at its own
|
|
326
|
+
gate. The project manager runs one gate at a time, so no second writer moves the sequence
|
|
327
|
+
between the read and the write.
|
|
276
328
|
|
|
277
329
|
**Warning: a wrong pairing survives the row-count rule, so read the contiguity case
|
|
278
330
|
instead.** `row count == highest round` reads a table that carries 168 twice and 170
|
|
@@ -281,7 +333,8 @@ pairing.
|
|
|
281
333
|
`tests/test_specification_changelog.py::test_the_changelog_assigns_every_round_from_one_to_the_row_count`
|
|
282
334
|
requires the rounds 1 to the row count, each on one row, and
|
|
283
335
|
`test_the_row_count_rule_passes_on_a_table_that_repeats_a_round` holds the measurement of
|
|
284
|
-
the older rule.
|
|
336
|
+
the older rule. **That case stays.** It caught the duplicate rounds of #482, and it is
|
|
337
|
+
cheap under the new model.
|
|
285
338
|
|
|
286
339
|
**One integration branch at a time also removes the race, and this project declines that
|
|
287
340
|
order.** It costs the concurrency the batch model exists to provide. #482 records the
|
|
@@ -62,9 +62,106 @@ method name plus an occurrence counter.
|
|
|
62
62
|
method that emits more fingerprints than the reference is a defect, and so is one that
|
|
63
63
|
emits fewer.
|
|
64
64
|
|
|
65
|
+
## What a green conformance run does not measure
|
|
66
|
+
|
|
67
|
+
**Warning: a green conformance run states nothing about the frame that carries a value.**
|
|
68
|
+
The suite compares one value for each stream, and it never compares the packet that
|
|
69
|
+
produced it. #736 measured the limit on 2026-08-16 and this section records it.
|
|
70
|
+
|
|
71
|
+
**#606 moved seven values from one frame to another, and the suite discriminated none of
|
|
72
|
+
them.** That issue moved the QUIC `JA4L-S` emission from the packet that fills point `B`
|
|
73
|
+
to the packet that fills point `D`. #736 restored the point `B` emission and ran the suite
|
|
74
|
+
again. The three counts held at 1676 passed, 142 skipped and 138 xfailed under the change
|
|
75
|
+
and under the restored defect. These are the seven moves.
|
|
76
|
+
|
|
77
|
+
| Capture | The move |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `chrome-cloudflare-quic-with-secrets.pcapng` | 49 to 52 |
|
|
80
|
+
| `ssh2.pcapng` | 1140 to 1147 |
|
|
81
|
+
| `tls3.pcapng` | 144 to 147 |
|
|
82
|
+
| `tls3.pcapng` | 149 to 153 |
|
|
83
|
+
| `tls3.pcapng` | 155 to 162 |
|
|
84
|
+
| `tls3.pcapng` | 159 to 167 |
|
|
85
|
+
| `tls3.pcapng` | 303 to 312 |
|
|
86
|
+
|
|
87
|
+
### One of the four reference sources states a frame
|
|
88
|
+
|
|
89
|
+
**The conformance value comparison reads the one source that frames nothing.** A per-frame
|
|
90
|
+
comparison is possible only where a source states the frame, and #736 read all four.
|
|
91
|
+
|
|
92
|
+
| Source | States a frame | Values |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| FoxIO Python expected output, `tests/foxio_vectors/*.json` | No | 1203 |
|
|
95
|
+
| FoxIO Rust snapshots, `tests/foxio_vectors/rust_expected/*.snap` | No | 460 |
|
|
96
|
+
| Zeek baselines, `tests/foxio_vectors/zeek_expected/` | No | 7 baselines |
|
|
97
|
+
| FoxIO Wireshark dissector, `tests/foxio_vectors/wireshark_expected/*.json` | Yes, `frame.number` | 724 |
|
|
98
|
+
|
|
99
|
+
**The first three key a value on the stream or on the connection.** A Zeek baseline names
|
|
100
|
+
`orig_pkts` and `resp_pkts`, and each one counts the packets of a connection rather than
|
|
101
|
+
names one of them. **The dissector frames every value it writes**, and #736 measured 724
|
|
102
|
+
framed values and none unframed across 26 files.
|
|
103
|
+
|
|
104
|
+
**The conformance suite builds all 1203 of its value cases from the first source.** No case
|
|
105
|
+
of the suite can read a frame, because the source it reads states none.
|
|
106
|
+
|
|
107
|
+
### Why the suite compares no frame
|
|
108
|
+
|
|
109
|
+
**The suite compares the FoxIO Python reference, and the dissector holds a different value
|
|
110
|
+
set.** A per-frame comparison reads a new source. It therefore adds no discrimination to
|
|
111
|
+
any case the suite runs today.
|
|
112
|
+
|
|
113
|
+
**#736 measured what that comparison would report on 2026-08-16.** The measurement ran the
|
|
114
|
+
`Processor` over each of the 26 captures this project holds, it numbered each packet, and
|
|
115
|
+
it read the 445 dissector values of a hashed form against the result. **Warning: the three
|
|
116
|
+
counts below are one measurement, and no case holds them.** Take them again before you
|
|
117
|
+
build on them.
|
|
118
|
+
|
|
119
|
+
| Reading | Values |
|
|
120
|
+
|---|---|
|
|
121
|
+
| The value agrees and the frame agrees | 206 |
|
|
122
|
+
| The value agrees and the frame differs | 136 |
|
|
123
|
+
| This project produces no such value | 103 |
|
|
124
|
+
|
|
125
|
+
**The 136 frame disagreements are values this project already produces correctly.** Each
|
|
126
|
+
one would enter `tests/foxio_deviations.json` as a new entry. Each entry would record a
|
|
127
|
+
difference this project has already ruled.
|
|
128
|
+
|
|
129
|
+
**The TCP `JA4L` and `JA4LS` values hold 70 of the 136.** The dissector writes each one on
|
|
130
|
+
a later frame than this project, and none of the 70 is a QUIC value. **A comparison whose
|
|
131
|
+
largest class is a recorded divergence measures the register and not the code.**
|
|
132
|
+
|
|
133
|
+
**The frame is an artifact of one dissector, and the value is what the standard defines.**
|
|
134
|
+
Two FoxIO implementations produce the same value on different packets, and neither one is
|
|
135
|
+
wrong. This project therefore declines the per-frame comparison in the conformance suite.
|
|
136
|
+
|
|
137
|
+
### Where the frame is measured instead
|
|
138
|
+
|
|
139
|
+
**A frame this project rules on gets a case of its own.**
|
|
140
|
+
`tests/test_ja4l_quic_point_d_emission.py` holds the frame of every QUIC `JA4L` value
|
|
141
|
+
against `frame.number` of the dissector, and it runs in the unit suite. #736 restored the
|
|
142
|
+
point `B` emission and measured 8 failures in that module, against 0 in the conformance
|
|
143
|
+
suite.
|
|
144
|
+
|
|
145
|
+
**Warning: leave that module in the unit suite, and never move it to the conformance
|
|
146
|
+
suite.** The `test` job runs the unit suite on five environments. `.github/workflows/test.yml:86-91`
|
|
147
|
+
holds that matrix: `ubuntu-latest` on Python 3.10, 3.11, 3.12 and 3.13, and `macos-latest`
|
|
148
|
+
on Python 3.12. The `conformance` job runs the conformance suite on one environment. A move
|
|
149
|
+
would therefore take four readings away from the one frame guard this project holds. #736
|
|
150
|
+
declined the move on that reading.
|
|
151
|
+
|
|
152
|
+
**Warning: the count of five is the matrix after #575, and an older record states six.**
|
|
153
|
+
That issue dropped Python 3.9 on 2026-08-10. `.claude/rules/batch-gate.md` records a
|
|
154
|
+
measurement of that date over six jobs, and that record stays exactly as it is. Read the
|
|
155
|
+
workflow for the present count, and never a record of a past measurement.
|
|
156
|
+
|
|
157
|
+
**Warning: read a frame ruling against the unit suite, and never against the conformance
|
|
158
|
+
counts.** `tests/test_conformance_frame_discrimination.py` holds this whole reading. A
|
|
159
|
+
source that starts to state a frame therefore fails a case there, and it leaves no reader
|
|
160
|
+
with a stale rule.
|
|
161
|
+
|
|
65
162
|
## When the FoxIO reference holds a defect
|
|
66
163
|
|
|
67
|
-
The FoxIO reference decides
|
|
164
|
+
The FoxIO reference decides behavior. It does not decide behavior that the reference
|
|
68
165
|
itself produces by accident.
|
|
69
166
|
|
|
70
167
|
**A defect is proven, never asserted.** Instrument the FoxIO implementation at the pinned
|
|
@@ -92,6 +189,116 @@ by analogy.
|
|
|
92
189
|
|
|
93
190
|
Decided on 2026-08-07. #96, #97 and #105 are the first three.
|
|
94
191
|
|
|
192
|
+
## What a delegated session may rule
|
|
193
|
+
|
|
194
|
+
**The user delegates a session to a project manager, and this section states what that
|
|
195
|
+
delegation permits.** The user granted two delegations, and both hold today. A question
|
|
196
|
+
that fails both belongs to the user.
|
|
197
|
+
|
|
198
|
+
| Delegation | Date | What it reaches | Where the delegation lives |
|
|
199
|
+
|---|---|---|---|
|
|
200
|
+
| The narrow delegation | 2026-08-12 | A schema violation. | `Crank-Git/ja4plus-go#246`, and #597 here |
|
|
201
|
+
| The recording delegation | 2026-08-15 | A reading this project already holds. | The ruling comments of #595, #607, #608 and #613 |
|
|
202
|
+
|
|
203
|
+
**A ruling lands in this repository and in the port together, or in neither.**
|
|
204
|
+
`.claude/rules/parity.md` of `Crank-Git/ja4plus-go` states that rule, and
|
|
205
|
+
`.claude/rules/rulings.md` of that repository holds the port half of the narrow
|
|
206
|
+
delegation.
|
|
207
|
+
|
|
208
|
+
### The narrow delegation of 2026-08-12
|
|
209
|
+
|
|
210
|
+
**A schema violation has one right answer, and a reference split has none.** That sentence
|
|
211
|
+
is the boundary. The project manager rules a schema violation under this delegation. It
|
|
212
|
+
rules no reference split, and it rules no other question.
|
|
213
|
+
|
|
214
|
+
**A delegated ruling is a ruling, and never a reading.** A reading concludes what one
|
|
215
|
+
source states. A delegated ruling settles what this project does where a published FoxIO
|
|
216
|
+
value contradicts a published FoxIO rule. No source settles that question, because FoxIO
|
|
217
|
+
publishes both of them.
|
|
218
|
+
|
|
219
|
+
A project manager makes a delegated ruling only where every one of these is true.
|
|
220
|
+
|
|
221
|
+
1. A published FoxIO rule states the answer. The rule reaches the material under
|
|
222
|
+
`technical_details/`, the transcription of it under `docs/specs/foxio/<METHOD>.md`, or
|
|
223
|
+
a FoxIO reference implementation.
|
|
224
|
+
2. Every FoxIO implementation enforces that rule. One implementation that departs makes
|
|
225
|
+
the question a reference split, and this delegation bars a reference split.
|
|
226
|
+
3. A recorded measurement proves the violation, and each citation names a file and a line.
|
|
227
|
+
`## When the FoxIO reference holds a defect` above states that a defect is proven and
|
|
228
|
+
never asserted.
|
|
229
|
+
4. The record of the ruling carries a provisional marker, and it names the issue.
|
|
230
|
+
5. The record names a reversal path, so the user reverses the ruling with one action.
|
|
231
|
+
|
|
232
|
+
**A question that fails one condition leaves this delegation.** The project manager reads
|
|
233
|
+
it against the recording delegation below.
|
|
234
|
+
|
|
235
|
+
### The recording delegation of 2026-08-15
|
|
236
|
+
|
|
237
|
+
**The user granted a second delegation on 2026-08-15.** Four ruling comments each state it
|
|
238
|
+
in these words: #595, #607, #608 and #613. This file quotes them, and it rewrites no word
|
|
239
|
+
of the delegation.
|
|
240
|
+
|
|
241
|
+
**Warning: never open a line of this file with an issue number.** The section reader of
|
|
242
|
+
`tests/test_ported_pattern_cost.py` reads a line that opens with `#` as a heading, and it
|
|
243
|
+
then stops at that line. A paragraph below such a line reaches no case.
|
|
244
|
+
|
|
245
|
+
> The maintainer granted a delegated session this carve-out on 2026-08-15: a delegated
|
|
246
|
+
> session may rule where the decision preserves the present behaviour, moves no
|
|
247
|
+
> fingerprint, and records an existing reading as a divergence register row. A decision
|
|
248
|
+
> that moves a value, that forks from `ja4plus-go`, or that changes the scope of the
|
|
249
|
+
> project stays with the maintainer.
|
|
250
|
+
|
|
251
|
+
**The delegation states three limits, and a permitted question meets every one of them.**
|
|
252
|
+
|
|
253
|
+
- The ruling keeps the present behavior of this project.
|
|
254
|
+
- The ruling moves no fingerprint value.
|
|
255
|
+
- The ruling writes one row of the divergence register.
|
|
256
|
+
|
|
257
|
+
**A ruling that moves a value stays with the user.** A ruling that parts this project from
|
|
258
|
+
the port stays with the user. A ruling that changes the scope of this project stays with
|
|
259
|
+
the user.
|
|
260
|
+
|
|
261
|
+
**The project manager ruled each of the four issues under this delegation on 2026-08-15,
|
|
262
|
+
and no line of a fingerprinter moved.** #595 records the JA4L eviction of the QUIC path, #607 records the
|
|
263
|
+
JA4H emission frame, #608 records the JA4SSH packet selection, and #613 records the one
|
|
264
|
+
QUIC packet each datagram fills point C from.
|
|
265
|
+
|
|
266
|
+
### How the two delegations relate
|
|
267
|
+
|
|
268
|
+
**The two delegations reach different questions, and neither one repeals the other.**
|
|
269
|
+
|
|
270
|
+
- The narrow delegation settles what this project does, and it can move a fingerprint
|
|
271
|
+
value. It therefore bars a reference split: a wrong answer there makes this project
|
|
272
|
+
answer differently from a FoxIO implementation on the same bytes.
|
|
273
|
+
- The recording delegation records what this project already does, and it moves no
|
|
274
|
+
fingerprint value. A reference split therefore reaches it. #595 and #613 are each such a
|
|
275
|
+
question, and each ruling of 2026-08-15 left every line of the fingerprinter as it
|
|
276
|
+
stood.
|
|
277
|
+
- **A reference split is never delegable as a schema violation.** Condition 2 of the
|
|
278
|
+
narrow delegation bars it, and no reading of the evidence removes that bar.
|
|
279
|
+
- **Every delegated ruling is provisional under both delegations**, and each one names a
|
|
280
|
+
reversal path.
|
|
281
|
+
|
|
282
|
+
**A question that fails both delegations belongs to the user.** The project manager labels
|
|
283
|
+
that issue `status:needs-feedback`. It records the reading it holds. It builds nothing that
|
|
284
|
+
depends on the answer.
|
|
285
|
+
|
|
286
|
+
**The user confirms a delegated ruling, or reverses it.** A delegated ruling that the user
|
|
287
|
+
has not confirmed stays provisional. A later reader reads a provisional ruling as
|
|
288
|
+
unconfirmed, and never as settled.
|
|
289
|
+
|
|
290
|
+
### The worked example both repositories share
|
|
291
|
+
|
|
292
|
+
`Crank-Git/ja4plus-go#223` is the first delegated ruling, and the user confirmed it on
|
|
293
|
+
2026-08-12. A published FoxIO value contradicts a rule that four implementations enforce.
|
|
294
|
+
`zeek/ja4ssh/main.zeek:63`, `wireshark/source/packet-ja4.c:400`, `rust/ja4/src/ssh.rs:284`
|
|
295
|
+
and `python/ja4ssh.py:51` each state that the JA4SSH mode is `0` when the side sent no SSH
|
|
296
|
+
packet. `python/test/testdata/ssh-scp-1050.pcap.json` holds `c112s1460_c0s200_c36s0`,
|
|
297
|
+
which pairs a client mode of `112` with a client packet count of `0`.
|
|
298
|
+
|
|
299
|
+
**This project already reads the mode of the window alone**, and #96 holds that rule. The
|
|
300
|
+
narrow delegation therefore moved no fingerprint here, and it moved no exported name.
|
|
301
|
+
|
|
95
302
|
## When the FoxIO material is ambiguous
|
|
96
303
|
|
|
97
304
|
Eleven of the twelve methods are published as an image. Only JA4 holds a complete text
|
|
@@ -350,6 +557,33 @@ Where FoxIO specifies nothing — a field name, a default, a subcommand — the
|
|
|
350
557
|
`Crank-Git/ja4plus-go` has already shipped a choice. Adopt it. Where FoxIO does specify,
|
|
351
558
|
FoxIO wins, even against the port. `docs/specs/spec.md` holds the divergence register.
|
|
352
559
|
|
|
560
|
+
### A pattern the port ships carries no statement of its cost
|
|
561
|
+
|
|
562
|
+
**Parity rule 2 adopts the interface the port ships. It adopts no statement of cost.** Go
|
|
563
|
+
runs a finite automaton, and it backtracks nowhere. Python `re` backtracks. The two
|
|
564
|
+
languages therefore read one pattern at two costs. The rule that carries the shape carries
|
|
565
|
+
no proof that the shape is safe against hostile input.
|
|
566
|
+
|
|
567
|
+
**Warning: a pattern that is safe in the port is a pattern this project has not
|
|
568
|
+
measured.** Measure a regular expression this project takes from the port against hostile
|
|
569
|
+
input before it lands. State the measurement where the change records its evidence.
|
|
570
|
+
|
|
571
|
+
**#612 followed parity rule 2 literally, and it shipped a backtracking defect to a
|
|
572
|
+
branch.** Its own self-review found the defect and measured it. `GET a` plus 32000 spaces
|
|
573
|
+
plus `HTTPX` cost **3017.9 milliseconds** under the ported form. The repaired form reads
|
|
574
|
+
the same payload at **0.630 milliseconds**. `REQUEST_LINE_LIMIT` of
|
|
575
|
+
`ja4plus/utils/http_utils.py` reads 8192. `is_http_request` reads that many bytes of every
|
|
576
|
+
TCP payload, so one crafted packet bought about 200 milliseconds of processor time.
|
|
577
|
+
|
|
578
|
+
**The rule reaches every construct whose cost differs between a finite automaton and a
|
|
579
|
+
backtracking engine.** A regular expression is the case this project has met.
|
|
580
|
+
|
|
581
|
+
**Warning: an atomic group states the bound directly, and this project cannot write
|
|
582
|
+
one.** Python accepts `(?>...)` from release 3.11, and `pyproject.toml:24` reads
|
|
583
|
+
`requires-python = ">=3.10"`. A repair that raises the floor of the package is a ruling
|
|
584
|
+
for the user. Verified against https://docs.python.org/3/library/re.html (retrieved
|
|
585
|
+
2026-08-15).
|
|
586
|
+
|
|
353
587
|
## Measuring coverage
|
|
354
588
|
|
|
355
589
|
Use the **directory** form, `--cov=ja4plus`. For one file, use the **path** form,
|
|
@@ -359,6 +593,6 @@ Use the **directory** form, `--cov=ja4plus`. For one file, use the **path** form
|
|
|
359
593
|
QUIC cases fail, and the cause is not in this project. `coverage` resolves a dotted source
|
|
360
594
|
name inside a `sys_modules_saved()` block, which imports `ja4plus`, scapy and
|
|
361
595
|
`cryptography` and then deletes them. The second `cryptography` import builds Python
|
|
362
|
-
classes the loaded Rust extension does not
|
|
596
|
+
classes the loaded Rust extension does not recognize, so every AES cipher raises
|
|
363
597
|
`UnsupportedAlgorithm`, and the second scapy import changes the dissection of a committed
|
|
364
598
|
capture. #177 holds the measurement, and Changelog round 47 records it.
|
|
@@ -42,7 +42,7 @@ Code inside this repository is different. Read the code.
|
|
|
42
42
|
|
|
43
43
|
## Rules specific to this project
|
|
44
44
|
|
|
45
|
-
**FoxIO is the authority on
|
|
45
|
+
**FoxIO is the authority on behavior.** The specification decides intent and schema. The
|
|
46
46
|
vectors decide the exact bytes where intent runs out. A provable reference defect is
|
|
47
47
|
declined and recorded.
|
|
48
48
|
|