file-observer 1.2.2__tar.gz → 1.2.3__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.
- {file_observer-1.2.2/src/file_observer.egg-info → file_observer-1.2.3}/PKG-INFO +1 -1
- {file_observer-1.2.2 → file_observer-1.2.3}/pyproject.toml +1 -1
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer/scanner.py +12 -5
- {file_observer-1.2.2 → file_observer-1.2.3/src/file_observer.egg-info}/PKG-INFO +1 -1
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer.egg-info/SOURCES.txt +2 -1
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_packaging.py +3 -3
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_unit.py +6 -6
- file_observer-1.2.3/tests/test_v1_2_3.py +41 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/LICENSE +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/LICENSE-AGPL +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/docs/README.md +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/setup.cfg +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer/__init__.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer.egg-info/dependency_links.txt +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer.egg-info/entry_points.txt +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer.egg-info/requires.txt +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/file_observer.egg-info/top_level.txt +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/scanner/__init__.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/src/scanner/scanner.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_edge_cases.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_golden.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_integration.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_v1_1.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_v1_2.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_v1_2_1.py +0 -0
- {file_observer-1.2.2 → file_observer-1.2.3}/tests/test_v1_2_2.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: file-observer
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: Not a file watcher — a one-shot, read-only scan that emits a deterministic JSON manifest of what's in a directory before you ingest it.
|
|
5
5
|
Author-email: Russell Pfister <russalo@russalo.com>
|
|
6
6
|
License: AGPL-3.0-or-later
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "file-observer"
|
|
7
|
-
version = "1.2.
|
|
7
|
+
version = "1.2.3"
|
|
8
8
|
description = "Not a file watcher — a one-shot, read-only scan that emits a deterministic JSON manifest of what's in a directory before you ingest it."
|
|
9
9
|
readme = "docs/README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -71,8 +71,8 @@ except ImportError:
|
|
|
71
71
|
_defusedxml_available = False
|
|
72
72
|
|
|
73
73
|
|
|
74
|
-
SCANNER_VERSION = "1.2.
|
|
75
|
-
LOGIC_VERSION = "1.1.
|
|
74
|
+
SCANNER_VERSION = "1.2.3"
|
|
75
|
+
LOGIC_VERSION = "1.1.3"
|
|
76
76
|
SCHEMA_VERSION = "1.2"
|
|
77
77
|
|
|
78
78
|
|
|
@@ -546,7 +546,7 @@ CHATLOG_TOOL = "chatlog_signals"
|
|
|
546
546
|
# any detection regex or extraction algorithm requires bumping METHOD_VERSION
|
|
547
547
|
# and updating the rules definition string.
|
|
548
548
|
CHATLOG_VECTOR_ID = "chatlog"
|
|
549
|
-
CHATLOG_METHOD_VERSION =
|
|
549
|
+
CHATLOG_METHOD_VERSION = 7 # v1.2.3: + Question/Answer stop-list (FAQ FP stopgap)
|
|
550
550
|
CHATLOG_RULES_DEFINITION = (
|
|
551
551
|
"detect:speaker_label_re(distinct>=2,total>=3,recurring>=1,stop_list),"
|
|
552
552
|
"h3_header_re(5+)|section_divider_re(3+)[require speaker_cosignal_distinct>=2],"
|
|
@@ -556,10 +556,10 @@ CHATLOG_RULES_DEFINITION = (
|
|
|
556
556
|
"turn_char_stats,speaker_turn_counts,speaker_turn_chars,alternation,"
|
|
557
557
|
"reference_tokens(at_mentions,wiki_links,code_fence_blocks,url_count),"
|
|
558
558
|
"top_capitalized_tokens(freq>=3,top20),vocabulary_size_estimate;"
|
|
559
|
-
"stop_list:Allow,Arguments,Authorization,Bcc,CAUTION,Cc,Command,Commands,"
|
|
559
|
+
"stop_list:ANSWER,Allow,Answer,Arguments,Authorization,Bcc,CAUTION,Cc,Command,Commands,"
|
|
560
560
|
"Copyright,Date,Description,Disallow,Distribution,Documentation,Error,Example,"
|
|
561
561
|
"Examples,FIXME,Format,From,IMPORTANT,License,Lines,Message,NOTE,Newsgroups,"
|
|
562
|
-
"Note,Options,Organization,Parameters,Password,Path,References,Result,Returns,"
|
|
562
|
+
"Note,Options,Organization,Parameters,Password,Path,QUESTION,Question,References,Result,Returns,"
|
|
563
563
|
"Sender,Subject,Summary,Synopsis,TIP,TODO,To,Usage,Version,Warning"
|
|
564
564
|
)
|
|
565
565
|
CHATLOG_STATIC_TUNING = {
|
|
@@ -624,6 +624,13 @@ CHATLOG_SPEAKER_STOP_LIST: set[str] = {
|
|
|
624
624
|
"Version", "Usage", "Options", "Command", "Commands", "Format", "Synopsis",
|
|
625
625
|
"Description", "Arguments", "Parameters", "Returns", "Summary",
|
|
626
626
|
"Authorization", "Documentation", "License", "Copyright", "Password",
|
|
627
|
+
# v1.2.3: FAQ labels — `Question:`/`Answer:` recur like speakers but aren't
|
|
628
|
+
# (stopgap for the most common recurring-Key:value FP; the real fix is a
|
|
629
|
+
# non-count signal — see scratch/review/v1_2_2_fp_findings.md). Deliberately
|
|
630
|
+
# NOT adding single letters `Q`/`A`: `A:`/`B:` is legitimate anonymized dialogue.
|
|
631
|
+
# Membership is case-sensitive and the label regex matches all-caps, so the
|
|
632
|
+
# common ALL-CAPS FAQ style needs its own entries (PR #30 review).
|
|
633
|
+
"Question", "Answer", "QUESTION", "ANSWER",
|
|
627
634
|
}
|
|
628
635
|
|
|
629
636
|
# v0.9: Reference tokens vector identity constants.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: file-observer
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: Not a file watcher — a one-shot, read-only scan that emits a deterministic JSON manifest of what's in a directory before you ingest it.
|
|
5
5
|
Author-email: Russell Pfister <russalo@russalo.com>
|
|
6
6
|
License: AGPL-3.0-or-later
|
|
@@ -17,7 +17,7 @@ def test_canonical_top_level_api():
|
|
|
17
17
|
|
|
18
18
|
import file_observer
|
|
19
19
|
|
|
20
|
-
assert file_observer.__version__ == "1.2.
|
|
20
|
+
assert file_observer.__version__ == "1.2.3"
|
|
21
21
|
assert "Scanner" in file_observer.__all__
|
|
22
22
|
|
|
23
23
|
|
|
@@ -49,9 +49,9 @@ def test_canonical_submodule_constants_unchanged():
|
|
|
49
49
|
"""Constants and the manifest field they feed stay stable across the 1.0.x → 1.1 line (the 1.0.1 import-package rename left them intact)."""
|
|
50
50
|
from file_observer.scanner import SCANNER_VERSION, LOGIC_VERSION, SCHEMA_VERSION
|
|
51
51
|
|
|
52
|
-
assert SCANNER_VERSION == "1.2.
|
|
52
|
+
assert SCANNER_VERSION == "1.2.3"
|
|
53
53
|
assert SCHEMA_VERSION == "1.2" # additive minor bump (v1.1 corpus-intelligence fields)
|
|
54
|
-
assert LOGIC_VERSION == "1.1.
|
|
54
|
+
assert LOGIC_VERSION == "1.1.3" # v1.2.3: + Question/Answer stop-list (FAQ FP stopgap)
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
def test_legacy_scanner_import_warns():
|
|
@@ -811,8 +811,8 @@ class TestScanContext:
|
|
|
811
811
|
(tmp_path / "a.txt").write_text("hello")
|
|
812
812
|
manifest = Scanner(source_dir=tmp_path).scan()
|
|
813
813
|
ctx = manifest.context
|
|
814
|
-
assert ctx.scanner_version == "1.2.
|
|
815
|
-
assert ctx.logic_version == "1.1.
|
|
814
|
+
assert ctx.scanner_version == "1.2.3"
|
|
815
|
+
assert ctx.logic_version == "1.1.3"
|
|
816
816
|
assert ctx.python_version # non-empty
|
|
817
817
|
assert ctx.platform # non-empty
|
|
818
818
|
|
|
@@ -850,7 +850,7 @@ class TestScanContext:
|
|
|
850
850
|
manifest = Scanner(source_dir=tmp_path).scan()
|
|
851
851
|
data = json_mod.loads(manifest_to_json(manifest))
|
|
852
852
|
assert "context" in data
|
|
853
|
-
assert data["context"]["scanner_version"] == "1.2.
|
|
853
|
+
assert data["context"]["scanner_version"] == "1.2.3"
|
|
854
854
|
|
|
855
855
|
|
|
856
856
|
# ---------------------------------------------------------------------------
|
|
@@ -2042,8 +2042,8 @@ class TestSemanticToolNames:
|
|
|
2042
2042
|
|
|
2043
2043
|
def test_version_is_current(self) -> None:
|
|
2044
2044
|
from file_observer.scanner import SCANNER_VERSION, LOGIC_VERSION
|
|
2045
|
-
assert SCANNER_VERSION == "1.2.
|
|
2046
|
-
assert LOGIC_VERSION == "1.1.
|
|
2045
|
+
assert SCANNER_VERSION == "1.2.3"
|
|
2046
|
+
assert LOGIC_VERSION == "1.1.3"
|
|
2047
2047
|
|
|
2048
2048
|
|
|
2049
2049
|
# ---------------------------------------------------------------------------
|
|
@@ -3530,4 +3530,4 @@ class TestMarkdownReport:
|
|
|
3530
3530
|
from file_observer.scanner import manifest_to_markdown
|
|
3531
3531
|
(tmp_path / "a.txt").write_text("hello")
|
|
3532
3532
|
md = manifest_to_markdown(Scanner(source_dir=tmp_path).scan())
|
|
3533
|
-
assert "1.2.
|
|
3533
|
+
assert "1.2.3" in md
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""v1.2.3 — FAQ false-positive stopgap.
|
|
2
|
+
|
|
3
|
+
Pro + flash both flagged that recurring `Question:`/`Answer:` labels (a FAQ doc)
|
|
4
|
+
satisfy the v1.2.2 prose rule (≥2 distinct, ≥3 total, ≥1 recurring) and
|
|
5
|
+
false-positive as a chatlog. v1.2.3 adds `Question`/`Answer` to the stop-list.
|
|
6
|
+
|
|
7
|
+
This is a STOPGAP for the most common single case — NOT the real fix. The root
|
|
8
|
+
issue (prose `Key:value` is ambiguous with dialogue) needs a non-count signal;
|
|
9
|
+
see scratch/review/v1_2_2_fp_findings.md. We deliberately do NOT stop-list single
|
|
10
|
+
letters like `Q`/`A` — `A:`/`B:` is a legitimate anonymized-dialogue pattern.
|
|
11
|
+
|
|
12
|
+
Falsify-first: the FAQ test FAILS on v1.2.2, passes after the stop-list add.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from file_observer.scanner import Scanner, ScannerConfig
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _is_chatlog(tmp_path, name, content):
|
|
19
|
+
(tmp_path / name).write_text(content)
|
|
20
|
+
return Scanner(source_dir=tmp_path, config=ScannerConfig()).scan().files[0].is_chatlog
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def test_faq_question_answer_not_flagged(tmp_path):
|
|
24
|
+
c = ("Question: How do I install?\nAnswer: Use pip.\n"
|
|
25
|
+
"Question: Where are the docs?\nAnswer: In docs/.\n")
|
|
26
|
+
assert _is_chatlog(tmp_path, "FAQ.md", c) is False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_faq_allcaps_not_flagged(tmp_path):
|
|
30
|
+
# case-sensitive stop-list + the label regex matches all-caps → ALL-CAPS FAQ
|
|
31
|
+
# style needs explicit coverage (PR #30 review: flash/codex/copilot flagged it).
|
|
32
|
+
c = ("QUESTION: How do I install?\nANSWER: Use pip.\n"
|
|
33
|
+
"QUESTION: Where are the docs?\nANSWER: In docs/.\n")
|
|
34
|
+
assert _is_chatlog(tmp_path, "FAQ.md", c) is False
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_anonymized_ab_dialogue_still_detected(tmp_path):
|
|
38
|
+
# `A:`/`B:` anonymized speakers are a LEGIT conversation — must stay detected
|
|
39
|
+
# (guards against over-stop-listing single letters while fixing FAQ).
|
|
40
|
+
c = "A: hey did you see this\nB: yeah just now\nA: what do you think\n"
|
|
41
|
+
assert _is_chatlog(tmp_path, "dialogue.txt", c) is True
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|