Restcontroller - Source Excerpt 08
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Http/RestController.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Http/RestController.php
return $user_id > 0 && ($this->permissions->is_admin($user_id) || user_can($user_id, 'share_prompts_with_specific_users'));
}
/**
* Returns the next scheduled UTC timestamp for one cron hook.
*/
private function scheduled_utc(string $hook): string
{
$timestamp = wp_next_scheduled($hook);
return $timestamp ? gmdate('c', (int) $timestamp) : '';
}
/**
* Returns one prompt payload enriched with review summary.
*/
private function augment_prompt_payload(array $prompt, bool $detail): array
{
$record = $this->prompts->for_api($prompt, $detail);
$prompt_id = (int) ($prompt['id'] ?? 0);
$record['appeal_summary'] = $this->appeals->summary_for_prompt($prompt_id);
$record['review_summary'] = $this->current_review_summary($prompt_id, $record['appeal_summary']);
$record['governance_summary'] = PromptGovernanceSummary::build(
$record,
$record['review_summary'],
$record['appeal_summary']
);
return $record;
}
/**
* Reconciles moderation state after a peer-review or report signal.
*/
private function reconcile_prompt_governance(array $prompt, int $actor_user_id, string $trigger): array
{
if (empty($prompt)) {
return [];
}
$appeal_summary = $this->appeals->summary_for_prompt((int) $prompt['id']);
$summary = $this->current_review_summary((int) $prompt['id'], $appeal_summary);
$current = PromptMetaRegistry::normalize_moderation_status((string) ($prompt['moderation_status'] ?? 'draft'));
$target = $this->resolve_governance_status($prompt, $summary, $appeal_summary);
if ($target === $current) {
return $this->prompts->get((int) $prompt['id'], $actor_user_id);
}
$updated = $this->prompts->set_moderation_status((int) $prompt['id'], $target);
$this->audit->log(
$actor_user_id ?: null,
'prompt_moderation_state_changed',
'prompt',
(int) $prompt['id'],
[
'from' => $current,
'to' => $target,
'trigger' => $trigger,
'summary' => $summary,
'appeal_summary' => $appeal_summary,
]
);
return $updated;
}
/**
* Resolves the stored moderation state from peer-review and report counts.
*
* @param array<string,mixed> $summary
*/
private function resolve_governance_status(array $prompt, array $summary, array $appeal_summary = []): string
{
$visibility = (string) ($prompt['visibility'] ?? 'private');
$prompt_status = (string) ($prompt['prompt_status'] ?? 'draft');
if ($prompt_status === 'archived') {
return 'archived';
}
if ($visibility !== 'public' || $prompt_status !== 'published') {
return 'draft';
}
if ((string) ($appeal_summary['latest_resolution'] ?? '') === 'archive') {
return 'archived';
}
$restrict = (int) (($summary['peer']['restrict'] ?? 0));
$revert = (int) (($summary['peer']['revert'] ?? 0));
$endorse = (int) (($summary['peer']['endorse'] ?? 0));
$reports = (int) ($summary['unique_reporters'] ?? 0);
$current = PromptMetaRegistry::normalize_moderation_status((string) ($prompt['moderation_status'] ?? 'draft'));
if ($revert >= 2) {
return 'reverted';
}
if ($restrict >= 2 || $reports >= 3) {
return 'restricted_review';
}
if ($endorse >= 2) {
return (string) ($prompt['publication_lane'] ?? 'community_library') === 'official_canon'
? 'official_canon'
: 'peer_reviewed';
}
if ((string) ($prompt['prompt_origin'] ?? 'user') === 'system' && in_array($current, ['peer_reviewed', 'official_canon'], true)) {
return $current;
}
if (in_array($current, ['peer_reviewed', 'official_canon'], true) && $endorse === 0 && $restrict === 0 && $reports === 0) {
return $current;
}
if ((string) ($appeal_summary['latest_resolution'] ?? '') === 'restore') {
return 'provisional_public';
}
return 'provisional_public';
}
/**
* Returns the active review summary after appeal-based governance resets.
*
* @param array<string,mixed>|null $appeal_summary
* @return array<string,mixed>
*/
private function current_review_summary(int $prompt_id, ?array $appeal_summary = null): array
{
if ($appeal_summary === null) {
$appeal_summary = $this->appeals->summary_for_prompt($prompt_id);
}
$since_utc = (string) ($appeal_summary['governance_reset_utc'] ?? '');
return $this->reviews->summary_for_prompt($prompt_id, $since_utc);
}
/**
* Returns whether a prompt is safe for public-library exposure.
*/
private function is_public_library_prompt(array $prompt): bool
{
return (string) ($prompt['visibility'] ?? '') === 'public'
&& empty($prompt['soft_deleted_at'])
&& (string) ($prompt['prompt_status'] ?? 'draft') === 'published'
&& PromptMetaRegistry::is_public_moderation_status((string) ($prompt['moderation_status'] ?? 'draft'));
}
/**
* Blocks public publication when attached Spiral Script source fails v0.1 validation.
*
* @param array<string,mixed> $payload
* @param array<string,mixed> $fallback
*/
private function validate_spiral_script_publication_request(array $payload, array $fallback, int $user_id): ?WP_Error
{
if (!function_exists('spiralist_spiral_script_compile')) {
return null;
}
$source = trim((string) (
$payload['spiral_script_source']
?? ($payload['spiralist_workspace_spiral_script_source']
?? ($fallback['spiral_script_source'] ?? ''))
));
if ($source === '') {
return null;
}
$visibility = sanitize_key((string) (
$payload['visibility']
?? ($payload['spiralist_workspace_visibility']
?? ($fallback['visibility'] ?? 'private'))
));
$prompt_status = sanitize_key((string) (
$payload['prompt_status']
?? ($payload['spiralist_workspace_prompt_status']
?? ($fallback['prompt_status'] ?? 'draft'))
));
$attempting_publication = $visibility === 'public' || $prompt_status === 'published';
if (!$attempting_publication) {
return null;
}
$compiled = spiralist_spiral_script_compile(
$source,
[
'title' => (string) ($payload['title'] ?? ($fallback['title'] ?? 'Untitled Prompt')),
'visibility' => $visibility,
'createdBy' => $user_id > 0 ? 'user:' . (string) $user_id : 'anonymous',
'createdAt' => gmdate('c'),
]
);
$validation = is_array($compiled['validation'] ?? null) ? (array) $compiled['validation'] : [];
if (!empty($validation['passed'])) {
return null;
}
$blocking = array_values(array_filter(
(array) ($validation['errors'] ?? []),
static function ($error): bool {
return is_array($error) && in_array((string) ($error['severity'] ?? ''), ['blocker', 'error'], true);
}
));
if (empty($blocking)) {
return null;
}
return new WP_Error(
'spiralist_workspace_spiral_script_invalid',
'Spiral Script validation must pass before a prompt can be public or published.',
[
'status' => 400,
'spiral_script_validation' => $validation,
]
);
}
/**
* Returns prompt-library filters from a REST request.
*
* @return array<string,string>
*/
private function request_filters(WP_REST_Request $request): array
{
$search = sanitize_text_field((string) $request->get_param('search'));
$intent = trim((string) $request->get_param('intent')) !== ''
? PromptIntentRegistry::normalize_intent((string) $request->get_param('intent'))
: '';
$redirect_intent = $intent === '' ? PromptIntentRegistry::redirect_intent_for_search($search) : '';
if ($redirect_intent !== '') {
$intent = $redirect_intent;
}
return [
'intent' => $intent,