# Statement Classification specification
Pair: [user guide](../../user/accounting/statement-classification.md). Entry public/classify.php; classifier.js, classifier.css, classifier-category-chooser.js/css; classification-api.php. Private files: classification.php loader, classification_catalog.php, classification_records.php, classification_review.php and rule modules.
## API and state
GET init returns sets, values, businesses, accounts, statements, rules and csrf. cf_catalog synchronizes the category projection and augments category values with parent_id/origin/depth. applicability is empty and has no eligibility meaning. cf_statements computes unfinished from saved snapshots, not suggestions alone.
POST load {statement_id}: transactionally locks statement, evaluates rules and permitted auto-commit, loads saved snapshots and reviewed suggestion evidence. Returns statement, rows, view_token, auto_committed and refreshed statement list. Session classification_view freezes statement ID, defaults and each row's saved snapshot and suggestions.
POST save {view_token,rows:[{id,draft}]}: rows must belong to frozen view, at most 5,000 entries. Lock statement; defaults and each current snapshot must equal frozen values. Reject stale view instead of overwriting. Validate drafts, skip unchanged previously saved rows, append revisions/projections/audit for changed or initial saves; transaction rollback on any error. Invalidate view after success.
POST context {statement_id,business_id,manual_review}: active business required if specified. Missing business forces manual review. Updates statement defaults and invalidates view. Does not rewrite saved classifications. Other endpoint actions are specified in [Rules](rules.md); movements calls the accounting latest-revision view.
## Draft and validation
Draft fields: use_type numeric catalog ID|null, accounting_category ID|null, business_id ID|null, business_percent decimal string|null. Saved fields take precedence over suggestions; statement defaults fill only unsaved relevant business context. Business becomes 100%, personal 0%; mixed accepts strictly between 0 and 100 with at most two fractional digits. IDs must belong to the correct classification set. Inactive existing selections may be retained; new inactive/deleted categories reject.
Use and Category are independently chosen. No category applicability filtering. Personal ignores business; business/mixed require appropriate details for completeness. Validation permits partial saves; cf_complete separately decides finished status. Missing/Unspecified Use or Category is unfinished. Every non-Unspecified category level, including a broad parent, can complete a row.
## Writes and history
cf_snapshot delegates to latest accounting revision. cf_write validates, appends financial allocation revision, updates changed classification projections, records accepted/overridden suggestion events, updates allocation projection and appends classification audit. Original source rows/vectors and earlier revisions remain immutable.
Status derives from saved state, suggestion evidence, completeness and unsaved client edits. Suggestions alone do not count as saved completion. Previously saved partial rows do not auto-commit merely by reopening. Reviewed suggestions are preserved from revision metadata so rule changes do not rewrite the explanation of earlier choices.
## Category chooser contract
StatementCategoryChooser.mount enhances existing row select controls, not storage. Active values only, same across every Use. Each open clears expanded state; show roots collapsed. Arrow only expands/collapses; name selects any level by setting select.value and dispatching its existing change event. Full selected path label. Clear Choose… selects empty string. Outside click closes; Escape closes and returns focus to trigger. Existing inactive selected label remains readable but absent from offered choices.
Rule creation still uses its existing category select in this baseline; the approved collapsed-tree change targets statement rows. Do not claim the same enhanced chooser was installed in the rule drawer.
## Verification
Category selection leaves Use unchanged. Same active tree for personal/business/mixed. Parents selectable, inactive descendants hidden, previous inactive retained. Clearing saves null and remains unfinished. Mixed validation boundaries. Statement default does not rewrite saved rows. Save includes populated/edited rows hidden by unfinished filter. Concurrent row/default edits reject. Repeated save of unchanged stored row does not append gratuitous revision. Original payment preserved and latest allocation view totals once.
## Planned extensions
The intended future name is Classify transactions, with statement as one organizational view among others. This stage retains Classify statements and its current controls. No new views are implied or implemented.