fix(close): freeze hard-close trial balance evidence - #53
Conversation
📝 WalkthroughWalkthrough이번 변경은 trial-balance snapshot의 단일성·불변성·범위·산술 검증을 추가합니다. 기간 저널 모집단 펜스와 장부-기간 권한 시드를 도입합니다. Soft-close 및 hard-close 증거 페어링을 커밋 시점에 검증합니다. 애플리케이션 조회와 설치·운영 문서를 갱신합니다. Changes기간 마감 증거 무결성
Estimated code review effort: 5 (Critical) | ~120 minutes Merge Risk: 🟡 Moderate · up to Manual deployments can omit the soft-close evidence guard, and unresolved close-path identity and reporting dependencies still risk failed or inaccurate closes. Resolve these before merge. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review 현재 exact head에서 stale |
|
Stack handoff correction — 2026-09-08 The PR body still names stale parent Do not restack this Period Close branch yet. #47 predecessor |
|
Current stack handoff update — 2026-09-08 Live parent has advanced normally/non-force to Do not restack this Period Close branch yet. The last executed #47 predecessor When #47 reaches one unchanged terminal hosted GREEN/current-review-clean successor, preserve every valid #53 delta and adopt that parent through ordinary non-force composition only; do not reuse parent checks or repair migration collisions by force-push/destructive rebase. |
|
Dependency handoff correction — 2026-09-08: the live maker-checker parent is now |
|
Dependency handoff correction: live parent #47 is now exact |
|
Stack handoff correction — 2026-09-08: live maker-checker parent is now |
|
Parent-state correction: |
|
Dependency handoff refresh: live parent is now |
|
Stack handoff refresh — 2026-09-08: live parent #47 is now exact |
|
Stack handoff refresh: live parent is now |
|
Live parent handoff correction only; no #53 source restack yet. Current parent is |
|
Parent exact-head update only: live parent is now |
|
Stack handoff correction — do not use the stale parent SHA in the PR body as current authority. Live parent is now |
|
Live parent handoff correction — 2026-09-08: #47 is now |
|
Live-parent handoff correction — 2026-09-08: do not use the body-pinned |
|
/opencode Continue PR #53 from live exact head Fresh evidence-audit finding: candidate Test-first descendant Make the smallest causal production repair:
Verify the focused real-PostgreSQL expiry/code-reuse tests first, then the complete exact-head Accounting Foundation/security/SAST/dependency/package gates. Push only a normal descendant if GREEN. Do not merge or mark Ready while the stale parent stack, current-head approval, or required evidence remains unresolved. |
|
CI admission note for exact |
|
/opencode Continue the existing #53 single-writer from live exact head Execute the already-isolated RED now: Use the checked-in real PostgreSQL regression on |
|
@codex address that feedback Continue the existing #53 source-writer lane from live exact head The verified RED is narrow: Minimal causal repair:
Keep the existing real-PostgreSQL code-reuse regression on |
|
You have reached your Codex usage limits. You can see your limits in the Codex usage dashboard. |
seonghobae
left a comment
There was a problem hiding this comment.
Current exact-head evidence-audit finding on 9c3dba6f12aa58062faa6ba11537aabef91486d8: the hard-close implementation now preserves historical posted Account Entity identity in both the retained trial-balance snapshot and the actual AIS-generated closing journal line, but the command/provenance digest still drops that identity.
_post_closing_journal() groups source balances by journal_entry_line.chart_account_id, records each P&L contra line in historical_chart_account_ids, and passes that map into _insert_journal(). _canonical_snapshot_hash() likewise serializes the account UUID. _canonical_closing_hash(), however, still serializes only chart_account_code, role, exact debit/credit, and line number. If account code X is expired and later reused by a different Account entity, the correct historical clearing line can therefore receive a source-payload hash indistinguishable from a close against the replacement Entity. The stored journal fact is Entity-specific while its immutable command evidence is not.
The checked-in real-PostgreSQL code-reuse regression on this head is the RED. Narrow GREEN: pass the existing line-number→historical-UUID map into _canonical_closing_hash() and include chart_account_id only for mapped historical P&L clearing lines; omit the field for retained earnings/current close-time policy destination. Preserve canonical JSON ordering/separators, exact Decimal formatting, ordinary active-account admission, snapshot identity, and the no-foreign-posting/no-Reporting-close-authority boundaries. Do not relax the test or add a second account lookup path.
This is a COMMENT review, not approval. The PR remains Draft/merge-conflicted with zero current-head PR workflow runs, so a source descendant is not hosted GREEN; full exact-head evidence must be reacquired after the prerequisite stack is normally integrated and the branch is non-force restacked.
|
/opencode Continue the existing #53 single-writer lane. The Codex handoff Address exact-head COMMENT review Minimal causal GREEN:
Use the checked-in real-PostgreSQL code-reuse regression on |
Accounting-control scope
trial_balance_snapshot/trial_balance_lineare retained Period Close evidence. This Draft owns the PostgreSQL Period Close foundation for one-population identity, retained-evidence immutability, tenant/legal-entity/book/reporting-currency/chart-account scope, exact monetary conservation, close-command authority, journal-population freshness, open-period posting concurrency, commit-time snapshot/status pairing, and historical posted role/account identity. Accounting Information Platform remains authoritative for journal/account/period/posting/reconciliation/financial-control truth. Billing and other foreign systems gain no posting, close, policy, reconciliation, or reporting authority.Live stack authority — 2026-09-09
Current PR head is
9c3dba6f12aa58062faa6ba11537aabef91486d8. The stored GitHub base is stillfeat/reconciliation-exception-resolution-command@6f81b258de94cf14d6af4258173d5eabc8ebad26, so this PR is Draft andmergeable=false.The live prerequisite is no longer the body-pinned historical #43/#47 generation. Current stack authority is:
#29@12e1a4bb9d8de5e4b6c72e2893107b07c515416b -> #47@263e4ffb79607dccee715686d0aa451981c2eeb8 -> #53#43 is merged history, not a separate live parent. #47 is Ready/mergeable with exact-head Accounting Foundation GREEN but still lacks a qualifying independent
APPROVEDreview. Therefore #53 must not be prematurely retargeted/restacked. After #47 normally integrates into #29, derive the resulting parent exact head, read every intervening delta, then rebuild #53 as an ordinary non-force descendant and reacquire all current-head evidence. No predecessor check or review transfers.Implemented Period Close foundation
Migrations 0029–0031 establish one retained trial-balance population per tenant/book/period, freeze retained header/line facts, own snapshot system time in PostgreSQL, enforce legal-entity -> accounting-book -> reporting-currency -> chart-account scope, and validate exact
numeric(38,6)debit/credit/net conservation.Migrations 0032/0033 protect journal-population freshness under
REPEATABLE READ/SERIALIZABLE: ordinary open-period journals update one of 64 pre-existing fence rows and period transitions lock all 64 in deterministic order. Weak isolation fails closed. SQLSTATE40001is coordination failure, not accounting evidence; retry the complete immutable command from a fresh transaction.Migration 0034 owns post-install book-period control materialization. New open periods and active books seed only literal
opencontrols plus all 64 freshness rows. Missing non-open pairs remain absent. Sharedfiscal_period.period_status_codeis only a compatibility projection and is never substituted for per-book close authority. Runtime seeding requires the exact tenant binding while the migration-owner backfill remains a separate bounded path.Migrations 0035/0036 enforce the bidirectional
hard_closed <-> retained trial_balance_snapshotcommit pair, including fail-closed upgrade preflight for legacy one-sided states under FORCE RLS. Migration 0037 requires soft-close command identity, immutable source payload hash, and source-journal-count evidence.These controls are repository-owned DDD/database mechanisms; IFRS does not prescribe these PostgreSQL implementation details.
Historical account identity and close authority
The first temporal-authority repair moved historical revenue/expense classification from mutable current
account_role_mappingto immutable postedjournal_entry_line.account_role_code.Real-PostgreSQL expiry/code-reuse REDs then established the stronger Entity boundary: Period Close must clear the exact immutable posted
journal_entry_line.chart_account_id, not re-resolve a reused account code against the current catalog. Production candidate3832cf72110ebc39d3978135400e0fb9378c34accarries the posted account UUID only for AIS-generated historical P&L clearing lines; ordinary_insert_journal()continues to require an active account, retained earnings remains a current close-time policy destination, and Reporting projection completeness is not allowed to become a second hard-close authority. Snapshot evidence now binds the exact account Entity. Doctoring successor7c75e05626fa8c7477089c1272bb43719d66bb17records that boundary.Current evidence-audit RED
Fresh review found one remaining identity gap in the closing-journal command evidence.
_post_closing_journal()already carrieshistorical_chart_account_idsinto the actual closing journal, and_canonical_snapshot_hash()bindschart_account_id; however_canonical_closing_hash()still serializes only account code, role, exact amounts and line number. Two legally distinct historical account Entities that reuse the same code can therefore produce the samejournal_proposal_record.source_payload_hasheven though the actual clearing line is intentionally Entity-specific.Exact RED head
9c3dba6f12aa58062faa6ba11537aabef91486d8extends the real PostgreSQL code-reuse scenario and requires the stored closing-journal source hash to include the exact historicalchart_account_idfor historical P&L lines while excluding it from the current retained-earnings destination.Selected narrow GREEN: pass the existing
historical_chart_account_idsmapping into_canonical_closing_hash()and serializechart_account_idonly for mapped historical lines. Preserve canonical serialization, exact Decimal formatting, ordinary active-account admission, retained-earnings current mapping, snapshot-hash identity and the no-posting/no-close foreign-system boundary. Do not relax account admission globally or invent a second Reporting/Period Close authority.Exact-head COMMENT review
5147490036records this causal finding. Codex execution handoff5592475501failed before source work with connector response5592476807(Codex usage limits), so it produced no descendant and is not an active writer. Current source-writer fallback is/opencodecomment5592533532, continuing the same single-writer lane. It must re-read the live head, ordinary-adopt any intervening descendant, and never force-push/rebase.Verification state
Current exact head
9c3dba6f12aa58062faa6ba11537aabef91486d8has 0 pull-request workflow runs. This is not GREEN and not runner-queue evidence. The PR remains merge-conflicted against its stale stored parent. Preserve the checked-in RED and reacquire hosted Accounting Foundation, exact 100% production statement/branch coverage, repository contracts, security/SAST/dependency/package/SBOM/provenance/recovery evidence only after the stack is conflict-free.Current inline review threads are resolved at source level, but resolved threads and COMMENT review do not substitute for exact-head GREEN or independent approval. Keep Draft. Do not merge, auto-merge, self-approve, bypass protection, manufacture status/no-op commits, force-push, destructively rebase, tag, or release while required evidence is absent or non-terminal.
Documentation and downstream ownership
Canonical
CHANGELOG.md,docs/doctoring/STANDARD_TRACEABILITY.md,docs/product-technical-gap-baseline.md, README/public product wording and their contracts remain PR #37's single-writer responsibility. #37 must reconstruct the durable invariant only after protected integration: effective-dated account-role/chart-account changes cannot retrospectively change, strand, redirect, or provenance-alias immutable historical account identity used by Period Close.PR #52 consumes this foundation only after normal integration and non-force restack. Reporting must not synthesize close control/snapshot/freshness/currency/calculation authority, infer book state from shared
fiscal_period, reconstruct historical account identity from current catalogs when immutable journal/snapshot evidence exists, or veto a valid hard close because a buyer projection is incomplete.