Codex audit of cbf9e03 surfaced two P1 gaps + one P2 scope concern,
all verified with code-level probes. Patches below.
P1: promote_entity did not re-check F-8 at status flip.
Legacy candidates with source_refs='[]' and hand_authored=0 can
exist from before V1-0 enforcement. promote_entity now raises
ValueError before flipping status so no F-8 violation can slip
into the active store through the promote path. Row stays
candidate on rejection. Symmetric error shape with the create
side.
P1: supersede_entity was missing the F-5 hook.
Plan calls for synchronous conflict detection on every
active-entity write path. Supersede creates a `supersedes`
relationship rooted at the `superseded_by` entity, which can
produce a conflict the detector should catch. Added
detect_conflicts_for_entity(superseded_by) call with fail-open
per conflict-model.md:256.
P2: backfill script --invalidate-instead was too broad.
Query included both active AND superseded rows; invalidating
superseded rows collapses audit history that V1-0 remediation
never intended to touch. Now --invalidate-instead scopes to
status='active' only. Default hand_authored-flag mode stays
broad since it's additive/non-destructive. Help text made the
destructive posture explicit.
Four new regression tests in test_v1_0_write_invariants.py:
- test_promote_rejects_legacy_candidate_without_provenance
- test_promote_accepts_candidate_flagged_hand_authored
- test_supersede_runs_conflict_detection_on_new_active
- test_supersede_hook_fails_open
Test count: 543 -> 547 (+4). Full suite green in 81.07s.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase V1-0 of the Engineering V1 Completion Plan. Establishes the
write-time invariants every later phase depends on so no later phase
can leak invalid state into the entity store.
F-1 shared-header fields per engineering-v1-acceptance.md:45:
- entities.extractor_version (default "", EXTRACTOR_VERSION="v1.0.0"
written by service.create_entity)
- entities.canonical_home (default "entity")
- entities.hand_authored (default 0, INTEGER boolean)
Idempotent ALTERs in both _apply_migrations (database.py) and
init_engineering_schema (service.py). CREATE TABLE also carries the
columns for fresh DBs. _row_to_entity tolerates old rows without
them so tests that predate V1-0 keep passing.
F-8 provenance enforcement per promotion-rules.md:243:
create_entity raises ValueError when source_refs is empty and
hand_authored is False. New kwargs hand_authored and
extractor_version threaded through the API (EntityCreateRequest)
and the /wiki/new form body (human wiki writes set hand_authored
true by definition). The non-negotiable invariant: every row either
carries provenance or is explicitly flagged as hand-authored.
F-5 synchronous conflict-detection hook on active create per
engineering-v1-acceptance.md:99:
create_entity(status="active") now runs detect_conflicts_for_entity
with fail-open per conflict-model.md:256. Detector errors log a
warning but never 4xx-block the write (Q-3 "flag, never block").
Doc note added to engineering-ontology-v1.md recording that `project`
IS the `project_id` per "fields equivalent to" wording. No storage
rename.
Backfill script scripts/v1_0_backfill_provenance.py reports and
optionally flags existing active entities that lack provenance.
Idempotent. Supports --dry-run and --invalidate-instead.
Tests: 10 new in test_v1_0_write_invariants.py covering F-1 fields,
F-8 raise + bypass, F-5 hook on active + no-hook on candidate, Q-3
fail-open, Q-4 partial scope_only=active excludes candidates.
Three pre-existing conflict tests adapted to read list_open_conflicts
rather than re-run the detector (which now dedups because the hook
already fired at create-time). One API test adds hand_authored=true
since its fixture has no source_refs.
conftest.py wraps create_entity so tests that don't pass source_refs
or hand_authored default to hand_authored=True (tests author their
own fixture data — reasonable default). Production paths (API route,
wiki form, graduation scripts) all pass explicit values and are
unaffected.
Test count: 533 -> 543 (+10). Full suite green in 77.86s.
Pending: Codex review on the branch before squash-merge to main.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>