A large collection of material does not automatically become a useful article. Records about the same event need to be connected, a reader question chosen and the facts available to a draft checked. I developed this small board from the separation of responsibilities described in K-POP PULSE’s initial structure and operating records.

This module is newly written. It is not a recovered copy of the historical program. Synthetic records make gaps in the evidence links visible. You can open the independent HTML interface or take the pure assessment function into another program. Actual source review, manuscript storage and publication approval remain responsibilities of an operating service.

Where this can be useful

The module is useful when an article draws from several announcements or when new material requires its evidence to be reconsidered. A date in one record and a venue in another can be connected. If a change notice introduces another date, the board first reports that different values are present.

It does not automatically select the true value. Someone must read the material to decide whether this is a correction, a different event or an input mistake. I separate signals about incomplete checks from the editorial judgment still required.

Try the example in this order

The schedule and venue records are initially linked, but their review is pending. Simulating completed source checks lets you inspect a draft fact sheet. Adding the changed-date record creates a conflict. Removing the old schedule from the current selection lets a new handoff use the changed date and venue.

Removing a record from the selection does not delete its original. Every synthetic record remains in the catalog; only the links for this story change. The review checkbox is also a simulation. Clicking it cannot establish the truth of any real announcement.

A newly written example using synthetic evidence. It does not store, publish or verify real sources.

Read evidence links without mutating the source

The core function receives a catalog and an issue containing sourceIds and requiredFacts. It finds the linked records and returns each fact with its source ID and observation time. Repeating the same link does not multiply the facts, and the source input is left unchanged.

The result distinguishes unknown links, pending source checks, missing required fields and conflicting values for a field. Its last state means a fact sheet can be handed to drafting. It does not mean an article is complete or approved for public access.

Explore the implementation

The newly written teaching function, not recovered code from the original project.

// A new teaching module derived from a source -> issue -> draft workflow.
// It links evidence and reports mechanical gaps. It cannot verify truth or publish.
export function assessIssue(catalog, issue) {
  if (!Array.isArray(catalog) || !issue || !Array.isArray(issue.sourceIds) ||
      !Array.isArray(issue.requiredFacts)) throw new TypeError('Invalid issue contract');
  const byId = new Map();
  for (const source of catalog) {
    if (!source || typeof source.id !== 'string' || !source.id || byId.has(source.id) ||
        typeof source.title !== 'string' || !Array.isArray(source.facts) ||
        typeof source.observedAt !== 'string' || !Number.isFinite(Date.parse(source.observedAt)) ||
        !['unchecked', 'checked'].includes(source.review)) throw new TypeError('Invalid source record');
    for (const fact of source.facts) {
      if (!fact || typeof fact.key !== 'string' || !fact.key ||
          typeof fact.value !== 'string' || !fact.value.trim()) throw new TypeError('Invalid fact');
    }
    byId.set(source.id, source);
  }
  if (issue.sourceIds.some(id => typeof id !== 'string') ||
      issue.requiredFacts.some(key => typeof key !== 'string' || !key)) throw new TypeError('Invalid links');
  const ids = [...new Set(issue.sourceIds)];
  const missingSources = ids.filter(id => !byId.has(id));
  const selected = ids.filter(id => byId.has(id)).map(id => byId.get(id));
  const pendingSources = selected.filter(source => source.review !== 'checked').map(source => source.id);
  const facts = selected.flatMap(source => source.facts.map(fact => ({
    key: fact.key, value: fact.value, sourceId: source.id, observedAt: source.observedAt
  })));
  const keys = new Set(facts.map(fact => fact.key));
  const missingFacts = [...new Set(issue.requiredFacts)].filter(key => !keys.has(key));
  const conflicts = [...keys].filter(key => new Set(facts.filter(fact => fact.key === key).map(fact => fact.value)).size > 1);
  const state = !ids.length || missingSources.length ? 'missing-source' :
    conflicts.length ? 'conflict' : pendingSources.length ? 'needs-source-review' :
    missingFacts.length ? 'missing-fact' : 'ready-for-draft';
  return {state, sourceIds: ids, missingSources, pendingSources, missingFacts, conflicts, facts};
}

Adapt the contract to your website

This example requires a date and venue. A product article might require a model and specification; a work diary might require a changed component and its observed result. The reader question determines which facts are needed. There is no universal fact sheet that must be imposed on every article.

Each source’s review field must be supplied from real source-review records. A single checkbox must not become an operational shortcut to verification. A production service should retain the reviewer, review time, relevant version and scope, while preserving earlier evidence when current links change.

  1. catalog: source identity, title, observation time, fact fields and review state
  2. sourceIds: the evidence selected for the current issue
  3. requiredFacts: fields needed to answer this particular question
  4. labels and CSS: language and layout suited to the website

Arrange one HTML structure for wide and narrow layouts

I wrote the layout with a source area and a result area. CSS stacks them in reading order at a narrow width. There are no separate copies of the list for desktop and mobile. Native checkboxes handle selection, while a separate status region is updated. Changing the result does not replace the input a person is using.

Use the CSS with the downloadable standalone HTML. I exercised the Korean and English public examples in actual Studio browser frames at 960px and 390px widths, checking selection, review, conflicts and fact-sheet display. The narrow layout stacks its panels without horizontal overflow. This verifies the example frames, not a physical phone or the whole integrating website. Recheck the article width and type sizes where you use it.

Explore the implementation

New layout CSS included in the standalone example; adapt it to the article width.


:root{color-scheme:light;font:16px/1.55 system-ui,sans-serif;color:#202b32;background:#f6f8f7}
*{box-sizing:border-box}body{margin:0;padding:24px}h1{font-size:clamp(24px,4vw,34px);line-height:1.2;margin:0 0 10px}
h2{font-size:20px;margin:0 0 18px}p{margin:0 0 16px}small{color:#526268}.layout{display:grid;gap:20px;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.panel{min-width:0;padding:20px;background:white;border:1px solid #d5ded9;border-radius:14px}.source{display:flex;gap:12px;margin-bottom:12px;padding:14px;border:1px solid #d5ded9;border-radius:10px;cursor:pointer}
.source input{margin-top:7px;flex:none}.source span{min-width:0}.source strong,.source small{display:block}.review{display:flex;gap:10px;align-items:start;margin-top:18px}
.review input{margin-top:6px}input{width:19px;height:19px;accent-color:#176b4f}button{font:inherit;padding:10px 15px;border:0;border-radius:8px;background:#176b4f;color:white;cursor:pointer;max-width:100%}
button:disabled{background:#63756c;cursor:not-allowed;opacity:.7}button:focus-visible,input:focus-visible{outline:3px solid #eda842;outline-offset:4px}
.status{padding:12px;border-left:4px solid #176b4f;background:#eff7f2;font-weight:650}ul{padding-left:22px}li{margin-bottom:9px;overflow-wrap:anywhere}pre{font:13px/1.5 ui-monospace,monospace;white-space:pre-wrap;overflow-wrap:anywhere;padding:14px;background:#eff2f0;border-radius:8px}
.boundary{font-size:14px;color:#526268;margin-top:18px}[hidden]{display:none!important}@media(max-width:680px){body{padding:16px}.layout{grid-template-columns:minmax(0,1fr)}.panel{padding:16px}}

Checks performed and responsibilities still to add

The new pure function passed local synthetic tests covering absent evidence, unknown links, date conflicts, missing required fields, pending review, repeated links, invalid source contracts and input immutability. These tests verify that function’s contract. They do not establish source truth, rendered browser interaction or the storage of operational data.

A production integration still needs authentication, revision records, server storage and editorial approval before publication. If private source records are bundled into public JavaScript, that content is delivered to visitors. An administrative board using private material needs a server access boundary and a separate projection containing only what may be public.

The download contains independent Korean and English screens, the core function, reproducible checks and instructions. You may copy and adapt it for your website. Before completing an integration, exercise source selection, conflict display, missing required fields and the fact-sheet handoff in the actual rendered screen.

Download the board HTML, code, checks and instructions
ZIP of the new teaching module with standalone Korean and English screens.