Skip to content

feat(core): order accepted project changes - #1382

Open
phernandez wants to merge 6 commits into
codex-1863-wiki-projector-corefrom
codex-1863-wiki-project-partition
Open

feat(core): order accepted project changes#1382
phernandez wants to merge 6 commits into
codex-1863-wiki-projector-corefrom
codex-1863-wiki-project-partition

Conversation

@phernandez

@phernandez phernandez commented Aug 30, 2026

Copy link
Copy Markdown
Member

Why

The deterministic Wiki projector needs a stable source watermark and durable, replayable accepted-change evidence. Timestamps, webhook arrival, and workspace activity cannot provide the strict project-local order required by SPEC-88 or the compatible future journal described by SPEC-83.

This is the second Core PR in the Spec 88 stack. It builds on #1381 and supports basicmachines-co/basic-memory-cloud#1863.

What Changed

  • Add an atomic Project.partition_position counter and Alembic migration.
  • Claim exactly one new partition position inside every successful canonical note create, update, edit, move, and delete transaction.
  • Persist each accepted project note change in a project-local journal in the same transaction as the note mutation.
  • Carry the same typed project-change evidence through accepted responses, materialization work, and file-delete cleanup.
  • Record operation, canonical paths, accepted revision checksum/version, source, actor, and timezone-aware acceptance time.
  • Track when each accepted revision reaches storage so a projector can defer incomplete source ranges safely.
  • Preserve rollback semantics so rejected or failed mutations consume neither positions nor journal rows.

Implementation Details

ProjectRepository.advance_partition_position() uses one SQL UPDATE ... SET partition_position = partition_position + 1 RETURNING partition_position, keeping the claim atomic on SQLite and PostgreSQL. The position claim and AcceptedProjectNoteChange row are written before the caller-owned transaction commits, so note state and ordering evidence succeed or roll back together.

The journal deliberately retains delete evidence after an entity is removed and exposes ordered range reads plus an idempotent materialization marker. RuntimeAcceptedProjectNoteChange remains runtime-neutral and storage-neutral; it is attached to existing materialization and cleanup requests instead of introducing a second queue or filesystem.

Testing

  • just fast-check
  • uv run pytest -q tests/repository/test_project_partition_repository.py tests/indexing/test_accepted_note_mutation_runner.py tests/api/v2/test_accepted_note_atomicity.py
  • uv run pytest -q tests/repository/test_project_partition_repository.py tests/indexing/test_accepted_note_mutation_runner.py tests/api/v2/test_accepted_note_atomicity.py tests/runtime/test_runtime_job_payloads.py tests/runtime/test_project_partition.py
  • BASIC_MEMORY_TEST_POSTGRES=1 uv run pytest -q tests/repository/test_project_partition_repository.py
  • uv run pytest -q tests/test_note_content_migration.py
  • Alembic reports s2p3e4c5w6k7 as the single head.
  • Load-bearing checks: changing the partition increment from +1 to +2 failed the ordering tests; removing the accepted-journal write failed the end-to-end API materialization-boundary test. Restoring each implementation returned the focused tests to green.

Risks / Follow-ups

  • This PR establishes Core's ordered accepted-evidence journal; durable Cloud scheduling and Wiki run-ledger state remain in the dependent Cloud stack.
  • Cloud scheduling, coalescing, projector execution, and canonical reserved-note writes land in the dependent Cloud PR.
  • No model calls, agent dependency, or mirrored Wiki filesystem are introduced.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T03:39:18.905678Z 1879452 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@phernandez
phernandez force-pushed the codex-1863-wiki-project-partition branch from d723b19 to 5b9501a Compare August 30, 2026 01:35

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d723b197d7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

entity_id=materialization.entity_id,
db_version=materialization.db_version,
db_checksum=materialization.db_checksum,
project_change=materialization.project_change,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve partition evidence across worker serialization

When a hosted enqueuer converts this request through RuntimeNoteMaterializationJobPayload.from_runtime_request, the payload model and both conversion methods omit project_change, so the worker reconstructs the request with project_change=None; RuntimeNoteFileDeleteJobPayload has the same omission for deletes. The transaction has already advanced the durable partition head, so queued materializations and deletes permanently lose the corresponding ordered change and downstream consumers observe a gap that retries cannot repair. Add this evidence to both Pydantic worker payload round trips.

AGENTS.md reference: AGENTS.md:L128-L129

Useful? React with 👍 / 👎.

Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez
phernandez force-pushed the codex-1863-wiki-project-partition branch from 5b9501a to 3897cc3 Compare August 30, 2026 01:51
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3897cc3918

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +613 to +617
change = await delete_accepted_note(
session,
project_id=project.id,
entity=entity,
note_content=note_content,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Refresh delete evidence after acquiring the note lock

When an update or move commits after entity/note_content are loaded but before delete_accepted_note acquires its existing NoteContent lock, these ORM objects retain the old title, path, version, and checksum; the delete then removes the newer row but permanently records the deletion using this stale snapshot. In particular, a concurrent move can leave the new directory's wiki projection unchanged because the durable delete event names only the old path, and no later pass can correct the journal entry. Acquire the existing lock before loading the evidence, or explicitly refresh the locked entity and NoteContent before constructing both the delete plan and project_change.

AGENTS.md reference: AGENTS.md:L184-L188

Useful? React with 👍 / 👎.

Signed-off-by: phernandez <paul@basicmachines.co>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5d35ec7fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

accepted_note_changes = relationship(
"AcceptedProjectNoteChange",
back_populates="project",
cascade="all, delete-orphan",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Let the database cascade journal deletion

When a long-lived project with a large mutation history is deleted, cascade="all, delete-orphan" with the default passive_deletes=False makes SQLAlchemy load every journal row and delete it through the ORM, even though the foreign key already specifies ON DELETE CASCADE. Because this table grows once per accepted mutation rather than once per note, project deletion can consume excessive memory or time out; configure the relationship with passive_deletes=True or delete these rows in bulk.

Useful? React with 👍 / 👎.

Signed-off-by: phernandez <paul@basicmachines.co>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7bbafd3ce4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +241 to +243
AcceptedProjectNoteChange.project_id == project_id,
AcceptedProjectNoteChange.partition_position == partition_position,
AcceptedProjectNoteChange.materialized_at.is_(None),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Mark superseded partition changes as satisfied

When two writes to the same note are accepted before the first materialization runs, the first job exits as stale after the second advances db_version, while this update API can mark only the exact newer partition position. The older journal row therefore remains materialized_at = NULL permanently; plan_wiki_projection() treats every such position above its watermark as pending, so one normal rapid-save race blocks that project's projector and all subsequent changes indefinitely. Mark superseded positions as satisfied when a newer generation materializes, or represent a terminal superseded state rather than leaving them indistinguishable from pending.

AGENTS.md reference: AGENTS.md:L184-L186

Useful? React with 👍 / 👎.

Signed-off-by: phernandez <paul@basicmachines.co>
Signed-off-by: phernandez <paul@basicmachines.co>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1985fb1b21

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +415 to +417
graph_silent_markdown = prepared.entity_markdown.model_copy(
update={"observations": [], "relations": []}
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve graph silence through materialization indexing

When publish_graph_facts=False is used for a derived note containing observation or relation syntax, this only clears the parsed model used by the accept transaction; the canonical Markdown remains unchanged, and the local materialization flow immediately calls file_indexer.index_file() (note_content_materialization.py:722-727), which reparses those bytes and publishes the facts again. The generated Wiki note therefore becomes part of the graph after materialization—and every later reindex restores that wrong state—defeating the recursion guard. Carry the graph-silent policy into indexing or otherwise suppress facts based on durable provenance.

AGENTS.md reference: AGENTS.md:L161-L166

Useful? React with 👍 / 👎.

Signed-off-by: phernandez <paul@basicmachines.co>
@phernandez
phernandez force-pushed the codex-1863-wiki-project-partition branch from 8dfd16a to 1879452 Compare August 30, 2026 03:33
@phernandez

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. What shall we delve into next?

Reviewed commit: 18794524ed

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant