| title | Implementation Working Agreement |
|---|---|
| summary | Execution rules for shaping, verifying, refactoring, and committing repo work. |
| doc_type | standard |
| audience | human |
| owner | repo |
| status | active |
| naming_scope | repo_policy |
| nav_order | 20 |
Use this document when actively coding in the repo. It is the execution contract for how work should be shaped, verified, refactored, and committed so future sessions do not depend on repeated reminders from the user.
This document complements:
docs/standards/engineering.mdfor placement and modularity rulesdocs/standards/commits.mdfor commit format and commit-boundary policydocs/concepts/reconciliation-tax-architecture.mdfor architecture directiondocs/status/migration-sequence.mdfor no-big-bang migration order
This repo uses the external environment at $(HOME)/.venvs/tallylot-py312.
Use the root Makefile as the standard local command interface. It prepends the
external environment's bin/ directory to PATH, which keeps repo commands
machine-neutral and sandbox-safe without inline environment prefixes.
Prefer the repo's built-in tooling before inventing local workflows:
- inspect a fresh VS Code Problems snapshot first when the
vscode-problemsskill or MCP server is available, then fall back to CLI checks when the snapshot is stale, missing, or incomplete - bootstrap each clone with
make install-hooksso the shared external environment is synced to the current checkout before hook installation; rerun that command ifmake cli ARGS='...'resolves a stale editable checkout after repo relocation or history rebuilds - run broad verification with
make quality - run the explicit full-suite override only when it is intentionally needed with
make quality-fullThe repo starts the standard quality gates together by default, keeps the fast pytest bundle on 4 workers by default, and reserves phased scheduling as an explicit alternate mode for comparison or debugging. Override the fast worker count only throughTALLYLOT_FAST_PYTEST_WORKERS; use0to force serial. - local verification runners may apply safe autofixes to staged Python and Markdown files before validation so style-only drift is repaired locally, while CI stays read-only and reports any remaining issues directly
- run the broad review suite locally when changing workflow, packaging, or
release behavior with
make pr-review-full - audit local CODEOWNERS coverage and live GitHub branch-protection settings
together when changing delivery policy, branch protection, or CI guardrails
with
make audit-delivery-guardrails - audit PR review file-group coverage with
make audit-pr-reviewand run the required review checks for the current diff withmake pr-review - run the blocking flake and order-sensitivity lane with
make test-stress - report coverage hotspots from a recent full-suite run with
make coverage-hotspots - scaffold new adapters with
make scaffold-adapter ARGS='...' - refresh generated pyright test-private execution environments with
make sync-pyright-configwhen adapter-localtests/packages are added or removed outside the scaffold tool;tools.run_quality_gatesalso refreshes that generated config and fails immediately when it had to update the file, so review and commitpyrightconfig.tests.jsonbefore rerunning - refresh adapter golden fixtures with
make refresh-adapter-goldens ARGS='...' - benchmark test-bundle changes with
make benchmark-tests - benchmark quality-gate scheduling changes with
make benchmark-quality
Do not replace these with ad hoc shell habits when the repo already has a supported path.
Use the repo benchmark tools only for explicit default-selection decisions.
- benchmark one suite or quality-gate comparison set at a time
- warm caches before measured runs
- use warmup runs plus repeated measured iterations, then compare medians instead of one-off timings
- benchmark both local hardware and GitHub runner classes before calling a default benchmark-backed in docs, tests, or review rationale
- keep
-n autoas a benchmark or debug candidate only; do not promote it to a repo default without fresh local and GitHub runner evidence
pyrightconfig.tests.json is generated repo policy for test-private execution
environments. Do not hand-maintain adapter executionEnvironments in
pyrightconfig.json; update adapter-local test package layouts and rerun the
sync or quality-gate tool instead. If the quality-gate runner refreshes the
generated file, commit that change and rerun the gates.
When repo-native tooling and tests need shared support:
- keep production/runtime concerns out of
tools/and the current liverepo_support/package area - keep shared repo-only support in the current live
repo_support/package, not in ad hoc duplicated test helpers or tool-local path constants - keep
tools/focused on entry points and task-specific dev modules - shape forward-looking repo-only support work toward a later rename and split
under
dev_support/; do not expandrepo_support/as if it were the desired long-term boundary
Live repo document enforcement stays in script-owned tools, not pytest:
- use
docs-maintenancefor generated sections, metadata, links, and docs-tree hygienedocs-maintenancealso ownsdocs/README.mdgenerated reference-group headings/order plus requirednaming_scopefrontmatter/default enforcement - use
target-namingfor naming, locality, vocabulary, and identifier rules - use
docs-auditfor semantic repo-state document parity and cross-surface correctnessdocs-auditalso owns forward-contract proof, owner-doc authority, and bridge cutover matrix semantics - keep pytest coverage for docs tooling on synthetic strings or temp repos instead of the live repo Markdown tree or live control-plane prose
Durable versus planning surfaces:
- forward-looking docs may use ephemeral planning language when they carry
planning, sequencing, or other future-oriented implementation detail;
ROADMAP.mdis not the only allowed planning surface - durable control-plane and delivery surfaces must stay phase-free and
roadmap-free:
docs/standards/**AGENTS.md.claude/commands/**.agents/skills/**.github/pull_request_template.md- commit messages
- PR titles and PR bodies
- branch names
- code, tooling, filenames, and generated durable examples
- keep ordinary repo-facing tests and named examples phase-free and roadmap-free
- synthetic tooling fixtures may intentionally mention forbidden roadmap or phase labels only when they are exercising validator or audit behavior on synthetic strings or temp repos
- when a new live-repo docs policy needs enforcement, add it to the owning script instead of adding live-repo Markdown or control-plane prose checks to pytest
Agents should assume all of these are expected unless the task explicitly says otherwise:
- keep the architecture aligned with
docs/concepts/reconciliation-tax-architecture.md - for reconciliation, checkpoint, journal, tax, or target pipeline work,
reload the owning roadmap and migration docs before shaping the change:
ROADMAP.mdanddocs/status/migration-sequence.md - read the narrow forward-looking roadmap, architecture, migration, or owning boundary guidance before shaping a non-trivial change
- refactor when a clearer shared boundary is already visible
- extract shared components before copy-paste patterns harden
- create or update tests alongside the implementation
- commit at stable checkpoints without waiting to be reminded
- do not close a non-trivial task until the verified checkpoint commit exists
- prefer typed, explicit models over loose dictionaries and convenience code
For non-trivial implementation work, use this order:
- confirm the target boundary and owning layer
- create or update the typed models, contracts, or artifact schemas first
- create or update tests that define the intended behavior
- implement the behavior
- refactor duplicated or cross-cutting logic into bounded shared components
- run the relevant quality gates
- checkpoint the work in a coherent commit
Do not start by patching call sites ad hoc and only later trying to discover the right structure.
Before shaping a non-trivial fix, reload the narrow forward-looking guidance that owns the change area. Prefer the intended end-state boundary over a local temporary patch when the repo already documents the target ownership model.
For reconciliation, checkpoint, journal, tax, and target pipeline work, the normal minimum routing set is:
docs/concepts/reconciliation-tax-architecture.mdROADMAP.mddocs/status/migration-sequence.md
Add docs/concepts/oracle-boundaries.md and
docs/concepts/transaction-classification.md when the change alters
boundaries or semantic classification.
Refactoring is expected when it clearly improves the current change, not only when the user says the word "refactor."
Refactor during the task when any of these are true:
- the same logic is being copied into a second place
- a module is gaining a second responsibility
- a new feature would deepen coupling across layers
- repeated parsing, validation, or mapping rules are visible
- tests are getting repetitive because the production boundary is wrong
- new work would make an existing hotspot materially worse
Do not defer an obvious structural fix if the change is already in the code you are touching and the bounded refactor is cheaper than carrying the duplication forward.
Extract shared code only to a specific, named boundary.
Good extractions:
- adapter-local row parsers
- issue-rule modules
- reconciliation decision helpers
- tax policy mapping modules
- journal posting assemblers
- typed artifact writers or parsers
Avoid generic sinks:
helpers.pyutils.pycommon.py- broad cross-layer convenience modules
For repo-native tooling and test support:
- use the current live
repo_support/package only for narrow shared boundaries that are reused by multiple repo-native areas - do not create generic
repo_support/helpers.pyorrepo_support/utils.py - if only one tool owns the logic, keep it local to that tool instead of
promoting it into
repo_support/ - later implementation should rename and split this dev-only support package area
under
dev_support/instead of treatingrepo_support/as the final name
Shared components must stay owned by one layer and one concept.
Prefer structure-first or test-first work when introducing:
- new domain models or invariants
- new artifact schemas
- classification rules
- reconciliation logic
- journal posting rules
- tax treatment behavior
Minimum expectation:
- add focused unit tests for new decision logic
- add contract tests for new external artifact parsing or rendering
- add regression tests for fixed edge cases
Meaningful tests only:
- add tests for user-visible behavior, real contracts, non-trivial decision logic, and fixed regressions
- do not add trivial getter or setter tests, wording-only assertions, duplicate coverage at multiple layers, or call-order tests unless that order is the contract
- when tests become repetitive, treat that as a signal that the production boundary may be wrong and refactor that boundary instead of piling on more near-duplicate tests
- for repo-side agent scripts and internal workflow entry points, cover behavior in-process when a callable entry point exists and reserve subprocess tests for the real launch boundary
- avoid duplicate in-process and subprocess tests that prove the same workflow
behavior; once behavior is covered in-process, thin launch-boundary tests may
use
@pytest.mark.no_cover
Do not leave edge-case behavior implicit in implementation code without a test that pins it down.
Mirror test structure to production structure whenever possible:
tests/unit/...for business rules and local decision logictests/contract/...for artifact contracts, parsers, renderers, and command interfacestests/e2e/...only when the end-to-end workflow itself is the behavior
When a feature becomes a package, mirror that package structure in tests rather than adding a growing pile of same-prefix test files.
Agents should treat commits as part of finishing the work, not as optional afterthoughts.
Expected behavior:
- make a commit when a bounded change is stable and verified
- keep commits cohesive and reviewable
- prefer one commit per coherent change, not one commit per file
- keep each authored commit bounded to one reviewable concern with a clear rollback boundary
- before a checkpoint commit is pushed, amend or fix up a small, scoped
follow-up patch into the owning non-pushed checkpoint when that avoids a
low-value micro-commit, and update the amended commit message so its
Why:,What:, andChecks:sections still describe the final content - before creating or amending a commit, reread
docs/standards/commits.mdin the current task and use the installed commit template plus.git/COMMIT_EDITMSGwhenever the message includes backticks, quotes, or other shell-sensitive text - do not use repeated amend cycles to grow one broad checkpoint that should be split into separate commits with clearer review and rollback boundaries
- for large but separable scopes, create multiple bounded checkpoint commits before finishing instead of ending on one umbrella authored commit
- do not bundle unrelated fixes
- do not wait for the user to remind you to commit once the task has reached a real checkpoint
- when a refactor spans structure, routing, tooling, and tests, checkpoint each stable change that already passes the narrow checks for that change
- when opening a PR, use a Conventional Commit title and the structured PR body
defined in
docs/standards/commits.mdbecause that metadata stays attached to the PR record and becomes the squash commit onmainfor the single-checkpoint exception - keep PR, commit, and doc language neutral and direct:
Why:should state the motivating repo problem, trigger, constraint, or risk that makes the patch necessary now;What:should state the concrete repo change; and neither section should use rhetorical or promotional wording - before merging a PR or rewriting mainline history, verify whether the pull request record must stay attached to the merged commit; if yes, do not rewrite that merge commit after merge
- if a multi-checkpoint PR merges with a merge commit, use
<pr title> (#<pr number>)as the merge subject so the mainline log keeps the PR number visible - if a repair PR replaces an older pull request, mark the old PR with the repo's neutral duplicate/superseded label before closing the older PR
- add a neutral replacement comment only when the repo has no suitable label or the user explicitly asks for explanatory prose
- when the work uncovers follow-up or out-of-scope changes that do not belong in the current PR, search existing open issues first and create the issue immediately when no suitable issue already exists
- open only repo-engineering follow-up issues in this repository:
- code
- tests
- docs and standards
- templates and other control-plane files
- automation and CI
- keep follow-up issues privacy-safe:
- no personal information
- no secrets or raw evidence
- no wallet or account identifiers
- no local absolute paths
- use the repo-standard issue structure from
docs/standards/issues.md - do not defer issue creation for out-of-scope work until after merge, handoff, or a later cleanup pass
- before closing a non-trivial task, ensure the commit already exists rather than leaving commit creation as follow-up work
- keep repo cleanup forward-only by default: do not use destructive rollback
commands such as
rm -rf,git restore,git reset, orgit checkout --unless the user explicitly requests that cleanup in the current thread - keep tracked docs, templates, and control-plane artifacts neutral and durable
- keep durable delivery metadata and ordinary branch names phase-free and roadmap-free; use durable repo-area or behavior wording instead of planning tags
- keep scratch review notes, temporary review ledgers, and compaction aids untracked; recover from deterministic repo facts instead
When not to commit:
- the worktree is inconsistent
- the tests for the change are failing
- the checkpoint would be hard to review or roll back
- the current diff still contains multiple separable reviewable changes
Do not collapse a broad but separable refactor into one giant commit unless the change truly cannot be reviewed or validated incrementally.
Treat compaction or context loss as an ordinary operating condition.
When context is lost before more edits, commits, or delivery steps:
- reload
git statusand the current branch tip - inspect the current diff and recent commits
- inspect current PR metadata and changed files when PR work is active
- reread only the narrow repo standards and start-skill docs for the active area
- reload the latest targeted verification results
Do not rely on tracked scratch notes, phase logs, or preserved review ledgers to recover task state.
Default verification expectations:
- use fresh VS Code Problems diagnostics first for instant editor-grounded lint and type feedback when they are available and current
- targeted tests during development
- full relevant checks before closing substantial work
Preferred commands are already defined in AGENTS.md, but the operating rule
is:
- do not call work done with only local reasoning
- verify the changed behavior at the smallest useful level first
- then run
tools.run_quality_gatesbefore closing the task - escalate to
tools.run_pr_review_checks --mode fullwhen the change touches CI, packaging, release, or other workflow areas where the local pass should mirror the final non-draft PR suite before handoff - avoid
tools.run_quality_gates --full-testsunless you explicitly need the full-suite override rather than the standard agent path - do not run
tools.run_quality_gates --full-testsagain immediately beforetools.run_pr_review_checks --mode full; the full PR-review runner already includes it - use
tools.run_fast_pytestfor an explicit fast pytest loop when you need one; the hook-owned pre-commit path now follows the staged-path planned verifier selection instead of a fixed pytest bundle
For PR review and repair loops, use tools.audit_pr_review to classify the
changed file groups and use tools.run_pr_review_checks as the shared
verification entrypoint:
- draft pull-request CI always runs
commit-messagesandpr-metadata, then selects the remaining checks from the changed diff - non-draft pull-request CI switches to the full non-duplicated blocking suite plus the non-blocking coverage hotspot report lane
- post-merge and manual CI stay change-sensitive and select only the atomic checks needed for the landed diff
- local planned runs follow the same change-sensitive selection policy as post-merge and draft pull-request CI
- local
tools.run_pr_review_checks --mode fullis the explicit broad-review override that mirrors the final non-draft PR suite for CI, packaging, release, or other workflow-sensitive changes tools.run_quality_gatesremains a quality-only convenience runner and does not decide PR or CI verification selection
Coverage hotspot reports are informative review output only. Use them to pick the next review target after a full-suite run; do not treat them as a replacement for correctness tests or the existing repo-wide coverage gate.
If you are changing commit-time or suite-selection policy, keep the hook path
limited to bounded commit checks and use the shared quality runner or the
full PR-review runner as the single broad verification source. Benchmark with
tools.benchmark_tests and tools.benchmark_quality_gates when you are
proposing a different test bundle or quality-gate schedule, and do not expand
the hook path into a second full-suite verification pass.
When a task touches a migrating area:
- implement on the fact-based path first
- preserve external output projections only as needed
- do not add new behavior to the legacy center unless required for migration
- add parity coverage before retiring older paths
If the change would force a big-bang rewrite, the migration sequence is wrong. Split the work into a smaller compatible increment.
Keep workflow integrity rules explicit while the repo continues migrating.
- filesystem scans that enumerate user evidence must be deterministic
- xdist-sensitive parametrization and collection inputs must preserve deterministic ordering; do not feed unordered collections into parametrized tests that need reproducible parallel collection
- tree-walking services should use the shared scan path with explicit output
exclusions rather than ad hoc
rglob()behavior - archive inspection, archive safety limits, and archive-member issue reporting belong in the shared intake scan layer rather than in source adapters or CLI commands
- profiling and normalization outputs must not be written inside raw evidence trees
- evidence references recorded in normalized or checkpoint-supporting artifacts must stay source-relative and portable across workspaces
- docs, command routes, and agent entrypoints must stay aligned with the implemented runtime
When adding or changing adapters:
- keep metadata, implementation, fixtures, and tests aligned
- use scaffold and golden-refresh tools instead of hand-rolling repetitive layout
- keep provider-specific parsing local to the adapter package
- extract shared behavior only when it is truly cross-provider and conceptually stable
When adding artifacts:
- define the schema explicitly first
- decide whether it is a runtime artifact, output-adapter artifact, or oracle-only artifact
- add contract coverage for parsers and renderers
Agents should not require repeated reminders to:
- keep layer boundaries intact
- preserve strong typing
- use
Decimal - log unsupported or ambiguous facts explicitly
- update roadmap and design docs when architecture changes
- extract shared boundaries when duplication becomes obvious
- add or update tests for new behavior
- create stable checkpoint commits
These are the default operating standards for the repo.
Current runtime note: CoinTracking-specific semantics mentioned below describe current-edge drift to avoid, not canonical target naming.
Pause feature work and fix the structure first when:
- a new change would require importing across a forbidden layer boundary
- a module is becoming a new catch-all
- a hotspot module called out in
docs/standards/engineering.mdis about to absorb materially new behavior without first being split - a flat directory would end up with more than 2 same-prefix files for one capability
- a feature already owns a package but new helpers are being left beside it as flat sibling modules
- CoinTracking-specific semantics are drifting into the core domain
- bridge-era, provider, or asset-class nouns are drifting into forward-looking domain, application, id, ref, record, or directory names
- an oracle-only artifact is being treated like a required runtime input
- a quick patch would hide unsupported behavior instead of surfacing it
Before closing non-trivial work, confirm:
- the owning layer is still clear
- shared logic is extracted to the right boundary
- tests pin the new behavior
- unsupported behavior is explicit
- docs are updated if architecture or workflow changed
- a stable checkpoint commit exists or is the immediate next step