atif-sql 0.2.0__py3-none-any.whl

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 (164) hide show
  1. atif_analytics/__init__.py +9 -0
  2. atif_analytics/application/__init__.py +3 -0
  3. atif_analytics/application/analyze.py +158 -0
  4. atif_analytics/application/prompts.py +750 -0
  5. atif_analytics/application/use_cases/__init__.py +3 -0
  6. atif_analytics/application/use_cases/_shared.py +264 -0
  7. atif_analytics/application/use_cases/classify.py +430 -0
  8. atif_analytics/application/use_cases/conflicts.py +448 -0
  9. atif_analytics/application/use_cases/friction.py +634 -0
  10. atif_analytics/application/use_cases/perceived.py +451 -0
  11. atif_analytics/domain/__init__.py +3 -0
  12. atif_analytics/domain/authorship.py +166 -0
  13. atif_analytics/domain/config.py +30 -0
  14. atif_analytics/domain/costs.py +50 -0
  15. atif_analytics/domain/friction.py +117 -0
  16. atif_analytics/domain/layout.py +94 -0
  17. atif_analytics/domain/models.py +385 -0
  18. atif_analytics/domain/ports.py +100 -0
  19. atif_analytics/domain/transcript.py +359 -0
  20. atif_analytics/infrastructure/__init__.py +3 -0
  21. atif_analytics/infrastructure/corpus_reader.py +546 -0
  22. atif_analytics/infrastructure/parquet_cache.py +186 -0
  23. atif_analytics/infrastructure/settings.py +114 -0
  24. atif_analytics/infrastructure/sqlite_state/__init__.py +3 -0
  25. atif_analytics/infrastructure/sqlite_state/checkpointer.py +326 -0
  26. atif_analytics/infrastructure/sqlite_state/retry_queue.py +296 -0
  27. atif_analytics/py.typed +0 -0
  28. atif_cli/__init__.py +3 -0
  29. atif_cli/__main__.py +8 -0
  30. atif_cli/app.py +2459 -0
  31. atif_cli/converter_adapter.py +151 -0
  32. atif_cli/corpus.py +409 -0
  33. atif_cli/cron.py +311 -0
  34. atif_cli/duck_errors.py +97 -0
  35. atif_cli/embed_lake.py +101 -0
  36. atif_cli/errors.py +89 -0
  37. atif_cli/lake.py +373 -0
  38. atif_cli/lake_sessions.py +270 -0
  39. atif_cli/output.py +297 -0
  40. atif_cli/py.typed +0 -0
  41. atif_converter/__init__.py +3 -0
  42. atif_converter/application/__init__.py +3 -0
  43. atif_converter/application/convert_and_audit.py +294 -0
  44. atif_converter/application/convert_codex.py +210 -0
  45. atif_converter/domain/__init__.py +9 -0
  46. atif_converter/domain/agents.py +40 -0
  47. atif_converter/domain/atif/__init__.py +55 -0
  48. atif_converter/domain/atif/agent.py +37 -0
  49. atif_converter/domain/atif/content.py +161 -0
  50. atif_converter/domain/atif/final_metrics.py +45 -0
  51. atif_converter/domain/atif/metrics.py +49 -0
  52. atif_converter/domain/atif/observation.py +21 -0
  53. atif_converter/domain/atif/observation_result.py +47 -0
  54. atif_converter/domain/atif/step.py +144 -0
  55. atif_converter/domain/atif/subagent_trajectory_ref.py +90 -0
  56. atif_converter/domain/atif/tool_call.py +36 -0
  57. atif_converter/domain/atif/trajectory.py +211 -0
  58. atif_converter/domain/atif/trajectory_validator.py +299 -0
  59. atif_converter/domain/blobs.py +510 -0
  60. atif_converter/domain/claude_code_conversion.py +1077 -0
  61. atif_converter/domain/codex_conversion.py +1036 -0
  62. atif_converter/domain/codex_edges.py +192 -0
  63. atif_converter/domain/codex_enrichment.py +419 -0
  64. atif_converter/domain/codex_fidelity.py +124 -0
  65. atif_converter/domain/codex_nested_calls.py +165 -0
  66. atif_converter/domain/edges.py +113 -0
  67. atif_converter/domain/enrichment.py +412 -0
  68. atif_converter/domain/errors.py +60 -0
  69. atif_converter/domain/fidelity.py +171 -0
  70. atif_converter/domain/model_prices.json +8538 -0
  71. atif_converter/domain/pricing.py +790 -0
  72. atif_converter/domain/result_signals.py +774 -0
  73. atif_converter/domain/schema_version.py +90 -0
  74. atif_converter/domain/session_events.py +408 -0
  75. atif_converter/infrastructure/__init__.py +3 -0
  76. atif_converter/infrastructure/census.py +89 -0
  77. atif_converter/infrastructure/claude_code_converter.py +127 -0
  78. atif_converter/infrastructure/codex_adapter.py +132 -0
  79. atif_converter/infrastructure/codex_census.py +100 -0
  80. atif_converter/infrastructure/codex_converter.py +82 -0
  81. atif_converter/infrastructure/harbor_adapter.py +187 -0
  82. atif_converter/infrastructure/raw_records.py +426 -0
  83. atif_converter/infrastructure/source_archive.py +154 -0
  84. atif_converter/py.typed +0 -0
  85. atif_corpus/__init__.py +13 -0
  86. atif_corpus/application/__init__.py +7 -0
  87. atif_corpus/application/materialize.py +1826 -0
  88. atif_corpus/domain/__init__.py +9 -0
  89. atif_corpus/domain/agents.py +33 -0
  90. atif_corpus/domain/generation.py +34 -0
  91. atif_corpus/domain/layout.py +168 -0
  92. atif_corpus/domain/ports.py +175 -0
  93. atif_corpus/domain/session_id.py +68 -0
  94. atif_corpus/domain/sessions.py +228 -0
  95. atif_corpus/domain/slug.py +72 -0
  96. atif_corpus/domain/source_layout.py +143 -0
  97. atif_corpus/domain/watermark.py +76 -0
  98. atif_corpus/infrastructure/__init__.py +7 -0
  99. atif_corpus/infrastructure/atomic.py +266 -0
  100. atif_corpus/infrastructure/compress_artifacts.py +161 -0
  101. atif_corpus/infrastructure/fake_converter.py +174 -0
  102. atif_corpus/infrastructure/scanner.py +316 -0
  103. atif_corpus/infrastructure/settings.py +130 -0
  104. atif_corpus/infrastructure/source_archive.py +202 -0
  105. atif_corpus/py.typed +0 -0
  106. atif_duck/__init__.py +43 -0
  107. atif_duck/domain/__init__.py +32 -0
  108. atif_duck/domain/artifacts.py +66 -0
  109. atif_duck/domain/authorship.py +165 -0
  110. atif_duck/domain/catalog.py +626 -0
  111. atif_duck/domain/columnar.py +149 -0
  112. atif_duck/domain/embedding_guard.py +88 -0
  113. atif_duck/domain/examples.py +265 -0
  114. atif_duck/domain/lake.py +427 -0
  115. atif_duck/domain/lake_sessions.py +97 -0
  116. atif_duck/domain/raw_readers.py +140 -0
  117. atif_duck/domain/session_id.py +69 -0
  118. atif_duck/domain/sql_literal.py +50 -0
  119. atif_duck/infrastructure/__init__.py +34 -0
  120. atif_duck/infrastructure/analytics.py +469 -0
  121. atif_duck/infrastructure/authorship.py +139 -0
  122. atif_duck/infrastructure/columnar.py +641 -0
  123. atif_duck/infrastructure/lake.py +1383 -0
  124. atif_duck/infrastructure/lake_sessions.py +194 -0
  125. atif_duck/infrastructure/lake_settings.py +63 -0
  126. atif_duck/infrastructure/lake_steps.py +225 -0
  127. atif_duck/infrastructure/projections.py +221 -0
  128. atif_duck/infrastructure/registry.py +2194 -0
  129. atif_duck/infrastructure/stored_artifacts.py +115 -0
  130. atif_duck/py.typed +0 -0
  131. atif_embed/__init__.py +12 -0
  132. atif_embed/application/__init__.py +3 -0
  133. atif_embed/application/embed.py +293 -0
  134. atif_embed/application/prune.py +80 -0
  135. atif_embed/domain/__init__.py +3 -0
  136. atif_embed/domain/discovery.py +70 -0
  137. atif_embed/domain/embedding_guard.py +83 -0
  138. atif_embed/domain/errors.py +94 -0
  139. atif_embed/domain/ports.py +223 -0
  140. atif_embed/domain/sql_literal.py +49 -0
  141. atif_embed/domain/text_stamp.py +71 -0
  142. atif_embed/infrastructure/__init__.py +3 -0
  143. atif_embed/infrastructure/cohere_bedrock.py +433 -0
  144. atif_embed/infrastructure/corpus_text_rows.py +273 -0
  145. atif_embed/infrastructure/gemma_local.py +355 -0
  146. atif_embed/infrastructure/lake_text_rows.py +203 -0
  147. atif_embed/infrastructure/lance_store.py +440 -0
  148. atif_embed/infrastructure/providers.py +30 -0
  149. atif_embed/infrastructure/settings.py +154 -0
  150. atif_embed/py.typed +0 -0
  151. atif_models/__init__.py +14 -0
  152. atif_models/domain/__init__.py +9 -0
  153. atif_models/domain/ports.py +143 -0
  154. atif_models/domain/registry.py +151 -0
  155. atif_models/domain/schema.py +109 -0
  156. atif_models/infrastructure/__init__.py +8 -0
  157. atif_models/infrastructure/openai_bedrock.py +314 -0
  158. atif_models/infrastructure/settings.py +85 -0
  159. atif_models/py.typed +0 -0
  160. atif_sql-0.2.0.dist-info/METADATA +272 -0
  161. atif_sql-0.2.0.dist-info/RECORD +164 -0
  162. atif_sql-0.2.0.dist-info/WHEEL +4 -0
  163. atif_sql-0.2.0.dist-info/entry_points.txt +2 -0
  164. atif_sql-0.2.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,139 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+
3
+ """The ``step_author`` macro and the three deterministic views built on it.
4
+
5
+ Every object here reads only the core ``steps`` view, so it registers on
6
+ every corpus, before any analytics pipeline has run (``requires: core``):
7
+
8
+ * ``step_author(src, msg)`` — scalar macro: who wrote a step
9
+ (:mod:`atif_duck.domain.authorship` holds the rule table).
10
+ * ``user_steps`` — every user-role step with its ``author``.
11
+ * ``human_turns`` — main-chain user steps a human wrote. The analytics rate
12
+ macros count their denominators from here.
13
+ * ``session_outcomes`` — one row per session: ``kind`` (interactive |
14
+ one_shot_job | turn_audit), ``outcome`` (pass | block | reviewer_blocked |
15
+ interrupted | clean_end) and the three counts behind them.
16
+
17
+ Must run after ``register_views`` (the bodies bind against ``steps`` at
18
+ CREATE time) and before the analytics macros, which read ``human_turns``.
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ from loguru import logger
26
+
27
+ from atif_duck.domain.authorship import INTERRUPT_PREDICATE_SQL, STEP_AUTHOR_CASE_SQL
28
+
29
+ if TYPE_CHECKING:
30
+ import duckdb
31
+
32
+ #: Leading ``{"ok": true`` / ``{"ok": false`` on an audit verdict, allowing a
33
+ #: code fence and any whitespace. Turn-audit sessions end on one of these.
34
+ _VERDICT_OK_TRUE_RE = r"""^\s*(```(json)?\s*)?\{\s*"ok"\s*:\s*true"""
35
+ _VERDICT_OK_FALSE_RE = r"""^\s*(```(json)?\s*)?\{\s*"ok"\s*:\s*false"""
36
+
37
+
38
+ def register_authorship(con: duckdb.DuckDBPyConnection) -> None:
39
+ """Create ``step_author`` then ``user_steps``, ``human_turns``, ``session_outcomes``.
40
+
41
+ Raises
42
+ ------
43
+ duckdb.Error
44
+ If any DDL fails (register-or-fail-loud).
45
+ """
46
+ try:
47
+ con.execute(f"CREATE OR REPLACE MACRO step_author(src, msg) AS ({STEP_AUTHOR_CASE_SQL});")
48
+
49
+ # Every user-role step, sidechain included (flagged), with its author.
50
+ # A compaction summary is harness whatever its text: the flag is the
51
+ # converter's own record of what the step is.
52
+ # ``uuid`` is the step's FIRST source uuid, the key user_friction.uuid
53
+ # and perceived_errors.turn_uuid carry, so either joins here directly.
54
+ con.execute(
55
+ """
56
+ CREATE OR REPLACE VIEW user_steps AS
57
+ SELECT session_id,
58
+ step_id,
59
+ ts,
60
+ json_extract_string(source_uuids, '$[0]') AS uuid,
61
+ is_sidechain,
62
+ is_compact_summary,
63
+ CASE WHEN is_compact_summary THEN 'harness'
64
+ ELSE step_author(source, message) END AS author,
65
+ message
66
+ FROM steps
67
+ WHERE source = 'user';
68
+ """
69
+ )
70
+
71
+ # What the user actually said: main chain only (a sidechain's "user"
72
+ # turn is the parent agent's prompt to a subagent).
73
+ con.execute(
74
+ """
75
+ CREATE OR REPLACE VIEW human_turns AS
76
+ SELECT session_id, step_id, ts, uuid, message
77
+ FROM user_steps
78
+ WHERE author = 'human'
79
+ AND NOT is_sidechain;
80
+ """
81
+ )
82
+
83
+ # One row per session with a main-chain step. ``kind`` comes from the
84
+ # opening user step and the human-turn count; ``outcome`` is the FIRST
85
+ # of these that holds: an audit verdict (pass / block) as the last
86
+ # agent message, any Stop hook block, any interrupt, else clean_end.
87
+ # The three counts are over the whole session, so ``reviewer_blocked``
88
+ # means the reviewer blocked at least once, not that it ended blocked.
89
+ con.execute(
90
+ f"""
91
+ CREATE OR REPLACE VIEW session_outcomes AS
92
+ WITH authored AS (
93
+ SELECT session_id, step_id, source, message,
94
+ CASE WHEN is_compact_summary AND source = 'user' THEN 'harness'
95
+ ELSE step_author(source, message) END AS author
96
+ FROM steps
97
+ WHERE NOT is_sidechain
98
+ ),
99
+ per_session AS (
100
+ SELECT session_id,
101
+ arg_min(author, step_id) FILTER (WHERE source = 'user')
102
+ AS first_user_author,
103
+ arg_max(message, step_id)
104
+ FILTER (WHERE source = 'agent' AND length(message) > 0)
105
+ AS last_agent_message,
106
+ count(*) FILTER (WHERE author = 'human') AS human_turns,
107
+ count(*) FILTER (
108
+ WHERE author = 'harness' AND {INTERRUPT_PREDICATE_SQL}
109
+ ) AS interrupts,
110
+ count(*) FILTER (WHERE author = 'stop_hook') AS reviewer_blocks
111
+ FROM authored
112
+ GROUP BY session_id
113
+ )
114
+ SELECT session_id,
115
+ CASE
116
+ WHEN first_user_author = 'audit_prompt' THEN 'turn_audit'
117
+ WHEN human_turns <= 1 THEN 'one_shot_job'
118
+ ELSE 'interactive'
119
+ END AS kind,
120
+ CASE
121
+ WHEN regexp_matches(last_agent_message, '{_VERDICT_OK_TRUE_RE}') THEN 'pass'
122
+ WHEN regexp_matches(last_agent_message, '{_VERDICT_OK_FALSE_RE}') THEN 'block'
123
+ WHEN reviewer_blocks > 0 THEN 'reviewer_blocked'
124
+ WHEN interrupts > 0 THEN 'interrupted'
125
+ ELSE 'clean_end'
126
+ END AS outcome,
127
+ human_turns,
128
+ interrupts,
129
+ reviewer_blocks
130
+ FROM per_session;
131
+ """ # noqa: S608 # nosec B608 - module constants and domain SqlFragment constants only
132
+ )
133
+ logger.debug("Registered step_author, user_steps, human_turns, session_outcomes")
134
+ except Exception:
135
+ logger.exception("Failed to register the authorship surface")
136
+ raise
137
+
138
+
139
+ __all__ = ["register_authorship"]