Skip to content

feat: add artifact provenance reconciliation workshop prototype#1162

Open
farchettiensis wants to merge 4 commits into
freeCodeCamp:mainfrom
farchettiensis:feat/artifact-provenance-workshop
Open

feat: add artifact provenance reconciliation workshop prototype#1162
farchettiensis wants to merge 4 commits into
freeCodeCamp:mainfrom
farchettiensis:feat/artifact-provenance-workshop

Conversation

@farchettiensis

@farchettiensis farchettiensis commented May 19, 2026

Copy link
Copy Markdown
Contributor

Checklist

This is the prototype for this issue.

This is part of the JS Objects module.

@farchettiensis farchettiensis marked this pull request as ready for review May 19, 2026 13:31
Copilot AI review requested due to automatic review settings May 19, 2026 13:31

Copilot AI 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.

Pull request overview

Adds a prototype JavaScript workshop script for an “artifact provenance reconciliation” exercise in the JS Objects module, demonstrating how to merge two curator submissions, detect conflicts, resolve via priority, and print an audit-style report.

Changes:

  • Introduces sample provenance records for two artifacts and collects them into an array.
  • Implements helpers to merge two submissions, detect a small set of conflicts, and resolve by priority.
  • Outputs a console-driven demo plus markdown-like audit report rendering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread fullstack-cert/js-projects/artifact-provenance/script.js Outdated
Comment thread fullstack-cert/js-projects/artifact-provenance/script.js Outdated
Comment thread fullstack-cert/js-projects/artifact-provenance/script.js Outdated
Comment thread fullstack-cert/js-projects/artifact-provenance/script.js Outdated
@farchettiensis farchettiensis marked this pull request as draft May 19, 2026 13:37

@jdwilkin4 jdwilkin4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The code looks good but I would suggest simplifying this a bit and making it shorter and scoped to a few key ideas. That will make for a better learning experience since we are still dealing with campers relatively new to JS.

something like this

const collection = [
  {
    id: 101,
    title: "Golden Mask",
    category: "Ceremonial",
    curator: {
      id: 201,
      name: "Sofia Reyes",
    },
    locations: [
      { gallery: "Hall A", year: 2020 },
      { gallery: "Hall C", year: 2024 },
    ],
    tags: ["gold", "egypt"],
    onDisplay: true,
  },
  {
    id: 102,
    title: "Bronze Tablet",
    category: "Inscription",
    curator: {
      id: 202,
      name: "Mia Chen",
    },
    locations: [{ gallery: "Archive Wing", year: 2019 }],
    tags: ["bronze", "writing"],
    onDisplay: false,
  },
];

console.log("FIRST ARTIFACT");
console.log(collection[0].title);
console.log(collection[0].curator.name);

console.log("---------");

function getArtifactTitle(id) {
  const artifact = collection.find((item) => item.id === id);
  return artifact ? artifact.title : "Artifact not found";
}

console.log("LOOKUP BY ID");
console.log(getArtifactTitle(102));

console.log("---------");

function addTag(id, tag) {
  const artifact = collection.find((item) => item.id === id);

  if (artifact && !artifact.tags.includes(tag)) {
    artifact.tags.push(tag);
  }
}

addTag(101, "royal");

console.log("UPDATED TAGS");
console.log(collection[0].tags);

console.log("---------");

function moveArtifact(id, gallery, year) {
  const artifact = collection.find((item) => item.id === id);

  if (artifact) {
    artifact.locations.push({ gallery, year });
  }
}

moveArtifact(102, "Hall B", 2026);

console.log("UPDATED LOCATIONS");
console.log(collection[1].locations);

console.log("---------");

function toggleDisplayStatus(id) {
  const artifact = collection.find((item) => item.id === id);

  if (artifact) {
    artifact.onDisplay = !artifact.onDisplay;
  }
}

console.log("DISPLAY STATUS");
console.log(collection[1].onDisplay);

toggleDisplayStatus(102);

console.log(collection[1].onDisplay);

console.log("---------");

function buildSummary(id) {
  const artifact = collection.find((item) => item.id === id);

  if (!artifact) {
    return "Artifact not found";
  }

  const currentLocation = artifact.locations[artifact.locations.length - 1];

  return `${artifact.title}
Category: ${artifact.category}
Curator: ${artifact.curator.name}
Current Gallery: ${currentLocation.gallery}
Tags: ${artifact.tags.join(", ")}
On Display: ${artifact.onDisplay}`;
}

console.log("SUMMARY");
console.log(buildSummary(101));

@farchettiensis

Copy link
Copy Markdown
Contributor Author

The code looks good but I would suggest simplifying this a bit and making it shorter and scoped to a few key ideas. That will make for a better learning experience since we are still dealing with campers relatively new to JS.

something like this

const collection = [
  {
    id: 101,
    title: "Golden Mask",
    category: "Ceremonial",
    curator: {
      id: 201,
      name: "Sofia Reyes",
    },
    locations: [
      { gallery: "Hall A", year: 2020 },
      { gallery: "Hall C", year: 2024 },
    ],
    tags: ["gold", "egypt"],
    onDisplay: true,
  },
  {
    id: 102,
    title: "Bronze Tablet",
    category: "Inscription",
    curator: {
      id: 202,
      name: "Mia Chen",
    },
    locations: [{ gallery: "Archive Wing", year: 2019 }],
    tags: ["bronze", "writing"],
    onDisplay: false,
  },
];

console.log("FIRST ARTIFACT");
console.log(collection[0].title);
console.log(collection[0].curator.name);

console.log("---------");

function getArtifactTitle(id) {
  const artifact = collection.find((item) => item.id === id);
  return artifact ? artifact.title : "Artifact not found";
}

console.log("LOOKUP BY ID");
console.log(getArtifactTitle(102));

console.log("---------");

function addTag(id, tag) {
  const artifact = collection.find((item) => item.id === id);

  if (artifact && !artifact.tags.includes(tag)) {
    artifact.tags.push(tag);
  }
}

addTag(101, "royal");

console.log("UPDATED TAGS");
console.log(collection[0].tags);

console.log("---------");

function moveArtifact(id, gallery, year) {
  const artifact = collection.find((item) => item.id === id);

  if (artifact) {
    artifact.locations.push({ gallery, year });
  }
}

moveArtifact(102, "Hall B", 2026);

console.log("UPDATED LOCATIONS");
console.log(collection[1].locations);

console.log("---------");

function toggleDisplayStatus(id) {
  const artifact = collection.find((item) => item.id === id);

  if (artifact) {
    artifact.onDisplay = !artifact.onDisplay;
  }
}

console.log("DISPLAY STATUS");
console.log(collection[1].onDisplay);

toggleDisplayStatus(102);

console.log(collection[1].onDisplay);

console.log("---------");

function buildSummary(id) {
  const artifact = collection.find((item) => item.id === id);

  if (!artifact) {
    return "Artifact not found";
  }

  const currentLocation = artifact.locations[artifact.locations.length - 1];

  return `${artifact.title}
Category: ${artifact.category}
Curator: ${artifact.curator.name}
Current Gallery: ${currentLocation.gallery}
Tags: ${artifact.tags.join(", ")}
On Display: ${artifact.onDisplay}`;
}

console.log("SUMMARY");
console.log(buildSummary(101));

Ok, thank you for the review and the suggestions. I will see how I can adjust it according to your suggestions, while still implementing the stories mentioned in the issue (that's the challenge, i think).

@farchettiensis

Copy link
Copy Markdown
Contributor Author

@jdwilkin4, I've refactored and simplified the prototype, cutting the length by almost half.

I've kept the issue's five functions and the technical notes (deep cloning to avoid side effects, plus the merge-conflict, missing-chain, and identical-entry test cases).

The focus is on three things: not mutating your inputs (clone instead of edit), building new objects from existing ones, and reading nested object and array data.

One important note: of those, only the no-mutation idea is genuinely new for this slot, and the rest is reinforcement. So if it still reads as too much, I feel like the weight is in the stories and the technical requirements described in the issue. So I might need to stray from them. If that's the direction I should go, can you point specifically what feels too advanced, and confirm if I can depart from the stories and technical notes?

@jdwilkin4 jdwilkin4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Since this is supposed to go in the objects module, we can't use map or join because that hasn't been taught yet.

If you need to deviate from the original user stories that is fine. It is important that this project fits in the module correctly in terms of difficulty. 👍🏾

@farchettiensis

Copy link
Copy Markdown
Contributor Author

Since this is supposed to go in the objects module, we can't use map or join because that hasn't been taught yet.

If you need to deviate from the original user stories that is fine. It is important that this project fits in the module correctly in terms of difficulty. 👍🏾

Updated per your suggestion @jdwilkin4, but I dropped the join, since you mentioned that's a restriction as well.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants