Commit Graph
37 Commits
Author SHA1 Message Date
gtiandClaude Sonnet 5 8a68819f8a fix: branch-local release manifest so the full suite is 100% green
Missão 5 / Bloco Z.2: RELEASE_MANIFEST.json on this branch now describes
its own local migration state (head 0033_cfop_ippt_write_mode) instead of
mirroring master's deployed state (0032) - the mismatch was making
test_manifest_records_the_real_migration_head fail for a real but
uninteresting reason (this branch adds a migration file master doesn't
have). The note field is explicit that this is branch-local metadata, never
applied to any real Postgres, and that master's own manifest (not this one)
is the source of truth for what production actually runs. No merge to
master, no Agent change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 14:54:19 -03:00
gtiandClaude Sonnet 5 efc8b54bc7 feat: Hub-side plumbing for CFOP/IPPT write capability (flag DEFAULT OFF)
Missão 4 / Bloco E.1-E.2, on feature/cfop-ippt-write only (never main):

- Migration 0033_cfop_ippt_write_mode: Installation.cfop_ippt_write_mode
  (DISABLED|DRY_RUN|APPROVAL_REQUIRED|ENABLED, DEFAULT 'DISABLED' for every
  installation, existing and new) + append-only cfop_ippt_write_audits table.
- central/app/cfop_ippt_audit.py mirrors rtc_audit.py for this narrower
  capability: job_authorizations(installation) (delivered inside the
  authenticated job/heartbeat authorizations, never a local Agent switch) and
  record_cfop_ippt_write_audits (persists applied/aborted cells; only CFOP/
  IPPT are ever accepted, everything else silently ignored).
- central/app/web.py: POST /agents/{id}/cfop-ippt-write - ADMIN only (SSO
  Gerenciador), CSRF, typing GRAVAR required for any mode other than
  DISABLED, every change audited (CFOP_IPPT_WRITE_MODE). Small toggle UI in
  agent_detail.html next to Contexto Fiscal.
- Wired into the existing job/heartbeat authorization payload and job
  completion handling in central/app/api.py, alongside (never mixed with)
  the RTC wiring.
- 18 new tests (central/tests/test_cfop_ippt_write_plumbing.py): default
  DISABLED everywhere (job payload AND /v1/agents/me/authorizations); a
  forged completion payload can never change the mode (read fresh from the
  Installation row, never from Agent-supplied JSON); PADRAO role gets 403
  with no audit row; ADMIN + wrong/missing CSRF is refused; ADMIN without
  typing GRAVAR is refused (422); disabling never requires GRAVAR; invalid
  mode is refused; the audit recorder only accepts CFOP/IPPT, silently
  drops any other field (e.g. a stray CCLASSTRIB row).
- Two existing RTC tests updated for the additive authorizations-dict key
  (cfop_ippt_write_mode) they now also carry.

Still NOT wired into agent/scripts/run_agent_service.py::execute_job - no
Agent code calls select_candidates/apply_candidates yet, so nothing writes
to Firebird from this branch. That wiring, an Agent version bump, a new
installer and Windows Sandbox validation are the next step, deliberately
left for after review (see docs/CFOP_IPPT_WRITE_CAPABILITY_V1.md) - this
mission explicitly asked not to publish this as an active release yet.

FULL_SUITE on this branch: 1 known, expected failure -
test_manifest_records_the_real_migration_head - because this branch adds
migration 0033 that was never merged to master/deployed; RELEASE_MANIFEST.json
intentionally still describes master/production (head 0032). Every other
test passes, including all CFOP/IPPT and RTC-adjacent tests.

REAL_PRODUCT_FISCAL_WRITES=0 (no write path is reachable from any Agent
code on any branch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 11:22:02 -03:00
gtiandClaude Sonnet 5 a3ced77fc5 chore: bump Hub to 1.3.11 (Missão 3 dossiê anonymization + evidence)
Hub-only version bump for the static dossie_contador.md anonymization fix
and the Bloco B PIS/COFINS-source evidence update committed just before.
No schema/migration change, no Agent file touched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 10:14:23 -03:00
gtiandClaude Sonnet 5 e935ed61d5 feat: audited-decision gate for PIS/COFINS and CFOP_ENTRADA NOT_APPLICABLE/OPERATION_TIME
Missao 2 (fechamento de lacunas fiscais, read-only + UI/engine gated):
- field_contract: pis_cofins_profile now also accepts the literal sentinels
  NOT_APPLICABLE/OPERATION_TIME, resolving to NA only from an audited
  FiscalContextEntry - never inferred from emission statistics. CFOP_ENTRADA
  under an already-decided entry_scope=MIXED_OR_DYNAMIC now resolves to NA
  instead of MANUAL, so it stops blocking product completeness and stops
  re-asking an already-answered question. Regression tests prove: no ADMIN
  decision => unchanged old behavior; decision present => gated bucket, no write.
- context_keys: validate_entry accepts the two sentinels for pis_cofins_profile.
- Contexto Fiscal UI: PIS/COFINS and CFOP_ENTRADA cards show the Bloco 2
  cross-database evidence (5 installations, CRT 1 and 3: emission never reads
  the PIS/COFINS cadastral fields anywhere) and a link to an ADMIN-facing,
  anonymized dossie-for-the-accountant; entry_scope is now a dropdown.
- release/tests: decoupled the Hub's GTI_FISCAL_VERSION from the Agent's own
  version (test_versions_are_coherent_across_hub_and_packages vs the new
  test_agent_version_is_internally_coherent) - a Hub-only release must not
  require touching, rebuilding or republishing the Agent.
- New read-only evidence: docs/runs/GTI_dryrun_universe_summary.json (527
  products, Agent 2's real database), docs/runs/BLOCO2_PIS_COFINS_CROSS_DB_V1.json
  (5 installations), docs/fiscal_completeness_matrix.md, docs/dossie_contador.md
  (internal, real names) + central/static/docs/dossie_contador.md (public,
  anonymized - no CNPJ/razao social/product names), docs/AGENT2_UPGRADE_RUNBOOK_V1.md.
- CLAUDE.md: recorded the permanent fiscal-mission rules (no AI/scraping, no
  Firebird schema changes, deploy only via deploy_hub.ps1, never reenroll,
  no remote access to client Agent hosts, no client data in unauthenticated
  static routes).

No schema/migration change. Zero Firebird writes (new scripts never open a
write connection). Hub only - Agent code untouched.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-28 09:44:05 -03:00
gti 1621ea4e0b feat: Contexto Fiscal admin UI - reduces fiscal policy list to 3 real decisions
Adds an ADMIN-only "Contexto Fiscal" section to the Agent detail page: confirm/alter/clear the fiscal decisions
field_contract.resolve_product genuinely cannot derive from the ERP alone (icms_treatment, pis_cofins_profile,
entry_scope). Persists through the existing FiscalContextEntry table (the same one blocker_resolution already
writes operator answers into) - no new persistence model, no opaque JSON box. CSRF + RBAC + audit reuse the exact
mechanism already proven for /agents/{id}/features. Confirming or clearing flags every already-enriched product on
the installation for re-evaluation.

The list was reduced from 5 candidates to 3 by auditing real production data (Agent 2, 2026-09-27/28):
icms_rate/credit_rate and rounding were dropped - both proven NOT_APPLICABLE / ALREADY_DERIVED for this CRT=1
company from real field_contract dry-runs, not assumption. Real evidence surfaced in the UI is a dated, one-time
manual read-only measurement (disclosed in the card copy itself as such) - the Hub has no direct Firebird access,
so this is not a live query; a follow-up should pipe it through the heartbeat the same way CRT/CONTRIBUINTE_IPI
were wired.

Also found, during the same audit, that this client's NFC-e emission ignores the product's cadastral PIS/COFINS
CST/rate fields entirely (verified on the 3 real products that DO have them populated - the emitted documents never
carry the cadastral value) - documented as a strong OPEN recommendation for a future field_contract change, not
applied here, since changing canonical fiscal semantics needs accountant sign-off, not just my own inference.

1129 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.9 (single GTI_FISCAL_VERSION). Hub
only - Agent unchanged, no new installer this release.
2026-09-27 22:09:41 -03:00
gti 4701ff8724 fix: REPROCESS_PRODUCTS resolved company=None for unified_fiscal/RTC
REPROCESS_PRODUCTS is not in SYNC_JOB_KINDS, so it fell to the else branch of execute_job and hardcoded company=None
for _unified_fiscal - a real gap, not a missing feature: the same deterministic, fail-closed company_context.resolve()
every sync job already uses is cheap (no full-table scan, confirmed against the real database) and applies just as
well to a one-off reprocess job. Now resolves the real company the same way; falls back to None only when the
company genuinely cannot be resolved yet, never a silent guess. Does not touch RTC rule logic.

Verified end-to-end against the real production database (dry-run, zero writes) that this was the last domain still
carrying the old bug - field_contract's post-NCM fiscal completion already bypassed it entirely by reading
Installation.company_uf/crt/company_contribuinte_ipi directly (populated via the 1.3.7 heartbeat fix).

1123 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.8 (single GTI_FISCAL_VERSION).
2026-09-27 21:32:28 -03:00
gti 7e83d17533 feat: wire field_contract into product enrichment; auto-discover CRT/CONTRIBUINTE_IPI at heartbeat; targeted per-product ERP evidence
field_contract.resolve_product was only exercised by its own unit tests. /v1/products/resolve now calls it for every product whose NCM
resolves, merging CFOP/CST/CSOSN/PIS-COFINS/CST_IPI/SITUACAO_TRIBUTARIA/IAT/IPPT decisions alongside CLASSIFICACAO_FISCAL/CEST/IPI - reusing
the same engine, the same FiscalContextEntry table the blocker-resolution workflow already writes to, no duplicated rules.

Closes three real transport/discovery gaps found while wiring it in:
- Agent heartbeat never sent company_crt (env-var UF only) or company_contribuinte_ipi, so Installation.company_crt stayed permanently empty
  even though company_context.resolve() already proves both from C000004/EMISSOR for every coverage job. Resolved once, cached, retried only
  while unresolved. Migration 0032 adds Installation.company_contribuinte_ipi (NULL=unknown, never coerced to "N").
- The Agent's enrichment payload only ever reported 3 old fields (CLASSIFICACAO_FISCAL/CEST/IPI) as "current", so the Hub could never see the
  product's own CFOP/CST/CSOSN/... nor the classification columns (TIPO/PROD_COZINHA/PRODUTO_SERVICO/CODGRUPO) infer_role needs - separated
  into a read-only CURRENT_REPORT_FIELDS list, the write allowlist (PRODUCT_ENRICHMENT_WRITE_V1) untouched.
- Added a targeted, product_code-scoped evidence query (firebird_reader.read_product_evidence: recipes/composed/purchases/stock, indexed WHERE,
  never a full-table scan) so st_withheld/product_role can be proven for a single ad-hoc resolve, not only during a full sync job.

Verified read-only against the real database (D:\PROJETOS\GTISISTEMAS\Banco\GTI.FDB): CRT=1, CONTRIBUINTE_IPI=N, company_context.resolve()
reaches HIGH confidence; infer_role correctly resolved RESALE/OWN_PRODUCTION for 5/8 sample real products with zero operator questions.

1121 tests passed (tests + central/tests + agent/tests), 0 failed. Version 1.3.7 (single GTI_FISCAL_VERSION shared by Hub and Agent per
central/app/version.py's own design - never independently versioned).
2026-09-27 18:26:20 -03:00
gtiandClaude Sonnet 5 fbff392ec9 fix: KB dashboard search was applying the strict fiscal name-match rule (used to authorize automatic writes) to human browsing, so a natural query (e.g. missing the unit word) found nothing; now a separate, lenient, global, paginated server-side search — filter over the whole KB, then count/order/paginate. 1.3.6 (Hub only)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-27 10:33:45 -03:00
gti 1333ac1bc4 feat: visible per-product enrichment status, flagged re-evaluation (panel/Reprocessar/Sincronizar/KB decision), operator NCM decision, deterministic name-only match, stale-write guard; 1.3.5 2026-09-26 14:37:37 -03:00
gtiandClaude Sonnet 5 c68c6c67ed feat: TECHNICAL_PLACEHOLDER (NCM 00000000) is replaceable by the product enrichment; real values preserved; Agent 1.3.4
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 10:50:12 -03:00
gtiandClaude Sonnet 5 1e4a31ea88 feat: OSCBR token support, Cosmos out of the active chain, quota-safe OSCBR backfill (dry-run selection), provider env passthrough; 1.3.3 (Hub only)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 10:04:51 -03:00
gtiandClaude Sonnet 5 ac1ecccc50 feat: coverage V2 - historical evidence miner, KB evidence model + promotion audit + revalidation, Kodebar/OSCBR limits, KB/provider panel, seed import; 1.3.2 (Hub only)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 08:14:57 -03:00
gtiandClaude Sonnet 5 e6bcf12d53 feat: OSCBR optional provider, re-baseline after inactivity, field audit, provider UI/feature matrix tests, benchmark chain; 1.3.1
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-26 00:48:18 -03:00
gtiandClaude Sonnet 5 4fc83a33d5 feat: product enrichment observability, lab KB study, benchmark, copy + local-Hub E2E, docs; 1.3.0
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 19:26:13 -03:00
gti 4a12640031 fix: gate cClassTrib applicability by CRT and date 2026-09-25 17:47:04 -03:00
gtiandClaude Sonnet 5 d8f1bd3415 fix: Agent tolerates ~3 minutes of network outage mid-job (10 attempts with backoff); 1.2.4
Sandbox test: a 26 s outage exhausted the previous 15 s retry budget and failed a REPROCESS_ALL.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:46:20 -03:00
gtiandClaude Sonnet 5 6f0f072d84 fix: fresh install archives stale state of a previous installation; a fatal Agent loop error stops the service instead of leaving a dead 'Running' one; 1.2.3
Found by uninstall + fresh install on the clean Windows Sandbox: the old agent_state.sqlite identity conflicted with the new enrollment and the service sat idle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:25:53 -03:00
gtiandClaude Sonnet 5 2e5598ce9c fix: Agent retries transient transport errors/proxy 5xx with backoff (classify, complete, fail); hide console behind the GUI wizard; 1.2.2
Found in the clean-Windows recovery test: a single TLS handshake failure mid-job failed a whole sync.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 12:02:11 -03:00
gtiandClaude Sonnet 5 7063c8c161 feat: re-check central RTC authorization right before every write (GET /v1/agents/me/authorizations), human labels on the cClassTrib control page, final corpus/scale evidence; 1.2.1
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-25 08:57:45 -03:00
gtiandClaude Sonnet 5 42dc172763 feat: central RTC write modes (DISABLED/DRY_RUN/APPROVAL/ENABLED), R4 suggestion-only, preview/approval, per-record rollback, bulk blocker upsert; 1.2.0
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 22:46:05 -03:00
gtiandClaude Sonnet 5 9f08998800 feat: deterministic cClassTrib resolver + gated CCLASSTRIB auto-apply (default OFF), RTC panel summary; 1.1.9
- resolver (rules RTC-R0..R4/A1..A3/G1..G2) over the official cClassTrib table 2026-06-22 and LC 214/2025 annexes; local vs official catalog comparison
- ONE root-cause RTC blocker per product (missing/unresolved/ambiguous/conflict/official mismatch/catalog outdated/evidence missing)
- auto-apply: C000025.CCLASSTRIB only, three switches (FIREBIRD_WRITES + RTC_AUTO_APPLY_ENABLED + Hub authorization), per-product re-read and re-decision, never overwrites, rowcount 1, audit table rtc_write_audits (migration 0027)
- copy-only write E2E (280/280 applied, only CCLASSTRIB changed, 2nd run 0 writes, stale decision 0 writes); real databases untouched
- docs: cclasstrib_resolution, rtc_auto_apply, unified_fiscal_completeness

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 21:18:34 -03:00
gtiandClaude Sonnet 5 1430042322 release: 1.1.8 - unified fiscal coverage (PIS/COFINS applicability + conditional RTC)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 16:43:39 -03:00
gtiandClaude Sonnet 5 f5f05d87e6 fix: installer tolerates localized 'service exists' (1073) and restarts the service if an upgrade step fails; 1.1.7
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 11:13:19 -03:00
gtiandClaude Sonnet 5 40a4d835fe fix: installer starts the service reliably (retry + verify + installer.log), fails loudly; 1.1.6
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 10:54:19 -03:00
gtiandClaude Sonnet 5 71bbf3e0bd fix: installer stops the service reliably before upgrading and retries locked file copies; 1.1.5
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 09:46:00 -03:00
gtiandClaude Sonnet 5 e40e9500a4 fix: Agent survives slow Hub on large syncs (25-product chunks, 120s timeout, retry) and keeps heartbeating during jobs; 1.1.4
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 09:33:54 -03:00
gtiandClaude Sonnet 5 bb663a979c feat: zero-touch Agent — central scheduler, central pause, delta sync, discovery-driven installer
Hub: installations.processing_enabled / sync_interval_seconds / last_sync_* (migration 0026).
The first heartbeat of an installation without coverage queues exactly one INITIAL_SYNC;
afterwards one SYNC_INCREMENTAL per interval (idempotent, backs off on failure). One fiscal
job at a time per Agent (FIFO, stale RUNNING recovery). Job completion now updates the
coverage snapshot, blockers and JOB_STARTED/COMPLETED/FAILED events. Panel: Sincronizar
agora / Reprocessar tudo / Pausar / Retomar + status; pause is enforced Hub-side.
Agent: local AGENT_JOBS_ENABLED is ignored (central control); SYNC_INCREMENTAL re-classifies
only new/changed products via a per-product fingerprint+decision cache and rebuilds coverage
from it; results carry operational summary and blockers; Firebird credentials come from a
DPAPI firebird.bin. Setup: read-only SGV Firebird discovery (auto-select only when
unambiguous, wizard chooser otherwise), starts the service, waits for the first heartbeat,
upgrade-in-place mode. All jobs stay read-only (FIREBIRD_WRITES=0). Version 1.1.3.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 08:47:00 -03:00
gtiandClaude Sonnet 5 9f9e06e9e9 fix: searchable client combobox in Nova instalação
Replaces the native list with a combobox (name/code/CNPJ search, accent- and
case-insensitive, keyboard + mouse, custom dropdown, hidden client_id = the
Gerenciador's real CLIENTE.ID). The backend resolves client_id against the
active GTI_GERENCIADOR mirror and rejects free text/unknown ids. Adds
Tenant.external_cnpj (migration 0025) mirrored via the internal endpoint.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-24 08:12:52 -03:00
gtiandClaude Sonnet 5 3ccef36c50 docs: record migration 0024 verified in production
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:56:57 -03:00
gtiandClaude Sonnet 5 e7d77beb26 feat: GTI Gerenciador as the single source of truth for clients; bump to 1.1.2
Tenant gains source (LOCAL|GTI_GERENCIADOR), external_client_id, external_code,
active and synced_at (migration 0024). central/app/client_sync.py fetches from
the panel's new GET /internal/fiscal/clients (dedicated bearer token, never
MySQL credentials) and upserts Tenant rows, never touching a LOCAL row.
/agents/new now offers only active GTI_GERENCIADOR tenants, with a client-side
search box; the POST validates the same rule server-side, not just in the
dropdown. central/scripts/sync_clients_from_gerenciador.py is the operator-run
sync + reconciliation report.

GTI_FISCAL_VERSION/AGENT_VERSION bumped to 1.1.2 (release/VERSION single
source of truth), incorporating the installation_id persistence fix. Rebuilt
the EXE installer trio at 1.1.2 (scripts/build_windows_installer.ps1).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 22:38:58 -03:00
gti a9aded1e49 installer v1 (C+D): Windows EXE installer trio + build script + local Hub E2E 2026-09-23 17:44:48 -03:00
gti 91c4030b06 installer v1 (A+B): install-code enrollment, panel code UI, EXE publish; DPAPI credential store 2026-09-23 16:38:19 -03:00
gtiandClaude Sonnet 5 e4c42dd9ff docs: record migration 0022 verified in production
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 13:26:25 -03:00
gtiandClaude Sonnet 5 8d6122c096 feat: Agent distribution with secure enrollment from the control panel
One universal Windows Agent package per version (agent_releases: version/
platform/architecture/sha256/status DRAFT|PUBLISHED|REVOKED; the binary
lives on a local release-storage volume, never in PostgreSQL). An operator
creates a pending installation (agent_enrollments) from Agents / Servidores
-> + Nova instalação, then either downloads it directly or generates a
one-time HTTPS link (short TTL, single use). Either path streams the
package plus a freshly minted enrollment.json whose token is never written
to storage in plaintext, only its SHA-256 hash. On the client host,
gti-agent.ps1 install-auto verifies the bundle's SHA-256, refuses a non-
HTTPS Hub, enrolls via POST /v1/agents/enroll (deleting the enrollment
token immediately after, success or failure), writes an ACL-restricted
.env with the newly issued permanent Agent token, and registers the
Windows Service without starting it (Firebird stays unconfigured on
purpose). Idempotent, replay-proof, rate-limited per IP, fully audited,
never logs a secret.

Migration 0022_agent_releases_enrollment (verified fresh-DB ==
upgrade-from-0021 by pg_dump diff). GTI_FISCAL_VERSION/AGENT_VERSION
bumped to 1.1.0 as the single source of truth across code, packages, the
release manifest and every published AgentRelease row.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-23 13:19:31 -03:00
gtiandClaude Opus 5.5 b1c496fc1b docs: record migration head 0021 (SSO) in production, TLS via NPM, Caddy removed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 12:30:49 -03:00
gtiandClaude Opus 5.5 d33149f5ee docs: record migration head 0020 in the release manifest and docs
RELEASE_MANIFEST.json still said head 0011 (repo was at 0018, now 0020)
and RELEASE_CANDIDATE_V1.md said 0010. Updated both, plus
AI_PROJECT_STATE.md and PILOT_DEPLOYMENT.md, to head
0020_not_null_timestamps as applied in production.

scripts/release_manifest.py reported the 4-digit file prefix as the head
("0020" instead of "0020_not_null_timestamps") and always read the
applied revision from the dev container. It now asks Alembic for the real
head and revision count, and the Hub container is configurable
(HUB_CONTAINER); the source is recorded in the manifest.

tests/test_release_candidate.py now fails when the manifest head differs
from Alembic's head.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 07:23:13 -03:00
OpenCode 9dcc263217 chore: establish project baseline 2026-09-21 15:51:47 -03:00