icv-trace 0.1.0rc4__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.
@@ -0,0 +1,80 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.0rc4] - 2026-09-09
8
+
9
+ ### Changed
10
+
11
+ - Prepared the CI and tag workflow for public PyPI publishing through a PyPI
12
+ trusted publisher on GitHub-hosted runners. The release gate now also checks
13
+ that `human.py` is included in the wheel.
14
+ - Added self-contained public contracts and renderer guides, contributor and
15
+ release instructions, and source-distribution copies of docs and examples.
16
+
17
+ ### Consumer behaviour
18
+
19
+ - Runtime behaviour and the supported package-root API are unchanged from
20
+ `0.1.0rc3`. This release moves the distribution target to PyPI. Private-index
21
+ consumers should validate an explicit `0.1.0rc4` PyPI install before removing
22
+ their private extra index, and retain that index while other private packages
23
+ still need it.
24
+
25
+ ## [0.1.0rc3] - 2026-09-09
26
+
27
+ ### Added
28
+
29
+ - Added `HumanRenderer` and `HumanTraceSink` for bounded, readable projection
30
+ and optional exact JSONL fanout of trace records.
31
+
32
+ ### Consumer behaviour
33
+
34
+ - Existing trace bindings, canonical human output, structured records and
35
+ admission budgets retain their behaviour. Readable rendering is opt-in:
36
+ hosts bind `HumanTraceSink` as the structured destination and inspect its
37
+ output health separately from core health. Its human view omits correlation
38
+ IDs; optional JSONL fanout preserves the original records. The core charges
39
+ structured bytes, not downstream presentation/fanout bytes.
40
+
41
+ ## [0.1.0rc2] - 2026-09-09
42
+
43
+ ### Fixed
44
+
45
+ - Added explicit Python setup before the private publish workflow validates
46
+ release metadata. `v0.1.0rc1` stopped in that pre-upload job because the
47
+ bare self-hosted runner had no `python` command; no distribution was
48
+ uploaded and the trace API is unchanged.
49
+
50
+ ## [0.1.0rc1] - 2026-09-09
51
+
52
+ ### Unpublished
53
+
54
+ - `v0.1.0rc1` did not upload a distribution. It remains historical evidence
55
+ of the failed pre-upload workflow run and must not be retagged.
56
+
57
+ ### Added
58
+
59
+ - Extracted the pure-Python trace core from icvlocal at source commit
60
+ `087479b96929a56447c2ac8011011023b4df2dcd`.
61
+ - Added bounded lifecycle diagnostics, correlation context, sink health and
62
+ same-thread callback capture as the initial private release candidate.
63
+
64
+ ### Changed
65
+
66
+ - Existing incubated consumers keep the same public API and runtime behaviour.
67
+ The implementation is now distributed as `icv-trace` for index installation.
68
+
69
+ ### Release gate record
70
+
71
+ - The release owner completes and records all six private release gates on the
72
+ exact tagged commit before pushing `v0.1.0rc2`: version and changelog,
73
+ green CI, clean publish-workflow simulation, artefact inspection and clean
74
+ installation, tagged-workflow review, and consumer-facing behaviour notes.
75
+
76
+ [Unreleased]: https://github.com/icvoss/icv-trace/compare/v0.1.0rc4...HEAD
77
+ [0.1.0rc4]: https://github.com/icvoss/icv-trace/releases/tag/v0.1.0rc4
78
+ [0.1.0rc3]: https://github.com/icvoss/icv-trace/releases/tag/v0.1.0rc3
79
+ [0.1.0rc2]: https://github.com/icvoss/icv-trace/releases/tag/v0.1.0rc2
80
+ [0.1.0rc1]: https://github.com/icvoss/icv-trace/releases/tag/v0.1.0rc1
@@ -0,0 +1,40 @@
1
+ # Contributing to icv-trace
2
+
3
+ ## Prerequisites
4
+
5
+ - Python 3.11 or later
6
+ - `uv` or pip
7
+
8
+ The package is pure Python. Django, a database and ICV sibling packages are
9
+ not required for development or tests.
10
+
11
+ ## Local setup and checks
12
+
13
+ ```bash
14
+ python -m venv .venv
15
+ source .venv/bin/activate
16
+ pip install -e ".[dev]"
17
+ ruff check .
18
+ ruff format --check .
19
+ mypy src/icv_trace
20
+ pytest tests -v --tb=short
21
+ ```
22
+
23
+ Use conventional commits and work on a branch. Public behaviour is the
24
+ package-root API and the `icv-trace.*.v1` contracts in
25
+ [docs/contracts.md](docs/contracts.md). Preserve caller ownership of domain
26
+ truth and safe facts, and host ownership of settings, transport, audit and
27
+ error reporting. Update the normative package contracts in `docs/` alongside
28
+ any change to supported behaviour.
29
+
30
+ ## Test modes
31
+
32
+ The normal suite supports an editable installation. CI additionally runs a
33
+ built-wheel job with `ICV_TRACE_REQUIRE_WHEEL=1`; it removes `src` from the
34
+ import path and fails unless `icv_trace` resolves from `site-packages`.
35
+
36
+ ## Releasing
37
+
38
+ See [RELEASING.md](RELEASING.md). A `v<version>` tag publishes to PyPI, so it
39
+ is pushed only after all release gates pass on that exact commit. The release
40
+ guide also records the transition for existing private-index consumers.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nigel Copley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ include README.md
2
+ include CHANGELOG.md
3
+ include CONTRIBUTING.md
4
+ include LICENSE
5
+ include PROVENANCE.md
6
+ include RELEASING.md
7
+ include VERIFICATION.md
8
+ recursive-include docs *.md
9
+ recursive-include examples *.py
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: icv-trace
3
+ Version: 0.1.0rc4
4
+ Summary: Bounded operation diagnostics, correlation and output health for Python hosts
5
+ Author: Nigel Copley
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/icvoss/icv-trace
8
+ Project-URL: Documentation, https://github.com/icvoss/icv-trace/tree/main/docs
9
+ Project-URL: Changelog, https://github.com/icvoss/icv-trace/blob/main/CHANGELOG.md
10
+ Project-URL: Issue Tracker, https://github.com/icvoss/icv-trace/issues
11
+ Project-URL: Source, https://github.com/icvoss/icv-trace
12
+ Keywords: diagnostics,observability,trace,tracing
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Requires-Python: >=3.11
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Provides-Extra: dev
25
+ Requires-Dist: mypy>=1.11; extra == "dev"
26
+ Requires-Dist: pytest>=8; extra == "dev"
27
+ Requires-Dist: ruff>=0.15; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # icv-trace
31
+
32
+ `icv-trace` is a pure-Python diagnostic boundary for meaningful operations.
33
+ It creates correlation identity, attempts immediate baseline lifecycle records,
34
+ admits bounded detail when enabled, and exposes local output health. It has no
35
+ Django, database, ICV-package, logger or exporter dependency.
36
+
37
+ The package consumes caller-selected safe scalar facts, a `TracePolicy`,
38
+ `TraceSinks`, and optional parent or retry context. It produces human and
39
+ JSONL records plus local sink health. The caller and host retain ownership of
40
+ domain truth, persistence, policy resolution, destinations, propagation,
41
+ error reporting, metrics and audit.
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ python -m pip install "icv-trace==0.1.0rc4"
47
+ ```
48
+
49
+ Public release candidates use PyPI and an explicit version as shown above.
50
+ `0.1.0rc3` remains available from the private index at `pypi.icvoss.com` for
51
+ existing consumers. Validate the explicit PyPI version before removing a
52
+ private extra index, and retain that index while any other private dependency
53
+ requires it. Install by distribution name, never by a sibling path.
54
+
55
+ ## Use
56
+
57
+ The default `trace()` binding writes baseline records to stderr. It reads the
58
+ documented `TRACE_*` environment values and has detail disabled by default.
59
+
60
+ ```python
61
+ from icv_trace import trace
62
+
63
+ with trace("catalogue.import", source="supplier") as operation:
64
+ operation.note("rows_loaded", count=12)
65
+ operation.result(imported=12, rejected=0)
66
+ ```
67
+
68
+ For explicit policy and separate human and JSONL destinations, a host binds a
69
+ callable. Sinks receive one complete rendered line and own writing, buffering
70
+ and flushing it.
71
+
72
+ ```python
73
+ import sys
74
+
75
+ from icv_trace import TracePolicy, TraceSinks, bind_trace, textio_sink
76
+
77
+ policy = TracePolicy(
78
+ TRACE_ENABLED=True,
79
+ TRACE_DESTINATIONS=("human", "structured"),
80
+ TRACE_MAX_DETAIL_EVENTS=100,
81
+ TRACE_MAX_BYTES=65536,
82
+ )
83
+ with open("trace.jsonl", "x", encoding="utf-8") as jsonl_file:
84
+ trace_scan = bind_trace(
85
+ lambda: policy,
86
+ TraceSinks(human=textio_sink(sys.stderr), structured=textio_sink(jsonl_file)),
87
+ )
88
+ with trace_scan("scan") as operation:
89
+ operation.note("classification", matched=4)
90
+ operation.result(completed=True)
91
+ ```
92
+
93
+ `TRACE_ENABLED` controls additional detail only. Baseline START and END are
94
+ attempted independently of `TRACE_ENABLED`, `DEBUG` and logging levels.
95
+ `TextIOSink` rejects short writes and never flushes or closes the caller's
96
+ stream. Logging, Eliot and OpenTelemetry trial adapters are retained as
97
+ internal comparison code in `icv_trace.adapters`; they are not supported
98
+ public delivery APIs.
99
+
100
+ ## Public API and contract
101
+
102
+ The supported package-root exports are `trace`, `bind_trace`,
103
+ `current_trace_context`, `emit_incomplete`, `capture_callback`, `TracePolicy`,
104
+ `TraceSinks`, `TraceContext`, `TraceAttempt`, `TraceIncomplete`,
105
+ `TraceOutputHealth`, `TraceHandle`, `TextIOSink`, `textio_sink`,
106
+ `HumanRenderer`, `HumanTraceSink`, `TraceInputError`,
107
+ `TraceConfigurationError` and `TraceSinkError`. The complete v1 input, output,
108
+ failure and compatibility contracts are in [docs/contracts.md](docs/contracts.md).
109
+
110
+ ## Readable projection of structured traces
111
+
112
+ `HumanRenderer` turns admitted JSONL records into compact, indented terminal
113
+ lines. It has no Django or worker dependency and only retains a bounded set of
114
+ open span identities for indentation. `HumanTraceSink` makes this useful with
115
+ the existing core: bind the core to its `structured` input, then it writes the
116
+ readable line and optionally forwards the original JSONL line unchanged.
117
+
118
+ ```python
119
+ import sys
120
+ from secrets import token_hex
121
+
122
+ from icv_trace import (
123
+ HumanTraceSink, TraceContext, TraceIncomplete, TracePolicy, TraceSinks,
124
+ bind_trace, emit_incomplete, textio_sink, trace,
125
+ )
126
+
127
+ human_sink = HumanTraceSink(human=textio_sink(sys.stderr))
128
+ policy = TracePolicy(TRACE_ENABLED=True, TRACE_DESTINATIONS=("structured",))
129
+ run = bind_trace(lambda: policy, TraceSinks(structured=human_sink))
130
+
131
+ with run("example.command", entrypoint="management_command") as command:
132
+ with trace("example.pipeline"):
133
+ with trace("example.service") as service:
134
+ service.note("loaded", count=2)
135
+ service.result(count=2)
136
+ command.result(completed=True)
137
+ command_context = command.context
138
+
139
+ # This simulates a supervisor observation of a context it saved at dispatch.
140
+ # A missing END alone never authorises an incomplete record.
141
+ assert command_context is not None
142
+ remote_context = TraceContext(command_context.trace_id, token_hex(8), token_hex(16), command_context.span_id)
143
+ emit_incomplete(
144
+ TraceIncomplete(remote_context, "example.worker.task", "worker_lost"),
145
+ policy=policy,
146
+ sinks=TraceSinks(structured=human_sink),
147
+ )
148
+ ```
149
+
150
+ Labels can replace operation names for a particular host:
151
+
152
+ ```python
153
+ from icv_trace import HumanRenderer
154
+
155
+ renderer = HumanRenderer(labels={"example.command": "import command"})
156
+ ```
157
+
158
+ Retry and continuation records include their attempt kind and number in this
159
+ view. Correlation IDs remain in the original JSONL rather than the compact
160
+ line. `HumanTraceSink.output_health` is sticky and must be checked separately
161
+ from core trace health because the core sees the composite as one destination.
162
+ The host owns prompt flushing: `textio_sink()` does not flush or close the
163
+ stream. The human and optional JSONL callables must be different underlying
164
+ channels. The adapter rejects the same callable object, but cannot detect two
165
+ wrappers around one stream. Do not make either destination call the same
166
+ `HumanTraceSink` recursively. If the host's warning channel is also broken,
167
+ it cannot report that diagnostic failure elsewhere.
168
+
169
+ The runnable dependency-free example mirrors a command invoking a pipeline of
170
+ services. It writes compact output to stderr, can fan the original JSONL to a
171
+ new file, and labels the remote incomplete record as an explicit simulated
172
+ supervisor observation rather than an inference from a missing END. The
173
+ [human-renderer guide](docs/human-renderer.md) covers labels, bounded nesting,
174
+ fanout, health and host-owned task supervision.
175
+
176
+ ```bash
177
+ python examples/human_trace.py
178
+ python examples/human_trace.py --detail --jsonl-file trace.jsonl
179
+ python examples/human_trace.py --fail
180
+ python examples/human_trace.py --simulate-worker-lost
181
+ ```
182
+
183
+ The same-thread `capture_callback()` bridge is bounded to its live owner and
184
+ creator thread. It does not register callbacks or transfer work across
185
+ threads or processes.
186
+
187
+ ## Development
188
+
189
+ ```bash
190
+ python -m venv .venv
191
+ source .venv/bin/activate
192
+ pip install -e ".[dev]"
193
+ ruff check .
194
+ ruff format --check .
195
+ mypy src/icv_trace
196
+ pytest tests -v --tb=short
197
+ ```
198
+
199
+ The normal development suite permits the editable install. CI and release
200
+ verification also build a wheel, install it without the source tree on the
201
+ import path, and assert that `icv_trace` resolves from `site-packages`.
202
+
203
+ ## Documentation
204
+
205
+ - [Contracts](docs/contracts.md): v1 inputs, policy and limits, records,
206
+ output health, task context and compatibility.
207
+ - [Human renderer](docs/human-renderer.md): readable services, commands,
208
+ pipelines and task observations.
209
+ - [Example](examples/human_trace.py): runnable dependency-free program.
210
+ - [Contributing](CONTRIBUTING.md), [verification](VERIFICATION.md), and
211
+ [releasing](RELEASING.md): development and publication practice.
212
+
213
+ ## Provenance
214
+
215
+ This package extracts the site-owned incubation core from icvlocal commit
216
+ `087479b96929a56447c2ac8011011023b4df2dcd`. See
217
+ [PROVENANCE.md](PROVENANCE.md) for historical source, retained hashes and
218
+ extraction adaptations. The public package documentation above is sufficient
219
+ to install and use the distribution; the historical material is not a runtime
220
+ dependency.
@@ -0,0 +1,40 @@
1
+ # Historical extraction provenance
2
+
3
+ This record explains the private incubation history. It is not required to
4
+ install or use the package. Current public contracts are in
5
+ [`docs/contracts.md`](docs/contracts.md) and
6
+ [`docs/human-renderer.md`](docs/human-renderer.md).
7
+
8
+ The package was extracted from site commit
9
+ `087479b96929a56447c2ac8011011023b4df2dcd`, which includes the initial trial
10
+ source, the local module-name substitution and the bounded callback-capture
11
+ extension. The archived source remains under
12
+ `docs/reviews/trace-adapter-trial-2026-09-08/` in the ICV OSS umbrella.
13
+
14
+ | Archived file | SHA-256 |
15
+ | --- | --- |
16
+ | `runtime/src/trace_trial/core.py` | `c28fbce7140fb5a1e1b35b82d0bb180ca2c0407969ca781f8a023d8f494638b5` |
17
+ | `runtime/src/trace_trial/adapters.py` | `8734ed435e3c2de4d5053f4ffe6aacc41bbbd72f5cb2fe52ccfaffbb9fd8a489` |
18
+ | `checks/conftest.py` | `34989ba7b5e7d738d79746a12e448d004305c13c8f24e299bc238eef38107c1b` |
19
+ | `checks/test_admission_precision.py` | `2c5d785fe76ad8d53a871c8db1c01cda2e9006d0c57c967aa62004b2ce10bba3` |
20
+ | `checks/test_core_hardening.py` | `6c6c6f1662d69184613733590a23ca1ac9896d2d6180d2c776fdd7fb450f395d` |
21
+ | `checks/test_invalid_child_admission.py` | `7d156e1dd344b1e1ca62916329b049df02ed49a0572294b00e1247629b29623b` |
22
+ | `checks/test_trace_contract.py` | `f929a0d2b31e8a3ab7e451c66cba40a535fa1d7cc0ac4fe18aba3abcecf0bd34` |
23
+ | `checks/test_trace_edges.py` | `7e359d32d57afc4d7f0cd3a258f5944f830a33c8b36fc13c55283a4b464547f2` |
24
+
25
+ The extracted files are not byte-identical to the archive. The module import
26
+ was substituted from `trace_trial` to `icv_trace`, and the callback bridge was
27
+ added during incubation. Extraction adds packaging metadata, public module
28
+ docstrings and `__version__`, and replaces the former `ICV_TRACE_SRC`
29
+ source-mode fixture with a built-wheel origin guard. It also adds
30
+ non-behavioural annotations and casts required by the blocking mypy gate, and
31
+ removes one unused test import. The archived hashes above remain provenance for
32
+ the source history; they are not hashes of the extracted files.
33
+
34
+ At extraction time, the rejected comparison-adapter delivery selector was not
35
+ a supported API. The historical statement that `TextIOSink` and `textio_sink`
36
+ were the only supported delivery helpers predates the released human renderer.
37
+ Today, `HumanRenderer` and `HumanTraceSink` are supported package-root APIs;
38
+ the complete current surface is documented in the README. Logging, Eliot and
39
+ OpenTelemetry helpers remain experimental comparison code, with no delivery or
40
+ conformance promise.
@@ -0,0 +1,191 @@
1
+ # icv-trace
2
+
3
+ `icv-trace` is a pure-Python diagnostic boundary for meaningful operations.
4
+ It creates correlation identity, attempts immediate baseline lifecycle records,
5
+ admits bounded detail when enabled, and exposes local output health. It has no
6
+ Django, database, ICV-package, logger or exporter dependency.
7
+
8
+ The package consumes caller-selected safe scalar facts, a `TracePolicy`,
9
+ `TraceSinks`, and optional parent or retry context. It produces human and
10
+ JSONL records plus local sink health. The caller and host retain ownership of
11
+ domain truth, persistence, policy resolution, destinations, propagation,
12
+ error reporting, metrics and audit.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ python -m pip install "icv-trace==0.1.0rc4"
18
+ ```
19
+
20
+ Public release candidates use PyPI and an explicit version as shown above.
21
+ `0.1.0rc3` remains available from the private index at `pypi.icvoss.com` for
22
+ existing consumers. Validate the explicit PyPI version before removing a
23
+ private extra index, and retain that index while any other private dependency
24
+ requires it. Install by distribution name, never by a sibling path.
25
+
26
+ ## Use
27
+
28
+ The default `trace()` binding writes baseline records to stderr. It reads the
29
+ documented `TRACE_*` environment values and has detail disabled by default.
30
+
31
+ ```python
32
+ from icv_trace import trace
33
+
34
+ with trace("catalogue.import", source="supplier") as operation:
35
+ operation.note("rows_loaded", count=12)
36
+ operation.result(imported=12, rejected=0)
37
+ ```
38
+
39
+ For explicit policy and separate human and JSONL destinations, a host binds a
40
+ callable. Sinks receive one complete rendered line and own writing, buffering
41
+ and flushing it.
42
+
43
+ ```python
44
+ import sys
45
+
46
+ from icv_trace import TracePolicy, TraceSinks, bind_trace, textio_sink
47
+
48
+ policy = TracePolicy(
49
+ TRACE_ENABLED=True,
50
+ TRACE_DESTINATIONS=("human", "structured"),
51
+ TRACE_MAX_DETAIL_EVENTS=100,
52
+ TRACE_MAX_BYTES=65536,
53
+ )
54
+ with open("trace.jsonl", "x", encoding="utf-8") as jsonl_file:
55
+ trace_scan = bind_trace(
56
+ lambda: policy,
57
+ TraceSinks(human=textio_sink(sys.stderr), structured=textio_sink(jsonl_file)),
58
+ )
59
+ with trace_scan("scan") as operation:
60
+ operation.note("classification", matched=4)
61
+ operation.result(completed=True)
62
+ ```
63
+
64
+ `TRACE_ENABLED` controls additional detail only. Baseline START and END are
65
+ attempted independently of `TRACE_ENABLED`, `DEBUG` and logging levels.
66
+ `TextIOSink` rejects short writes and never flushes or closes the caller's
67
+ stream. Logging, Eliot and OpenTelemetry trial adapters are retained as
68
+ internal comparison code in `icv_trace.adapters`; they are not supported
69
+ public delivery APIs.
70
+
71
+ ## Public API and contract
72
+
73
+ The supported package-root exports are `trace`, `bind_trace`,
74
+ `current_trace_context`, `emit_incomplete`, `capture_callback`, `TracePolicy`,
75
+ `TraceSinks`, `TraceContext`, `TraceAttempt`, `TraceIncomplete`,
76
+ `TraceOutputHealth`, `TraceHandle`, `TextIOSink`, `textio_sink`,
77
+ `HumanRenderer`, `HumanTraceSink`, `TraceInputError`,
78
+ `TraceConfigurationError` and `TraceSinkError`. The complete v1 input, output,
79
+ failure and compatibility contracts are in [docs/contracts.md](docs/contracts.md).
80
+
81
+ ## Readable projection of structured traces
82
+
83
+ `HumanRenderer` turns admitted JSONL records into compact, indented terminal
84
+ lines. It has no Django or worker dependency and only retains a bounded set of
85
+ open span identities for indentation. `HumanTraceSink` makes this useful with
86
+ the existing core: bind the core to its `structured` input, then it writes the
87
+ readable line and optionally forwards the original JSONL line unchanged.
88
+
89
+ ```python
90
+ import sys
91
+ from secrets import token_hex
92
+
93
+ from icv_trace import (
94
+ HumanTraceSink, TraceContext, TraceIncomplete, TracePolicy, TraceSinks,
95
+ bind_trace, emit_incomplete, textio_sink, trace,
96
+ )
97
+
98
+ human_sink = HumanTraceSink(human=textio_sink(sys.stderr))
99
+ policy = TracePolicy(TRACE_ENABLED=True, TRACE_DESTINATIONS=("structured",))
100
+ run = bind_trace(lambda: policy, TraceSinks(structured=human_sink))
101
+
102
+ with run("example.command", entrypoint="management_command") as command:
103
+ with trace("example.pipeline"):
104
+ with trace("example.service") as service:
105
+ service.note("loaded", count=2)
106
+ service.result(count=2)
107
+ command.result(completed=True)
108
+ command_context = command.context
109
+
110
+ # This simulates a supervisor observation of a context it saved at dispatch.
111
+ # A missing END alone never authorises an incomplete record.
112
+ assert command_context is not None
113
+ remote_context = TraceContext(command_context.trace_id, token_hex(8), token_hex(16), command_context.span_id)
114
+ emit_incomplete(
115
+ TraceIncomplete(remote_context, "example.worker.task", "worker_lost"),
116
+ policy=policy,
117
+ sinks=TraceSinks(structured=human_sink),
118
+ )
119
+ ```
120
+
121
+ Labels can replace operation names for a particular host:
122
+
123
+ ```python
124
+ from icv_trace import HumanRenderer
125
+
126
+ renderer = HumanRenderer(labels={"example.command": "import command"})
127
+ ```
128
+
129
+ Retry and continuation records include their attempt kind and number in this
130
+ view. Correlation IDs remain in the original JSONL rather than the compact
131
+ line. `HumanTraceSink.output_health` is sticky and must be checked separately
132
+ from core trace health because the core sees the composite as one destination.
133
+ The host owns prompt flushing: `textio_sink()` does not flush or close the
134
+ stream. The human and optional JSONL callables must be different underlying
135
+ channels. The adapter rejects the same callable object, but cannot detect two
136
+ wrappers around one stream. Do not make either destination call the same
137
+ `HumanTraceSink` recursively. If the host's warning channel is also broken,
138
+ it cannot report that diagnostic failure elsewhere.
139
+
140
+ The runnable dependency-free example mirrors a command invoking a pipeline of
141
+ services. It writes compact output to stderr, can fan the original JSONL to a
142
+ new file, and labels the remote incomplete record as an explicit simulated
143
+ supervisor observation rather than an inference from a missing END. The
144
+ [human-renderer guide](docs/human-renderer.md) covers labels, bounded nesting,
145
+ fanout, health and host-owned task supervision.
146
+
147
+ ```bash
148
+ python examples/human_trace.py
149
+ python examples/human_trace.py --detail --jsonl-file trace.jsonl
150
+ python examples/human_trace.py --fail
151
+ python examples/human_trace.py --simulate-worker-lost
152
+ ```
153
+
154
+ The same-thread `capture_callback()` bridge is bounded to its live owner and
155
+ creator thread. It does not register callbacks or transfer work across
156
+ threads or processes.
157
+
158
+ ## Development
159
+
160
+ ```bash
161
+ python -m venv .venv
162
+ source .venv/bin/activate
163
+ pip install -e ".[dev]"
164
+ ruff check .
165
+ ruff format --check .
166
+ mypy src/icv_trace
167
+ pytest tests -v --tb=short
168
+ ```
169
+
170
+ The normal development suite permits the editable install. CI and release
171
+ verification also build a wheel, install it without the source tree on the
172
+ import path, and assert that `icv_trace` resolves from `site-packages`.
173
+
174
+ ## Documentation
175
+
176
+ - [Contracts](docs/contracts.md): v1 inputs, policy and limits, records,
177
+ output health, task context and compatibility.
178
+ - [Human renderer](docs/human-renderer.md): readable services, commands,
179
+ pipelines and task observations.
180
+ - [Example](examples/human_trace.py): runnable dependency-free program.
181
+ - [Contributing](CONTRIBUTING.md), [verification](VERIFICATION.md), and
182
+ [releasing](RELEASING.md): development and publication practice.
183
+
184
+ ## Provenance
185
+
186
+ This package extracts the site-owned incubation core from icvlocal commit
187
+ `087479b96929a56447c2ac8011011023b4df2dcd`. See
188
+ [PROVENANCE.md](PROVENANCE.md) for historical source, retained hashes and
189
+ extraction adaptations. The public package documentation above is sufficient
190
+ to install and use the distribution; the historical material is not a runtime
191
+ dependency.
@@ -0,0 +1,58 @@
1
+ # Releasing icv-trace
2
+
3
+ `0.1.0rc3` remains available from the private index at `pypi.icvoss.com`.
4
+ The public repository publishes new releases to PyPI through the GitHub Actions
5
+ trusted publisher.
6
+ Pushing a `v<semver>` tag is irreversible and must point to the merged `main`
7
+ commit.
8
+
9
+ This is a pure-Python package. There are no Django, database or migration
10
+ legs, but static, built-wheel and clean-environment checks are required.
11
+
12
+ ## Before tagging
13
+
14
+ Record all six gates for the exact commit:
15
+
16
+ 1. `pyproject.toml` and `src/icv_trace/__init__.py` contain the same version,
17
+ and `CHANGELOG.md` has a dated matching heading with nothing to ship under
18
+ Unreleased.
19
+ 2. Every lint, mypy and Python 3.11 through 3.14 test leg in `ci.yml` is green.
20
+ 3. In a clean virtual environment, reproduce the `publish.yml` install list
21
+ and pass its installed-wheel test command.
22
+ 4. Build wheel and sdist, run `twine check`, inspect the wheel for
23
+ `icv_trace`, `core.py`, `adapters.py`, `human.py` and `py.typed`, then
24
+ install the wheel cleanly and import the documented package-root API. After
25
+ publication repeat the installation by name from the target index.
26
+ 5. Review the tagged commit's own `publish.yml`.
27
+ 6. State all existing-consumer behaviour in the release notes. For `0.1.0rc3`,
28
+ the human renderer is opt-in and core record semantics remain unchanged.
29
+ Logging, Eliot and OpenTelemetry helpers remain experimental and unsupported.
30
+
31
+ ## Tag
32
+
33
+ ```bash
34
+ git checkout main
35
+ git pull
36
+ git tag v<version>
37
+ git push origin v<version>
38
+ ```
39
+
40
+ Confirm the workflow publishes to PyPI, creates the appropriate release
41
+ record, and that the package installs by name. Do not move a tag. If any gate
42
+ or publish step fails, fix it on a new commit and publish a new release-
43
+ candidate version.
44
+
45
+ ## Public PyPI release and private-index transition
46
+
47
+ The repository is public and its trusted publisher is restricted to
48
+ `icvoss/icv-trace`, workflow `publish.yml`, environment `pypi`. Run every gate
49
+ above against the exact commit whose workflow targets PyPI, including a clean
50
+ PyPI installation after publication.
51
+
52
+ The first public version is a deliberate compatibility point. Release notes
53
+ must state the upgrade path for private-index consumers: pin the version while
54
+ validating the PyPI artefact, remove the private extra index only after all
55
+ private dependencies are absent, and retain the private index where other
56
+ private packages still require it. Do not replace an existing tag or silently
57
+ move consumers across indexes. Record the target index, installed artefact
58
+ version and consumer-visible behaviour in the release evidence.