Door A (manifest -> connector -> deterministic materialization -> index) is no longer implemented here. src/portfolio_optimiser/ingest.py becomes a thin consumer seam over the shared library, git-pinned to v0.3.1 on the same Forgejo channel portfolio-optimiser-claude uses. Net -626/+385; ingest.py 599 -> 145 lines. shared/ingest-spec.md remains the normative spec: the library implements it, it does not replace it. Spec changes continue to go via commons. Acceptance criterion met and proven: all three golden bundles (file/sql/http) are byte-exact before and after, including the idempotence re-run. examples/ and shared/ carry ZERO modifications -- the fasit was not adjusted to fit. The rejection set was verified equivalent, not assumed: all 22 malformations the repo's pydantic models refused are refused by the library, with typed codes (okf_type_reserved, credential_embedded, extraction_id_duplicate, ...). Test rebinding (invariants preserved, vehicle changed): the library has zero runtime dependencies by design, so pydantic is unavailable to it. ManifestV1.model_validate(dict) -> load_manifest_bytes(bytes); ValidationError -> ManifestError; model_fields -> dataclasses.fields; PathSecurityError -> SourceError(path_escape); ValueError -> MaterializationError(ingested_at_invalid). Tests now also pin the refusal `code`, the library's documented stability contract -- a sharper assertion than "some validation error was raised". Two accepted behavioural deltas, recorded rather than silently dropped: - Title whitespace is stored verbatim instead of collapsed at validation, so the frontmatter title and the index label are no longer guaranteed identical for irregular whitespace. Both behaviours are spec-conformant (the spec is SILENT; the old one was a repo-local pinned decision). Queued as a commons-amendment candidate so both stacks pin the same answer. Goldens unaffected. - The section 8 audit log moves to logger llm_ingestion_okf.materialize. Nothing in the repo consumed the old channel. Also: the `type` discriminator is no longer a dataclass field, so the spec cross-check asserts it explicitly -- without that line the swap would have silently narrowed the test. New tests/test_ingest_library_seam.py pins the seam itself: the restated section 5 stamp formula against the stamp the library actually writes (the one place the adapter does not purely delegate, since v0.3.1 exposes no stamp helper), the local-only allow_network default, the list[Path] unwrapping, and a guard that the adapter never regrows local Door A machinery. All four verified RED when detached, as were both golden regressions under a byte-level render mutation. Door A is UNGATED: it calls no guard before writing to disk. Gating untrusted content remains the caller's responsibility (guard wiring still planned). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01B4jNN186eVqfe1x5DnTU6r
70 lines
3.9 KiB
TOML
70 lines
3.9 KiB
TOML
[project]
|
||
name = "portfolio-optimiser"
|
||
version = "0.1.0"
|
||
description = "Generic framework on Microsoft Agent Framework for per-project cost-savings optimization"
|
||
readme = "README.md"
|
||
requires-python = ">=3.10"
|
||
dependencies = [
|
||
# MAF — GA-pakker, IKKE meta-pakken `agent-framework`. Metaen drar `agent-framework-core[all]`,
|
||
# og `[all]` trekker inn de fortsatt-beta integrasjonene (azure-ai-search/cosmos/ollama/…) som
|
||
# tvinger pre-releases og drar med en ALPHA pydantic. Offisiell guide: installer kun det du trenger.
|
||
# Beta-integrasjoner legges til per-fase (med snevert pre-release-scope) når de faktisk trengs.
|
||
"agent-framework-core>=1.9.0,<2", # kjerne (GA) — to-sidig pin (S2.5): major-bump krever re-verifisering av privat-API-premissene (test_maf_version_guard)
|
||
"agent-framework-foundry>=1.8.2", # Azure/Foundry-profil: FoundryChatClient (GA)
|
||
"azure-identity>=1.25", # S4.1: AzureFoundryBackend passes an explicit AzureCliCredential (Foundry requires it); already transitive via foundry — promoted to a declared direct dep (zero new install weight)
|
||
"agent-framework-openai>=1.8.2", # OpenAI + OpenAI-kompatible lokale endpoints (GA) → lokal profil
|
||
# Promotert dev→core i Fase 2 (MVP-runtime, ikke lenger spike-only):
|
||
"agent-framework-orchestrations>=1.0.0", # GA orchestration builders (GroupChat/Concurrent/Magentic); resolves med core 1.9.0
|
||
"pulp>=2.8", # deterministisk validator-solver; PuLP bundler CBC i wheelen (R2). Installert 3.3.2.
|
||
# PuLP 4.0 vil kreve `pip install pulp[cbc]` + COIN_CMD (Fase-migrasjonsnotat).
|
||
"mcp>=1.28.0", # tynn lokal-mappe MCP-server (Step 7) — GA (resolverte 1.28.0) per Step 1-beslutning
|
||
"pydantic>=2.11,<3", # IR/validering (B1) — eksplisitt pin til STABIL 2.x, aldri alpha
|
||
"llm-ingestion-okf", # Door A ingest (§4–§6) — the shared implementation of shared/ingest-spec.md; zero runtime deps, MAF-free (D7)
|
||
]
|
||
|
||
# Distribution channel for the shared ingest library (mirrors portfolio-optimiser-claude,
|
||
# verified in consumer CI): git pin against the public Forgejo repo — reproducible for every
|
||
# consumer, uv.lock pins the exact commit behind the tag. Bump the rev on a new library tag.
|
||
[tool.uv.sources]
|
||
llm-ingestion-okf = { git = "https://git.fromaitochitta.com/open/llm-ingestion-okf.git", rev = "v0.3.1" }
|
||
|
||
# Dev tooling as a PEP 735 dependency-group (uv includes it by default in `uv sync`/`uv run`),
|
||
# so the documented bare `uv sync` + `uv run pytest` workflow installs it without `--extra`.
|
||
#
|
||
# INTENTIONAL, RECORDED DEVIATION (Fase 2 review F4): the original plan Step 1 authorized only
|
||
# moving `agent-framework-orchestrations` + `pulp` from the dev extra into core. Migrating the
|
||
# dev group from `[project.optional-dependencies]` to this PEP 735 `[dependency-groups]` block
|
||
# went beyond that stated scope, but is KEPT (not reverted) because it is what makes the brief's
|
||
# Success Criterion SC1 ("bare `uv sync` + `uv run pytest`") install dev tooling without
|
||
# `--extra` — reverting would break SC1. Logged here so the deviation is no longer silent.
|
||
[dependency-groups]
|
||
dev = [
|
||
"pytest>=8",
|
||
"ruff>=0.6",
|
||
"mypy>=1.11",
|
||
"pytest-asyncio>=0.24", # MAF orchestrations are async (await workflow.run(...)) — test-only
|
||
]
|
||
|
||
[build-system]
|
||
requires = ["hatchling"]
|
||
build-backend = "hatchling.build"
|
||
|
||
[tool.hatch.build.targets.wheel]
|
||
packages = ["src/portfolio_optimiser"]
|
||
|
||
[tool.ruff]
|
||
line-length = 100
|
||
src = ["src", "tests", "spikes"]
|
||
|
||
[tool.pytest.ini_options]
|
||
pythonpath = ["src", "."]
|
||
testpaths = ["tests"]
|
||
asyncio_mode = "auto"
|
||
|
||
[tool.mypy]
|
||
python_version = "3.10"
|
||
|
||
# Third-party libs without bundled type stubs (py.typed) — analysed as untyped, not errors.
|
||
[[tool.mypy.overrides]]
|
||
module = ["pulp.*", "agent_framework_foundry.*"]
|
||
ignore_missing_imports = true
|