Repository navigation
factory r3: round-3 schema and vocabulary (one migration, entities, stores, Actor/refs, views, web types, fixture) - #137
Merged
Merged
Conversation
LittleChimera
force-pushed
the
round3/r3-03
branch
from
October 27, 2026 20:34
36fa770 to
239d38c
Compare
…tores, Actor/refs, views, web types, fixture) All round-3 persistence lands in one forward-only migration (fz1a2b3c4d5e) so later packages add no migrations: - 12 tables: factory_people, factory_chat_messages, factory_chat_reads, factory_proposals, factory_tasks, factory_loops, factory_issues, factory_spans, factory_cost_daily, factory_versions, factory_definitions, factory_feedback (workspace-led keys, Uuid16 ids, SMALLINT enums with named CHECKs, compressed JSON, no foreign keys). - New columns on factory_projects (status, parent_slug, closed_at, def_version, version_id), factory_prs (opened_at, first_ready_at, task_id, version_id) and factory_decisions (assignee, claimed_by, claimed_at, thread, subject); ck_factory_decisions_source widened to 1..9 via batch_alter_table. Data layer only, no behaviour change: - enum codecs for every new enum; decision sources proposal/loop/ access_request/done_check. - entities and FactoryStore CRUD + queries (in-memory and SQL) for every table, each naming its consumer package; per-factory numbering (C-n, T-n, INC-n/F-n, chat seq, definition versions) is serialized with advisory locks on PostgreSQL plus UNIQUE-retry; spans insert-or-ignore by dedupe_key; cost ledger atomic upsert-increment; versions deduped by content hash. - omnigent/factory.py vocabulary (labels, ROLE_PLANNER, decision actions, states/kinds/taxonomies, thread keys); the planner registers the roster tool only. - server/factory/actor.py: Actor plus ref parsing/formatting for T-n, C-n, D-n, INC-n, F-n, !n, #slug, p:<slug>, task:<slug>/<key>. - schemas.py round-3 views (PersonView, ViewerBlock, ChatMessageView, ThreadView, ProposalView, TaskView, LoopView, IssueView, SpanView, NowState, DefinitionView) and optional snapshot additions; matching factoryApi.ts types. - snapshot.round3.json fixture (7 projects incl. base-env, 41 agents, 3 humans, C-4 pending, db-version task graph, implement 3/3 exhausted, INC-13, C-14 on trial, def_version 7) validated by the contract test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- put_definition raises DefinitionVersionExists only for an explicit version; an auto-numbered put that loses its number replays. - _write replays UNIQUE collisions and lock conflicts (MySQL 1213/1205, PostgreSQL 40001/40P01) with jittered exponential backoff; numbered sequences get a larger budget and are serialized on MySQL with a GET_LOCK named lock held across the write (advisory lock on Postgres). - Both stores clip free-text values to their VARCHAR bounds. - append_chat with an existing message_id returns the stored message in both stores. - The role guard imports ROLE_PLANNER from the vocabulary (R3-04 TODO). - project_ref formats projects named like a Room thread as p:<slug>. - pydantic floor raised to 2.11 (validate_by_name / serialize_by_alias). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LittleChimera
force-pushed
the
round3/r3-03
branch
from
October 27, 2026 21:04
239d38c to
35d1927
Compare
Raising the floor touched uv.lock, which trips the OSV scan in the security gate. _ClassView now uses populate_by_name and dumps by alias by default, which hold on any pydantic 2.x. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 of 13 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Related issue
Closes #
Round-3 work package R3-03 (schema and vocabulary). Spec: ROUND3-SPEC §16, plus the data shapes of §8–§15.
Summary
All round-3 persistence lands in one forward-only migration, so the later round-3 packages add no migrations and never fight over alembic heads. This is the data layer only: nothing calls the new tables yet, so runtime behaviour does not change.
fz1a2b3c4d5e(chains afterfy1a2b3c4d5e, the single head on staging):factory_people,factory_chat_messages,factory_chat_reads,factory_proposals,factory_tasks,factory_loops,factory_issues,factory_spans,factory_cost_daily,factory_versions,factory_definitions,factory_feedback. They follow the cockpit conventions:workspace_id-led keys,Uuid16ids, SMALLINT enums with named CHECKs, compressed JSON, and no foreign keys.factory_projects:status(default 1),parent_slug,closed_at,def_version,version_id.factory_prs:opened_at,first_ready_at,task_id,version_id.factory_decisions:assignee,claimed_by,claimed_at,thread,subject.ck_factory_decisions_sourceis dropped and recreated asIN (1..9)throughbatch_alter_table, so it also works on SQLite.downgrade()reverses everything.proposal=6,loop=7,access_request=8,done_check=9) and frozen entity dataclasses.FactoryStore, with in-memory and SQL implementations that behave the same). Each method's docstring names the package that will use it.(project, key), an atomic attempt counter;(kind, subject);dedupe_key(bumps the count and reopens resolved issues), numbered per class;dedupe_key, open-span and range queries;C-n,T-n,INC-n/F-n,D-n, chatseq, definition versions) are serialized where the backend can: a transaction advisory lock on PostgreSQL, aGET_LOCKnamed lock held across the write on MySQL, andBEGIN IMMEDIATEon SQLite. Every write replays UNIQUE collisions and lock conflicts (MySQL 1213/1205, PostgreSQL 40001/40P01) after a jittered exponential pause; sequence writes get a larger budget (12), because CockroachDB serializes nothing and relies on the key.DataErroron PostgreSQL.append_chatwith amessage_idthat already exists returns the stored message in both stores (a replayed append adds nothing).omnigent/factory.py):def_version,version,bundle,mode;ROLE_PLANNER, which is inROLESbut notTOP_LEVEL_ROLES. The planner registers the roster tool only, matching spec §18. The role guard now imports it from here (R3-04 defined it locally with a TODO), and R3-04's planner rules apply;LABEL_DEFAULT_REPO,LABEL_DEFAULT_BASE,PROJECT_KINDSand theProjectKindview type come from R3-01 (merged first); this PR reuses them.server/factory/actor.py:Actor(§10.1) plus ref parse/format/find forT-n,C-n,D-n,INC-n,F-n,!n,#slug,p:<slug>andtask:<slug>/<key>. A project sluggedfactoryorimprovementsformats asp:<slug>, so it never reads back as a Room thread.classalias views (ProposalView,IssueView) usepopulate_by_nameand dump by alias by default, so they construct by attribute name and emitclasson any pydantic 2.x (validate_by_name/serialize_by_aliasalone need 2.11). Raising the floor instead would touchuv.lock, which trips the security gate's OSV scan.schemas.pyaddsPersonView,ViewerBlock,ChatMessageView,ThreadView,ProposalView,TaskView,LoopView,IssueView,SpanView,NowStateandDefinitionView.viewer,people_count,presence,counts,def_version,engine_mode, project/PR/member/decision extras andtotals.usd_per_h.factoryApi.tsmirrors them.TeamStripgets the planner label.snapshot.round3.json, derived from the live run:base-env(integration);agent.repeat) and C-14 (tuning) on trial;Test Plan
uv run --frozen pytest -q tests/db/test_migration_factory_round3_tables.py tests/stores/test_factory_store_round3.py tests/factory/test_factory_vocabulary.py tests/server/factory/test_contract_fixture.pystatus=1, that each CHECK accepts its last code and rejects the next, and that the downgrade drops round-3 decision sources.Actor.OMNIGENT_TEST_DB_URI=postgresql+psycopg://…. The wholetests/db+tests/storesset passes there too (1335 passed), except the Databricks volume store, which needs thedatabricksextra.pytest tests/server/factory tests/runner tests/examples tests/policies tests/test_factory_gates.py tests/factory tests/integration/test_factory_tree.py: everything passes except 7 runner tests that fail locally for environment reasons. 4 need thedatabricksmodule, 1 needslinux_bwrap(Linux only), and 2 compare against the local Claude subscription model catalog. None of these touch factory code.alembic headsreturnsfz1a2b3c4d5eonly.test_definition_numbering_replays_unserialized_racersraces 8 auto-numberedput_definitioncalls with the sequence lock off (the CockroachDB situation); with the oldDefinitionVersionExistscheck it failed 1 run in 3 on PostgreSQL, with the fix it passes every run.test_writes_replay_lock_conflictspins the replay classification: MySQL 1213/1205 and PostgreSQL 40P01 replay, other operational errors raise at once.npm run type-check,npm run lintandnpm run format:checkpass; vitest onsrc/components/factory,src/lib/factory*andsrc/pages/factorypasses (634 tests);storybook buildpasses.pre-commit run --files <changed>: ruff, the hardcoded-model check, prettier, oxlint and web-tsc all pass. pyrefly shows no errors in the touched files (the existing 24 are missing opentelemetry imports and one launcher override).Demo
N/A. No visible UI change; the only web edits are types and the planner role label.
Type of change
Test coverage
Coverage notes
Manual verification: I ran the migration and store suites against a throwaway local PostgreSQL 16 container, which is the same image as CI's stores-postgres lane.
Not verified locally:
alembic upgrade headon a copy of the sandbox database. The Postgres test seeds cockpit-era rows and upgrades them instead.Updated existing tests:
fy1a2b3c4d5e→fz1a2b3c4d5e;test_enum_codecs.py;🤖 Generated with Claude Code