Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
63a0905
test(zotero): require worksheet finalization contract
seonghobae Sep 4, 2026
be54e98
feat(zotero): finalize reviewed steward worksheets
seonghobae Sep 4, 2026
9992dfa
test(zotero): preserve duplicate decision coordinates
seonghobae Sep 4, 2026
f3d076e
docs(zotero): define worksheet finalization boundary
seonghobae Sep 4, 2026
03ced90
style(zotero): format finalization tests
seonghobae Sep 4, 2026
fbbba10
test(zotero): cover finalization trust boundary
seonghobae Sep 4, 2026
0f709e6
fix(zotero): bind finalization to classification report
seonghobae Sep 4, 2026
9b577ec
style(zotero): format report-bound finalization
seonghobae Sep 4, 2026
b88dc92
test(zotero): cover report-bound finalization
seonghobae Sep 4, 2026
7ca97b4
style(zotero): format finalization coverage
seonghobae Sep 4, 2026
f5a45e8
Merge current paired-artifact parent into worksheet finalization
seonghobae Sep 4, 2026
a96a2d2
Merge repaired write receipt evidence into zotero-worksheet-finalization
seonghobae Sep 4, 2026
b21959b
Merge current receipt repair parent into zotero-worksheet-finalization
seonghobae Sep 4, 2026
93f61d4
Merge remote-tracking branch 'origin/autoresearch/zotero-worksheet-cl…
seonghobae Sep 4, 2026
42994f7
merge(zotero): adopt current worksheet-cli parent
seonghobae Sep 4, 2026
9d89805
merge(zotero): adopt current worksheet-cli parent and gap baseline
seonghobae Sep 5, 2026
b3e781a
merge(research): inherit verified source and proposal approval binding
seonghobae Sep 5, 2026
4718073
test(research): reproduce finalization proposal approval reuse
seonghobae Sep 5, 2026
61fee4c
fix(research): validate proposal approval before worksheet finalization
seonghobae Sep 5, 2026
e472db9
merge(research): inherit canonical local transport repairs into PR #27
seonghobae Sep 5, 2026
0a87c0a
merge(research): inherit deterministic transport framing regression i…
seonghobae Sep 5, 2026
9c4ecf5
merge(zotero): propagate validated approval ordering through PR 27
seonghobae Sep 5, 2026
3df0c12
merge(research): inherit bounded metadata reads into PR #27
seonghobae Sep 6, 2026
5fa34b4
merge(research): retain finalization and verified export scope
seonghobae Sep 6, 2026
f02631e
test(research): reproduce stale worksheet finalization admission
seonghobae Sep 6, 2026
d44b9fe
fix(research): require worksheet content continuity during finalization
seonghobae Sep 6, 2026
e90a02b
test(research): separate local finalization from independent completi…
seonghobae Sep 6, 2026
da2556b
docs(research): distinguish finalization continuity from independent …
seonghobae Sep 6, 2026
fd5ef23
docs(research): record finalization binding RED and exact verification
seonghobae Sep 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ All notable changes to ConceptWeave are documented here.
- A complete-review evaluator that rejects partial steward labels as full reclassification evidence.
- A snapshot-bound steward worksheet with one blank decision per bibliographic item and no duplicated bibliographic text.
- An explicit `--worksheet` CLI mode that writes the live worksheet with owner-only report protections.
- Fail-closed conversion from a fully decided worksheet to the existing externally verified golden-set boundary.

### Security

Expand Down
70 changes: 70 additions & 0 deletions crates/conceptweave-zotero/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1248,6 +1248,76 @@ pub struct GoldenSetApproval {
pub snapshot_items: Vec<SnapshotItemRevision>,
}

/// Converts a fully decided local worksheet into the input for approval verification.
///
/// The supplied approval must already bind the current complete proposal records.
/// This function validates that binding without creating or renewing authority.
/// The worksheet must independently match the current proposal identity; changing
/// approval coordinates cannot refresh an older worksheet. Successful conversion
/// is still unverified input, not complete-library, full-text or write authority.
pub fn reviewed_golden_set_from_worksheet(
report: &ClassificationReport,
worksheet: &StewardReviewWorksheet,
approval: GoldenSetApproval,
) -> Result<ReviewedGoldenSet, EvaluationError> {
let expected =
build_steward_review_worksheet(report).map_err(|_| EvaluationError::InvalidReview)?;
if worksheet.decisions.len() != expected.decisions.len() {
return Err(EvaluationError::IncompleteReview);
}
if approval.receipt_id.trim().is_empty()
|| approval.reviewer_subject.trim().is_empty()
|| approval.proposal_digest.trim().is_empty()
|| worksheet.rule_revision.trim().is_empty()
|| worksheet.snapshot_digest.trim().is_empty()
|| worksheet.proposal_digest.trim().is_empty()
{
return Err(EvaluationError::InvalidReview);
}
if approval.library_version != worksheet.library_version
|| approval.rule_revision != worksheet.rule_revision
|| approval.snapshot_digest != worksheet.snapshot_digest
|| approval.proposal_digest != classification_proposal_digest(report)
|| approval.snapshot_items != worksheet.snapshot_items
{
return Err(EvaluationError::SnapshotMismatch);
}
if worksheet.library_version != expected.library_version
|| worksheet.rule_revision != expected.rule_revision
|| worksheet.snapshot_digest != expected.snapshot_digest
|| worksheet.proposal_digest != expected.proposal_digest
|| worksheet.snapshot_items != expected.snapshot_items
{
return Err(EvaluationError::SnapshotMismatch);
}

let mut labels = Vec::with_capacity(worksheet.decisions.len());
for (decision, expected_decision) in worksheet.decisions.iter().zip(expected.decisions) {
if decision.item_key != expected_decision.item_key
|| decision.item_version != expected_decision.item_version
|| decision.proposed_disposition != expected_decision.proposed_disposition
|| decision.abstention_reason != expected_decision.abstention_reason
{
return Err(EvaluationError::InvalidReview);
}
let expected_disposition = decision
.reviewed_disposition
.ok_or(EvaluationError::IncompleteReview)?;
if expected_disposition == Disposition::NeedsStewardReview {
return Err(EvaluationError::InvalidExpectedDisposition);
}
labels.push(GoldenLabel::new(
decision.item_key.clone(),
expected_disposition,
));
}
if labels.is_empty() {
return Err(EvaluationError::IncompleteReview);
}

Ok(ReviewedGoldenSet { approval, labels })
}

/// Computes the canonical content identity verified by a golden-set approval.
pub fn classification_snapshot_digest(report: &ClassificationReport) -> String {
report.snapshot_digest.clone()
Expand Down
Loading