Skip to content

M1 external review: Gate B approved

Reviewed: 2026-07-25 Issue: hector-sanchez-eu/conductor#3

Status note (2026-07-26): This file preserves successive historical review findings. The active handoff is now review requested; Gates A-D, schema creation, candidate import, representative review, and fresh-client foundation retrieval completed after the decisions below. See gate-status.md and handoff.md.

Historical decision: Keep M1 at definition. Gates A and B are approved; Gates C and D remain blocked.

This review is the current external decision for M1. The earlier handoff is implementation-agent evidence, not verification.

Gate C scope decision (2026-07-26)

Hector approved proceeding with Gate C and clarified that the real-estate application is an example used to prove Conductor can discover and analyze an application correctly. It is not a manually enumerated Gate C prerequisite.

Gate C now approves source-defined discovery: bounded source locators, exclusions, least-privilege credentials, privacy filtering, pagination, and explicit partial/denied/stale/unavailable behavior. After activation, the live dry run selects at least one representative application—or a related group—for reviewed golden-path evidence, preferably real estate when a suitable candidate is found.

Conductor-Gate-C: approve is recorded on issue #3. Operator discovery is complete for the accepted application boundary; runtime adapters remain fail-closed without dedicated read bindings. Gate D mutation/import remains blocked pending package approval.

Hector subsequently approved authenticated gh for the initial operator dry run. This does not alter the adapter credential boundary. The first GitHub enumeration initially covered 102 repositories across the three approved owners and discovered two real-estate-domain candidates: germany-real-estate-intelligence and modular-property-management. Initial evidence treats them as related but not duplicates because they serve investors and property managers respectively.

After the private incubator publication, the refreshed boundary contains 103 GitHub repositories and 29 incubator projects. Excluding the incubator container, the source registry contains 131 candidate project units. Gate C is complete.

Gate B final re-review: approved

Re-reviewed: 2026-07-25 against the uncommitted remediation on durable baseline dcb7b8a.

The independent reviewer found no remaining Gate B bypass and recommends approval. The final implementation:

  • accepts only parser-issued EstateComparison, validator-issued PhysicalBatchReport, and factory-issued ExhaustiveSnapshot objects;
  • binds the snapshot to the validated batch, mapped estate, comparison, asserted need, source completeness, and snapshot version;
  • strictly parses comparison payloads, rejects ambiguity, and validates actor, freshness, privacy, exact Asset coverage, dispositions, no-gap evidence, and semantic extends evidence;
  • validates all physical Asset child stores and Decision/Event rows, including identifiers, required fields, duplicates, orphans, relation cardinality/pagination, privacy, dates, and target membership;
  • treats Initiatives as authoritative event context: redacted or malformed rows fail closed, duplicate IDs/pages fail, and caller-supplied relation indexes cannot confer authority.

Final adversarial verification covers direct constructor forgery, estate substitution, malformed scalar/payload values, empty and orphan child rows, ambiguous or invalid events, incomplete Initiative relations, redacted/malformed/duplicate Initiatives, and forged Initiative indexes.

External recommendation: Conductor-Gate-B: approve for asset-registry.v2 and the typed EstateComparison boundary. This does not authorize Gate C live reads or Gate D mutation/import.

Gate B EstateComparison re-review (superseded by final approval above)

Re-reviewed: 2026-07-24 after remediation commit 469e5fa and durable tip dcb7b8a.

The architecture is substantially improved, but its claimed authority and exhaustiveness boundaries remain forgeable:

  1. Typed authority objects are publicly forgeable. EstateComparison, ExhaustiveSnapshot, and PhysicalBatchReport have public constructors; adapter_seal() publicly returns the private seal; the runtime test helper bypasses parser validation; and evaluate_reuse does not verify the comparison seal (estate_comparison.py:47-65,105-183,282-324; reuse.py:129-135). Reproduced: a caller-manufactured typed comparison and snapshot produced forged_typed_result=new without an authoritative event or physical read.
  2. Physical batch validation still seals malformed child state. Repository/environment rows may omit IDs, schema, Asset relation, URL, role/environment, and privacy; uniqueness, relation cardinality, target membership, and freshness are not enforced (physical.py:242-262; state-model.md:214-241). Reproduced: repositories=[{}], environments=[{}] produced empty_child_batch_ok=true.
  3. The snapshot is not bound to the estate it certifies. ExhaustiveSnapshot contains completeness labels and flags but no source version, record-ID set, batch digest, mapped-estate digest, request, or comparison binding (estate_comparison.py:105-138). A valid snapshot can be reused with substituted mutable Asset dictionaries.
  4. Comparison selection is ambiguous and under-validated. Preparation chooses the first parseable need-matching event without ordering, latest/non-superseded selection, comparison ID/version, or conflict rejection (app.py:424-434). Parser authority does not enforce actor ownership, freshness, or comparison privacy compatibility.
  5. Any existing event can still support extend. Event evidence resolution proves only that an event ID exists, not that its class/type/assets/need/delta/reviewer/privacy support the relationship (physical.py:607-684; reuse.py:557-620).
  6. Payload parsing is not schema-safe. A valid JSON array reaches .get and crashes instead of returning parser errors (estate_comparison.py:327-348). Reproduced: comparison_payload=[] raised AttributeError. Numeric 0/1 also satisfy the current Boolean test.
  7. Global orphan/cardinality validation remains incomplete. Valid-shaped evidence and relationships targeting unknown Assets can pass; event related-Asset resolution, duplicate event/page indexes, and complete relation cardinality/pagination are not fully bound into the batch report (physical.py:103-240,538-604).
  8. Privacy/freshness are not consistently bound. Comparison, evidence, relationship, and event privacy are not all checked against the request/Assets; provenance and comparison freshness do not use the configured freshness window.
  9. Repository/environment stores are queried but not mapped into Assets. Their current contribution to exhaustiveness is envelope status plus weak batch checks, not authoritative Asset bindings (app.py:326-363).

Gate B remains changes-requested. Gate C live access was not required or treated as a Gate B failure.

Gate B event-bound re-review (superseded by EstateComparison findings above)

Re-reviewed: 2026-07-24 after remediation commit 636f06d and durable tip 9b68898.

The named close-out tests now fail closed, but Gate B still permits decisive semantic and physical bypasses:

  1. Decision/Event binding does not bind the decisive payload. _bind_event checks event identity, type, need, actor, date, Asset, and claim/disposition IDs, but not claim polarity/text/citations or disposition status/negative claim/evidence (reuse.py:523-569,575-650,795-869). Reproduced: an authentic claim event was reinterpreted with opposite polarity and produced reinterpreted_claim=new.
  2. Overbroad event classes authorize comparisons. AUTHORITATIVE_EVENT_CLASSES includes asset-verification and other, beyond the documented estate-comparison / portfolio-disposition authority (reuse.py:41-48,548-553; state-model.md:330-332). Reproduced: event_class=other produced other_class_claim=reuse.
  3. Arbitrary evt.* relationship evidence can authorize extend. Direct event IDs are marked resolved by prefix without lookup or event validation (physical.py:500-518; reuse.py:755-784). Reproduced: evt.fake produced fake_event_extend=extend.
  4. Global physical validation misses malformed orphan rows. validate_physical_batch performs only ID/duplicate checks, while full validation runs only after association with a mapped Asset (physical.py:84-135,204-265). Reproduced: an orphan evidence row with wrong schema/enums and a future date returned orphan_batch_errors=[].
  5. The physical Decision/Event schema cannot represent required bindings. The evaluator requires asserted_need, claim_ids, and disposition_ids, but the Decisions/Events property table defines none of them or their Notion types (state-model.md:296-332; reuse.py:548-569). Tests inject flattened Python fields rather than Notion-shaped records.
  6. Exhaustiveness is not sealed at the evaluator boundary. search_exhaustive remains an ordinary Boolean argument; direct/future callers can set it without adapter provenance (reuse.py:96-107,380-418).
  7. Orphan, duplicate, truncated, privacy, and freshness validation remains incomplete. Event rows are absent from batch validation; duplicate event/page IDs overwrite; relation cardinality and has_more are ignored; event/relationship privacy compatibility and provenance freshness are not fully enforced (physical.py:51-169,367-464; reuse.py:504-572).
  8. Authoritative repository/environment stores are omitted from exhaustiveness. The preparation path does not query asset_repositories or asset_environments, despite those being physical Asset stores (app.py:321-400; state-model.md:214-241).

Gate B remains changes-requested. Gate C live access was not required or treated as a Gate B failure.

Gate B close-out re-review (superseded by event-bound findings above)

Re-reviewed: 2026-07-24 after remediation commit 5ef8a67 and durable tip 3607ca0.

Gate A was explicitly approved by Hector on issue #3 with Conductor-Gate-A: approve, naming state-model.v2 / c519ee3. The approval remains design-only; Gate D still owns database creation/import.

The literal v2.2 regression cases now fail closed, but Gate B still permits unsupported decisive outcomes:

  1. Caller-authored assertions masquerade as reviewed evidence. Claims/no-gap validation accepts caller-supplied need, reviewer, date, assertion text, and an Asset locator; no authoritative Decision/Event or comparison record binds the citation to the semantic claim (reuse.py:440-531). Reproduced: an invented capability claim with well-shaped metadata produced invented_semantic_claim=reuse.
  2. Unsupported statuses and duplicate Asset IDs shrink the comparison set. Visible rows outside exact reviewed/candidate are ignored, and sets/maps silently collapse duplicate IDs (reuse.py:114-126,344-345). Reproduced: unknown_status_new=new and duplicate_asset_reuse=reuse.
  3. Candidate dispositions remain unreviewed caller objects. Candidate-specific citation binding is fixed, but dispositions have no unique ID, negative claim, asserted need/request, reviewer, reviewed timestamp, or authoritative event; duplicates are silently collapsed (reuse.py:612-647). Reproduced: candidate_unreviewed_disposition=new.
  4. Exhaustiveness ignores redacted child/GitHub records. The preparation path checks only redacted mapped Assets before deriving search_exhaustive; redacted evidence, relationships, and GitHub repositories can remain under complete envelopes (app.py:335-350; physical.py:61-63,104-107).
  5. extends request binding is not physically realizable and relation evidence is unresolved. asserted_need / asserted_delta are consumed by mapper/evaluator but absent from the authoritative asset_relationships schema; Notion relation page_ids and evidence_event are not resolved by _edge_evidence_ids (state-model.md:262-279; physical.py:152-161,252-266; reuse.py:553-609).
  6. Physical validation remains incomplete. Evidence and relationship ID uniqueness/formats, supported kind/privacy values, provenance freshness/privacy compatibility, unresolved additional targets, relationship schema/version/privacy, and duplicate edges are not fail-closed (physical.py:104-207).
  7. Evaluator-bound exhaustiveness is forgeable outside the current MCP call site. evaluate_reuse accepts an ordinary search_coverage dictionary, so future/internal callers can directly set search_exhaustive=true without adapter provenance (reuse.py:77-90,333-399).

Gate B remains changes-requested. Gate C live access was not required or treated as a Gate B failure.

Gate A/B v2.2 re-review (superseded by the Gate B close-out findings above)

Re-reviewed: 2026-07-24 after remediation commit c519ee3 and durable tip 5613f25.

Gate A v2.2: external review passed

All prior Gate A findings are resolved:

  • Repository/environment rows now have stable repo_id / env_id, uniqueness and idempotent upsert rules, and explicit stored privacy_class (state-model.md:214-241).
  • state-model.md and asset-registry.md agree on physical schema_version=state-model.v2 plus asset_registry_version=asset-registry.v2.
  • The workspace, parent, nine-database layout, lossless evidence model, per-edge relationships, Asset-linked events, identifier flow, writeback representation, migration, and rollback are specified.
  • c519ee3 and 5613f25 are present on tracked origin/main; local HEAD equals origin/main.

External recommendation: Gate A is ready for Hector to approve by commenting Conductor-Gate-A: approve and naming state-model.v2 / commit c519ee3 (durable tip 5613f25). This design approval does not authorize database creation or import; those remain Gate D.

Gate B v2.2: changes requested

The three v2.1 regression cases now fail closed, but decisive bypasses remain:

  1. new trusts caller-asserted exhaustiveness. search_exhaustive is not protected by CALLER_FORBIDDEN_COVERAGE_KEYS, so search_coverage_json can assert it and authorize new (reuse.py:39-49,315-381). Reproduced: caller_exhaustive_new=new.
  2. Privacy-redacted Assets disappear from exhaustiveness. The evaluator drops redacted rows before building reviewed/candidate sets (reuse.py:106-115) without downgrading a complete source. Reproduced: a redacted reviewed Asset was ignored and the visible negative produced redacted_asset_new=new.
  3. Candidate disposition evidence is estate-union-bound, not candidate-bound. _validate_candidate_dispositions accepts a citation from any reviewed Asset or candidate (reuse.py:545-580). Reproduced: Asset A's repository evidence ruled out asset.cand and produced cross_asset_candidate_evidence_new=new.
  4. Claim and no-gap citations prove locator membership, not the asserted comparison. A selected Asset's real repository/evidence token can accompany an invented capability or no-gap assertion because evidence is not bound to claim ID, need/request version, reviewer, or review time (reuse.py:384-496).
  5. extends evidence is not resolved or edge-bound. Any populated evidence relation/event identifier or HTTP URL sets has_evidence; the referenced record is not resolved and validated for this edge, delta, or request (physical.py:225-239; reuse.py:499-542).
  6. Physical evidence permits metadata-only and multiply attached rows. _evidence_ref falls back to evidence_id, so ref_missing cannot reject a row with no ref_url/ref_text; exactly-one Asset targeting and nonfuture timestamps are not fully enforced (physical.py:146-176,242-249).
  7. Deprecated Asset-level verification can survive mapping. map_physical_asset copies the input Asset and only replaces verification_evidence when mapped verification rows exist, allowing stale legacy values into the authoritative citation set (physical.py:47-91; reuse.py:404-419).

Gate B remains changes-requested. Live Gate C reads were not required or treated as a Gate B failure.

Gate A/B v2.1 re-review (superseded by v2.2 findings above)

Re-reviewed: 2026-07-24 after remediation pass 3 and commits e0cf737 / 356c1e9. Decision: Do not approve Gate A or Gate B yet.

Gate A v2.1 findings

Verified:

  • The target Notion workspace and parent page are recorded.
  • All nine database definitions carry schema_version=state-model.v2; Assets separately carry asset_registry_version=asset-registry.v2.
  • The schema and paired evaluator are bound to committed revision e0cf737, recorded by 356c1e9.
  • The lossless evidence, per-edge relationship, and Asset-linked event findings remain resolved.

Remaining:

  1. asset_repositories and asset_environments define neither stable child-row IDs nor uniqueness/idempotency rules (state-model.md:209-228). Gate A requires identifiers and idempotent persistence, while Notion page IDs are adapter locators rather than stable IDs (state-model.md:81-96; brief.md:61-70).
  2. Those child rows have no privacy_class or explicit inheritance rule, conflicting with the read contract that each record carries a privacy classification (read-access-contract.md:111-118).
  3. The paired Asset contract says Asset.schema_version=asset-registry.v2, while the physical model uses Asset.schema_version=state-model.v2 plus asset_registry_version=asset-registry.v2 (asset-registry.md:47-53; state-model.md:179-187). The latter split is sound, but the authoritative documents must agree.
  4. The binding commits are local and main is two commits ahead of origin/main. This is a GitHub-first durability risk until the revision exists on the tracked remote.

Gate A remains changes-requested. Database creation is Gate D and was not treated as a Gate A failure.

Gate B v2.1 findings

  1. Caller-controlled coverage can override observed source completeness. prepare_estate_context merges search_coverage_json over adapter-derived completeness values (app.py:333-359). The same unreviewed input can set runtime/deploy mismatch waivers consumed by reuse.py:143-158.
  2. No-gap evidence is not bound to the selected Asset or request. _validate_no_material_gaps accepts any citation in the union of all reviewed Assets (reuse.py:414-433). Reproduced: Asset B evidence authorized reuse of Asset A.
  3. extend accepts unresolved identities and weak review evidence. Relation mapping falls back to raw Notion page IDs (physical.py:148-164), and _validate_extends_edge requires only a nonempty distinct source (reuse.py:456-471). It does not require a known stable source Asset, parse/nonfuture reviewed_at, resolved evidence, or a request-bound edge. Reproduced: source asset.not-in-estate yielded extend.
  4. new permits unresolved candidates. open_candidates blocks reuse but is not checked by the new branch (reuse.py:188-193,277-306). Reproduced: a deferred candidate yielded new. Candidate disposition evidence is also arbitrary text rather than citation-bound evidence.
  5. Mapped evidence is not schema- or freshness-validated. physical.py:41-66 ignores required version, author, timestamp, and privacy fields and treats promotion evidence as verification evidence. Asset freshness is checked independently, so malformed or stale evidence can support a decisive result.
  6. Schema compatibility is not enforced. Evaluator-required fields omit physical and registry versions (reuse.py:14-25), and tests use versionless records. An incompatible record can participate in a decision.

Gate B remains changes-requested. The straightforward remediation tests pass, but the evaluator can still produce unsupported reuse, extend, and new outcomes.

Gate A/B v2 re-review (superseded by v2.1 findings above)

Re-reviewed: 2026-07-24 after the state-model.v2 / asset-registry.v2 remediation handoff.
Decision: The core Gate A schema remediation is verified, and the Gate B evaluator is materially improved. Do not approve either gate yet.

Gate A v2 findings

Verified:

  • asset_evidence is a lossless one-row-per-reference representation.
  • asset_relationships is a per-edge source of record with review metadata.
  • Decisions/Events can link Asset verification and promotion evidence through related_assets.

Remaining:

  1. The target Notion workspace and parent page are still unconfirmed (state-model.md:20-28). This is correctly disclosed as owner-blocked.
  2. state-model.v2 is proposed but not bound to a commit; the remediation files are currently untracked. Naming a revision in the document is not a committed schema revision.
  3. The schema-version rule says every database page carries state-model.v2, while Assets define only schema_version=asset-registry.v2, and Asset Repository/Environment rows define no schema-version property (state-model.md:26,168-212). Resolve the physical version representation before approval.

Gate A remains changes-requested: design remediation verified; owner input, a consistent physical version field, and a committed revision are still required.

Gate B v2 findings

Verified:

  • Claim IDs, Asset membership, duplicate/contradictory polarity, claim text, and citation presence are validated.
  • new requires exact negative coverage of reviewed Assets and per-candidate dispositions.
  • Future verification dates are rejected.
  • Dedicated read-token settings, default legacy-write containment, fail-closed webhook checks, physical mapping, and decision-critical negative tests exist.

Remaining:

  1. Claim citations are accepted as arbitrary nonempty strings and are not checked against mapped provenance or verification evidence (reuse.py:319-363,416-437). Fabricated citations can therefore support reuse.
  2. Missing material_gaps is treated as proof of no gaps (reuse.py:190-203). A decisive reuse must require an explicit reviewed no-gap assertion.
  3. extend accepts any human-reviewed extends edge without checking direction, reviewer, reviewed timestamp, or evidence; caller-supplied human_reviewed=true plus arbitrary review_evidence also bypasses a physical edge (reuse.py:216-260).
  4. Physical relation-only source/target values can become Notion page IDs rather than stable Asset IDs, and human_reviewed is derived from status alone (physical.py:56-78,93-120).
  5. Runtime/deploy requirements do not fail when the Asset value is absent, and the application preparation path supplies no request constraints at all (reuse.py:127-161; app.py:331-336). The integrated path cannot demonstrate the claimed compatibility decision.
  6. Tests do not cover unbound citations, omitted material-gap evidence, incomplete/wrong-direction reviewed edges, stable-ID relation resolution, or integrated request constraints.

Gate B remains changes-requested. The evaluator must bind decision evidence to authoritative mapped records and fail closed when no-gap, compatibility, or reviewed-edge evidence is absent.

Prior v1 re-review (superseded by the v2 findings above)

Re-reviewed: 2026-07-24 after the 12/28-test remediation handoff.
Decision: Do not approve Gate A or Gate B yet.

Gate A residual findings

  1. docs/state-model.md:21-27 still lacks the confirmed Notion workspace and parent page required by its Gate A checklist.
  2. Asset provenance is split between provenance_kinds and ordered provenance_refs (state-model.md:186-187). This cannot safely represent repeated kinds and depends on pairwise ordering across unrelated properties.
  3. Relationship review is Asset-wide (relationship_human_reviewed) rather than edge-specific (state-model.md:174-181). It cannot prove which target edge was reviewed, by whom, when, or against what evidence.
  4. Additional Asset verification evidence is redirected to Decision/Event, but Decisions/Events have no Asset relation (state-model.md:222-247). Promotion and verification evidence cannot be reliably attached to the Asset.

Gate A remains changes-requested. Before approval:

  • Confirm and record workspace and parent page.
  • Add a lossless Asset Provenance/Evidence child database or equivalent one-row-per-reference model.
  • Add an Asset Relationship edge database with source, target, kind, review status, reviewer, evidence/event, and timestamp.
  • Add an Asset relation to verification/promotion events or represent those events in the evidence child model.
  • Bind approval to a committed schema revision.

Gate B residual findings

The conceptual Asset contract is mostly sound. Its physical realization and evaluator do not yet enforce it:

  1. reuse.py:174-175 does not validate claim shape, Asset IDs, uniqueness, contradictions, or claim citations.
  2. Unknown or duplicate positive IDs can produce reuse/extend; duplicate negatives can satisfy new without covering every reviewed Asset.
  3. Multiple overlaps produce extend without selecting a base or proving a justified delta (reuse.py:177-207).
  4. A global candidates_ruled_out Boolean is not a per-candidate disposition with evidence.
  5. Privacy/runtime compatibility is not compared; a nonempty privacy_class is insufficient.
  6. Relationship checks expect a synthetic relationships list rather than the physical rel_* representation.
  7. The integrated path does not map physical provenance fields into the evidence shape or supply required capability-claim evidence.
  8. Future verification dates are accepted as fresh.
  9. Tests omit unknown/duplicate/contradictory claims, claim citations, valid/invalid extension, exhaustive negative comparison, candidate dispositions, privacy/runtime mismatch, physical relationship evidence, and future dates.

Gate B remains changes-requested. Require evidence-schema validation, claim-linked citations, exact per-Asset coverage, per-candidate dispositions, explicit base/delta/human review for extend, request compatibility checks, physical relationship/provenance mapping, bounded freshness, and negative tests.

The remediated completion fields, relation-aware reads, privacy fail-closed behavior, legacy-write gating, webhook fail-closed behavior, and failure envelopes were materially improved. They are not the current Gate A/B blockers.

Summary

The Gate B contract and evaluator are approved, but the live M1 state foundation and estate baseline remain incomplete:

  • Gates A, B, and C are approved; Gate C application discovery is complete; Gate D package is in human review.
  • No live Notion or GitHub estate read occurred.
  • No Notion databases or reviewed Asset baseline exist.
  • No live inventory or representative golden-path candidate exists yet.
  • Fixture retrieval is not fresh-client retrieval from authoritative state.
  • The approved Gate B implementation is published in draft PR #4; live adapter behavior still requires active Gate C credentials and evidence.

Gate decision

Gate Review status Reason
A — Physical Notion model approved Hector posted Conductor-Gate-A: approve naming state-model.v2 / c519ee3; Gate D still owns mutation
B — Asset/reuse model approved Independent final review found no remaining typed-boundary, physical-validation, Initiative-authority, or decisive-result bypass
C — Source/access scope approved; discovery complete 131 candidate project units registered from the accepted GitHub/incubator boundary; runtime dedicated binding remains a hardening gap
D — Mutation/import package in review Nine-database/131-candidate dry run prepared; human review and rollback/writer approval remain

Prior initial findings (superseded for Gates A/B)

Critical: live mutation surface must be contained before Gate C

The deployed application still exposes pre-M1 Notion/GitHub/Calendar mutation tools and schema bootstrap:

  • service/conductor/app.py:122-127,321-478
  • service/conductor/integrations/notion.py:36-82
  • service/conductor/integrations/orchestrator.py:31-87,127-132,185-199
  • service/conductor/integrations/schema_bootstrap.py:21-53

The GitHub webhook is exempt from normal MCP authentication, and signature validation is skipped when its optional secret is empty:

  • service/conductor/auth.py:9-17,37-40
  • service/conductor/app.py:524-545
  • service/conductor/config.py:42,119-121

Mapped webhook events can update Notion through service/conductor/integrations/orchestrator.py:214-249.

These paths predate the M1 read adapters, but live M1 access must not be enabled while this fail-open mutation surface exists. Remediation may remove/hard-disable the writer paths or place them behind an explicit fail-closed legacy feature gate with no production enablement. Webhook signature verification must fail closed.

High: physical Notion schema is incomplete

docs/state-model.md:152-172 cannot represent the complete Asset contract in docs/asset-registry.md:34-58. Missing physical fields include aliases, repositories, deployments, stack/deploy shape, verification evidence, extraction notes, and portability gaps.

The single related_assets relation cannot represent typed relationships such as duplicate_of, replaces, depends_on, and extends.

docs/state-model.md:177-199 also lacks completion properties required at lines 210-231, including actions, decisions, unresolved items, result, idempotency key, and written time.

Gate A and Gate B remain changes-requested until the physical schema can store the approved conceptual records without lossy free-text substitutions.

High: live Notion relations cannot be read

service/conductor/integrations/read_adapters/notion_read.py:181-206 does not decode Notion relation properties. workstreams_for_initiative expects a flat initiative_id at lines 138-156, while the proposed schema uses a relation.

The fixture at service/tests/test_read_adapters.py:21-40 supplies the flat field and masks the live defect.

Implement relation decoding and relation-aware lookup tests using Notion-shaped payload fixtures.

High: privacy enforcement is not identity- or role-aware

service/conductor/integrations/read_adapters/__init__.py:58-81 hard-codes public and internal access for every caller and defaults unclassified records to internal.

GitHub results receive no privacy filtering in github_read.py:45-58,130-141, including metadata from private repositories.

Pass authenticated identity, active role, and organization privacy policy into filtering. Unclassified records should fail closed or use an explicitly approved source default. Apply permission filtering to GitHub and supplemental results before returning them.

High: reuse results exceed their evidence

service/conductor/integrations/read_adapters/reuse.py:72-122 maps lexical matches directly to reuse, extend, or new.

The evaluator must not issue these outcomes unless it validates the evidence contract in docs/asset-registry.md:102-119, including:

  • Required reviewed fields.
  • Actual freshness policy.
  • Search coverage and source completeness.
  • Capability overlap and material gaps.
  • Privacy/runtime constraints.
  • Human-reviewed relationship evidence where required.
  • Relevant unresolved candidates.
  • Citations derived from actual provenance rather than synthesized IDs.

If those conditions are unavailable, return insufficient-context with explicit missing evidence.

High: failure envelopes are incomplete

The adapters do not reliably convert transport exceptions, JSON failures, malformed payloads, missing pagination cursors, rate limits, and partial pagination into the required envelope.

Examples:

  • notion_read.py:158-179 can stop an incomplete pagination sequence and later report complete.
  • notion_read.py:83-95,174-179 does not normalize all transport/decoding exceptions.
  • github_read.py:75-93 lacks rate-limit and retry metadata.

Add explicit contract tests for partial, unavailable, denied, stale, and malformed, including pagination and rate-limit cases.

High: read credentials and application wiring are incomplete

The GitHub token configuration falls back to generic tokens also used by write synchronization. Read credentials must be distinct from governance or writer credentials.

The read adapters are not wired into an application preparation/query path. CONDUCTOR_READ_ALLOW_LIVE exists but does not establish a permission-filtered adapter factory or retrieval surface.

Do not enable live reads until Gate C approves scopes, dedicated read bindings, and privacy behavior.

Medium: implementation started before Gate C

The M1 brief permits adapter implementation only after Gate C and through the normal issue/PR process. gate-status.md cannot override that brief.

Keep the experiments as unapproved prototypes while remediating them. Do not call them shipped or production-ready. Future external implementation must occur on a linked branch/PR after the applicable gate.

Medium: fixture evidence is not baseline evidence (superseded Gate C prerequisite)

The three real-estate records in service/tests/test_read_adapters.py are invented fixtures. The entries in docs/estate/candidates.yml are unnamed placeholders.

Neither is evidence that the estate has been inventoried. The 2026-07-26 Gate C decision supersedes the naming prerequisite: approved sources must be enumerated after activation, then a representative golden-path application or related group must be selected and reviewed.

Work-package status

Package Review result
M1.1 State schema state-model.v2 design approved at Gate A; Gate D still owns creation/import
M1.2 Asset registry asset-registry.v2 and typed EstateComparison boundary approved at Gate B
M1.3 Read access Gate C operator discovery complete; runtime dedicated-token path remains fail-closed and unverified
M1.4 Source inventory 131 candidate project units registered; golden-path/relationship review pending
M1.5 Reviewed baseline Not started
M1.6 Retrieval verification Fixture demonstration only

Acceptance matrix

# Result Reason
1 Not met Schema is unapproved and target workspace/parent are unknown
2 Not met No physical records or validated live relations
3 Not met Writeback physical fields and persistence tests are incomplete
4 Not met No permission proof; privacy and credential separation are incomplete
5 Partial Draft scope and explicit not-run failures exist; no approved/live coverage
6 Partial Candidate/reviewed policy exists; no reviewed production records
7 Not met No reviewed Asset baseline
8 Not met Real-estate applications remain unnamed and non-comparable
9 Not met No human duplicate/supersession decisions
10 Not met Retrieval uses local fixtures, not authoritative remote state
11 Met for Gate B Typed comparison and exhaustive snapshot bind decisive results to validated authoritative records; live proof remains gated
12 Not met Error, malformed, pagination, and rate-limit cases are incomplete
13 Partial Policy forbids candidate/index authority; no live enforcement evidence
14 Not met No rollback rehearsal or PR/CI evidence

Validation reproduced

```text python -m pytest service/tests/test_read_adapters.py -q 41 passed

python -m pytest service/tests -q 57 passed

python -m mkdocs build --strict passed

git diff --check -- docs service pyproject.toml pytest.ini passed with line-ending warnings only

independent final review no findings; Gate B approve ```

Prior remediation sequence (completed for Gate B)

  1. Preserve Gate A approval as design-only; do not create databases before Gate D.
  2. Remove public seal access and runtime test factories; prevent direct authoritative construction and verify comparison provenance in the evaluator.
  3. Build the snapshot only from internally produced validation output and bind it to an immutable estate/batch digest, source versions, request, and comparison.
  4. Fully validate repositories/environments and every orphan child/event against Asset membership, required fields, IDs, uniqueness keys, privacy, freshness, cardinality, and pagination.
  5. Define deterministic comparison selection by explicit ID/version or one non-superseded latest record; reject ambiguity.
  6. Bind relationship event evidence to a validated typed event payload covering endpoints, need, delta, reviewer/time, privacy, and review action.
  7. Require exact payload object schemas and strict Booleans; convert every malformed payload into fail-closed parser errors.
  8. Enforce actor authority and privacy/freshness compatibility across comparisons, evidence, relationships, events, and requests.
  9. Map repository/environment rows into the immutable estate payload or include their validated identity digest in the snapshot.
  10. Add adversarial tests for constructor/seal forgery, estate substitution, empty/orphan child rows, ambiguous events, unrelated event evidence, and parser type confusion.

Do not mark M1 review requested until all four gates and all acceptance evidence are complete.