cc-transcript 14.37.1__tar.gz → 14.38.0__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.
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/PKG-INFO +1 -1
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/request.schema.json +28 -4
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/response.schema.json +14 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/pyproject.toml +1 -1
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot.rs +156 -9
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_prepared_service.rs +53 -18
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_root_warm.rs +36 -1
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/Cargo.lock +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/Cargo.toml +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/LICENSE +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/README.md +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/__init__.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/__init__.pyi +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/_native.pyi +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/activity.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/activity_probe.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/builders.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/codex.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/command.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/context.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/corrections.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/cost.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/decision_store.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/decisions.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/discovery.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/disktruth.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/evidence.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/extract/__init__.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/extract/correct.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/facts.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/filterspec.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/heartbeats.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/ids.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/judge/__init__.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/judge/llm.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/judge/similar.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/judge/verdicts.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/ledger.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/literals.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/__init__.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/candidates.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/confidence.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/engine.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/formats.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/sampling.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/signals.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/sourcekind.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/spec.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/mining/store.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/models.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/nlp.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/notifications.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/parser.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/py.typed +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/query.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/render.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/__init__.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/buckets.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/data/afinn-en-165.tsv +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/data/domain_overrides.tsv +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/data/en-ewt.udpipe +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/engine.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/lexicon.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/sentiment/scorespec.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/config.schema.json +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/context.schema.json +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/tool_registry.schema.json +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshots.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/synthetic.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/tools.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/watch.py +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/Cargo.toml +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/blame.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/corpus.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/corrections.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/digest.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/facts.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/grep.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/list.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/mod.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/scratchpad.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/show.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/slice.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/stats.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/commands/watch.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/lib.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/output.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/target.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/cli/src/timearg.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/Cargo.toml +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/benches/parse.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/benches/render.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/benches/toolcall.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/activity.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/actor.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/blame.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/buckets.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/discovery.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/lower.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/mod.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/parse.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/probe.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/protocol.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/codex/types.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/command.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/context.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/corrections.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/cost.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/discovery.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/facts.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/feedback.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/filter.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/gateway.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/ids.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/judge.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/lib.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/literals/command.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/literals/corrections.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/literals/feedback.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/literals/mining.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/literals/mod.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/literals/protocol.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/notifications.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/parse.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/protocol.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/pystr.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/query.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/render.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/rng.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_checkpoint.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_grep.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_grep_stream.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_grep_stream_tests.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_index.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_projection.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_regressions.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/scan_stream.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/schema.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_activity.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_codec.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_codex_append.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_labels.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_ledger.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_ledger_tests.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_memory.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_owned.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_prepared.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_prepared_disk.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_projection.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_regressions.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_text.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/sqlite.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/toolcall.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/types.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/value.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/watch.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/tests/sonic_arena_model.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/tests/std_allocation_model.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/Cargo.toml +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/build.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/data/command_prefix_pins.tsv +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/actor_bridge.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/bin/stub_gen.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/codex.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/command.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/context.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/corrections.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/discovery.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/feedback.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/judge.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/lexicon.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/lib.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/mining.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/nlp.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/python.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/render.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/score.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/snapshot_decode.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/snapshots.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/sqlite.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/toolcall.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/attachment.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/blocks.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/command.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/convert.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/dunder.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/events.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/meta.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/mod.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/print.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/store.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/system.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/toolcall.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/toolresult.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/views/transcript.rs +0 -0
- {cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/py/src/watch.rs +0 -0
{cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/request.schema.json
RENAMED
|
@@ -1032,6 +1032,20 @@
|
|
|
1032
1032
|
"PrepareGraph": {
|
|
1033
1033
|
"additionalProperties": false,
|
|
1034
1034
|
"properties": {
|
|
1035
|
+
"active_since_unix_ms": {
|
|
1036
|
+
"anyOf": [
|
|
1037
|
+
{
|
|
1038
|
+
"exclusiveMinimum": 0,
|
|
1039
|
+
"maximum": 9007199254740991,
|
|
1040
|
+
"type": "integer"
|
|
1041
|
+
},
|
|
1042
|
+
{
|
|
1043
|
+
"type": "null"
|
|
1044
|
+
}
|
|
1045
|
+
],
|
|
1046
|
+
"default": null,
|
|
1047
|
+
"title": "Active Since Unix Ms"
|
|
1048
|
+
},
|
|
1035
1049
|
"deadline_unix_ms": {
|
|
1036
1050
|
"exclusiveMinimum": 0,
|
|
1037
1051
|
"maximum": 9007199254740991,
|
|
@@ -1045,7 +1059,6 @@
|
|
|
1045
1059
|
"pattern": "^/",
|
|
1046
1060
|
"type": "string"
|
|
1047
1061
|
},
|
|
1048
|
-
"maxItems": 1024,
|
|
1049
1062
|
"title": "Direct Paths",
|
|
1050
1063
|
"type": "array"
|
|
1051
1064
|
},
|
|
@@ -1085,7 +1098,6 @@
|
|
|
1085
1098
|
"minLength": 1,
|
|
1086
1099
|
"type": "string"
|
|
1087
1100
|
},
|
|
1088
|
-
"maxItems": 1024,
|
|
1089
1101
|
"title": "Thread Ids",
|
|
1090
1102
|
"type": "array"
|
|
1091
1103
|
},
|
|
@@ -2341,6 +2353,20 @@
|
|
|
2341
2353
|
"WarmRegistered": {
|
|
2342
2354
|
"additionalProperties": false,
|
|
2343
2355
|
"properties": {
|
|
2356
|
+
"active_since_unix_ms": {
|
|
2357
|
+
"anyOf": [
|
|
2358
|
+
{
|
|
2359
|
+
"exclusiveMinimum": 0,
|
|
2360
|
+
"maximum": 9007199254740991,
|
|
2361
|
+
"type": "integer"
|
|
2362
|
+
},
|
|
2363
|
+
{
|
|
2364
|
+
"type": "null"
|
|
2365
|
+
}
|
|
2366
|
+
],
|
|
2367
|
+
"default": null,
|
|
2368
|
+
"title": "Active Since Unix Ms"
|
|
2369
|
+
},
|
|
2344
2370
|
"classifier": {
|
|
2345
2371
|
"$ref": "#/$defs/Classifier"
|
|
2346
2372
|
},
|
|
@@ -2357,7 +2383,6 @@
|
|
|
2357
2383
|
"pattern": "^/",
|
|
2358
2384
|
"type": "string"
|
|
2359
2385
|
},
|
|
2360
|
-
"maxItems": 1024,
|
|
2361
2386
|
"title": "Direct Paths",
|
|
2362
2387
|
"type": "array"
|
|
2363
2388
|
},
|
|
@@ -2416,7 +2441,6 @@
|
|
|
2416
2441
|
"minLength": 1,
|
|
2417
2442
|
"type": "string"
|
|
2418
2443
|
},
|
|
2419
|
-
"maxItems": 1024,
|
|
2420
2444
|
"title": "Thread Ids",
|
|
2421
2445
|
"type": "array"
|
|
2422
2446
|
}
|
{cc_transcript-14.37.1 → cc_transcript-14.38.0}/cc_transcript/snapshot_schema/response.schema.json
RENAMED
|
@@ -293,6 +293,19 @@
|
|
|
293
293
|
"minimum": 0,
|
|
294
294
|
"title": "Window Start",
|
|
295
295
|
"type": "integer"
|
|
296
|
+
},
|
|
297
|
+
"window_started_unix_ms": {
|
|
298
|
+
"anyOf": [
|
|
299
|
+
{
|
|
300
|
+
"exclusiveMinimum": 0,
|
|
301
|
+
"maximum": 9007199254740991,
|
|
302
|
+
"type": "integer"
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
"type": "null"
|
|
306
|
+
}
|
|
307
|
+
],
|
|
308
|
+
"title": "Window Started Unix Ms"
|
|
296
309
|
}
|
|
297
310
|
},
|
|
298
311
|
"required": [
|
|
@@ -308,6 +321,7 @@
|
|
|
308
321
|
"parser_version",
|
|
309
322
|
"source_bytes",
|
|
310
323
|
"window_start",
|
|
324
|
+
"window_started_unix_ms",
|
|
311
325
|
"committed_bytes",
|
|
312
326
|
"event_count",
|
|
313
327
|
"turn_count",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "cc-transcript"
|
|
3
|
-
version = "14.
|
|
3
|
+
version = "14.38.0" # informational — releases stamp the version from the git tag
|
|
4
4
|
description = "Grep every Claude Code session you've ever run."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "PolyForm-Noncommercial-1.0.0"
|
|
@@ -204,6 +204,10 @@ impl SourceStamp {
|
|
|
204
204
|
self
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
pub fn window_bytes(&self) -> u64 {
|
|
208
|
+
self.size - self.identity.window_base
|
|
209
|
+
}
|
|
210
|
+
|
|
207
211
|
pub fn viewed_as(mut self, pinned: SourceStamp) -> Self {
|
|
208
212
|
self.identity.window_base = pinned.identity.window_base;
|
|
209
213
|
self
|
|
@@ -365,6 +369,17 @@ impl TranscriptSnapshot {
|
|
|
365
369
|
.collect()
|
|
366
370
|
}
|
|
367
371
|
|
|
372
|
+
pub fn window_started_unix_ms(&self) -> Option<i64> {
|
|
373
|
+
if self.window_start == 0 {
|
|
374
|
+
return None;
|
|
375
|
+
}
|
|
376
|
+
self.chunks
|
|
377
|
+
.iter()
|
|
378
|
+
.flat_map(|chunk| chunk.entries.iter())
|
|
379
|
+
.find_map(Entry::meta)
|
|
380
|
+
.map(|meta| meta.timestamp.timestamp_millis())
|
|
381
|
+
}
|
|
382
|
+
|
|
368
383
|
pub fn entry(&self, position: usize) -> &Entry {
|
|
369
384
|
let at = self.chunks.partition_point(|chunk| chunk.start <= position) - 1;
|
|
370
385
|
&self.chunks[at].entries[position - self.chunks[at].start]
|
|
@@ -2919,6 +2934,24 @@ fn tail_bytes(request: &Value) -> Result<Option<u64>, SnapshotError> {
|
|
|
2919
2934
|
.transpose()
|
|
2920
2935
|
}
|
|
2921
2936
|
|
|
2937
|
+
fn active_since_ns(request: &Value) -> Result<Option<i128>, SnapshotError> {
|
|
2938
|
+
request
|
|
2939
|
+
.get("active_since_unix_ms")
|
|
2940
|
+
.filter(|value| !value.is_null())
|
|
2941
|
+
.map(|value| {
|
|
2942
|
+
value
|
|
2943
|
+
.as_u64()
|
|
2944
|
+
.filter(|since| *since > 0)
|
|
2945
|
+
.map(|since| i128::from(since) * 1_000_000)
|
|
2946
|
+
.ok_or_else(|| invalid("active_since_unix_ms must be a positive integer"))
|
|
2947
|
+
})
|
|
2948
|
+
.transpose()
|
|
2949
|
+
}
|
|
2950
|
+
|
|
2951
|
+
fn active(source: &PreparedSourceRef, since: Option<i128>) -> bool {
|
|
2952
|
+
since.is_none_or(|since| source.stamp.mtime_ns >= since)
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2922
2955
|
fn io_error(error: std::io::Error) -> SnapshotError {
|
|
2923
2956
|
let status = match error.kind() {
|
|
2924
2957
|
std::io::ErrorKind::NotFound => Status::Missing,
|
|
@@ -5535,7 +5568,7 @@ impl NativeStore {
|
|
|
5535
5568
|
"device": snapshot.stamp.identity.device.to_string(), "inode": snapshot.stamp.identity.inode.to_string(),
|
|
5536
5569
|
"mtime_ns": snapshot.stamp.mtime_ns.to_string(), "ctime_ns": snapshot.stamp.ctime_ns.to_string(),
|
|
5537
5570
|
"provider": snapshot.provider.as_str(), "parser_version": PARSER_VERSION,
|
|
5538
|
-
"source_bytes": snapshot.stamp.size, "window_start": snapshot.window_start, "committed_bytes": snapshot.committed_bytes,
|
|
5571
|
+
"source_bytes": snapshot.stamp.size, "window_start": snapshot.window_start, "window_started_unix_ms": snapshot.window_started_unix_ms(), "committed_bytes": snapshot.committed_bytes,
|
|
5539
5572
|
"event_count": snapshot.event_count, "turn_count": snapshot.activity.turn_count(),
|
|
5540
5573
|
"classifier": classifier, "provisional_tail": snapshot.provisional_tail,"lease_expires_unix_ms":expires})
|
|
5541
5574
|
}
|
|
@@ -6765,13 +6798,10 @@ impl NativeStore {
|
|
|
6765
6798
|
return Err(invalid("source must be a regular file"));
|
|
6766
6799
|
}
|
|
6767
6800
|
let stamp = SourceStamp::of(&metadata);
|
|
6768
|
-
|
|
6769
|
-
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
));
|
|
6773
|
-
}
|
|
6774
|
-
let budget = limits.max_source_read_bytes.min(stamp.size as usize);
|
|
6801
|
+
let budget = limits
|
|
6802
|
+
.max_source_read_bytes
|
|
6803
|
+
.min(self.config.source)
|
|
6804
|
+
.min(stamp.size as usize);
|
|
6775
6805
|
let mut reservation = self.reserve_projection(context, 0)?;
|
|
6776
6806
|
let mut pending: Vec<u8> = Vec::new();
|
|
6777
6807
|
let mut pending_start = stamp.size;
|
|
@@ -6962,7 +6992,7 @@ impl NativeStore {
|
|
|
6962
6992
|
}
|
|
6963
6993
|
let window = tail_bytes(request)?;
|
|
6964
6994
|
let stamp = SourceStamp::of(&metadata).windowed(window);
|
|
6965
|
-
if stamp.
|
|
6995
|
+
if stamp.window_bytes() > self.config.source as u64 {
|
|
6966
6996
|
return Err(SnapshotError::new(
|
|
6967
6997
|
Status::SourceLimit,
|
|
6968
6998
|
"source exceeds owner bound",
|
|
@@ -11875,6 +11905,22 @@ mod tests {
|
|
|
11875
11905
|
);
|
|
11876
11906
|
}
|
|
11877
11907
|
|
|
11908
|
+
#[test]
|
|
11909
|
+
fn tail_reads_the_newest_events_of_a_source_past_the_owner_bound() {
|
|
11910
|
+
let source = Source::new(&users(0..50));
|
|
11911
|
+
let store = NativeStore::new(&json!({"max_read_bytes_per_step":64,"max_source_bytes":users(40..50).len(),"max_retained_bytes":32*1024*1024,"reserved_hook_accounted_bytes":4096})).unwrap();
|
|
11912
|
+
let owner = context("a");
|
|
11913
|
+
let response = store.request(
|
|
11914
|
+
&tail_request(&source.path, 5, 1024 * 1024),
|
|
11915
|
+
&owner,
|
|
11916
|
+
&Cancellation::default(),
|
|
11917
|
+
);
|
|
11918
|
+
assert_eq!(response["status"].as_str(), Some("ok"), "{response:?}");
|
|
11919
|
+
assert_eq!(tail_uuids(&response), ["45", "46", "47", "48", "49"]);
|
|
11920
|
+
let read = response["usage"]["source_bytes_read"].as_u64().unwrap() as usize;
|
|
11921
|
+
assert!(read <= users(40..50).len(), "{read}");
|
|
11922
|
+
}
|
|
11923
|
+
|
|
11878
11924
|
#[test]
|
|
11879
11925
|
fn tail_refuses_codex_sources_and_counts_outside_the_budgets() {
|
|
11880
11926
|
let codex = Source::new(
|
|
@@ -11971,6 +12017,10 @@ mod tests {
|
|
|
11971
12017
|
let response = windowed(&store, &source.path, 4096, &owner);
|
|
11972
12018
|
let description = &response["data"]["description"];
|
|
11973
12019
|
assert_eq!(description["window_start"].as_u64(), Some(start));
|
|
12020
|
+
assert_eq!(
|
|
12021
|
+
description["window_started_unix_ms"].as_u64(),
|
|
12022
|
+
Some(1_767_323_045_000)
|
|
12023
|
+
);
|
|
11974
12024
|
assert_eq!(description["source_bytes"].as_u64(), Some(size));
|
|
11975
12025
|
assert_eq!(description["committed_bytes"].as_u64(), Some(size));
|
|
11976
12026
|
assert_eq!(
|
|
@@ -12282,6 +12332,7 @@ mod tests {
|
|
|
12282
12332
|
unwindowed["data"]["description"]["window_start"].as_u64(),
|
|
12283
12333
|
Some(0)
|
|
12284
12334
|
);
|
|
12335
|
+
assert!(unwindowed["data"]["description"]["window_started_unix_ms"].is_null());
|
|
12285
12336
|
}
|
|
12286
12337
|
|
|
12287
12338
|
#[test]
|
|
@@ -14012,6 +14063,102 @@ mod tests {
|
|
|
14012
14063
|
assert_eq!(changed["status"].as_str(), Some("changed"), "{changed:?}");
|
|
14013
14064
|
}
|
|
14014
14065
|
|
|
14066
|
+
#[test]
|
|
14067
|
+
fn registered_graph_admits_only_members_active_since_the_cutoff() {
|
|
14068
|
+
let tool = |name: &str| {
|
|
14069
|
+
format!(
|
|
14070
|
+
r#"{{"type":"assistant","uuid":"{name}","sessionId":"s","timestamp":"2026-01-02T03:04:06Z","message":{{"model":"test","content":[{{"type":"tool_use","id":"{name}","name":"{name}","input":{{}}}}]}}}}"#
|
|
14071
|
+
)
|
|
14072
|
+
};
|
|
14073
|
+
let source = Source::new(&format!("{}\n", user("root")));
|
|
14074
|
+
let stale = std::time::SystemTime::now() - std::time::Duration::from_secs(3600);
|
|
14075
|
+
let ids: Vec<String> = (0..1030).map(|index| format!("thread-{index}")).collect();
|
|
14076
|
+
for id in &ids {
|
|
14077
|
+
let path = source.directory.join(format!("{id}.jsonl"));
|
|
14078
|
+
let body = match id.as_str() {
|
|
14079
|
+
"thread-3" => format!("{}\n{}\n", user(id), tool("Grep")),
|
|
14080
|
+
"thread-7" => format!("{}\n{}\n", user(id), tool("Read")),
|
|
14081
|
+
_ => format!("{}\n", user(id)),
|
|
14082
|
+
};
|
|
14083
|
+
std::fs::write(&path, body).unwrap();
|
|
14084
|
+
if id != "thread-7" {
|
|
14085
|
+
File::options()
|
|
14086
|
+
.write(true)
|
|
14087
|
+
.open(&path)
|
|
14088
|
+
.unwrap()
|
|
14089
|
+
.set_modified(stale)
|
|
14090
|
+
.unwrap();
|
|
14091
|
+
}
|
|
14092
|
+
}
|
|
14093
|
+
let store = store();
|
|
14094
|
+
let owner = context("a");
|
|
14095
|
+
let mut background = owner.clone();
|
|
14096
|
+
background.insert("work_class", json!("background"));
|
|
14097
|
+
let root = finish(
|
|
14098
|
+
&store,
|
|
14099
|
+
store.request(&acquire(&source.path), &owner, &Cancellation::default()),
|
|
14100
|
+
&owner,
|
|
14101
|
+
);
|
|
14102
|
+
let mut template = acquire(&source.path);
|
|
14103
|
+
template["limits"].insert("max_discovery_entries", json!(20_000));
|
|
14104
|
+
let since = now_ms() - 60_000;
|
|
14105
|
+
let warm = || {
|
|
14106
|
+
let mut request = json!({"schema":SCHEMA,"id":"warm","operation":"warm_registered","classifier":{"id":"native","version":"1"},"thread_ids":ids,"roots":[source.directory.to_string_lossy().as_ref()],"direct_paths":[],"start_index":0,"membership_revision":null,"active_since_unix_ms":since,"deadline_unix_ms":template["deadline_unix_ms"],"limits":template["limits"]});
|
|
14107
|
+
for _ in 0..12 {
|
|
14108
|
+
let reply = store.request(&request, &background, &Cancellation::default());
|
|
14109
|
+
assert_eq!(reply["status"].as_str(), Some("ok"), "{reply:?}");
|
|
14110
|
+
if reply["data"]["complete"].as_bool() == Some(true) {
|
|
14111
|
+
return;
|
|
14112
|
+
}
|
|
14113
|
+
request.insert("start_index", reply["data"]["next_index"].clone());
|
|
14114
|
+
request.insert(
|
|
14115
|
+
"membership_revision",
|
|
14116
|
+
reply["data"]["membership_revision"].clone(),
|
|
14117
|
+
);
|
|
14118
|
+
}
|
|
14119
|
+
panic!("registered warming did not complete");
|
|
14120
|
+
};
|
|
14121
|
+
let prepare = json!({"schema":SCHEMA,"id":"prepare","operation":"prepare_graph","view":{"handle":handle(&root),"classifier":{"id":"native","version":"1"},"selectors":[],"attachments":[]},"thread_ids":ids,"roots":[source.directory.to_string_lossy().as_ref()],"direct_paths":[],"active_since_unix_ms":since,"deadline_unix_ms":template["deadline_unix_ms"],"limits":template["limits"]});
|
|
14122
|
+
let has = |graph: &Value, name: &str| {
|
|
14123
|
+
let result = finish_prepared(
|
|
14124
|
+
&store,
|
|
14125
|
+
store.request(&json!({"schema":SCHEMA,"id":"query","operation":"query_graph","handle":graph["data"]["handle"],"selectors":[],"query":{"kind":"has_tool","pattern":name,"subagents":true},"deadline_unix_ms":template["deadline_unix_ms"],"limits":template["limits"]}), &owner, &Cancellation::default()),
|
|
14126
|
+
&owner,
|
|
14127
|
+
);
|
|
14128
|
+
assert_eq!(result["status"].as_str(), Some("ok"), "{result:?}");
|
|
14129
|
+
result["data"]["value"].as_bool().unwrap()
|
|
14130
|
+
};
|
|
14131
|
+
warm();
|
|
14132
|
+
let graph = finish_prepared(
|
|
14133
|
+
&store,
|
|
14134
|
+
store.request(&prepare, &owner, &Cancellation::default()),
|
|
14135
|
+
&owner,
|
|
14136
|
+
);
|
|
14137
|
+
assert_eq!(graph["status"].as_str(), Some("ok"), "{graph:?}");
|
|
14138
|
+
assert!(has(&graph, "Read"));
|
|
14139
|
+
assert!(!has(&graph, "Grep"));
|
|
14140
|
+
std::fs::OpenOptions::new()
|
|
14141
|
+
.append(true)
|
|
14142
|
+
.open(source.directory.join("thread-3.jsonl"))
|
|
14143
|
+
.unwrap()
|
|
14144
|
+
.write_all(format!("{}\n", user("resumed")).as_bytes())
|
|
14145
|
+
.unwrap();
|
|
14146
|
+
let stale_membership = store.request(&prepare, &owner, &Cancellation::default());
|
|
14147
|
+
assert_eq!(
|
|
14148
|
+
stale_membership["status"].as_str(),
|
|
14149
|
+
Some("incomplete"),
|
|
14150
|
+
"{stale_membership:?}"
|
|
14151
|
+
);
|
|
14152
|
+
warm();
|
|
14153
|
+
let resumed = finish_prepared(
|
|
14154
|
+
&store,
|
|
14155
|
+
store.request(&prepare, &owner, &Cancellation::default()),
|
|
14156
|
+
&owner,
|
|
14157
|
+
);
|
|
14158
|
+
assert_eq!(resumed["status"].as_str(), Some("ok"), "{resumed:?}");
|
|
14159
|
+
assert!(has(&resumed, "Grep"));
|
|
14160
|
+
}
|
|
14161
|
+
|
|
14015
14162
|
#[test]
|
|
14016
14163
|
fn background_warming_preserves_a_foreground_load_slot() {
|
|
14017
14164
|
let source = Source::new(&format!("{}\n", user("root")));
|
{cc_transcript-14.37.1 → cc_transcript-14.38.0}/rust/crates/core/src/snapshot_prepared_service.rs
RENAMED
|
@@ -654,6 +654,7 @@ impl NativeStore {
|
|
|
654
654
|
"thread_ids": request["thread_ids"],
|
|
655
655
|
"roots": request["roots"],
|
|
656
656
|
"direct_paths": request["direct_paths"],
|
|
657
|
+
"active_since_unix_ms": request["active_since_unix_ms"],
|
|
657
658
|
"registry_generation": context["registry_generation"],
|
|
658
659
|
"admission": context["admission"],
|
|
659
660
|
"authority": context["authority"],
|
|
@@ -767,13 +768,14 @@ impl NativeStore {
|
|
|
767
768
|
.get("roots")
|
|
768
769
|
.and_then(Value::as_array)
|
|
769
770
|
.ok_or_else(|| invalid("missing roots"))?;
|
|
770
|
-
|
|
771
|
+
request
|
|
771
772
|
.get("direct_paths")
|
|
772
773
|
.and_then(Value::as_array)
|
|
773
774
|
.ok_or_else(|| invalid("missing direct_paths"))?;
|
|
774
|
-
if
|
|
775
|
+
if roots.len() > 64 {
|
|
775
776
|
return Err(invalid("prepared registry input exceeds its bound"));
|
|
776
777
|
}
|
|
778
|
+
let since = active_since_ns(request)?;
|
|
777
779
|
if !ids.is_empty() {
|
|
778
780
|
let key = Self::warm_membership_key(request, context)?;
|
|
779
781
|
let (members, sidechain_dirs, complete) = self
|
|
@@ -814,14 +816,20 @@ impl NativeStore {
|
|
|
814
816
|
Some(index) => (&members[..index], &members[index + 1..]),
|
|
815
817
|
None => (&members[..], &members[members.len()..]),
|
|
816
818
|
};
|
|
817
|
-
let others = ||
|
|
819
|
+
let others = || {
|
|
820
|
+
before
|
|
821
|
+
.iter()
|
|
822
|
+
.chain(after)
|
|
823
|
+
.filter(move |source| active(source, since))
|
|
824
|
+
};
|
|
825
|
+
let copied = shared.is_some() || since.is_some();
|
|
818
826
|
let graph_id = self.token("prepared-graph");
|
|
819
827
|
let stamps_bytes = (others().count() + 1) * size_of::<(PathBuf, SourceStamp)>()
|
|
820
828
|
+ root.canonical_path.as_os_str().len()
|
|
821
829
|
+ others()
|
|
822
830
|
.map(|source| source.path.as_os_str().len())
|
|
823
831
|
.sum::<usize>();
|
|
824
|
-
let buffers: usize = if
|
|
832
|
+
let buffers: usize = if copied {
|
|
825
833
|
arc_slice_bytes::<PreparedSourceRef>(others().count())
|
|
826
834
|
+ others()
|
|
827
835
|
.map(|source| source.path.as_os_str().len())
|
|
@@ -845,7 +853,7 @@ impl NativeStore {
|
|
|
845
853
|
+ stamps_bytes
|
|
846
854
|
+ buffers,
|
|
847
855
|
)?;
|
|
848
|
-
let sources: Arc<[PreparedSourceRef]> = if
|
|
856
|
+
let sources: Arc<[PreparedSourceRef]> = if copied {
|
|
849
857
|
#[cfg(test)]
|
|
850
858
|
self.registered_sources.fetch_add(1, Ordering::Relaxed);
|
|
851
859
|
others().cloned().collect()
|
|
@@ -1154,7 +1162,26 @@ impl NativeStore {
|
|
|
1154
1162
|
if build.seen.contains(&stamp.identity.file()) {
|
|
1155
1163
|
continue;
|
|
1156
1164
|
}
|
|
1157
|
-
if build.
|
|
1165
|
+
if active_since_ns(&build.request)?.is_some_and(|since| stamp.mtime_ns < since) {
|
|
1166
|
+
self.extend_projection_reservation(
|
|
1167
|
+
reservation,
|
|
1168
|
+
context,
|
|
1169
|
+
set_growth(&build.seen, 1) + canonical.as_os_str().len(),
|
|
1170
|
+
)?;
|
|
1171
|
+
let predicted = (set_capacity_for(&build.seen, 1), build.tasks.capacity());
|
|
1172
|
+
build.seen.insert(stamp.identity.file());
|
|
1173
|
+
build.tasks.push(GraphTask::List {
|
|
1174
|
+
parent: canonical,
|
|
1175
|
+
depth: depth + 1,
|
|
1176
|
+
});
|
|
1177
|
+
assert_eq!(
|
|
1178
|
+
(build.seen.capacity(), build.tasks.capacity()),
|
|
1179
|
+
predicted,
|
|
1180
|
+
"prepared build collections landed off their predicted capacities"
|
|
1181
|
+
);
|
|
1182
|
+
continue;
|
|
1183
|
+
}
|
|
1184
|
+
if build.stamps.len() >= build.remaining.max_sources {
|
|
1158
1185
|
return Err(SnapshotError::new(
|
|
1159
1186
|
Status::Incomplete,
|
|
1160
1187
|
"prepared graph source budget exhausted",
|
|
@@ -1363,9 +1390,12 @@ impl NativeStore {
|
|
|
1363
1390
|
)?;
|
|
1364
1391
|
#[cfg(test)]
|
|
1365
1392
|
self.warm_records.fetch_add(1, Ordering::Relaxed);
|
|
1393
|
+
let since = active_since_ns(request)?;
|
|
1366
1394
|
let mut located = HashMap::new();
|
|
1367
|
-
|
|
1368
|
-
let
|
|
1395
|
+
for chunk in ids.chunks(1024.min(remaining.max_items)) {
|
|
1396
|
+
let mut bounds = *remaining;
|
|
1397
|
+
bounds.max_sources = chunk.len();
|
|
1398
|
+
let location = json!({"schema":SCHEMA,"id":"warm-registered-locate","operation":"locate","session_ids":chunk,"roots":roots,"deadline_unix_ms":remaining.deadline_unix_ms,"limits":bounds.to_json()});
|
|
1369
1399
|
let before = usage[17];
|
|
1370
1400
|
let mut outcome = self.locate(&location, context, cancel, usage)?;
|
|
1371
1401
|
loop {
|
|
@@ -1434,12 +1464,6 @@ impl NativeStore {
|
|
|
1434
1464
|
let mut examined = 0usize;
|
|
1435
1465
|
while examined < members.len() {
|
|
1436
1466
|
cancel.check(remaining.deadline_unix_ms)?;
|
|
1437
|
-
if members.len() > remaining.max_sources {
|
|
1438
|
-
return Err(SnapshotError::new(
|
|
1439
|
-
Status::Incomplete,
|
|
1440
|
-
"registered source bound exhausted",
|
|
1441
|
-
));
|
|
1442
|
-
}
|
|
1443
1467
|
let source = &members[examined];
|
|
1444
1468
|
let directory = sidechain_directory(
|
|
1445
1469
|
source
|
|
@@ -1522,6 +1546,12 @@ impl NativeStore {
|
|
|
1522
1546
|
}
|
|
1523
1547
|
examined += 1;
|
|
1524
1548
|
}
|
|
1549
|
+
if members.iter().filter(|member| active(member, since)).count() > remaining.max_sources {
|
|
1550
|
+
return Err(SnapshotError::new(
|
|
1551
|
+
Status::Incomplete,
|
|
1552
|
+
"registered source bound exhausted",
|
|
1553
|
+
));
|
|
1554
|
+
}
|
|
1525
1555
|
let mut digest = Sha256::new();
|
|
1526
1556
|
for source in &members {
|
|
1527
1557
|
digest.update(source.path.as_os_str().as_encoded_bytes());
|
|
@@ -1597,16 +1627,16 @@ impl NativeStore {
|
|
|
1597
1627
|
if request["classifier"] != json!({"id":"native","version":"1"}) {
|
|
1598
1628
|
return Err(invalid("registered warming requires the native classifier"));
|
|
1599
1629
|
}
|
|
1600
|
-
|
|
1630
|
+
request["thread_ids"]
|
|
1601
1631
|
.as_array()
|
|
1602
1632
|
.ok_or_else(|| invalid("missing registered thread ids"))?;
|
|
1603
1633
|
let roots = request["roots"]
|
|
1604
1634
|
.as_array()
|
|
1605
1635
|
.ok_or_else(|| invalid("missing registered roots"))?;
|
|
1606
|
-
|
|
1636
|
+
request["direct_paths"]
|
|
1607
1637
|
.as_array()
|
|
1608
1638
|
.ok_or_else(|| invalid("missing registered direct paths"))?;
|
|
1609
|
-
if
|
|
1639
|
+
if roots.len() > 64 {
|
|
1610
1640
|
return Err(invalid("registered warming input exceeds its bound"));
|
|
1611
1641
|
}
|
|
1612
1642
|
let start = number(request, "start_index")?;
|
|
@@ -1661,11 +1691,16 @@ impl NativeStore {
|
|
|
1661
1691
|
"registered warming membership changed",
|
|
1662
1692
|
));
|
|
1663
1693
|
}
|
|
1694
|
+
let since = active_since_ns(request)?;
|
|
1664
1695
|
let mut next = start;
|
|
1665
1696
|
let mut steps = 0usize;
|
|
1666
1697
|
'warming: while next < members.len() && steps < 8 {
|
|
1667
1698
|
cancel.check(remaining.deadline_unix_ms)?;
|
|
1668
1699
|
let source = &members[next];
|
|
1700
|
+
if !active(source, since) {
|
|
1701
|
+
next += 1;
|
|
1702
|
+
continue;
|
|
1703
|
+
}
|
|
1669
1704
|
let before_read = usage[1];
|
|
1670
1705
|
let before_events = usage[3];
|
|
1671
1706
|
let (stamp, mut outcome) = match self.prepared_source(
|
|
@@ -1777,7 +1812,7 @@ impl NativeStore {
|
|
|
1777
1812
|
"registered warming membership changed",
|
|
1778
1813
|
));
|
|
1779
1814
|
}
|
|
1780
|
-
for source in members.iter() {
|
|
1815
|
+
for source in members.iter().filter(|source| active(source, since)) {
|
|
1781
1816
|
cancel.check(remaining.deadline_unix_ms)?;
|
|
1782
1817
|
let key = crate::snapshot_prepared_disk::PreparedDiskKey::new(
|
|
1783
1818
|
source.stamp,
|
|
@@ -23,7 +23,7 @@ impl NativeStore {
|
|
|
23
23
|
return Err(invalid("root source must be a regular file"));
|
|
24
24
|
}
|
|
25
25
|
let current = SourceStamp::of(&metadata).windowed(tail_bytes(request)?);
|
|
26
|
-
if current.
|
|
26
|
+
if current.window_bytes() > self.config.source as u64 {
|
|
27
27
|
return Err(SnapshotError::new(
|
|
28
28
|
Status::SourceLimit,
|
|
29
29
|
"root source exceeds owner bound",
|
|
@@ -346,6 +346,41 @@ mod root_warm_tests {
|
|
|
346
346
|
std::fs::remove_dir_all(directory).unwrap();
|
|
347
347
|
}
|
|
348
348
|
|
|
349
|
+
#[test]
|
|
350
|
+
fn a_trailing_window_of_a_root_past_the_source_bound_warms_and_acquires() {
|
|
351
|
+
let (directory, path) = source(4 * 1024 * 1024);
|
|
352
|
+
let bound = std::fs::metadata(&path).unwrap().len() - 1;
|
|
353
|
+
let store = NativeStore::new(&json!({"max_read_bytes_per_step":256*1024,"max_source_bytes":bound,"max_retained_bytes":128*1024*1024,"reserved_hook_accounted_bytes":4096,"max_leases":16,"reserved_hook_leases":1})).unwrap();
|
|
354
|
+
let context = context("bounded-window");
|
|
355
|
+
let mut request = warm_request(&path, 256 * 1024);
|
|
356
|
+
request.insert("tail_bytes", json!(256 * 1024));
|
|
357
|
+
let mut finished = false;
|
|
358
|
+
for _ in 0..24 {
|
|
359
|
+
let reply = store.request(&request, &context, &Cancellation::default());
|
|
360
|
+
assert_eq!(reply["status"].as_str(), Some("ok"), "{reply:?}");
|
|
361
|
+
if reply["data"]["complete"].as_bool() == Some(true) {
|
|
362
|
+
finished = true;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
assert!(finished);
|
|
367
|
+
let mut acquire = request.clone();
|
|
368
|
+
acquire.insert("operation", json!("acquire"));
|
|
369
|
+
let acquired = store.request(&acquire, &context, &Cancellation::default());
|
|
370
|
+
assert_eq!(acquired["status"].as_str(), Some("ok"), "{acquired:?}");
|
|
371
|
+
acquire.insert("tail_bytes", json!(null));
|
|
372
|
+
let whole = store.request(&acquire, &context, &Cancellation::default());
|
|
373
|
+
assert_eq!(whole["status"].as_str(), Some("source_limit"), "{whole:?}");
|
|
374
|
+
assert_eq!(whole["reason"].as_str(), Some("source exceeds owner bound"));
|
|
375
|
+
let whole_warm = store.request(
|
|
376
|
+
&warm_request(&path, 256 * 1024),
|
|
377
|
+
&context,
|
|
378
|
+
&Cancellation::default(),
|
|
379
|
+
);
|
|
380
|
+
assert_eq!(whole_warm["status"].as_str(), Some("source_limit"), "{whole_warm:?}");
|
|
381
|
+
std::fs::remove_dir_all(directory).unwrap();
|
|
382
|
+
}
|
|
383
|
+
|
|
349
384
|
#[test]
|
|
350
385
|
fn a_base_advance_supersedes_the_previous_window_pin() {
|
|
351
386
|
let (directory, path) = source(4 * 1024 * 1024);
|
|
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
|
|
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
|