Skip to content

feat(research): add reversible duplicate review manifest - #12

Draft
seonghobae wants to merge 27 commits into
autoresearch/zotero-reclassification-sep04from
autoresearch/zotero-duplicate-review-manifest
Draft

feat(research): add reversible duplicate review manifest#12
seonghobae wants to merge 27 commits into
autoresearch/zotero-reclassification-sep04from
autoresearch/zotero-duplicate-review-manifest

Conversation

@seonghobae

@seonghobae seonghobae commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Current duplicate source-scope checkpoint — 2026-09-06

Exact head 3d2c2529af3c57c10d7e31e806b8e39dbf524efe normally preserves old #12 a4a7c2d56fc592ef1c7abf64ca6875b0fe10c5ee and parent #11 6dff8c2ee42cfeb7bf8688c1f7e95989b61be266. Base remains autoresearch/zotero-reclassification-sep04; OPEN Draft. Runtime repair fc0465e, regression additions 0c825d9, test-only Clippy repair 5fff9d0.

Exact candidate membership was already independently bound by this owner, and remains so. RED 4656d6b instead reproduced three source-scope bypasses: invalid inventory accepted, changed standalone evidence reaching governance, and legacy receipt missing complete-scope binding. Required v2 proposal_digest now binds current proposals, retained metadata and pending sources in both reviewed set and output manifest. Recomputing it does not reuse independent approval. Receipt comparison preserves SnapshotMismatch precedence; shared report/audit validation and all local component/decision checks run before external governance. No duplicate semantics, connected-component evidence or rollback mapping was discarded.

Exact-head locked tests87/17unfiltered suites including2doctests; strictClippy, warnings-denied rustdoc, release build, format, CI contract and diff checks passed. Independent source review reran12duplicate tests without actionable findings; this is not GitHub approval. Unchanged pinned coverage passed153/153functions1294/1294normalizedregions220/220normalizedbranches. Raw1649/1658lines2516/2536regions200/220branches are not100%. No added exclusion or dependency.

PRD/TRD/DDD/ProposedADR0006/Gap/CHANGELOG record the breaking receipt and source boundaries. Restored-report, worksheet and write consumers still require forward integration; no empty defaults, full-text downcast, capture rewrite or automatic approval transfer. Fresh visual evidence remains the preceding native Zotero screenshot+AX3719items observation, not a new reclassification or screenshot claim. No actual decision, approval, mutation, protected merge or release is claimed. Earlier checkpoints below are historical.

Latest bounded-read integration checkpoint

Exact head a4a7c2d56fc592ef1c7abf64ca6875b0fe10c5ee normally merges parent 1dc032598b41a35d52c09d8690c871e07365d7e3 while retaining previous child ee2c494a3136a4bfa520c29f1c938b621e1ecb9c. Base remains autoresearch/zotero-reclassification-sep04. The #9 whole-snapshot elapsed-time repair and its RED/GREEN evidence are inherited without reverse-merging later features or discarding predecessor deltas.

This exact head passes Rust 1.98.0 locked workspace tests=68 suites=17, including doctests and excluding filtered subprocess duplicates, strict all-target Clippy, warnings-denied rustdoc, formatting, the existing CI contract and diff checks. Log: /private/tmp/conceptweave-deadline-pr12-20260906.log. Intermediate coverage is not inferred from owner/final-endpoint coverage. No new dependency, actual paper read/decision, Zotero mutation or authority issuer was used.

Draft and protected prerequisites remain. Local tests are not hosted GREEN, independent approval, merged/released source or evidence for another head. Earlier checkpoints below are retained history, not the current head.

Current source-integrity note — 2026-09-05

  • Exact head: autoresearch/zotero-duplicate-review-manifest@3bed88707b347a6db52ea9722f5a1c8f00933813.
  • Exact base: autoresearch/zotero-reclassification-sep04@082710e8c9a0e37ddae528e305cd75ab3574d0bb.
  • This head inherits PR feat(research): add steward golden-set evaluation #10 root e7d4e59f1b55b5954c5f8436527bc96e7ef2fb13 through ordinary merge ancestry. The source-snapshot digest binds complete captured raw provider JSON and the actual typed classifier inputs; source evidence and derived proposals retain separate identities.
  • GoldenSetApproval.proposal_digest is required and binds the complete proposal records used for evaluation. The current proposal digest is checked before the caller-owned governance verifier. Do not backfill old receipts: regenerate evidence and obtain a new approval bound to the reviewed evidence.
  • Keep Draft. This note does not claim current exact-head hosted GREEN, independent approval, protected merge, live Zotero mutation, or governed publication. Root, predecessor, and terminal-stack local test evidence is not transferred as per-PR hosted evidence.

Earlier heads, runtime snapshots, campaign counts, and verification statements below are historical notes, not current acceptance evidence.

Historical PR notes — original text retained

Outcome

Adds a Foundation-dependent, local-only reversible duplicate-review manifest for Issue #8. Reviewed duplicate decisions bind to an opaque authority receipt plus exact library/rule/raw-snapshot identity and produce deterministic before/after/rollback canonical-key mappings while preserving every Zotero source record. This branch performs no Zotero mutation or deletion.

Current exact stack — 2026-09-05

Review -> test -> repair lineage

The current lineage enforces the reviewed duplicate-manifest invariants at the source boundary:

  • reviewed.snapshot_items must exactly equal report.snapshot_items, binding item keys and exact item revisions to the verified review rather than re-reading mutable report coordinates after approval;
  • reviewed.duplicate_candidates must exactly equal report.duplicate_candidates, so a caller cannot substitute another valid snapshot key into a reviewed candidate while retaining the old authority receipt;
  • blank and duplicate snapshot item keys fail closed before revision maps are built;
  • overlapping duplicate candidates are expanded to their transitive connected component;
  • every decision touching one component must select the same component-level retained item;
  • emitted operation evidence contains the complete connected component and exact source revisions, including the retained item even when it is not in the immediate candidate pair;
  • missing component revisions fail closed rather than materializing incomplete provenance;
  • DDD artifacts define the reviewed duplicate set, authority receipt, canonical-key operation and Research Intake -> Governance & Publication verification handoff.

Previously returned review threads remain intentionally unresolved where they require execution evidence. A restack does not convert source inspection or predecessor evidence into GREEN.

Existing manifest boundary

The manifest binds decisions to review/authority receipts, exact library version, rule revision, raw snapshot digest, exact snapshot item coordinates and exact duplicate-candidate membership; requires one decision per candidate; rejects unknown/repeated decisions; retains source revisions; emits deterministic before/after/rollback canonical-key mappings; and marks source records preserved.

Reviewed Duplicate Merge Set is one steward decision set over a connected duplicate component. Governance & Publication remains the authority boundary. Candidate duplicate evidence does not become semantic truth merely because deterministic mappings can be generated.

Issue #8 AC4 remains partial until real duplicate groups receive actual steward decisions through the governance boundary.

Dependency boundary

Keep Draft behind #11 -> #10 -> #9 -> Foundation. #13 and later descendants must retain the current #12 ancestry. Downstream write-plan or transport work does not back-prove this manifest. Do not perform Zotero write-back, promote candidate classification to semantic authority, resolve valid review findings before their required verification, or transfer predecessor/cancelled evidence.

Merge gate

Require one unchanged exact head with terminal Product/security/SAST/dependency/review evidence and zero valid unresolved findings. No self-approval, routine bypass, force-push, destructive rebase, mutable foreign dependency, or gate weakening.

Refs #8.

Signed-off-by: Seongho Bae <me@seonghobae.me>
@seonghobae

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 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-09-04T15:03:42.232514Z e77a2d2 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.

@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@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: 4324218125

ℹ️ 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 thread crates/conceptweave-zotero/src/lib.rs Outdated
Comment on lines +602 to +606
let after_canonical_keys = candidate
.item_keys
.iter()
.map(|item_key| (item_key.clone(), decision.retained_item_key.clone()))
.collect::<BTreeMap<_, _>>();

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 Reject conflicting choices across overlapping duplicate groups

When records share more than one identity—for example, two items with both the same DOI and title—the report contains overlapping DOI and title candidates, but each decision is validated independently. A steward can therefore retain A for the DOI group and B for the title group, producing simultaneous mappings B -> A and A -> B; downstream canonical resolution then depends on which operation is applied or queried rather than yielding one canonical record. Require consistent retained keys across overlapping groups or collapse candidates into connected components before emitting mappings.

Useful? React with 👍 / 👎.

Comment on lines +553 to +557
let item_revisions = report
.snapshot_items
.iter()
.map(|item| (item.item_key.as_str(), item.item_version))
.collect::<BTreeMap<_, _>>();

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 Validate snapshot-key uniqueness before recording revisions

When the public classify_snapshot entry point receives repeated Zotero keys, it can produce a candidate containing the same key more than once, and this collect silently keeps only the last version. A subsequently approved manifest then emits that surviving version for every occurrence while claiming to preserve the exact source revisions, corrupting the review evidence instead of failing closed. Validate that snapshot_items contains unique, nonblank keys before building this map, as the golden-set path already does.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

Comment on lines +164 to +170
/// Snapshot-bound duplicate decisions verified by the caller's governance boundary.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct ReviewedDuplicateMergeSet {
/// Opaque steward review receipt.
pub review_id: String,
/// Opaque governance authority receipt; contains no person identity.
pub authority_receipt: String,

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 Add the duplicate-review concepts to the DDD documentation

This introduces new public domain concepts—including the reviewed duplicate set, authority receipt, canonical-key operation, and the Research Intake-to-Governance verification handoff—but neither docs/UBIQUITOUS_LANGUAGE.md nor docs/CONTEXT_MAP.md defines that language or relationship. Update those DDD artifacts so the newly documented workflow does not diverge from the repository's canonical domain model.

AGENTS.md reference: AGENTS.md:L11-L11

Useful? React with 👍 / 👎.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: 44114d1abe

ℹ️ 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".

@seonghobae
seonghobae marked this pull request as draft September 4, 2026 14:31
@seonghobae
seonghobae marked this pull request as ready for review September 4, 2026 14:37
@seonghobae

Copy link
Copy Markdown
Contributor 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: f7ef6504df

ℹ️ 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 thread crates/conceptweave-zotero/src/lib.rs Outdated
Comment on lines +600 to +604
if canonical_choices
.insert(item_key, decision.retained_item_key.as_str())
.is_some_and(|retained_key| retained_key != decision.retained_item_key)
{
return Err(DuplicateReviewError::InvalidReview);

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 Collapse transitive duplicate groups before enforcing one choice

When duplicate identities form a chain such as DOI {A,B}, title {B,C}, and DOI {C,D}, no review can pass this check: the first overlap forces the middle group to retain B, while the second forces it to retain C. Fresh evidence beyond the earlier conflicting-choice finding is that the new per-item consistency check rejects every possible decision set for this valid classifier output, even though the documented Reviewed Duplicate Merge Set requires one canonical item across the whole overlapping cluster. Collapse connected candidates into a component before review, or permit every group to select a component-level retained key.

AGENTS.md reference: AGENTS.md:L11-L11

Useful? React with 👍 / 👎.

Comment thread crates/conceptweave-zotero/src/lib.rs Outdated
Comment on lines +556 to +559
.map(|item| item.item_key.as_str())
.collect::<BTreeSet<_>>()
.len()
!= report.snapshot_items.len()

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 Reject blank snapshot keys before building mappings

When the public classify_snapshot entry point receives one uniquely blank Zotero key alongside another item sharing its DOI or title, this cardinality check passes and the manifest can emit source_items and canonical maps containing "" as a source or retained identity. Fresh evidence beyond the earlier duplicate-key finding is that the added validation checks uniqueness only and never checks item_key.trim().is_empty(), so the supposedly stable source identity remains unusable for downstream resolution and provenance. Reject blank snapshot keys before verifying or materializing the review.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

@seonghobae
seonghobae marked this pull request as draft September 4, 2026 14:41
@seonghobae

Copy link
Copy Markdown
Contributor 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: 7fb7bfa5dc

ℹ️ 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 +641 to +645
item_revisions
.get(item_key.as_str())
.map(|item_version| SnapshotItemRevision {
item_key: item_key.clone(),
item_version: *item_version,

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 Bind emitted item revisions to the reviewed snapshot

The new key-only validation still permits a caller to alter a public ClassificationReport.snapshot_items entry's version while retaining the original reviewed digest; every check passes and this line emits the altered version under the authority receipt for the original snapshot. Since the tests already treat mutated reports as untrusted inputs, bind the reviewed set to the complete item-key/version coordinates, as the golden-set contract does, before materializing these source revisions.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

Comment thread crates/conceptweave-zotero/src/lib.rs Outdated
Comment on lines +637 to +639
let source_items = candidate
.item_keys
.iter()

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 Include the component canonical key in operation evidence

The new component-level retained-key acceptance allows the transitive {A,B}, {B,C}, {C,D} case to choose A, but the operation for {C,D} still builds source_items only from candidate.item_keys; it therefore names A as the retained record without preserving A's source revision in that operation. This makes the supposedly exact operation evidence incomplete for independent validation or replay, so build each operation from the connected component (or collapse the component into one operation).

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

@seonghobae

Copy link
Copy Markdown
Contributor 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: e77a2d232c

ℹ️ 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".

.ok_or(DuplicateReviewError::UnknownCandidate)?;
// ponytail: quadratic component expansion is enough for a steward-sized review;
// replace with union-find only if measured duplicate sets become large.
let mut component_keys = candidate.item_keys.iter().collect::<BTreeSet<_>>();

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 Bind candidate membership to the reviewed snapshot

When a reviewed {A,B} candidate shares a snapshot with an unrelated item C, replacing the public candidate's B key with C after review passes every check because C exists in item_revisions; this line then emits C -> A under the unchanged verified receipt while silently omitting B. Although the new detached-key test rejects missing, substitution with another valid snapshot key still bypasses it because candidate membership is absent from ReviewedDuplicateMergeSet and is never rederived from the reviewed digest. Bind the exact candidate/component membership into the verified review or recompute and validate it from immutable snapshot evidence before materializing operations.

AGENTS.md reference: AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Non-force two-parent restack onto current classification-audit parent. Preserve the duplicate-review manifest delta while inheriting the repaired Foundation CI contract through the parent chain.

Signed-off-by: Seongho Bae <me@seonghobae.me>

Copy link
Copy Markdown
Contributor Author

Current-stack correction (2026-09-05): exact base #11 472dd348e8f0f07b154af2f63e868104e7519de5; exact head 42103a8cb5813bce5966d63bf472408570a5263f. Non-force restack preserves the duplicate-review manifest delta. Older body coordinates are historical only.

Normal merge of PR11 6dff8c2 into priorPR12 a4a7c2d retains candidate membership receipts, transitive components, raw source, inventory, v2 proposals and audit checks. Combine both UML paths without discarding either owner delta.

Copy link
Copy Markdown
Contributor Author

Fresh owner-stack reconciliation (2026-09-06): the named base branch autoresearch/zotero-reclassification-sep04 has advanced normally to #11 exact 6dff8c2ee42cfeb7bf8688c1f7e95989b61be266, while this Draft remains a4a7c2d56fc592ef1c7abf64ca6875b0fe10c5ee. Direct compare is diverged from merge base 1dc032598b41a35d52c09d8690c871e07365d7e3 (child +20, parent +24), and GitHub currently reports this PR non-mergeable. This is a stale-parent integration finding, not a reason to close or retarget the PR.

Required repair: read/adopt the complete #11 successor delta, including the new #10 source-scope admission lineage and #11 derived-audit/provenance repairs, then normally non-force merge/restack it into this existing branch while preserving every #12 duplicate-review manifest/test/DDD delta. Resolve overlaps causally; do not drop either side, force-push, destructive-rebase, transfer predecessor GREEN, or mark review threads resolved from source adoption alone. Re-run Rust 1.98 locked workspace tests, strict fmt/Clippy/rustdoc, release/CI contract/diff and the owned coverage gate on one unchanged successor head before advancing descendants #13+.

No source/base/head mutation is performed by this coordination comment; it leaves the current writer free to complete the normal restack.

Reuse shared report admission; exact candidate membership remains independently bound. Remove subsumed key checks and move governance after all local decisions. Require v2 proposal identity on receipt and manifest, with no legacy default or approval issuance.
Receipt/source comparison remains before structural admission, and both remain before independent governance. Preserve existing exact error contracts without weakening newly added source and decision checks.

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Current-head read-only review found one additional acceptance defect independent of the stale-parent restack. This is a review finding, not approval or GREEN.

Comment thread crates/conceptweave-zotero/src/lib.rs Outdated
{
return Err(DuplicateReviewError::SnapshotMismatch);
}
if !verify_review(reviewed) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

P1: complete local validation before invoking the governance verifier. At this exact head verify_review(reviewed) runs here, but blank/duplicate report.snapshot_items are rejected only below (lines 636–648), and later candidate/decision structural checks also occur after this call. A malformed untrusted report can therefore invoke the external authority boundary and receive UnverifiedApproval precedence before ConceptWeave has finished its own fail-closed validation. This is inconsistent with the repository’s existing local-check-before-authority contract and can spend/trigger verifier work on inputs ConceptWeave already knows are invalid.

RED: use a counting verifier and prove blank/duplicate snapshot identity plus each existing invalid candidate/decision structural case invoke it 0 times; a fully valid reviewed set invokes it exactly 1 time. Minimal GREEN: perform every deterministic local report/review/candidate/component check before verify_review; after adopting current parent #11 6dff8c2..., also run its shared validate_classification_report(report) (or an error-mapped equivalent) before the verifier so the parent’s forged-audit/provenance repair cannot be bypassed in this duplicate-owner path. Do not change authority semantics or turn local validation into approval.

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