Skip to main content
POST
Score a Cycle

Proposed rehearsal behavior

DCinside sends new candidates, engagement updates for all pending posts and removals. Surf returns waiting before queue entry plus 15 minutes, then refreshed scores for every eligible pending candidate each cycle. The rehearsal cadence is fixed at five minutes.
This endpoint reference describes the rehearsal proposal. Verify the deployed artifact, persistence, cadence and alert delivery against Rehearsal and acceptance before starting.

Request guidance

extracted_at means original entry into DCinside’s queue, including for posts delivered after an operator decision. Model 0924 first scores at or after extracted_at + 15 minutes. Before then, the result is waiting, with due_cycle set to the first five-minute boundary at or after that point. The target remains at least 99% first scored within two cycles after the 15-minute mark; reaching that target does not end retention. Saved/hidden decisions remain in that denominator; immediate deleted/aged_out removals before the mark retain the early-removal exclusion. A null entry time returns not_scored / missing_clock; a later retransmission can fill a previously unknown entry time, but cannot replace one already known. New rehearsal candidates must provide a non-null, RFC 3339 extracted_at. The field remains nullable on the API for compatibility and repair. A missing clock cannot establish scoring eligibility or prove the first-score SLA, and must not be silently removed from the 99% denominator; report and repair it. An early saved/hidden decision is not an exclusion under the new policy. The sending worker must validate queue-entry clocks before sending; the shared transport helper rejects missing or invalid candidate entry clocks. Pending posts keep being rescored after their first score and after 25 minutes; the API has no automatic 24-hour expiry. The client sends deleted/aged_out removals when its deletion or age condition is met. The API applies received removals before scoring that cycle, so a candidate and its removal sent together do not obtain a first score. Saved/hidden enum values remain accepted for compatibility and still remove the post if received. Resending any removed identity does not revive it, including after restart; backfilling previously removed posts requires a separately agreed re-entry policy. Use the field reference below for proposed types and examples. JSON may be plain or gzip-compressed. Current size and array protections are listed in Conventions; do not truncate the full queue to fit them.

Response and retry semantics

The response contains post IDs, final scores, model and weight versions, scoring times and counts. Per-part predictions are optional. All raw score rows remain present, including same-event duplicates. After raw scoring, the API durably prepares the cycle’s scores and exact candidate/published-window evidence, then allows background checks to progress within the remaining response budget before freezing one final response. The separate deduplication report compares candidates only against that cycle’s supplied windows. For Main and Light independently, ranked contains all scored candidates except confirmed duplicates; unchecked is a diagnostic subset of ranked and does not exclude candidates. Facts completed during this bounded wait can therefore appear in the same cycle. A newer cycle cannot substitute its window or scores into an older response. Surf prioritizes the highest-scored work eligible to run. The wait ends when the prepared cycle’s still-needed comparisons have settled or its remaining wait budget expires; finding one usable candidate does not end the wait. Validated full-evidence unknowns and unavailable evidence can leave rows unchecked even when no further assessment is currently possible. Transient failures and incomplete evidence delivery remain retryable; a retry cooldown is not a completed check. A partial report includes unchecked candidates in ranked; only confirmed duplicates are excluded. Unchecked remains diagnostic, not proof of uniqueness. Missing content or a failed LLM check does not remove raw scores or certify those posts as unique. The latest client requirement allows 60 seconds from sending, including at most one retry. A late response is skipped for that cycle, but its data must still be reconciled. Recover using GET /v1/scores/{cycle_id} or replay the original request. See the worker integration notes for retry budgeting. The server’s default 25-second processing budget includes preparation, raw scoring, bounded waiting and finalization, with time reserved to persist the response. Waiting releases the database writer so background results can commit. Background inference can continue after the response; this budget does not promise that every comparison resolves or prove the client’s end-to-end deadline. New cycles may change scores and dedup decisions. Retries and GET for a completed cycle return its original response, including any partial/unavailable dedup result. Later images, a recovered provider, a background verdict or a different published snapshot do not rewrite that cycle. Send the next scheduled new cycle to receive an updated report; GET does not poll for newer verdicts. Changing a snapshot under an accepted cycle ID returns 409. If a request stops after preparation but before finalization, replaying the unchanged request resumes its prepared scores, counts and evidence without scoring or ingesting them again. GET returns 404 until a final result exists. For newly prepared cycles, scored_at records raw model score completion before the deduplication wait; it is not the final response time or client round-trip duration. counts.candidates and counts.removals count identities first accepted in that cycle, excluding repeats within or across requests. Removal counts describe receipt, not when an operator decided; saved/hidden labels remain a separate client-side series and no longer generate removal receipts under this policy. counts.scored_now counts scoring events in that cycle, including rescoring, not unique first scores. For daily reconciliation, join by post identity, group unique entrants by original extracted_at KST date, and track first scores separately from per-cycle scoring and removal receipt. Between-cycle entrants increase the unique entrant totals. Original queue-entry and delivered removal timestamps are retained after removal. Removals remain effective after restart or candidate retransmission. DCinside must record the actual policy switch time and cohort assignment. The proposed 2026-10-15 00:00 KST cycle 20261015T0000 is not confirmed; the earlier first-score-or-25-minute hold was never activated. Do not relabel historical measurements or infer a deployed policy period from a documentation update. Retrospective backfill of prior removals remains undecided. These API counters support reconciliation but do not calculate the first-score SLA denominator. Scores use engagement and admin observations available through cycle_time, and age features at that time. Retaining a post after an operator decision does not produce an as-of-decision score: report these comparisons separately from scores available before the decision. Hidden alone does not veto a client pick under the new policy. The client skips currently real-board posts and selects the next eligible candidate; intervention follows actual publication/unpublication. A post already present in a supplied tier window is excluded from that tier’s dedup ranking while its raw score remains in results. Those last-20 snapshots do not replace the client’s full current-board check. Examples illustrate the contract, not measured deployment results. Empty titles and unknown creation times can still be scored once queue-entry eligibility is known. Images may arrive later and do not delay scoring. DCinside applies the 24-hour queue filter and sends removals.

Authorizations

Authorization
string
header
required

Proposed API key sent as the whole Authorization header value. One long-lived key, handed privately to the partner contact and rotated on either side's request. Per-endpoint scopes are not currently enforced.

Headers

Content-Encoding
enum<string>

Optional compression. Set to gzip only for a gzip-compressed body; plain JSON is also supported.

Available options:
gzip

Body

application/json

Proposed rehearsal wire shape. Required arrays and extra metadata need payload review. Current other-array and request-size protections are engineering limits, not client quotas.

cycle_id
string
required

Idempotency key: the cycle time in KST as YYYYMMDDTHHMM, for example 20260929T0205. The same id with the same body returns the stored response. The same id with a different body returns 409.

Pattern: ^\d{8}T\d{4}$
Example:

"20260929T0205"

cycle_time
string<date-time>
required

Scheduled five-minute rehearsal boundary with an explicit RFC 3339 offset; normalize to KST for cycle_id. Up to 60 seconds ahead of server time is allowed, inclusive. Runtime supports other configured intervals outside this rehearsal.

Pattern: ^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})$
Example:

"2026-09-29T02:05:00+09:00"

candidates
object[]
required

New posts since acknowledged delivery; re-include after uncertain timeout when GET finds no completed response. Identity gall_id/post_no is stored and counted once across repeated rows/cycles. Original content and known extracted_at remain unchanged. No candidate-count cap; the whole JSON body must fit within 16 MiB after decompression. Pending candidates remain until removed.

engagement
object[]
required

One row for every pending candidate, every cycle. Pending means sent in this or an earlier call and not yet in removals. The current 5,000-row cap is an engineering protection, not an agreed business quota; validate it against full-queue delivery.

Maximum array length: 5000
candidate_scores
object[]
required

Available admin snapshots, when present. Existing wire shape requires the array but permits []. Confirm feature mapping and requiredness with the client and delivered model. The current 5,000-row cap is an engineering protection, not an agreed business quota; validate it against full-queue delivery.

Maximum array length: 5000
removals
object[]
required

Saved, hidden, deleted or aged-out post identities. Re-inclusion within/across cycles is idempotent and counts only first accepted removals; candidate retransmission cannot revive a removed post.

Maximum array length: 5000
published_windows
PublishedWindows · object | null

Optional independent current last20 Main/Light published snapshots. Required for published-window dedup coverage; omission/null stays unknown, while [] asserts an empty feed. References reuse archived evidence. For never-delivered posts, bootstrap title/body/image metadata once here, with JPEGs uploaded separately; do not add them as pending candidates.

Response

Complete raw scores and the immutable deduplication report for this cycle. Provider failure can return 200 with raw scores and explicit unavailable/unchecked deduplication.

cycle_id
string
required

Echoed from the request.

Pattern: ^\d{8}T\d{4}$
Example:

"20260929T0205"

cycle_time
string<date-time>
required

Echoed from the request.

Pattern: ^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})$
Example:

"2026-09-29T02:05:00+09:00"

received_at
string<date-time>
required

First valid receipt of this cycle ID, preserved across failed inference retries and completed replays.

Pattern: ^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})$
Example:

"2026-09-29T02:05:03+09:00"

scored_at
string<date-time>
required

Actual scoring completion time sampled after the full inference batch. Measure client receipt time separately.

Pattern: ^\d{4}-\d{2}-\d{2}[Tt]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:[Zz]|[+-]\d{2}:\d{2})$
Example:

"2026-09-29T02:05:09+09:00"

model_version
string
required

Version reported by the actual loaded Model 0924 adapter and configured down-vote coefficient. No environment-only label override or proxy scorer is used.

Example:

"model0924-downvote0"

weights_version
string
required

Weights that actually produced this cycle's scores. Verify that refreshed scores and their version match; do not relabel cached scores.

Example:

"w0924-downvote0"

counts
object
required

Row counts for this cycle.

missing_feature_share
number
required

Fraction of missing request counter fields. This does not count missing values across the model feature set and is not a rehearsal acceptance metric.

Required range: 0 <= x <= 1
Example:

0.11

warnings
string[]
required

Implementation warnings. Unknown fields are not guaranteed to be listed. An empty list does not prove model or data readiness.

Example:
results
object[]
required

One result per pending candidate under the proposed refresh policy. Scores may change across new cycles; replay of a completed cycle is unchanged. Removed posts are absent from subsequent cycles.

deduplication
DeduplicationReport · object | null

Persisted LLM same-event rankings and honest unchecked coverage for main/light. Every raw score remains in results. Omitted for legacy completed cycles. Partial/unavailable completed reports remain immutable on POST replay and GET.