bantamkit 0.33.0__tar.gz → 0.34.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.
- {bantamkit-0.33.0 → bantamkit-0.34.0}/PKG-INFO +66 -1
- {bantamkit-0.33.0 → bantamkit-0.34.0}/README.md +65 -0
- bantamkit-0.34.0/dist-0.33.0/bantamkit-0.33.0-py3-none-any.whl +0 -0
- bantamkit-0.34.0/dist-0.33.0/bantamkit-0.33.0.tar.gz +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/__init__.py +1 -1
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/eventlog.py +23 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/hostinstall.py +6 -4
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/__init__.py +2 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/store.py +67 -0
- bantamkit-0.34.0/tests/test_bantamkit_gitignore.py +236 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/.gitignore +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/contracts/default.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/manifest.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/HISTORY.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/README.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/docs/architecture.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/docs/runbook.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/issues/142-settlement-timeout.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/patches/0009-retry-budget.patch +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/__init__.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/config.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/errors.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/posting.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/registry.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/report.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/retry.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/settle.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/src/ledger/validate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/tests/test_posting.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/tests/test_settle.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-error-contract.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-handler-map.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-patch-before-after.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-retry-attempts.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-settlement-config.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-symbol-home.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-trace-blame.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-unread-key.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-large-in-137.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-large-in-359.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-large-in-372.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-large-out-11764.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-large-out-4137.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-large-out-8022.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-small-137.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-small-261.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/document/tasks/doc-small-388.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/fixtures/.gitkeep +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/fixtures/catalog.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/perturbations/task-completion.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/.gitkeep +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/extract-contact.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/extract-invoice.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/extract-order.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/extract-schedule.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/extract-versions.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/nav-prod-port.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/nav-release-bundle.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-audit-retention.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-cache-ttl.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-db-port.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-deploy.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-env-endpoint.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-oncall-rotation.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-oncall.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-org-quota.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/recall-owner.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/shop-basket-total.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/shop-cheapest.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/shop-compare.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/shop-gadget-value.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/shop-stock-total.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/tasks/shop-total.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/pricing/default.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/profiles/default.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/profiles/patient.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/rubrics/.gitkeep +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/rubrics/code-quality.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/rubrics/grounded-completion.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/rubrics/task-completion.yaml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/schemas/shiftwork-checkpoint.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/skills/.gitkeep +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/skills/file-graph.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/skills/memory.md +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/.gitkeep +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/bantamkit_read.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/bantamkit_status.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/build_identity.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/document_list.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/document_read.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/file_graph.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/memory_compact.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/memory_dream.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/memory_recall.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/memory_save.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/repo_map.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/shiftwork_clock_in.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/shiftwork_clock_out.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/shiftwork_status.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/skill_audit.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/token_ledger.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/tools/validate_json.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/hatch_build.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/pyproject.toml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/agent.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/assets.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/budget.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/client.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/contract.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/criticreplay.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/critique.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/docmanifest.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/docread.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/evalrun.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/filegraph.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/loopguard.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/mcpreport.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/mcpserver.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/__main__.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/component.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/divergence.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/dream.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/memory/layers.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/pdfread.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/pricing.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/profile.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/repomap.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/selfupdate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/shiftwork.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/skillaudit.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/statusline.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/structured.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/textutil.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/src/bantamkit/tokenledger.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/cli_exit_status_probe.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/conftest.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/bad-crc.docx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/charref-4301-digits.html +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/charset-table.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/compression-method-9.docx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/corrupt-deflate.docx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/encrypted-member.docx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/encrypted-mimetype.odt +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/eszett-cell-ref.xlsx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/internal-dtd-entity.docx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/rfc2231-charset.eml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/rfc822-nested-twice.eml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/unicode-digit-shared-string.xlsx +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/docread/x-uuencode.eml +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/f8404ab-perturbation-baseline.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/platform-assumption-baseline.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/data/served-tool-surface.json +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/docread_fixtures.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/perturbation_baseline_harness.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/rbp16_effect_probe.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/rbp18_payload_probe.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_adapter.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_agent.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_amendguard.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_bantamkit_read_tool.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_budget.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_build_identity.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_client.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_compaction_corpus_survey.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_conformance.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_conformance_harness_resilience.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_conformance_suite_table_gate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_contract_fanout.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_criticreplay.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_critique.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_doc_commands_gate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_docread.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_docread_ceilings.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_document_manifest_parity.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_document_setup.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_document_tasks.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_document_tools.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_encoding_gate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_evalrun.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_eventlog.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_field_program_gates.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_field_programs.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_filegraph.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_hostinstall.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_install_shape.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_ladder_statistics.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_launcher_which.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_layers.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_loopguard.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_mcp_endpoint.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_mcpdrift.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_mcpreport.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_mcpserver.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory_compact_tool.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory_component.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory_divergence.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory_dream.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory_layers.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_memory_store_tripwire.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_mutmatrix.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_newline_gate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_packaging.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_pdfread.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_pinharness_ledger.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_platform_assumption_gate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_pricing.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_repo_map_tool.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_repomap.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_selfupdate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_served_tool_count_records.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_shiftwork.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_skillaudit.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_status_surface.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_statusline.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_structured.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_thread_exception_gate.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_tokenledger.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_tool_manifest.py +0 -0
- {bantamkit-0.33.0 → bantamkit-0.34.0}/tests/test_version_agreement.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: bantamkit
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.34.0
|
|
4
4
|
Summary: bantamweight tooling — harness primitives that lift small-model agents
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Requires-Python: >=3.11
|
|
@@ -50,6 +50,63 @@ The uv equivalent is `uvx --from "bantamkit[mcp]" bantamkit-mcp`. uv is not
|
|
|
50
50
|
installed on the machine this README was measured on, so unlike every other
|
|
51
51
|
command here that one is the documented form rather than a measured one.
|
|
52
52
|
|
|
53
|
+
> **AMENDED 2026-09-15 (job51) — `pipx run` launches online, and it is offline only while
|
|
54
|
+
> pipx's own cache lasts.** The first form above is fine to try the server. As the command a
|
|
55
|
+
> host runs on every launch, it has a cost. Measured with pipx 1.11.1 and `bantamkit 0.33.0`,
|
|
56
|
+
> with the network cut by pointing the proxy variables at a closed port:
|
|
57
|
+
>
|
|
58
|
+
> ```bash
|
|
59
|
+
> PIPX_HOME=<scratch> https_proxy=http://127.0.0.1:1 HTTPS_PROXY=http://127.0.0.1:1 \
|
|
60
|
+
> http_proxy=http://127.0.0.1:1 HTTP_PROXY=http://127.0.0.1:1 PIP_PROXY=http://127.0.0.1:1 \
|
|
61
|
+
> PIP_RETRIES=0 PIP_TIMEOUT=5 pipx run --spec "bantamkit[mcp]==0.33.0" bantamkit-mcp --assets-root
|
|
62
|
+
> ```
|
|
63
|
+
>
|
|
64
|
+
> On a `PIPX_HOME` that had never run it, this exited 1 in 1.33 s. After one run online into
|
|
65
|
+
> the same `PIPX_HOME`, the same command exited 0 in 0.47 s. So a `pipx run` host entry needs
|
|
66
|
+
> the package index on a new machine, after the cache is cleared, and whenever pipx decides
|
|
67
|
+
> its cached environment is stale. That last one is pipx's policy and was not measured here.
|
|
68
|
+
> For a host, install into an environment you keep, as in the next section.
|
|
69
|
+
|
|
70
|
+
### Install once, run offline
|
|
71
|
+
|
|
72
|
+
Install into an environment you keep, then let `--install` record that environment's console
|
|
73
|
+
script:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
python -m venv <env>
|
|
77
|
+
<env>/bin/pip install "bantamkit[mcp]"
|
|
78
|
+
<env>/bin/bantamkit-mcp --install cursor # or claude, claude-desktop, copilot
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
After that, no launch needs the network. `--install` writes the absolute path of the console
|
|
82
|
+
script you ran. Measured 2026-09-15 on macOS arm64 against `bantamkit 0.33.0`,
|
|
83
|
+
`<env>/bin/bantamkit-mcp --install cursor` wrote `"command": "<env>/bin/bantamkit-mcp", "args": []`.
|
|
84
|
+
That command answered `initialize` and `tools/list` with 12 tools under the PATH a GUI app
|
|
85
|
+
inherits on macOS, `/usr/bin:/bin:/usr/sbin:/sbin`. The Windows layout (`<env>\Scripts\`) was
|
|
86
|
+
not measured.
|
|
87
|
+
|
|
88
|
+
**For a machine with no network at all, carry a wheelhouse.** On a connected machine with the
|
|
89
|
+
**same operating system, CPU architecture and Python minor version** as the target:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
python -m pip download "bantamkit[mcp]==0.33.0" -d wheels
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
With Python 3.12.13 on macOS arm64 that wrote 33 files. One of them is
|
|
96
|
+
`pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl`, which is built for CPython 3.12 on
|
|
97
|
+
arm64 macOS and nothing else. That is why the two machines must match. Copy `wheels/` across,
|
|
98
|
+
then on the target:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
python -m venv <env>
|
|
102
|
+
<env>/bin/pip install --no-index --find-links wheels "bantamkit[mcp]==0.33.0"
|
|
103
|
+
<env>/bin/bantamkit-mcp --install cursor
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Measured in a fresh venv with `PIP_INDEX_URL=http://127.0.0.1:1/` (a closed port): the install
|
|
107
|
+
finished in 1.69 s, and the installed console script served the 12 tools as above. To move to
|
|
108
|
+
a newer version, repeat the download and the install with the new version number.
|
|
109
|
+
|
|
53
110
|
### Connect it to a host
|
|
54
111
|
|
|
55
112
|
**One command, and it writes the entry for you:**
|
|
@@ -80,6 +137,14 @@ hand. Every host runs the same command; only the file and the key around it chan
|
|
|
80
137
|
you installed with `pip` into an environment you keep, replace the `command`/`args` pair
|
|
81
138
|
with the absolute path to the `bantamkit-mcp` console script in that environment.
|
|
82
139
|
|
|
140
|
+
**Prefer that absolute form over the `pipx run` lines below.** A `pipx run` entry needs the
|
|
141
|
+
package index whenever pipx's cache is cold (measured in the amendment under *Install and
|
|
142
|
+
run*). An entry that names a kept console script needs nothing at launch:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{"mcpServers": {"bantamkit": {"command": "/absolute/path/to/env/bin/bantamkit-mcp", "args": []}}}
|
|
146
|
+
```
|
|
147
|
+
|
|
83
148
|
**Claude Code** — one command, no file to edit. `-s user` makes it available in every
|
|
84
149
|
project; drop it for this project only.
|
|
85
150
|
|
|
@@ -33,6 +33,63 @@ The uv equivalent is `uvx --from "bantamkit[mcp]" bantamkit-mcp`. uv is not
|
|
|
33
33
|
installed on the machine this README was measured on, so unlike every other
|
|
34
34
|
command here that one is the documented form rather than a measured one.
|
|
35
35
|
|
|
36
|
+
> **AMENDED 2026-09-15 (job51) — `pipx run` launches online, and it is offline only while
|
|
37
|
+
> pipx's own cache lasts.** The first form above is fine to try the server. As the command a
|
|
38
|
+
> host runs on every launch, it has a cost. Measured with pipx 1.11.1 and `bantamkit 0.33.0`,
|
|
39
|
+
> with the network cut by pointing the proxy variables at a closed port:
|
|
40
|
+
>
|
|
41
|
+
> ```bash
|
|
42
|
+
> PIPX_HOME=<scratch> https_proxy=http://127.0.0.1:1 HTTPS_PROXY=http://127.0.0.1:1 \
|
|
43
|
+
> http_proxy=http://127.0.0.1:1 HTTP_PROXY=http://127.0.0.1:1 PIP_PROXY=http://127.0.0.1:1 \
|
|
44
|
+
> PIP_RETRIES=0 PIP_TIMEOUT=5 pipx run --spec "bantamkit[mcp]==0.33.0" bantamkit-mcp --assets-root
|
|
45
|
+
> ```
|
|
46
|
+
>
|
|
47
|
+
> On a `PIPX_HOME` that had never run it, this exited 1 in 1.33 s. After one run online into
|
|
48
|
+
> the same `PIPX_HOME`, the same command exited 0 in 0.47 s. So a `pipx run` host entry needs
|
|
49
|
+
> the package index on a new machine, after the cache is cleared, and whenever pipx decides
|
|
50
|
+
> its cached environment is stale. That last one is pipx's policy and was not measured here.
|
|
51
|
+
> For a host, install into an environment you keep, as in the next section.
|
|
52
|
+
|
|
53
|
+
### Install once, run offline
|
|
54
|
+
|
|
55
|
+
Install into an environment you keep, then let `--install` record that environment's console
|
|
56
|
+
script:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python -m venv <env>
|
|
60
|
+
<env>/bin/pip install "bantamkit[mcp]"
|
|
61
|
+
<env>/bin/bantamkit-mcp --install cursor # or claude, claude-desktop, copilot
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
After that, no launch needs the network. `--install` writes the absolute path of the console
|
|
65
|
+
script you ran. Measured 2026-09-15 on macOS arm64 against `bantamkit 0.33.0`,
|
|
66
|
+
`<env>/bin/bantamkit-mcp --install cursor` wrote `"command": "<env>/bin/bantamkit-mcp", "args": []`.
|
|
67
|
+
That command answered `initialize` and `tools/list` with 12 tools under the PATH a GUI app
|
|
68
|
+
inherits on macOS, `/usr/bin:/bin:/usr/sbin:/sbin`. The Windows layout (`<env>\Scripts\`) was
|
|
69
|
+
not measured.
|
|
70
|
+
|
|
71
|
+
**For a machine with no network at all, carry a wheelhouse.** On a connected machine with the
|
|
72
|
+
**same operating system, CPU architecture and Python minor version** as the target:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python -m pip download "bantamkit[mcp]==0.33.0" -d wheels
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
With Python 3.12.13 on macOS arm64 that wrote 33 files. One of them is
|
|
79
|
+
`pydantic_core-2.46.5-cp312-cp312-macosx_11_0_arm64.whl`, which is built for CPython 3.12 on
|
|
80
|
+
arm64 macOS and nothing else. That is why the two machines must match. Copy `wheels/` across,
|
|
81
|
+
then on the target:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
python -m venv <env>
|
|
85
|
+
<env>/bin/pip install --no-index --find-links wheels "bantamkit[mcp]==0.33.0"
|
|
86
|
+
<env>/bin/bantamkit-mcp --install cursor
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Measured in a fresh venv with `PIP_INDEX_URL=http://127.0.0.1:1/` (a closed port): the install
|
|
90
|
+
finished in 1.69 s, and the installed console script served the 12 tools as above. To move to
|
|
91
|
+
a newer version, repeat the download and the install with the new version number.
|
|
92
|
+
|
|
36
93
|
### Connect it to a host
|
|
37
94
|
|
|
38
95
|
**One command, and it writes the entry for you:**
|
|
@@ -63,6 +120,14 @@ hand. Every host runs the same command; only the file and the key around it chan
|
|
|
63
120
|
you installed with `pip` into an environment you keep, replace the `command`/`args` pair
|
|
64
121
|
with the absolute path to the `bantamkit-mcp` console script in that environment.
|
|
65
122
|
|
|
123
|
+
**Prefer that absolute form over the `pipx run` lines below.** A `pipx run` entry needs the
|
|
124
|
+
package index whenever pipx's cache is cold (measured in the amendment under *Install and
|
|
125
|
+
run*). An entry that names a kept console script needs nothing at launch:
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{"mcpServers": {"bantamkit": {"command": "/absolute/path/to/env/bin/bantamkit-mcp", "args": []}}}
|
|
129
|
+
```
|
|
130
|
+
|
|
66
131
|
**Claude Code** — one command, no file to edit. `-s user` makes it available in every
|
|
67
132
|
project; drop it for this project only.
|
|
68
133
|
|
|
Binary file
|
|
Binary file
|
|
@@ -29,4 +29,4 @@ from bantamkit.structured import StructuredOutputError, extract_json, structured
|
|
|
29
29
|
# file as its dynamic version source, so the wheel's metadata and the string the MCP
|
|
30
30
|
# server advertises are the same committed bytes, and neither is a function of when
|
|
31
31
|
# someone last ran `pip`.
|
|
32
|
-
__version__ = "0.
|
|
32
|
+
__version__ = "0.34.0"
|
|
@@ -69,6 +69,8 @@ from datetime import UTC, datetime, timedelta
|
|
|
69
69
|
from pathlib import Path
|
|
70
70
|
from typing import Any
|
|
71
71
|
|
|
72
|
+
from bantamkit.memory.store import ensure_bantamkit_gitignore
|
|
73
|
+
|
|
72
74
|
#: Environment switch. Unset or `off`/`0`/`false`/`no`/empty -> disabled. `on`/`1`/
|
|
73
75
|
#: `true`/`yes` -> the default file inside the memory store. Anything else is taken as
|
|
74
76
|
#: the literal path of the log file.
|
|
@@ -276,7 +278,28 @@ class EventLog:
|
|
|
276
278
|
intent, not a live path.
|
|
277
279
|
"""
|
|
278
280
|
assert self.path is not None
|
|
281
|
+
# AUDIT FINDING (J51-1): this `mkdir(parents=True)` can bring a whole `.bantamkit`
|
|
282
|
+
# directory into existence on its own -- `BANTAMKIT_EVENT_LOG=on` with a project
|
|
283
|
+
# store that was never saved to reaches here first -- entirely bypassing
|
|
284
|
+
# `MemoryStore._ensure_dirs`, which is the only other place a `.bantamkit`
|
|
285
|
+
# directory gets created. Without this call a store built that way would never get
|
|
286
|
+
# its self-ignoring `.gitignore`. Cheap and idempotent: a no-op unless one of
|
|
287
|
+
# `self.path`'s ancestors is literally named `.bantamkit`.
|
|
288
|
+
#
|
|
289
|
+
# USER RULING #2 (J51-8a): the ignore file is written only when THIS call is what
|
|
290
|
+
# creates `.bantamkit`, so existence has to be checked BEFORE the mkdir below --
|
|
291
|
+
# after it, the directory unconditionally exists and the question is unanswerable.
|
|
292
|
+
bantamkit_dir = None
|
|
293
|
+
for parent in self.path.parents:
|
|
294
|
+
if parent.name == ".bantamkit":
|
|
295
|
+
bantamkit_dir = parent
|
|
296
|
+
break
|
|
297
|
+
bantamkit_dir_existed_before = bantamkit_dir is not None and bantamkit_dir.exists()
|
|
279
298
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
|
299
|
+
if bantamkit_dir is not None:
|
|
300
|
+
ensure_bantamkit_gitignore(
|
|
301
|
+
bantamkit_dir, created=not bantamkit_dir_existed_before
|
|
302
|
+
)
|
|
280
303
|
try:
|
|
281
304
|
size = self.path.stat().st_size
|
|
282
305
|
except FileNotFoundError:
|
|
@@ -15,10 +15,12 @@ convenience — a file the host owns and rewrites is a file we should not be mer
|
|
|
15
15
|
hand.
|
|
16
16
|
|
|
17
17
|
WHAT THIS WRITES IS WHAT IS RUNNING. The command recorded is this interpreter's own
|
|
18
|
-
`bantamkit-mcp` console script, by absolute path.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
`bantamkit-mcp` console script, by absolute path. Since J51-4, the Node side records its
|
|
19
|
+
own absolute command the same way -- `<absolute node> <absolute dist/cli.js>` of the kept
|
|
20
|
+
install under `~/.bantamkit/mcp` -- for the same reason: the thing installed should be the
|
|
21
|
+
thing that answers, and neither side should send a host looking for the other's runtime.
|
|
22
|
+
The two outputs therefore DIFFER by construction (different interpreter, different path)
|
|
23
|
+
and that difference is ruled in `docs/porting.md`.
|
|
22
24
|
|
|
23
25
|
WHY IT NEVER PROMPTS. An overwrite is exactly the moment a program wants to ask, and asking
|
|
24
26
|
requires a terminal. Measured repeatedly on this machine: Claude Code's `!` channel has no
|
|
@@ -30,6 +30,7 @@ from bantamkit.memory.layers import (
|
|
|
30
30
|
resolve_project_store,
|
|
31
31
|
)
|
|
32
32
|
from bantamkit.memory.store import (
|
|
33
|
+
BANTAMKIT_GITIGNORE_TEXT,
|
|
33
34
|
DEFAULT_INDEX_BUDGET,
|
|
34
35
|
INDEX_PRESSURE_PERCENT,
|
|
35
36
|
RECALL_MIN_SCORE_RATIO,
|
|
@@ -40,5 +41,6 @@ from bantamkit.memory.store import (
|
|
|
40
41
|
MemoryStore,
|
|
41
42
|
MemoryValidationError,
|
|
42
43
|
SaveResult,
|
|
44
|
+
ensure_bantamkit_gitignore,
|
|
43
45
|
undegraded_index_ceiling,
|
|
44
46
|
)
|
|
@@ -252,6 +252,67 @@ def _mtime_date(path: Path) -> str:
|
|
|
252
252
|
return date.fromtimestamp(path.stat().st_mtime).isoformat()
|
|
253
253
|
|
|
254
254
|
|
|
255
|
+
# The exact bytes written into a `.bantamkit/.gitignore` the first time such a directory
|
|
256
|
+
# is brought into existence (user ruling 2026-09-15, `.shiftwork/notes-job51/P0-probes.md`).
|
|
257
|
+
# Both runtimes hold this text byte-for-byte -- a conformance case pins it against this
|
|
258
|
+
# literal -- so it is spelled once, here, rather than re-typed at each call site.
|
|
259
|
+
BANTAMKIT_GITIGNORE_TEXT = (
|
|
260
|
+
"# Created by bantamkit: this directory is local state. Delete this file to commit it.\n"
|
|
261
|
+
"*\n"
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def ensure_bantamkit_gitignore(directory: Path, *, created: bool) -> None:
|
|
266
|
+
"""Best-effort, idempotent: give `directory` a self-ignoring `.gitignore` if it is
|
|
267
|
+
literally named `.bantamkit` AND `created` says THIS CALLER'S OWN mkdir is what just
|
|
268
|
+
brought it into existence.
|
|
269
|
+
|
|
270
|
+
USER RULING #2 (2026-09-15, after J51-8 measured the fallout of the first rule): the
|
|
271
|
+
ignore file is written only when bantamkit itself creates the `.bantamkit` directory.
|
|
272
|
+
An existing `.bantamkit` -- made by an earlier bantamkit, by hand, or checked out from
|
|
273
|
+
git; with or without a `.gitignore` already in it -- is never given one. That is why
|
|
274
|
+
`created` is the caller's job, not this function's: only the caller knows whether
|
|
275
|
+
`.bantamkit` existed immediately before ITS mkdir, because by the time this function
|
|
276
|
+
runs the directory unconditionally exists either way. (Was: written whenever the
|
|
277
|
+
ignore file itself was absent, regardless of whether `.bantamkit` predated the call --
|
|
278
|
+
which meant deleting the file never stuck, and a store a team already commits would
|
|
279
|
+
silently start ignoring new fact files after an upgrade. `P0-probes.md` ruling 4.)
|
|
280
|
+
|
|
281
|
+
THE PROPERTY, not the mechanism: whenever a `.bantamkit` directory is brought into
|
|
282
|
+
existence -- by `MemoryStore._ensure_dirs`, or by anything else in this runtime that
|
|
283
|
+
creates one, such as `EventLog._append`'s own `mkdir` when the event log is on and
|
|
284
|
+
the project store was never saved to -- this is the one place that decides whether it
|
|
285
|
+
gets ignored. A second creator that skipped this call, or that got `created` wrong,
|
|
286
|
+
would leave a `.bantamkit` that git can see (or ignore one it should not), which is
|
|
287
|
+
the whole bug this closes.
|
|
288
|
+
|
|
289
|
+
NEVER REWRITES. A `.gitignore` that already exists -- whatever its bytes -- is left
|
|
290
|
+
exactly as it is, kept as a second guard even when `created` is `True`: an operator
|
|
291
|
+
who deleted it to commit the directory keeps that decision, and this never diffs its
|
|
292
|
+
own output against what is on disk.
|
|
293
|
+
|
|
294
|
+
NEVER RAISES. Failing to write the ignore file must never be why a fact does not get
|
|
295
|
+
saved -- the parent write (`save`, `compact`, an event record) still has to succeed
|
|
296
|
+
exactly as it does today. A missing ignore file is not worth a lost fact, so an
|
|
297
|
+
unwritable filesystem, a permissions error, or the directory disappearing under this
|
|
298
|
+
call are all swallowed the same way `EventLog.record` already swallows its own
|
|
299
|
+
`OSError`.
|
|
300
|
+
|
|
301
|
+
NEVER CREATES `directory` ITSELF. `write_text` fails into a missing parent exactly
|
|
302
|
+
like any other `OSError` here, so calling this before `directory` exists is a no-op,
|
|
303
|
+
not a way to bring `.bantamkit` into existence early.
|
|
304
|
+
"""
|
|
305
|
+
if directory.name != ".bantamkit" or not created:
|
|
306
|
+
return
|
|
307
|
+
gitignore = directory / ".gitignore"
|
|
308
|
+
if gitignore.exists():
|
|
309
|
+
return
|
|
310
|
+
try:
|
|
311
|
+
gitignore.write_text(BANTAMKIT_GITIGNORE_TEXT, encoding="utf-8")
|
|
312
|
+
except OSError:
|
|
313
|
+
pass
|
|
314
|
+
|
|
315
|
+
|
|
255
316
|
class MemoryStore:
|
|
256
317
|
def __init__(
|
|
257
318
|
self,
|
|
@@ -341,6 +402,11 @@ class MemoryStore:
|
|
|
341
402
|
mkdir's internals. `self.root` is the path the caller named and both sides agree on
|
|
342
403
|
it, which is what lets one conformance case pin this line byte for byte.
|
|
343
404
|
"""
|
|
405
|
+
# Checked BEFORE the mkdir, per user ruling #2: this is the one moment that can
|
|
406
|
+
# tell whether `.bantamkit` already existed. After the mkdir it unconditionally
|
|
407
|
+
# exists either way, so the answer has to be captured now or not at all.
|
|
408
|
+
bantamkit_dir = self.root.parent
|
|
409
|
+
bantamkit_dir_existed_before = bantamkit_dir.exists()
|
|
344
410
|
try:
|
|
345
411
|
(self.root / "facts").mkdir(parents=True, exist_ok=True)
|
|
346
412
|
(self.root / "archive").mkdir(parents=True, exist_ok=True)
|
|
@@ -349,6 +415,7 @@ class MemoryStore:
|
|
|
349
415
|
f"memory store could not be created: {self.root}; the directory is not"
|
|
350
416
|
" there and this filesystem would not make it, so nothing was written"
|
|
351
417
|
) from e
|
|
418
|
+
ensure_bantamkit_gitignore(bantamkit_dir, created=not bantamkit_dir_existed_before)
|
|
352
419
|
|
|
353
420
|
# ---- ops ----
|
|
354
421
|
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""J51-1 / J51-8a: a `.bantamkit` directory ignores itself in git — but ONLY the one
|
|
2
|
+
bantamkit itself brings into existence.
|
|
3
|
+
|
|
4
|
+
User ruling 2026-09-15 (`.shiftwork/notes-job51/P0-probes.md`): `.bantamkit` stays out of
|
|
5
|
+
git by default via a self-ignoring `.bantamkit/.gitignore` (`*`), never by editing the
|
|
6
|
+
repository's own `.gitignore`. The property, from `.shiftwork/briefs-job51/J51-1.md`,
|
|
7
|
+
AS AMENDED by user ruling #2 (2026-09-15, `.shiftwork/briefs-job51/J51-8a.md`) after J51-8
|
|
8
|
+
measured that a deleted ignore file came back on the next save and that a store a team
|
|
9
|
+
already commits would silently start ignoring new fact files after an upgrade:
|
|
10
|
+
|
|
11
|
+
1. The ignore file is written IF AND ONLY IF, in this call, the `.bantamkit` directory
|
|
12
|
+
did not exist immediately before the directories were made and exists afterwards.
|
|
13
|
+
"Did not exist" is decided by checking the `.bantamkit` directory itself BEFORE the
|
|
14
|
+
mkdir — never the `.gitignore` file, never `memory/`. (Was: written whenever the
|
|
15
|
+
store's directories are brought into existence and the ignore file itself is absent,
|
|
16
|
+
regardless of whether `.bantamkit` already existed — J51-8 measured this makes
|
|
17
|
+
deletion not stick.)
|
|
18
|
+
2. A `.bantamkit` directory that already existed — made by an earlier bantamkit, by hand,
|
|
19
|
+
or checked out from git; with or without a `.gitignore` — is never given one. In
|
|
20
|
+
particular, an existing `.gitignore` is never rewritten (unchanged from J51-1).
|
|
21
|
+
3. Writing it is best-effort: an unwritable `.gitignore` never fails the write that
|
|
22
|
+
triggered it.
|
|
23
|
+
4. A store whose parent is not named `.bantamkit` gets no `.gitignore` anywhere.
|
|
24
|
+
5. End-to-end: a fresh `git init` directory shows nothing under `.bantamkit` in
|
|
25
|
+
`git status --porcelain --untracked-files=all` after a `memory_save`.
|
|
26
|
+
6. Consequence of 1: deleting the file after bantamkit created it, then saving again,
|
|
27
|
+
leaves it deleted — the file's own first line ("Delete this file to commit it") is
|
|
28
|
+
now true.
|
|
29
|
+
|
|
30
|
+
Also covers the bypass this audit found: `EventLog._append`'s own
|
|
31
|
+
`self.path.parent.mkdir(parents=True, exist_ok=True)` can bring a `.bantamkit` directory
|
|
32
|
+
into existence WITHOUT ever calling `MemoryStore._ensure_dirs` — e.g. when
|
|
33
|
+
`BANTAMKIT_EVENT_LOG=on` and the project store has never been saved to. That path must
|
|
34
|
+
carry the same gitignore-write (and the same "only if `.bantamkit` did not already
|
|
35
|
+
exist" gate), or a `.bantamkit` created that way is never ignored, or is ignored when it
|
|
36
|
+
should not be.
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
import shutil
|
|
40
|
+
import subprocess
|
|
41
|
+
|
|
42
|
+
import pytest
|
|
43
|
+
|
|
44
|
+
from bantamkit.eventlog import EventLog, default_path
|
|
45
|
+
from bantamkit.memory import Memory, MemoryStore
|
|
46
|
+
from bantamkit.memory.store import BANTAMKIT_GITIGNORE_TEXT, ensure_bantamkit_gitignore
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_property_1_gitignore_written_when_store_root_parent_is_dot_bantamkit(tmp_path):
|
|
50
|
+
root = tmp_path / ".bantamkit" / "memory"
|
|
51
|
+
MemoryStore(root) # create=True by default; brings facts/ and archive/ into existence
|
|
52
|
+
|
|
53
|
+
gitignore = tmp_path / ".bantamkit" / ".gitignore"
|
|
54
|
+
assert gitignore.exists()
|
|
55
|
+
assert gitignore.read_bytes() == BANTAMKIT_GITIGNORE_TEXT.encode("utf-8")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_property_1_also_fires_on_save_not_only_construction(tmp_path):
|
|
59
|
+
root = tmp_path / ".bantamkit" / "memory"
|
|
60
|
+
store = MemoryStore(root, create=False)
|
|
61
|
+
gitignore = tmp_path / ".bantamkit" / ".gitignore"
|
|
62
|
+
assert not gitignore.exists()
|
|
63
|
+
|
|
64
|
+
store.save("project", "widget-cache", "one line", "body", ())
|
|
65
|
+
|
|
66
|
+
assert gitignore.exists()
|
|
67
|
+
assert gitignore.read_text(encoding="utf-8") == BANTAMKIT_GITIGNORE_TEXT
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_property_2_an_existing_gitignore_is_never_rewritten(tmp_path):
|
|
71
|
+
root = tmp_path / ".bantamkit" / "memory"
|
|
72
|
+
bantamkit_dir = tmp_path / ".bantamkit"
|
|
73
|
+
bantamkit_dir.mkdir()
|
|
74
|
+
gitignore = bantamkit_dir / ".gitignore"
|
|
75
|
+
gitignore.write_text("operator's own content\n", encoding="utf-8")
|
|
76
|
+
|
|
77
|
+
store = MemoryStore(root)
|
|
78
|
+
store.save("project", "widget-cache", "one line", "body", ())
|
|
79
|
+
store.compact()
|
|
80
|
+
|
|
81
|
+
assert gitignore.read_text(encoding="utf-8") == "operator's own content\n"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_property_3_unwritable_gitignore_is_best_effort(tmp_path, monkeypatch):
|
|
85
|
+
root = tmp_path / ".bantamkit" / "memory"
|
|
86
|
+
|
|
87
|
+
from pathlib import Path
|
|
88
|
+
|
|
89
|
+
real_write_text = Path.write_text
|
|
90
|
+
|
|
91
|
+
def refuse(self, *args, **kwargs):
|
|
92
|
+
if self.name == ".gitignore":
|
|
93
|
+
raise OSError("simulated: read-only filesystem")
|
|
94
|
+
return real_write_text(self, *args, **kwargs)
|
|
95
|
+
|
|
96
|
+
monkeypatch.setattr(Path, "write_text", refuse)
|
|
97
|
+
|
|
98
|
+
store = MemoryStore(root) # must not raise
|
|
99
|
+
result = store.save("project", "widget-cache", "one line", "body", ()) # must not raise
|
|
100
|
+
|
|
101
|
+
assert result.status == "saved"
|
|
102
|
+
assert not (tmp_path / ".bantamkit" / ".gitignore").exists()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def test_property_4_store_not_under_dot_bantamkit_gets_no_gitignore(tmp_path):
|
|
106
|
+
root = tmp_path / "somewhere" / "mem"
|
|
107
|
+
MemoryStore(root)
|
|
108
|
+
|
|
109
|
+
assert not (tmp_path / "somewhere" / ".gitignore").exists()
|
|
110
|
+
assert not (tmp_path / ".gitignore").exists()
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_ensure_bantamkit_gitignore_is_a_noop_off_a_non_bantamkit_directory(tmp_path):
|
|
114
|
+
"""API change for J51-8a: `created` is now a required keyword — the caller must say
|
|
115
|
+
whether ITS OWN mkdir is what brought `directory` into existence. Passed `True` here
|
|
116
|
+
on purpose: the name check must refuse even when the caller claims a fresh creation.
|
|
117
|
+
"""
|
|
118
|
+
directory = tmp_path / "not-bantamkit"
|
|
119
|
+
directory.mkdir()
|
|
120
|
+
ensure_bantamkit_gitignore(directory, created=True)
|
|
121
|
+
assert list(directory.iterdir()) == []
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def test_property_1_amended_existing_bantamkit_without_gitignore_gets_none_on_save(tmp_path):
|
|
125
|
+
"""J51-8a (a): a `.bantamkit` that already existed — with no `.gitignore` in it —
|
|
126
|
+
never gets one, even though the ignore file itself is absent. FAILS on the
|
|
127
|
+
pre-J51-8a source, which writes whenever the file is absent.
|
|
128
|
+
"""
|
|
129
|
+
bantamkit_dir = tmp_path / ".bantamkit"
|
|
130
|
+
bantamkit_dir.mkdir()
|
|
131
|
+
gitignore = bantamkit_dir / ".gitignore"
|
|
132
|
+
assert not gitignore.exists()
|
|
133
|
+
|
|
134
|
+
root = bantamkit_dir / "memory"
|
|
135
|
+
store = MemoryStore(root)
|
|
136
|
+
store.save("project", "widget-cache", "one line", "body", ())
|
|
137
|
+
|
|
138
|
+
assert not gitignore.exists()
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def test_property_1_amended_deleting_the_gitignore_after_creation_stays_deleted(tmp_path):
|
|
142
|
+
"""J51-8a (b): bantamkit creates `.bantamkit` itself, so the ignore file is written —
|
|
143
|
+
delete it, save again, and it must stay deleted. FAILS on the pre-J51-8a source,
|
|
144
|
+
which rewrites it on the next save because the file is absent.
|
|
145
|
+
"""
|
|
146
|
+
root = tmp_path / ".bantamkit" / "memory"
|
|
147
|
+
gitignore = tmp_path / ".bantamkit" / ".gitignore"
|
|
148
|
+
|
|
149
|
+
store = MemoryStore(root)
|
|
150
|
+
assert gitignore.exists()
|
|
151
|
+
|
|
152
|
+
gitignore.unlink()
|
|
153
|
+
store.save("project", "widget-cache", "one line", "body", ())
|
|
154
|
+
|
|
155
|
+
assert not gitignore.exists()
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def test_eventlog_amended_existing_bantamkit_without_gitignore_gets_none(tmp_path):
|
|
159
|
+
"""J51-8a (c), condition (a): the event-log creator follows the same rule — a
|
|
160
|
+
`.bantamkit` that already existed, with no `.gitignore`, is left alone.
|
|
161
|
+
"""
|
|
162
|
+
bantamkit_dir = tmp_path / ".bantamkit"
|
|
163
|
+
bantamkit_dir.mkdir()
|
|
164
|
+
gitignore = bantamkit_dir / ".gitignore"
|
|
165
|
+
assert not gitignore.exists()
|
|
166
|
+
|
|
167
|
+
store_root = bantamkit_dir / "memory"
|
|
168
|
+
log = EventLog(default_path(store_root))
|
|
169
|
+
log.record("memory_save", "saved", {"budget": 1, "index_bytes": 1})
|
|
170
|
+
|
|
171
|
+
assert log.write_failed is False
|
|
172
|
+
assert not gitignore.exists()
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def test_eventlog_amended_deleting_the_gitignore_after_creation_stays_deleted(tmp_path):
|
|
176
|
+
"""J51-8a (c), condition (b): the event-log creator brought `.bantamkit` into
|
|
177
|
+
existence itself, so deleting the ignore file it wrote must stick on the next append.
|
|
178
|
+
"""
|
|
179
|
+
store_root = tmp_path / ".bantamkit" / "memory"
|
|
180
|
+
gitignore = tmp_path / ".bantamkit" / ".gitignore"
|
|
181
|
+
|
|
182
|
+
log = EventLog(default_path(store_root))
|
|
183
|
+
log.record("memory_save", "saved", {"budget": 1, "index_bytes": 1})
|
|
184
|
+
assert gitignore.exists()
|
|
185
|
+
|
|
186
|
+
gitignore.unlink()
|
|
187
|
+
log.record("memory_save", "saved", {"budget": 1, "index_bytes": 1})
|
|
188
|
+
|
|
189
|
+
assert not gitignore.exists()
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@pytest.mark.skipif(shutil.which("git") is None, reason="git is not on PATH")
|
|
193
|
+
def test_property_5_end_to_end_git_status_is_clean_under_dot_bantamkit(tmp_path):
|
|
194
|
+
subprocess.run(["git", "init", "-q"], cwd=tmp_path, check=True)
|
|
195
|
+
subprocess.run(
|
|
196
|
+
["git", "config", "user.email", "test@example.com"], cwd=tmp_path, check=True
|
|
197
|
+
)
|
|
198
|
+
subprocess.run(["git", "config", "user.name", "test"], cwd=tmp_path, check=True)
|
|
199
|
+
|
|
200
|
+
memory = Memory(tmp_path / ".bantamkit" / "memory")
|
|
201
|
+
outcome = memory.save_outcome("project", "widget-cache", "one line", "body", ())
|
|
202
|
+
assert outcome.status == "saved"
|
|
203
|
+
|
|
204
|
+
result = subprocess.run(
|
|
205
|
+
["git", "status", "--porcelain", "--untracked-files=all"],
|
|
206
|
+
cwd=tmp_path,
|
|
207
|
+
check=True,
|
|
208
|
+
capture_output=True,
|
|
209
|
+
encoding="utf-8",
|
|
210
|
+
)
|
|
211
|
+
bantamkit_lines = [line for line in result.stdout.splitlines() if ".bantamkit" in line]
|
|
212
|
+
assert bantamkit_lines == []
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_eventlog_mkdir_bypass_still_gets_the_gitignore(tmp_path):
|
|
216
|
+
"""The finding: `EventLog._append` mkdir's a `.bantamkit` tree on its own when the
|
|
217
|
+
project store was never saved to. That must not skip the gitignore write.
|
|
218
|
+
"""
|
|
219
|
+
store_root = tmp_path / ".bantamkit" / "memory"
|
|
220
|
+
assert not (tmp_path / ".bantamkit").exists()
|
|
221
|
+
|
|
222
|
+
log = EventLog(default_path(store_root))
|
|
223
|
+
log.record("memory_save", "saved", {"budget": 1, "index_bytes": 1})
|
|
224
|
+
|
|
225
|
+
assert log.write_failed is False
|
|
226
|
+
gitignore = tmp_path / ".bantamkit" / ".gitignore"
|
|
227
|
+
assert gitignore.exists()
|
|
228
|
+
assert gitignore.read_text(encoding="utf-8") == BANTAMKIT_GITIGNORE_TEXT
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def test_eventlog_path_unrelated_to_dot_bantamkit_writes_no_gitignore(tmp_path):
|
|
232
|
+
log = EventLog(tmp_path / "custom" / "log.jsonl")
|
|
233
|
+
log.record("memory_save", "saved", {"budget": 1, "index_bytes": 1})
|
|
234
|
+
|
|
235
|
+
assert log.write_failed is False
|
|
236
|
+
assert not list(tmp_path.glob("**/.gitignore"))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/issues/142-settlement-timeout.md
RENAMED
|
File without changes
|
{bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/repo/patches/0009-retry-budget.patch
RENAMED
|
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
|
{bantamkit-0.33.0 → bantamkit-0.34.0}/_assets/evals/devteam/tasks/dt-patch-before-after.yaml
RENAMED
|
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
|