R1 · Consistency across specs¶
Step page: R1
Round: R1 (consistency) · Date: 2026-10-26 · Found by: spec-reviewer, four instances in parallel · Status of the round: triaged (TRIAGE1, 2026-10-27): 13 accepted, 0 rejected, 40 inbox (25 assumed) · triage: TRIAGE1 · APPLY1 (2026-10-27): 11 applied, 26 partly applied, 1 not applied
Sources.
- Branch and commit:
autopilot/integrationat3b209d3. Line numbers ("l.") refer to that commit. - Read: every spec in
docs/specs/, the decision log (log.md), decision 0001, the roadmap page,map.mdandnext-phase.md. -
Reviewer scopes:
- (a)
synthesis.md+ui-spec.md; - (b)
api-and-data-model.md+admin-and-operations.md; - (c)
architecture-plugins-and-packaging.md+cli-and-shared-libraries.md+dev-environment-and-testing.md; - (d)
checking-scenarios.md+schedulers-and-monitoring.md+depictio-ecosystem-reuse.md.
Each reviewer also checked its scope against the decision log and the other specs.
- (a)
-
Reviewer status: all four reviewers returned output. None failed.
- Renames checked: maintainer→editor, agent→runner, Settings→Administration, spectio-runner merged into spectio, broker split into tasks/pubsub. Only the last three left leftovers (SR-039, SR-040, SR-049).
- Earlier rounds: findings already open in R12 (
UX-) and R8b (DEP-T-) are cited, not repeated.
Merge method (review-round skill, steps 3-4):
- De-duplication: the four reviewers returned 82 findings (8 blockers, 50 majors, 24 minors as rated by them). Findings about the same problem were merged into one, crediting every reviewer, with the original IDs listed under "Found by". Where two reviewers rated the same problem differently, the higher rating was kept when the problem touches the 0.1 scope; the reason is given in the finding.
- Verification: every quoted passage of every blocker and major was opened at
3b209d3and confirmed. All of them reproduced, so 0 findings were dropped. Claims about other tools keep the reviewer's source, or are marked [to be validated]. - Ranking: by severity, then by the number of documents the finding touches (specs, the decision log, decision 0001, the roadmap, map.md), shown in the findings table. The "five findings that matter most" are chosen on impact on 0.1, not on that count.
- Proposed new sections: where a finding proposes a new section, it uses a number that is free today. Several reviewers proposed the same number for different content (architecture §12), so this file assigns one number per topic:
- api §7.1: run and gate state machines;
- api §14: ingest contract;
- architecture §7.7: runner protocol;
- architecture §12: compatibility between components;
- checking §12:
spectio.ymlreference; - dev-env §15: what ships in which stage;
- ui-spec §11: component states.
Format: README.md. Prefix SR (spec reviewer). Specs were not edited in this round.
Summary¶
| Severity | Count |
|---|---|
| Blocker | 5 |
| Major | 33 |
| Minor | 15 |
| Total | 53 |
| Dropped (not reproducible) | 0 |
The five findings that matter most:
- SR-001: the engine → server ingest contract does not exist. Decision 0001 removed Tower's
/trace/create, and with it the only thing that gave an observed run its ID. Nothing defines the payload, the run handshake, the credential (no ingest scope exists) or the bridge behaviour when the server is down. Both engine plugins, spike T2 and the walking skeleton depend on it. Three of the four reviewers found it independently. - SR-002: the runner ↔ server protocol has no owner and two transports. api §5 says WebSocket; architecture §7.6, admin §3.2 and the log say outbound HTTPS pull. No command catalogue, ack or replay rule exists, and the runner credential either rotates or lives until revoked. Nothing can be launched without it.
- SR-003: check providers run on the server in three specs, on the runner in three others. The logged rule is "only the runner reads files". The MVP is centred on checks, so this decides which package carries MultiQC, anndata and polars, and whether the 80 MB runner budget holds.
- SR-004:
spectio.ymlhas four shapes and no owner. Synthesis, checking §7, checking §11.2 and ui-spec §5.1 disagree on the gate ↔ stage link, the policy block and the evidence form. The parser, the overlay merge,spectio workflow validateand the 0.1 gate all need one schema. - SR-007: phase labels do not map to release stages. "1b" means four different things. Synthesis §9 still describes a tracking-only MVP, against the logged MVP scope. The WES facade has four dates (SR-010). P1 cannot cut the walking skeleton until dev-env §14 owns a "capability → stage" table.
SR-005 (two tables named tasks) is also a blocker: the first migration cannot be written. The fix, a rename, is mechanical.
Findings table¶
| ID | Severity | Title | Documents touched |
|---|---|---|---|
| SR-001 | blocker | The engine → server ingest contract is undefined | 8 |
| SR-002 | blocker | Runner ↔ server protocol: no owner, two transports, two credential lifetimes | 8 |
| SR-003 | blocker | Check providers run on the server in three specs, on the runner in three others | 6 |
| SR-004 | blocker | spectio.yml has four shapes and no owner of its schema |
5 |
| SR-005 | blocker | tasks names two different tables, ID spaces and endpoint families |
4 |
| SR-006 | major | The CLI command tree lacks commands that other specs cite | 10 |
| SR-007 | major | Phase labels do not map to release stages, and the phase tables contradict each other | 7 |
| SR-008 | major | How Spectio drives Snakemake: Python API worker or command-line head job | 7 |
| SR-009 | major | Environment-variable and config-file names follow incompatible rules | 6 |
| SR-010 | major | The WES facade has four release dates and is under-specified | 6 |
| SR-011 | major | How a gate stops Nextflow: --stage parameter or generated ext.when |
6 |
| SR-012 | major | Gate decisions: five verb sets, two resource names, stale MCP tools and scopes | 5 |
| SR-013 | major | Endpoint catalogues duplicated between api §5 and admin §5; three public config endpoints | 5 |
| SR-014 | major | Which Unix account runs a launch on a group-owned environment is undefined | 5 |
| SR-015 | major | Background-task ledger and schedules: two schemas, two locking designs, no Jobs object | 5 |
| SR-016 | major | Run and gate states: five vocabularies, no enum, a 2-of-11 WES mapping | 4 |
| SR-017 | major | Engine bridge behaviour when the server is unreachable: Tower-era text and no testable bound | 4 |
| SR-018 | major | "Pause": immediate stop or after the current stage | 4 |
| SR-019 | major | Principal kinds: guests, plugin and bridge principals are outside the enum | 4 |
| SR-020 | major | The system-admin flag, protected groups and P.I. fields are missing from the schema | 4 |
| SR-021 | major | Launcher instances and Environments are two models of the same cluster | 4 |
| SR-022 | major | No compatibility window between CLI, runners, engine bridges, plugins and server | 4 |
| SR-023 | major | Gate checks depend on the depictio catalogue, but 0.1 has no depictio | 4 |
| SR-024 | major | Tokens are specified twice, differently | 3 |
| SR-025 | major | launcher and reviewer: rungs on a ladder or capability flags |
3 |
| SR-026 | major | Webhooks are both a project table and a notifier plugin instance | 3 |
| SR-027 | major | The base install's "nothing else" dependency rule is contradicted by the specs' own choices | 3 |
| SR-028 | major | The TypeScript client handles bearer tokens for the UI, which should use HttpOnly cookies | 3 |
| SR-029 | major | Project visibility has three values in the model and two in the UI | 2 |
| SR-030 | major | A restore rewinds the database under runs still executing; token handling is contradictory | 2 |
| SR-031 | major | Single-user mode trusts loopback, but loopback is shared on a login node | 2 |
| SR-032 | major | Built-in plugins are separate distributions, yet one uv tool install spectio is said to be enough |
2 |
| SR-033 | major | on_fail: open_gate creates a gate with no items, policy or deciders |
2 |
| SR-034 | major | schedulers §8 defines tables, events and endpoints the API spec does not have | 2 |
| SR-035 | major | Push transport needs an inbound Kafka consumer the architecture does not have | 2 |
| SR-036 | major | The checks_as preset shape requested from depictio does not match Spectio's check syntax |
2 |
| SR-037 | major | SLURM job names: the head-job pattern and the Snakemake join do not work as written | 1 |
| SR-038 | major | Maintenance mode does not say which writes still work | 1 |
| SR-039 | minor | "Settings" leftovers next to Administration, with a different grouping in api §11/§13.5 | 8 |
| SR-040 | minor | Stale names: agent for runner, perspectio, companion plugin, Duplicate |
6 |
| SR-041 | minor | Run and review screens are specified outside ui-spec; two cross-references are broken | 4 |
| SR-042 | minor | The built-in AI assistant has UI and a runner command but no API, data model or CLI entry | 4 |
| SR-043 | minor | "v1" means both the API path and a release; the API rule conflicts with 0.x semver | 4 |
| SR-044 | minor | Superseded merge and staging rules remain in dev-env, map.md and auth | 4 |
| SR-045 | minor | The event catalogue is incomplete, and gate notifications have two paths | 3 |
| SR-046 | minor | Pipeline identifier and workflow version key: @ vs /, no column |
3 |
| SR-047 | minor | Fixture workflows and step numbers in dev-env disagree with the playbook and with §10.1 | 3 |
| SR-048 | minor | Untestable thresholds: "head silent" and the 10,000-file watch limit | 3 |
| SR-049 | minor | api §3 repeats the plugin-kind table with the stale "broker" kind and another engine contract | 3 |
| SR-050 | minor | The backup and restore contract differs between the CLI and admin specs | 2 |
| SR-051 | minor | Kubernetes RBAC differs between specs, and the Nextflow head pod has none | 2 |
| SR-052 | minor | Check-result vocabulary: state vs verdict, and how severity maps to them |
2 |
| SR-053 | minor | ui-spec contradicts the logged shell and list decisions without a new log entry | 2 |
Blockers¶
SR-001 · blocker · The engine → server ingest contract is undefined¶
- Where: no owner today. The natural owner is api-and-data-model.md (new §14 "Ingest contract", linked from §5). Touches api §2.D, §5, §6; authentication-and-access.md §3; ui-spec.md §4.4, §6; synthesis.md §2bis, §5ter.6, §9; architecture §4, §6; cli §2 (
engine,login); dev-env §6; decision 0001. -
Evidence:
- "
POST /ingest/events(Nextflow pluginnf-spectio, Snakemake logger)" (api §5, l.102) is the only definition. It has no body, batching, response or error codes. - "A run started in a terminal with Spectio enabled is attached to the user's default project, or the project given by
SPECTIO_PROJECT" (api §2.D, l.50). Nothing says how that run is created. - Tower's
/trace/createreturned theworkflowId(synthesis §2bis, l.39). Decision 0001 removed the Tower routes without a replacement. - "with the Spectio run ID passed to
nf-spectioby us (wasTOWER_WORKFLOW_ID…)" (synthesis §5ter.6). No variable or config key is named. - "Run token | the run's life + 24 h | … | Issued to a provisioned run (§4) or an engine plugin; ingest only, for that run" (auth §3, l.104), against "a
spectioconfig profile/env set once byspectio login" (ui-spec §6, l.196) and "one plugin to install, set once byspectio login" (0001, l.24). A credential set once at login cannot be a per-run token. - The scope list "
runs:read,runs:launch,gates:decide,gates:propose,artifacts:read,admin" (api §6, l.155) has no ingest scope. Synthesis §9 (l.377) says "one ingestion token". - "
spectio-sdkcontains all interfaces, settings helpers, event schemas" (architecture §4, l.196; §6, l.232) names a package but defines no event. - "golden fixtures for
nf-spectioevents" (dev-env §6, l.141) have no schema to be checked against. - "
engine|nextflow config(prints thenf-spectioplugin config for observed runs …)" (cli §2, l.54);login(cli §2, l.44) configures no engine. - "Logs … per-task stdout/stderr (fetched on demand through the runner)" (ui-spec §4.4, l.90) against "logs streamed by the engine plugin" (ui-spec §6, l.204).
- "
-
Problem: both engine bridges are needed in 0.1 ("both engines from the start", synthesis §9 l.386). Spike T2 only captures what the engines emit; nothing says what Spectio accepts. Implementers of
nf-spectio, the Snakemake logger andIngestAdapterwould each invent:- the envelope and its versioning;
- how a batch names its run (Spectio run ID, Nextflow
sessionId+runName, Snakemake run UUID); - who creates the run for an observed (terminal-started) run, and which credential the plugin uses before a run token can exist;
- how the runner hands the run ID and token to the engine for a driven run;
- the response, backpressure and batch limits;
- whether task logs travel over ingest or through the runner.
-
Proposal: add api §14 "Ingest contract" as the single owner. The reviewers converge on:
- Envelope:
{schema_version, run_id | client_run_key, events: [{event_id (ULID, idempotency per synthesis §4), seq, ts, engine, engine_version, type, payload}]}, with the raw engine payload kept. The JSON Schema is published fromspectio-sdk, and both bridges and T2 golden fixtures validate against it. - Run handshake: a create-or-attach call (
POST /ingest/runs, or a firstrun.startedevent) that returnsrun_id. It is idempotent on (engine, NextflowsessionId+runNameor Snakemake run UUID, host, launch directory) and creates acli-observedrun in the default orSPECTIO_PROJECTproject. - Driven runs: the runner passes
SPECTIO_URL,SPECTIO_RUN_IDandSPECTIO_RUN_TOKEN(names to fix once); the run token stays "ingest only, for that run". - Observed runs: a personal token with a new ingest scope, written by a named command (for example
spectio engine nextflow config --install). The reviewers proposed three names (runs:ingest,runs:report,ingest:create); pick one and register it in auth §3, which owns scopes (SR-024). - Batching and errors: at most 1,000 events or 1 MB per POST (proposed); response
{run_id, accepted, duplicates, rejected, acked_through};429/503withRetry-After. - Logs: state whether task logs travel over ingest or only through the runner, and fix ui-spec §4.4 / §6 to match.
- Bridge behaviour when the server is down is in this section too (SR-017).
Then align synthesis §5ter.6, ui-spec §6, cli §2 and 0001 (see also SR-006 for the enabling commands). Related, not duplicates: UX-116 (Tower payload for terminal runs, R12).
- Envelope:
-
Found by: spec-reviewer (a) SR-101, (b) SR-205, (c) SR-301
- Status: inbox (TRIAGE1, 2026-10-27)
SR-002 · blocker · Runner ↔ server protocol: no owner, two transports, two credential lifetimes¶
- Where: architecture §7.6 vs api-and-data-model.md §5 and §6 vs admin-and-operations.md §3.2, §3.4, §5 vs authentication-and-access.md §3; also synthesis §7quater, checking-scenarios §11.1 and §11.3, ui-spec §4.8, decision log 2026-10-25.
-
Evidence:
- "runner channel
WS /runners/{id}/channel(commands, heartbeats, file streaming)" (api §5, l.92). - "Commands to runners: launch, cancel, resume | … | runner pulls over outbound HTTPS (long poll or SSE)" (architecture §7.6, l.385). "Commands to runners are pulled over HTTPS, not brokered" (log, l.136).
- "Commands are pulled, never pushed (launch, cancel, "Run diagnostics"). The server records the request and the runner claims it" (admin §3.2, l.146); "
POST /runners/{id}/diagnostics(pulled by the runner)" (admin §5, l.334); "runners ship their daemon logs over HTTPS in batches" (admin §3.4, l.161). - "It opens an outgoing …" WebSocket, "same principle as Seqera's Tower Agent" (synthesis §7quater, l.339). The Tower Agent claim is unsourced [to be validated].
- Commands the specs need but never list: "
S->>R: evaluate check(s) on path" andcheck.evaluated(checking §11.1, l.278); "a stop file the runner writes" (checking §11.3); directory listing (UX-117); log range reads; drain. - Credential: "a one-time registration token becomes a rotating runner credential" (api §6, l.155) vs "Runner token | until revoked" (auth §3, l.103).
- Offline: decisions "queued and applied on reconnect" (ui-spec §4.8, l.137; log 2026-10-25).
- "runner channel
-
Problem: launch, cancel, file streaming for viewers (
GET /artifacts/{id}/content),check.evaluated, stop files, logs and heartbeats all go through this protocol, and it is on the critical path of the 0.1 walking skeleton. Five things are open:- the transport (WebSocket, or HTTPS long-poll / SSE), which matters behind HPC proxies and SSH tunnels (synthesis §8);
- the command catalogue and the result path (
check.evaluatedhas no ingestion route;/ingest/eventsis for engines); - claim, lease, ack, ordering and idempotency;
- how file bytes are streamed (long poll alone cannot stream large files back);
- offline semantics: what happens to pending evaluations, and to a
pause_after_stagestop file that cannot be written (the run then continues past the boundary).
R12 UX-117 (list_dir) and UX-124 (token lifetimes) cover only pieces of this. Rated blocker by reviewer (c), major by (a), (b) and (d); kept as blocker because no launch can be built without it.
-
Proposal:
- Add architecture §7.7 "Runner protocol" as the owner; api §5, admin §3.2 and checking §11 link to it.
- Transport: the reviewers split. (b) and (c) recommend a runner-initiated WebSocket over 443 with HTTPS long-poll and chunked upload as fallback; (d) recommends HTTPS long-poll claim, as in admin §3.2, and removing the WS route. Either way, keep one primary transport. Whether EMBL proxies block WebSocket upgrades is [to be validated at EMBL]. Question for Thomas.
- Commands: a typed catalogue (
run.launch,run.cancel,run.resume,stage.stop_after,check.evaluate,fs.list,fs.read_range,diagnostics,drain), each withcommand_id, run, idempotency key, deadline and lease; ack and result messages (orPOST /runners/{id}/results); at-least-once delivery. - Heartbeat and offline: heartbeat interval and the offline rule (3 × 30 s, as in admin §3.2); queued commands and evaluations are replayed on reconnect; a missed
pause_after_stageshows a warning on the run. - Credential: settle on rotating (api §6) and fix auth §3, or the reverse.
-
Found by: spec-reviewer (a) SR-110, (b) SR-213, (c) SR-302, (d) SR-406
- Status: inbox (TRIAGE1, 2026-10-27)
SR-003 · blocker · Check providers run on the server in three specs, on the runner in three others¶
- Where: owner checking-scenarios.md §11.1. Conflicts with architecture §2, §3.6, §6, §7.3, §7.6; api-and-data-model.md §3; admin-and-operations.md §3.1. Agrees with api §13.6 and the log 2026-10-26.
-
Evidence:
- Server side: "Check provider |
spectio.check| server | multiqc, table, json" (architecture §2, l.45); "Check provider | server | … | file → item × metric table for gate checks" (api §3, l.64); the architecture §6 diagram lists "Runner-side plugins: engine, launcher, resolver, secrets" (l.277), socheckis server-side;class CheckProvider: def evaluate(self, files, check_spec)(architecture §3.6, l.187); "evaluate gate checks" is a server background task (architecture §7.6, l.384); task kindcheck.evaluate(admin §3.1, l.134). - Runner side: "The runner is the only component that reads files. … The server never mounts storage" (checking §11.1, l.261); "computed once, by the runner at gate time" (api §13.6, l.346); "only the runner reads files, and only values travel" (log, l.299).
- Footprint: the runner base install has "no compiled dependencies" (architecture §7.3, l.335) and must stay "< 80 MB environment, CI-checked" (cli §6, l.170). The bindings need
multiqc -m <module> <file>(checking §11.2), h5ad readers andbcftools stats(checking §7), and polars for depictio recipes (depictio-qc-integration-2026-10-26.md§4).
- Server side: "Check provider |
-
Problem: the MVP's focus is checks and quality control (log 2026-10-26). An implementer following architecture §2 or api §3 would build check plugins that run on the server and cannot reach the files. The placement also decides which package depends on MultiQC, anndata or polars, the import-linter rules in architecture §6, and whether
check.evaluateis a server task or a runner command. -
Proposal:
- Settle it in checking §11.1, the owner: the source binding (file → values) runs on the runner; the verdict (values × thresholds → outcome) runs on the server, so a threshold change in an overlay re-evaluates without reading files again.
- Architecture §2: "Runs on: runner" for
spectio.check; §6: movecheckto the runner-side plugins and the dependency rules; §3.6:evaluate(files, check_spec, ctx)returns values. - Admin §3.1: redefine
check.evaluateas "dispatch to a runner and wait forcheck.evaluated" (or rename itcheck.dispatch). - Ship heavy bindings as an extra (
spectio[checks]) or as separate check plugins so the 80 MB budget holds, and state which extra 0.1 needs (see SR-027). - api §3 links to architecture §2 instead of restating the table (SR-049).
-
Found by: spec-reviewer (b) SR-202, (c) SR-303, (d) SR-401
- Status: partly applied (APPLY1, 2026-10-27): admin §3.1; architecture §2, §6, §7.3; checking-scenarios §11.1 (assumed — pending Thomas, inbox #28); pending: architecture §3.6
CheckProvidersignature and §7.6 'evaluate gate checks' (inbox #25); footprint ofspectio[checks](spike runner-footprint)
SR-004 · blocker · spectio.yml has four shapes and no owner of its schema¶
- Where: no owner today. Shapes in synthesis.md §5ter.1; checking-scenarios.md §7 and §11.2; ui-spec.md §5.1, §9; api-and-data-model.md §6 and §13.3. Consumers in cli §2.
-
Evidence:
- Gate ↔ stage link:
gates: <id>: … after_stage: align(checking §7, l.157) vsstages: - id: align … gate: false # a gate stays optional (§7)(checking §11.2, l.300) vs "stages(id, name,matchglobs …, optionalgate, …)" (ui-spec §5.1, l.187). - Stage → engine mapping:
snakemake: { until: [qc_report] }andnextflow: { params: { stage: preprocess } }(synthesis §5ter.1, l.208) vsmatchglobs (checking §11.2, ui-spec §5.1). - Policy:
intervention: { type, evidence, params_schema, policy: { mode: agent_proposes_human_confirms, timeout: 48h, on_timeout: stop } }(synthesis §5ter.1, l.212-213) vsdecide: {item_actions, per_item, rules, constraints, humans, agents}(checking §7) vs "decide(auto_approve, humans, agents: propose | approve | none, timeout)" (ui-spec §5.1, l.187). - Evidence: a list of globs under
intervention(synthesis) vsevidence: - { kind: report, per_item: true, path: … }(checking §7, l.172). - Other keys:
depictio:(api §13.3), a Snakemakeui:block ("draft its format alongsidespectio.yml", ui-spec §9, l.253), andworkflow,reports,launch(ui-spec §5.1), defined nowhere else. - Consumers:
workflow validate spectio.yml(cli §2, l.49) andrun launch --gates spectio.yml(cli §2, l.47).
- Gate ↔ stage link:
-
Problem: the parser, the overlay merge rules ("can add watches, never remove an author's
blockcheck", checking §11.1), the CLI validator and theWorkflowOverlayboard would each follow a different source. ui-spec also duplicates content, against the one-owner rule. Rated blocker by (d) and major by (a); kept as blocker because the 0.1 gate is defined in this file. -
Proposal:
- Add checking-scenarios §12 "
spectio.ymlreference" as the single owner, backed by a JSON Schema inspectio-sdkthatspectio workflow validateuses. - Choose one gate ↔ stage link. (d) recommends
stages[].gate: <gate_id>and droppingafter_stage; (a) only asks for one. Decide at triage. - One policy block (
decide.humans / agents / auto_approve / timeout / on_timeout), the object form ofevidence, the keys of each check kind (SR-036), thedepictio:andui:keys, and the overlay merge rules. - Synthesis §5ter.1 gets a "superseded" note; ui-spec §5.1 keeps only "where stages come from"; api §6 and §13.3 link to §12.
- Add checking-scenarios §12 "
-
Found by: spec-reviewer (a) SR-107, (d) SR-402
- Status: partly applied (APPLY1, 2026-10-27): api §13.3; checking-scenarios §12 (new, §12.1–§12.7); cli §2; synthesis §5ter.1; ui-spec §5.1, §9 (assumed — pending Thomas, inbox #29); pending: api §6 gate-policy sentence (inbox #13, #14, #15); checking §7 example keys (inbox #16, #19); overlay precedence (inbox #19); tool: JSON Schema in
spectio-sdkandspectio workflow validate
SR-005 · blocker · tasks names two different tables, ID spaces and endpoint families¶
- Where: api-and-data-model.md §5 and §7 vs admin-and-operations.md §3.1, §3.4, §4.3, §5; architecture §7.2 and §7.6; depictio-ecosystem-reuse.md §1.1.
-
Evidence:
- Engine tasks: "
tasks,attempts,scheduler_jobs,attempt_jobs| run_id, process_or_rule, stage, tag …" (api §7, l.224); "GET /runs/{id}/tasks,GET /tasks/{id},GET /tasks/{id}/attempts" (api §5, l.94). - Background ledger: "The
taskstable is the source of truth whatever the backend" (admin §3.1, l.121) with "id(task_…),kind,queue,priority" (l.127); "New tables. These extend [api] §7:tasks,schedules…" (admin §5, l.344-345); "tasks(id, kind, project_id, created_by, state: queued|running|…" (architecture §7.6, l.391); "taskstable + jobs view" (reuse §1.1, l.45). - Spill-over: "Logs and task ledgers (derived or self-expiring data)" are excluded from backups (admin §4.3, l.248);
log_recordshas atask_idfield (admin §3.4, l.164).
- Engine tasks: "
-
Problem: the first Alembic revision cannot hold two tables with one name and incompatible columns. The ambiguity spreads:
- read literally, excluding "task ledgers" from a backup drops every run's engine tasks;
log_records.task_idand thetask_…prefix are ambiguous;GET /tasks/{id}vsGET /admin/tasks/{id},spectio run tasksvsspectio admin tasks;- "jobs" also clashes with
scheduler_jobs.
Rated blocker by (b), major by (d). Kept as blocker because the schema cannot be created; the fix is a mechanical rename.
-
Proposal:
- Keep
tasks/attemptsandtask_for engine tasks: they match synthesis §2ter/§4, WES/tasksand the UI Tasks tab. - Rename the ledger
background_tasks, prefixbtask_, API/admin/background-tasks, UI label "Background tasks". - Define the user-facing "Jobs" as a view (
created_by = caller) with no table of its own; see SR-015 for tying it to the api §4Operation. - Split
log_records.task_idintoengine_task_idandbackground_task_id. - Update architecture §7.2/§7.6, admin §3.1/§4.3/§5 and reuse §1.1.
- Keep
-
Found by: spec-reviewer (b) SR-201, (d) SR-407
- Status: partly applied (APPLY1, 2026-10-27): map (reading order 8); admin §1, §3.1, §3.4, §4.3, §5; api §5; architecture §7.2, §7.6; cli §2; ui-spec §2, §4.9 (assumed — pending Thomas, inbox #29); pending: depictio-ecosystem-reuse §1.1 (inbox #26); boards AdminTasks and AdminNav labels → 'Background tasks'
Majors¶
SR-006 · major · The CLI command tree lacks commands that other specs cite¶
- Where: cli-and-shared-libraries.md §2 vs api-and-data-model.md §6; depictio-ecosystem-reuse.md §2.1; authentication-and-access.md §2; ui-spec.md §6; architecture §7.2; schedulers-and-monitoring.md §6; admin-and-operations.md §0.2, §5; decision 0001; log 2026-10-25.
-
Evidence: the CLI "covers the whole API" (cli §0.1, l.12) and "Nothing an admin can do is UI-only" (admin §0.2, l.16). These are cited elsewhere and missing from cli §2:
spectio auth enable oidc --issuer …(api §6, l.163). Auth §1 treats OIDC as a method, not a mode.spectio user import --from depictio(reuse §2.1, l.128); cli §2userhas onlylist, create, deactivate, set-admin(l.56).spectio login --print-link(auth §2, l.66).spectio run nextflow …/spectio run snakemake …(ui-spec §6, l.198), andloginwriting engine config ("set once byspectio login", ui-spec §6 l.196, 0001 l.24). cli §2 hasrun launch|list|show|…|adopt|watchandengine nextflow config, andlogin(l.44) writes no engine config.spectio serve --tls(architecture §7.2, l.317).spectio ai serve(log, l.110; ui-spec §4.9).- The foreground daemon command that
spectio-runner@.serviceexecutes (schedulers §6, l.208).runnerhas onlyconnect, status, list, drain, logs(cli §2, l.46). - Plugin-instance management, announcements, log capture level (admin §5), share links (auth §2).
-
Problem: implementers of the CLI, the systemd unit and the onboarding docs have nothing to wire, and there are three inconsistent ways to enable Spectio on a terminal run.
-
Proposal:
- Add these commands to cli §2. Name OIDC
auth method enable oidc. - For terminal runs, cli §2 owns the choice: either add
run nextflow|snakemake -- <args>and alogin --configure-enginesoption, or drop them from ui-spec §6 and 0001 in favour ofengine nextflow config --install/engine snakemake profile --install. ui-spec §6 links to the result; the credential follows SR-001. - Add a CI check that every admin OpenAPI operation maps to a CLI command.
- Add these commands to cli §2. Name OIDC
-
Found by: spec-reviewer (a) SR-115, (c) SR-313, (d) SR-418 (CLI part)
- Status: partly applied (APPLY1, 2026-10-27): cli §2, §6; ui-spec §6 (assumed — pending Thomas, inbox #28); pending: api §6
spectio auth method enable oidc(inbox #13, #14, #15); share-link CLI commands (inbox #18, #19); ingest credential written bylogin(inbox #11); CI: admin-operation → CLI-command test
SR-007 · major · Phase labels do not map to release stages, and the phase tables contradict each other¶
- Where: synthesis.md §7quinquies and §9; architecture §9; schedulers-and-monitoring.md §11; api-and-data-model.md §5, §10; ui-spec.md §4.9; dev-environment-and-testing.md §7.4 and §14 (owner of release stages, per synthesis §9); decision log 2026-10-26 ("MVP scope").
-
Evidence:
- Synthesis §9 table: "1 (MVP) | Snakemake agent …" (l.377), "1b | Nextflow agent (V2 plugin) …", "1c | … QC gates". The same section says "The MVP covers both engines from the start" (l.386), then "I propose to start with read-only tracking of both engines, then add steering (phase 1c)" (l.391).
- The 0.1 entry condition is "launch, observe, check, gate, resume" (dev-env §14, l.421).
- "1b" means "Nextflow agent,
sacct" (synthesis §9), "RO-Crate export and import, WES facade" (synthesis §7quinquies, l.321), "instances and scopes …, OIDC, SQL task workers on Postgres, backup and restore, sinks (RO-Crate, depictio)" (architecture §9, l.437) and "capacity (L4), quotas, reservations, pre-flight" (schedulers §11). - OIDC: "phase 2" (api §10; synthesis §9) vs 1b (architecture §9). Postgres: "3 | Postgres, WES facade, …" (synthesis §9, l.381) vs Postgres task workers in 1b and Postgres in the Compose
teamprofile (architecture §9, §7.4). - Kubernetes: schedulers §11 MVP has "head Job, watch, pod reasons and OOMKilled"; architecture §2 lists built-in launchers "local, slurm" (l.42) with
kubernetesoptional, and no row of architecture §9 lists the Kubernetes launcher; the Helm chart is phase 2 (l.438). The 1.0 gate requires "Nextflow and Snakemake on SLURM and on Kubernetes" (dev-env §14, l.429), and the public instance uses the Helm chart at the beta (dev-env §7.4). - Kafka: phase 2 (schedulers §11) vs phase 3 (architecture §9, l.439).
- Architecture §9 puts "sinks (… depictio)" in 1b; the log says "automatic hand-off to depictio comes later, not in 0.1" (l.318).
- MCP: "MCP or REST" is the MVP default for agents (ui-spec §4.9, l.148); no phasing table lists MCP.
-
Problem: two calendars (MVP/1b/1c/2/3 and 0.1/alpha/beta/1.0) with no mapping, and feature lists that contradict each other. The closing sentence of synthesis §9 still describes a tracking-only MVP, against the logged MVP scope. P1 cannot cut the walking skeleton, and P2 milestones cannot place features.
-
Proposal:
- Add dev-env §15 "What ships in which stage": one capability × stage table (0.1, alpha 0.2-0.4, beta 0.5-0.9, 1.0, unscheduled), the single owner. Cover at least: engines, launchers (local, SLURM, Kubernetes), Postgres, Compose, Helm, OIDC/SAML, MCP, WES (SR-010), embedded elements, depictio hand-off, TRS/DRS, Kafka, capacity/pre-flight, background-task kinds (SR-043).
- Synthesis §7quinquies and §9, architecture §9 and schedulers §11 either rename their rows to stages or are marked "historical (23/10)" with a link. Strike the closing sentence of synthesis §9.
- api §5 gets a "From" column; api §10 links to the table.
- Reviewer recommendations to settle at triage: local + SLURM in 0.1; Kubernetes launcher, Postgres, Compose and OIDC in the alpha; Helm in the beta; depictio sink after 0.1; Kafka unscheduled (SR-035).
-
Found by: spec-reviewer (a) SR-103, (b) SR-203 (partly), (c) SR-305, (d) SR-412 (partly)
- Status: inbox (TRIAGE1, 2026-10-27)
SR-008 · major · How Spectio drives Snakemake: Python API worker or command-line head job¶
- Where: synthesis.md §2, §5ter.3, §5ter.6; ui-spec.md §4.6, §5.1, §6; architecture §3.6; dev-environment-and-testing.md §10.1; cli-and-shared-libraries.md §6; schedulers-and-monitoring.md §3.1; decision log (technical constraints).
-
Evidence:
- "Clean steering: one Python worker per run that calls the API (
SnakemakeApi,DAGSettings(until=…),ConfigSettings) rather than asubprocesson the CLI" (synthesis §2, l.29); "Snakemake launches the stage withDAGSettings(until=[…])via the Python API" (synthesis §5ter.3, l.230). The log's constraint: "no ad hoc log parsing or Pythonsubprocessthat would degrade the UX" (log, l.78). - "Snakemake —
--untilthe last rules of the stage; Continue drops--until; rerun from a stage uses--forcerun" (ui-spec §5.1, l.189); "Snakemake:--until qc_report… then a plain rerun" (dev-env §10.1, l.262). - "
def plan(self, launch: LaunchSpec) -> ExecutionPlan # command, env, generated config" (architecture §3.6, l.174);submit(plan) -> Handle # local process, sbatch, Kubernetes Job…(l.180). - On HPC "the engine's head process is run as a head job:
sbatch…" (schedulers §3.1, l.64). - The runner is "
uv tool install spectio| CLI + Python client + runner" (cli §6, l.170) in its own environment, not in the workflow's Snakemake environment.
- "Clean steering: one Python worker per run that calls the API (
-
Problem: the two designs differ in process model, in which Snakemake version runs (the runner's or the workflow's) and in how to stop (API call vs SIGINT). The API worker would have to run inside the user's Snakemake environment, in the head job, which no spec describes. The CLI route breaks the logged "no subprocess" constraint as worded.
- Proposal: Thomas picks one. Reviewer (a) recommends a CLI head job, which matches the boards, the synthetic suite and
ExecutionPlan.command. Record the choice in the log, revise synthesis §2, §5ter.3 and §5ter.6, and restate the constraint as "no parsing of process output for tracking". - Found by: spec-reviewer (a) SR-106
- Status: applied (APPLY1, 2026-10-27): synthesis §2, §5ter.3, §5ter.5, §5ter.6 (merged with CH-009); choice recorded in decisions/log.md (APPLY1 entry) (assumed — pending Thomas, inbox #28)
SR-009 · major · Environment-variable and config-file names follow incompatible rules¶
- Where: architecture §0.4, §3.2, §7.3; cli §3; api-and-data-model.md §13.1; authentication-and-access.md §1; admin-and-operations.md §4.1, §4.3; telemetry-and-analytics.md §0.4.
-
Evidence:
- "
SPECTIO_NOTIFIER_MATTERMOST_WEBHOOK_URL" with config table[notifier.mattermost.<instance>](architecture §3.2, l.126). - "
SPECTIO_*env vars, with__for nesting" (architecture §7.3, l.339). - "switched by
DATABASE_URL" (architecture §0.4, l.13), with no prefix. - Flat names elsewhere:
SPECTIO_AUTH_MODE(auth §1, l.39),SPECTIO_AUTH_PUBLIC_ACCESS_CODE,SPECTIO_BRANDING_PRESET(admin, l.211),SPECTIO_BACKUP_*,SPECTIO_TELEMETRY_ENABLED(telemetry, l.32),SPECTIO_EXTRA_PLUGINS. - CLI config:
~/.config/spectio/servers.yaml(cli §3, l.106) vs "~/.spectio/config.yaml,SPECTIO_*" (api §13.1, l.297).
- "
-
Problem: with pydantic-settings and
__nesting, none of the flat names resolve. The plugin env var has no slot for a tagged instance. Two CLI config paths are documented. -
Proposal: architecture §7.3 states one rule:
- flat
SPECTIO_<AREA>_<FIELD>names through explicit aliases, since they are already user-facing in six specs; DATABASE_URLaccepted as an alias ofSPECTIO_DATABASE_URL;- plugin env vars set only the default (untagged) instance, as Snakemake does; tagged instances come from the file or the UI;
- api §13.1 points to cli §3 for the CLI file.
- flat
-
Found by: spec-reviewer (c) SR-309
- Status: partly applied (APPLY1, 2026-10-27): architecture §0 item 4, §7.3; pending: api §13.1 CLI config row → cli §3 (inbox #21); architecture §3.2 derived-forms table (inbox #25; covered by the §7.3 rule)
SR-010 · major · The WES facade has four release dates and is under-specified¶
- Where: synthesis.md §7quinquies, §9, §11 Q5; docs/roadmap/index.md; api-and-data-model.md §0, §1, §2.B, §5, §7, §10; ui-spec.md §4.1; architecture §6, §9; log 2026-10-26.
-
Evidence:
- "Phase 1b: RO-Crate export and import, WES facade" (synthesis §7quinquies, l.321).
- "3 | Postgres, WES facade, …" (synthesis §9, l.381).
- "Is a WES facade needed from the MVP, or later?" is still open (synthesis §11, l.409).
- "GA4GH WES and TES interfaces" under "Ideas, not scheduled" (roadmap, l.42).
- With no phase: "the MCP server, the WES facade … are all clients of the same public API" (api §0.1, l.8); "Headless | … only API, WES, webhooks, MCP" (api §1, l.20); "Facades |
/ga4gh/wes/v1/*(WES 1.1 +x-spectioextensions)" in the "Endpoint catalogue (v1)" (api §5, l.103); api §10 gives TRS/DRS "phase 2" (l.265) and WES no phase;runs.originalready includeswes(api §7, l.222); "API: REST, SSE, WES, MCP, ingest" (architecture §6 diagram, l.267), with no WES row in architecture §9. - The public landing page has a "works-with strip (… GA4GH WES)" (ui-spec §4.1, l.72).
- "When the WES facade ships is inconsistent across docs … That is left to review R1" (log, l.326).
- Under-specification: "Spectio maps it to a native run in the caller's default project" (api §2.B, l.44), but a WES
RunRequesthas no field for Spectio's requiredenvironment_id(WES 1.1.0 schema, ga4gh/workflow-execution-service-schemas, [to be validated]). Theworkflow_typevaluesNFL/SMKare [to be validated] against Sapporo'sservice-info(https://github.com/sapporo-wes/sapporo-service).
-
Problem: P1 cannot decide whether
/ga4gh/wes/v1is in the walking skeleton; an implementer reading api §1 or architecture §6 would build it into the first server. The landing page would advertise an interface that the roadmap calls unscheduled. -
Proposal:
- Thomas picks one stage, recorded once in the dev-env §15 table (SR-007). Reviewer recommendations differ: public beta (0.5-0.9) with
service-info,POST/GET /runs,/status,/cancel,/tasks, andx-spectiogate extensions later ((a), (c)); before the public beta ((b)); unscheduled until a design partner needs it ((d)). All agree: not in 0.1, because LabID and design partners use the native API. - Replace the two synthesis phase cells with a link and close §11 Q5; move the roadmap item to that stage (TES stays under Ideas); mark api §0, §1, §5, §10 and architecture §6/§9 "from
<stage>" (or "when enabled"). - Drop "GA4GH WES" from the landing strip until it ships.
- When the facade is specified, api §2.B says how the environment is chosen (
workflow_engine_parameters.spectio_environment, or a per-token default).
- Thomas picks one stage, recorded once in the dev-env §15 table (SR-007). Reviewer recommendations differ: public beta (0.5-0.9) with
-
Found by: spec-reviewer (a) SR-102, (b) SR-203, (c) SR-304, (d) SR-412
- Status: inbox (TRIAGE1, 2026-10-27)
SR-011 · major · How a gate stops Nextflow: --stage parameter or generated ext.when¶
- Where: synthesis.md §5bis, §5ter.1, §5ter.3, §5ter.5; ui-spec.md §4.6, §5 vs §5.1; checking-scenarios.md §11.3; architecture §3.6; dev-env §3, §10.1; log 2026-10-25 "UI review round 2".
-
Evidence:
- "Nextflow launches with the
--stageparameter, and the pipeline testsparams.stagein itsworkflowblock … the pipeline must cooperate" (synthesis §5ter.3, l.231);nextflow: { params: { stage: preprocess } }(§5ter.1, l.208); "next--stage" (§5ter.5, l.243); "--stageparameter for Nextflow" (§5bis, l.187). - "Nextflow: stages through a
stageparameter" (ui-spec §5, l.181) vs "Nextflow — a generated config setsext.when = falseon the processes of later stages (nf-core modules honourtask.ext.when)" (ui-spec §5.1, l.189). - "Gates stop Nextflow via a generated
ext.when = falseconfig" (log, l.108); architecture §3.6 (l.174, "gates → ext.when / --until"), dev-env §3 (l.88) and §10.1 (l.261) and checking §11.3 (l.323) agree with the log. checking §11.3 cites synthesis §5ter for this mechanism, which describes the other one. - Rerun from a stage: "Forcing a specific stage requires a 'salt' parameter … [to be validated]" (synthesis §5ter.5) vs "Nextflow stage override +
-resume" (ui-spec §4.6, l.122). Neither is specified.
- "Nextflow launches with the
-
Problem: synthesis comes first in the reading order and still requires pipelines to cooperate through
params.stage, which unmodified nf-core pipelines do not do. ui-spec contradicts itself. An implementer ofEngine.plancould build either mechanism, and rerun-from-stage has no Nextflow mechanism at all. -
Proposal:
- Record
ext.whenas the only Nextflow boundary (unconditional for gates; the stop-file closure for live checks), owned by checking §11.3 or the new checking §12 (SR-004). - Add a "Revised on 25/10 (log)" note to synthesis §5bis, §5ter.1, §5ter.3 and §5ter.5, as was done for decision 0001; fix the ui-spec §5 bullet to "stages from
matchglobs, stopped by a generatedext.whenconfig (§5.1)". - The claim that nf-core modules honour
task.ext.whenneeds a source (nf-core modules template, file:line) or [to be validated]. - Specify rerun-from-stage for Nextflow, for example a generated per-process
extkey that enters the task hash, [to be validated] in spike T2.
- Record
-
Found by: spec-reviewer (a) SR-105, (d) SR-403
- Status: applied (APPLY1, 2026-10-27): checking-scenarios §11.3, §12.3; synthesis §5, §5bis, §5ter.1, §5ter.3, §5ter.5; ui-spec §4.6, §5, §5.1
SR-012 · major · Gate decisions: five verb sets, two resource names, stale MCP tools and scopes¶
- Where: owner checking-scenarios.md §5. Also synthesis.md §5, §5bis, §5ter.2, §7bis; api-and-data-model.md §5, §6, §7; ui-spec.md §2, §4.5; cli-and-shared-libraries.md §2.
-
Evidence:
- Checking: "Gate | approve · stop · go back to a stage · reassign · wait for a signal" (checking §5, l.114), with item verbs "keep · exclude · redo · flag · replace input".
- api: "
POST /gates/{id}/decisions(approve, apply, go back, stop …)" (api §5, l.96);POST /gates/{id}/signals(api §2, l.53); scopesgates:decide,gates:propose(api §6, l.155);/mcpwith no tool list (api §5);decisions.actionandgates.statewith no values (api §7). - Synthesis:
POST /interventions/{id}/signal(§5bis, l.181); MCP toolslist_interventions,get_intervention,propose_decision,submit_decision(l.176); scopeinterventions:resolve(§7bis, l.280); decisionscontinue,params_changed,rerun_all(l.223),reject→STOPPED(§5ter.2); lifecyclepending → awaiting_review → approved | rejected | params_changed(§5, l.140); modeshuman_only,agent_proposes_human_confirms,agent_auto,system(§5bis, l.168). - ui-spec: "approve / change params / rerun / reject" (§2, l.21) vs "Approve and continue / Apply and continue / Discard changes; More: go back, stop the run here, reassign" (§4.5, l.111).
- CLI: "
decide <gate> --approve|--reject|--hold" (cli §2, l.48).
-
Problem: the
decisions.actionCHECK values, thegates.statevalues, the MCP tool names, the token scopes and the CLI flags cannot be derived from the specs.rejectandhold(CLI),rerun_all(synthesis) andapply(api) map to nothing.reassignand "wait for a signal" are listed as decisions but change no run state. -
Proposal:
- checking §5 stays the owner and enumerates
decisions.action:approve(continue unchanged),apply(continue with the change set),go_back(+ stage),stop.reassignandwaitbecome gate operations, not decisions. - api §5/§7 own the
decisions.actionandgates.stateenums (with SR-016) and the MCP tool list, named after gates (list_gates,get_gate,propose_decision,decide_gate). - cli §2 becomes
decide <gate> approve|apply|stop|go-back --stage Swith--keep/--exclude/--redo/--flagitem options and--rule;--rejectmaps tostop,--holdis dropped or defined. - Synthesis §5/§5bis/§5ter/§7bis get "Intervention = Gate; names superseded by api §5";
interventions:resolvebecomesgates:decide. ui-spec §2 uses the same verbs. - Related, not duplicates: UX-106, UX-107 (more verbs), UX-110 (waiting for a signal), R12.
- checking §5 stays the owner and enumerates
-
Found by: spec-reviewer (a) SR-109, (c) SR-312, (d) SR-404
- Status: partly applied (APPLY1, 2026-10-27): api/index.md; api §5, §7; cli §2; synthesis §5, §5bis, §5ter.2, §7bis; ui-spec §2 (assumed — pending Thomas, inbox #29); pending: checking §5 decision verbs (inbox #19); MCP tool names in api §5 and synthesis §5bis (inbox #19); gate assignment fields (inbox #14)
SR-013 · major · Endpoint catalogues duplicated between api §5 and admin §5; three public config endpoints¶
- Where: api-and-data-model.md §5 vs admin-and-operations.md §5; authentication-and-access.md §1; telemetry-and-analytics.md §4; architecture §5.
-
Evidence:
- At the root in api §5: "
GET/POST /users,GET/PATCH /users/{id},GET/POST /groups,GET/POST/DELETE /groups/{id}/members" (l.88); "GET/PATCH /settings,GET /audit-log,GET /plugins,GET /health" (l.101). - Under
{root}/api/v1/adminin admin §5 (l.330), with other shapes:/groups/{id}/members/{principal}(l.332);GET /health"(all checks)" (l.336);GET /plugins(l.338). admin §5 has no audit-log endpoint although Audit log is one of its sections (admin §1, l.48). - Public config: "public
GET /public-config" inside the admin-prefixed table (admin, l.337);GET /api/v1/public-config(telemetry, l.132);GET {root}/api/v1/auth/config(auth §1, l.52). GET /api/v1/plugins/ui-manifest(architecture §5, l.219) is missing from api §5.
- At the root in api §5: "
-
Problem: two owners give the same resources different paths, so the generated clients diverge. Group admins, who are not system admins, must manage members (admin §2.2), but no path is defined for them.
-
Proposal:
- Rule:
/api/v1/admin/*is for system admins only and owned by admin §5. Everything a non-admin may call (group admins managing members, the plugin UI manifest, a project's audit log for owners) lives at the root and is owned by api §5. - Remove the duplicated rows from the api §5 Admin row and keep the link; add
ui-manifestand the admin audit-log endpoint. - One public
GET /api/v1/public-configwith sectionsauth,brandingandanalytics;/auth/configgoes or becomes an alias.
- Rule:
-
Found by: spec-reviewer (b) SR-211, (c) SR-310 (endpoint part)
- Status: partly applied (APPLY1, 2026-10-27): admin §5; api §5 (assumed — pending Thomas, inbox #29); pending: auth §1
GET /api/v1/auth/config→GET /public-configsectionauth(inbox #15, #21); logout and session endpoints (inbox #20)
SR-014 · major · Which Unix account runs a launch on a group-owned environment is undefined¶
- Where: schedulers-and-monitoring.md §0.2, §3.2, §6, §10; checking-scenarios.md §11.1; api-and-data-model.md §6; admin-and-operations.md §3.2; ui-spec.md §4.8, §6.
-
Evidence:
- "A runner asks the scheduler once per interval about all jobs of its user" (schedulers §0.2, l.21).
- "It runs on the cluster under the user's account" (checking §11.1, l.261).
- "Clusters and their credentials belong to groups, not to users" (api §6, l.141) and "a rotating runner credential bound to one environment" (api §6, l.155); the heartbeat lists "environments" (admin §3.2).
- "Unix user / service account" (ui-spec §4.8, l.132); "a runner running as the same user on that host" (ui-spec §6).
- "Service or VM node … the runner submits through
ssh loginor REST" (schedulers §6, l.210). - EnvCapacity shows "your limits and fairshare" (schedulers §10).
-
Problem: when user B launches on an environment whose runner runs as user A, the jobs, quota, fairshare and file permissions are A's. Nothing routes a launch to a runner, and the runner ↔ environment cardinality conflicts between specs.
-
Proposal:
- Add
execution_identityto environments:per_user(one runner per principal × environment; a launch goes to the launching user's runner or is refused with a reason) orshared(a service account, stated in the UI). - Add
runners.principal_idandunix_user. api §6 owns this.
- Add
-
Found by: spec-reviewer (d) SR-410
- Status: inbox (TRIAGE1, 2026-10-27)
SR-015 · major · Background-task ledger and schedules: two schemas, two locking designs, no Jobs object¶
- Where: admin-and-operations.md §3.1, §5 vs architecture §7.2, §7.6; api-and-data-model.md §4 (
Operation); docs/map.md (items 5 and 7 both claim "tasks"). -
Evidence:
- Fields differ:
error {type, message, traceback_ref}(architecture §7.6, l.393) vserror {type, message},traceback_refas its own field, pluslogs,duration_ms,expires_at(admin §3.1, l.131). - Scheduling: "an atomic database claim per slot decides who runs it … unchanged with one SQLite process or several Postgres replicas" (admin §3.1, l.140); "
schedules(slot claims)" (admin §5, l.345); "schedules by atomic DB claim (no beat)" (log, l.136) vs "Scheduled jobs | … worker, Postgres advisory lock" (architecture §7.2, l.313) and "run scheduled tasks under a Postgres advisory lock" (§7.6, l.401). - Which processes run the loops: "each process runs the loops" (admin §3.1) vs workers only (architecture §7.6).
- "Jobs (users). The user-facing view of a task the user started" (admin §3.1, l.122) has no table or endpoint; api §4 has "an
Operationresource (/operations/{id})" (l.78). - map.md gives "tasks" to architecture (l.9) and to admin (l.11).
- Fields differ:
-
Problem: two schemas and two locking designs for one thing; advisory locks are per-session and do not exist on SQLite. The user-facing record is a third, undefined object. Each spec defers to the other.
- Proposal: admin §3.1 owns the ledger schema (renamed per SR-005) and the screen; architecture §7.6 owns the mechanism and links to admin for the columns. Use one mechanism, a unique insert into
schedules(schedule_key, slot_start), portable to SQLite; onlyworkerandallroles run the loops. Define "Jobs" as the api §4Operation: a projection of the ledger that the caller created. Update map.md so that each aspect has one owner. - Found by: spec-reviewer (b) SR-214, (c) SR-315
- Status: partly applied (APPLY1, 2026-10-27): map (reading order 6, 8); admin §3.1, §5; api §4; architecture §7.2, §7.6 (assumed — pending Thomas, inbox #29); pending: architecture §7.6 link to admin §3.1 and worker-role rule (inbox #25)
SR-016 · major · Run and gate states: five vocabularies, no enum, a 2-of-11 WES mapping¶
- Where: owner api-and-data-model.md §7 (new §7.1) and §10; ui-spec.md §3.1; synthesis.md §4, §5, §5bis, §5ter.2; schedulers-and-monitoring.md §7.
-
Evidence:
- ui-spec §3.1 (l.40-46): Queued, Running, Awaiting review, Paused, Succeeded, Failed, Cancelled.
- "a common subset with WES (11 states), plus internal states:
AWAITING_QC,PAUSED" (synthesis §4, l.134); "The platform holds theAWAITING_INTERVENTIONstate" (§5bis, l.187); "QUEUED → RUNNING(stage k) → STAGE_DONE → AWAITING_INTERVENTION" (§5ter.2, l.220),STOPPED, "PAUSING → PAUSED" (l.226); gate lifecyclepending → awaiting_review → …(§5, l.140). - "
AWAITING_REVIEWandPAUSED→PAUSED" (api §10, l.264) is the whole WES mapping. runshasstate(api §7, l.222) andgateshasstate(l.227), both without values, although §7 requires "CHECKconstraints instead of enums" (l.170). The launch example returns lower-case "state: queued" (api §5, l.130).- "head silent" (schedulers §7, l.218) and "runner offline" appear as run conditions.
- WES 1.1.0 defines 11 states: UNKNOWN, QUEUED, INITIALIZING, RUNNING, PAUSED, COMPLETE, EXECUTOR_ERROR, SYSTEM_ERROR, CANCELED, CANCELING, PREEMPTED (
openapi/workflow_execution_service.openapi.yaml:659-673, tag1.1.0of ga4gh/workflow-execution-service-schemas, fetched 2026-10-26 by reviewer (b)).
-
Problem: four names exist for "stopped at a gate" (
AWAITING_QC,AWAITING_INTERVENTION,AWAITING_REVIEW, "Awaiting review").STAGE_DONE,PAUSINGandSTOPPEDhave no UI rendering, and the UI does not say whether a gatestopshows as Cancelled or Failed. The CHECK constraints,spectio.run.state_changedpayloads,?state=/--statefilters and the WES facade cannot be written. -
Proposal:
-
api §7.1 "Run and gate state machines" owns two lower-snake-case enums, their transitions and the triggering event per transition:
runs.state:queued,running,pausing,paused,awaiting_review,cancelling,succeeded,failed,cancelled;gates.state:open,decided,expired,superseded.
-
"Head silent" and "runner offline" are flags on the run, not states. Waiting for an external signal is a gate condition (UX-110).
- api §10 gets the full WES table:
queued→QUEUED;running→RUNNING;pausing/paused/awaiting_review→PAUSED;succeeded→COMPLETE;failed→EXECUTOR_ERROR or SYSTEM_ERROR by failure class (schedulers §3.5);cancelling→CANCELING;cancelled→CANCELED. - ui-spec §3.1 maps every value to icon, word and colour, including the transient states. Synthesis §4, §5, §5bis and §5ter.2 link to §7.1 and are marked superseded.
-
-
Found by: spec-reviewer (a) SR-104, (b) SR-204, (c) SR-306, (d) SR-404 (state part)
- Status: partly applied (APPLY1, 2026-10-27): api §7, §7.1 (new), §10; synthesis §4, §5, §5bis, §5ter.2; ui-spec §3.1 (assumed — pending Thomas, inbox #29); pending: boards: Legend and run lists (Pausing, Cancelling, head-silent and runner-offline flags); pause verbs (inbox #16, SR-018)
SR-017 · major · Engine bridge behaviour when the server is unreachable: Tower-era text and no testable bound¶
- Where: synthesis.md §8, §10 risk 2; decision 0001 "Consequences"; checking-scenarios.md §11.1; schedulers-and-monitoring.md §3.2.
-
Evidence:
- "Keep the spool fallback. On the Nextflow side, a server outage during
create,beginorprogressaborts the run" (synthesis §10 risk 2, l.396). This is thenf-towerAbortRunExceptionbehaviour (synthesis §2bis, l.46), no longer used. - "It needs its own heartbeat, batching and local buffer, on the Tower model" (0001, l.41).
- "Agents: disk buffer, batched sending, retry with exponential backoff, never block the workflow if the server is unreachable" (synthesis §8, l.369).
- "Fallback: the agent writes JSONL to the shared file system, and a server-side forwarder reads it" (synthesis §8, l.367), against "The server never mounts storage" (checking §11.1, l.261).
- "Without the Nextflow plugin, Spectio only knows the task's work directory" (checking §11.1, l.259). Under 0001, without
nf-spectioSpectio knows nothing about a Nextflow run. - "only if a future companion plugin feeds states back; that is not planned" (schedulers §3.2, l.84).
nf-spectiois that plugin.
- "Keep the spool fallback. On the Nextflow side, a server outage during
-
Problem: "on the Tower model" can be read as copying Tower's abort-on-error, and risk 2 says the new plugin may abort runs. "Never block" has no measurable bound. The spool fallback puts file access on the server, which the architecture forbids. Whether an exception thrown inside a
TraceObserverV2hook aborts the run is [to be validated] in T2. Decision 0001's list of changed sections does not include synthesis §10 or checking §11.1. -
Proposal: in the ingest contract (SR-001, api §14), state as testable requirements (values proposed):
- plugin hooks never throw and return in ≤ 50 ms (enqueue only);
- the on-disk buffer keeps at least 24 h or 200 MB, whichever comes first, then drops the oldest progress events and keeps lifecycle events;
- backoff is capped at 5 min, and a run never fails because of Spectio;
- with the server down for 30 min, the run completes and every event is delivered after reconnect;
- the spool is read by the runner, not the server.
Rewrite synthesis §10 risk 2 accordingly (or mark the last sentence Tower-only); reword checking §11.1 l.259 ("for
when: task_done, until reading declared outputs through the handler is validated, the runner lists the task work directory"); reword schedulers §3.2 ("only ifnf-spectiofed scheduler states back into Nextflow; not planned"). -
Found by: spec-reviewer (a) SR-111, (b) SR-222, (d) SR-416
- Status: partly applied (APPLY1, 2026-10-27): checking-scenarios §11.1 (reconciled with FC-034); schedulers §3.2; synthesis §8 (rest superseded by CH-001) (assumed — pending Thomas, inbox #28); pending: api §14 bridge bounds (inbox #11)
SR-018 · major · "Pause": immediate stop or after the current stage¶
- Where: synthesis.md §5ter.2-3; api-and-data-model.md §5 (Runs); ui-spec.md §3.1, §4.4, §4.8, §4.11, §5.1; checking-scenarios.md §11.3, §11.5.
-
Evidence:
- "For an unplanned pause ("Pause" button):
PAUSING → PAUSED" (synthesis §5ter.2, l.226) and "Unplanned: SIGINT to Snakemake …, SIGTERM to Nextflow … Running tasks are lost" (§5ter.3, l.232). - "
:pause(after current stage)" (api §5, l.93). - "Pause after stage" on the phone Run detail (ui-spec §4.11, l.174); the desktop actions are "(Resume, Relaunch…, Cancel, Duplicate)" (ui-spec §4.4, l.86), with no Pause.
- "Live checks never kill a running task and never stop the run in the middle of a stage" (checking §11.3, l.329). A conditional Nextflow stage boundary is [to be validated] (checking §11.3). Runs without stages show "task quarters" (ui-spec §5.1).
- "For an unplanned pause ("Pause" button):
-
Problem: two meanings. "After current stage" is undefined for a run with no declared stages, for a Nextflow run launched without a stop-file closure, and when stages overlap as dataflow (checking §11.5). The desktop UI has no Pause at all.
-
Proposal:
- api §5 (with the state machine of SR-016) defines two verbs:
:pause(after the stage; needs a boundary generated at launch; refused with a problem+json reason otherwise) and:stop(immediate, running tasks lost, cache kept). - Synthesis §5ter links to them. ui-spec §4.4 adds "Pause after stage", disabled with the reason when no boundary exists.
- api §5 (with the state machine of SR-016) defines two verbs:
-
Found by: spec-reviewer (a) SR-108
- Status: inbox (TRIAGE1, 2026-10-27)
SR-019 · major · Principal kinds: guests, plugin and bridge principals are outside the enum¶
- Where: api-and-data-model.md §6, §7, §13.2 vs authentication-and-access.md §1-§2; architecture §3.4, §7.6; admin-and-operations.md §2.1, §2.3.
-
Evidence:
- "
kind ∈ {user, service, agent, runner, system}" (api §6, l.137);service_accountswith "owning_group_id, purpose (lims,ci,robot,agent)" (api §7, l.214). - "Visitors get temporary principals (
kind=guest, sliding 24 h expiry …)" (auth §1, l.45); "The recipient becomes a guest principal bound to that link" (auth §2, l.67). - "acting as the plugin instance's service principal" (architecture §3.4, l.154); "the bridge instance's service principal" (architecture §7.6, l.416).
- "Non-human principals: LIMS, CI, robots, event bridges" (admin §2.3, l.106); the Users kind filter is "People · Service accounts · Agents · Runners" (admin §2.1, l.83), with no guests.
- "
-
Problem: api §7 mandates CHECK constraints, so guest rows and plugin or bridge principals fail to insert. Instance-scoped plugins have no group for
owning_group_id. Admins cannot list or expire guests. - Proposal: add
guesttoprincipals.kindwithexpires_atandshare_link_id; add purposespluginandbridge; makeowning_group_idnullable for instance-scoped principals, owned bysystem; add "Guests" to the admin §2.1 filter; state in api §13.2 that guests are never mirrored to depictio. - Found by: spec-reviewer (b) SR-207
- Status: partly applied (APPLY1, 2026-10-27): api §7 service_accounts (assumed — pending Thomas, inbox #18); pending:
guestprincipal kind, admin §2.1 'Guests' filter and api §13.2 mirroring rule (inbox #18, #21); api §6 kind list (inbox #13, #14, #15)
SR-020 · major · The system-admin flag, protected groups and P.I. fields are missing from the schema¶
- Where: api-and-data-model.md §6, §7, §13.1 vs admin-and-operations.md §1, §2.1, §2.2, §5; authentication-and-access.md §1; cli §4.
-
Evidence:
- "
User.is_adminbypasses permissions | same flag and meaning" (api §13.1, l.294), butusershas "principal_id, email, username, default_project_id, preferences (JSON)" (api §7, l.213) andgroupshas "name, parent_id". - Admin uses: "System admin" in the create-user form (admin §2.1, l.79); "
PATCHstate, admin flag" (admin §5, l.332); "adminandusersare protected and cannot be deleted" (admin §2.2, l.100); "<email>becomes P.I. and group admin at their first sign-in" (admin §2.2, l.94);/groups/{id}/pending-pi(admin §5, l.332). pending_pi_email(cli §4, l.132) andmust_change_password(auth §1, l.143) appear only outside the schema.- Single-user start creates only "a group
personal" (api §6, l.158).
- "
-
Problem: the root of authorisation has no column. Open: is "admin" the flag, membership of the
admingroup, or theadmintoken scope? Areadminanduserscreated in single-user mode? Can onegroup_members.rolesay "P.I. and group admin"? May an admin's token without theadminscope reach/admin/*? - Proposal: api §7 adds
users.is_admin,must_change_password,email_verified_at,last_login_at, andgroups.description,sso_managed,pi_principal_id,pending_pi_email;group_members.role∈ {member,admin}.is_adminis the only source of admin rights; theadmingroup is a mirror kept for depictio./admin/*requiresis_adminand theadminscope. Single-user start setsis_admin=trueand creates the protected groups. - Found by: spec-reviewer (b) SR-210
- Status: inbox (TRIAGE1, 2026-10-27)
SR-021 · major · Launcher instances and Environments are two models of the same cluster¶
- Where: architecture §3.3, §5; api-and-data-model.md §5, §7; admin-and-operations.md §5; schedulers-and-monitoring.md §3.2.
-
Evidence:
- "One plugin can have several configured instances: … or two SLURM clusters" (architecture §3.3, l.135).
- "
environments| owning_group_id, kind (slurm, k8s, local…), config (JSON)" (api §7, l.219); observer settings live "in the environment settings" (schedulers §3.2, l.83). - The scope rules cover "Notifier, sink, resolver, check, viewer and AI provider" (architecture §3.3, l.142) but not engine, launcher, analytics, API or CLI extensions.
- Scoped instances have only
GET/POST/PATCH/DELETE /plugin-instancesunder the admin prefix (admin §5, l.338).
-
Problem: an implementer cannot tell where a SLURM cluster's settings and secrets live (
plugin_instancesorenvironments). A group admin cannot add the group's own Slack instance. - Proposal: an Environment is the launcher instance:
environments.configis validated by the launcher's settings model, launchers are excluded fromplugin_instances, and the "two SLURM clusters" example goes. Complete the scope rules for every kind. Add/projects/{id}/plugin-instancesand/groups/{id}/plugin-instances, guarded by owner or group admin. (The/pluginsvs/admin/pluginsandui-manifestparts are in SR-013.) - Found by: spec-reviewer (c) SR-310
- Status: inbox (TRIAGE1, 2026-10-27)
SR-022 · major · No compatibility window between CLI, runners, engine bridges, plugins and server¶
- Where: cli §1, §2 (exit code 6); admin-and-operations.md §3.2; dev-env §12; architecture §2, §3.1, §3.2, §4.
-
Evidence:
- "
GET /versionat start, warning on skew, error past the supported window" (cli §1, l.31). The window is never defined. - "Version skew beyond one minor version shows a warning" (admin §3.2, l.147).
- "Pre-1.0 policy: minor versions may break the API" (dev-env §12, l.377).
- "the previous major stays supported for one Spectio minor release" (architecture §4, l.198).
- A plugin declares
spectio-sdk>=1.2,<2(architecture §3.1, l.81) and a per-kindapirange while the core is 0.x.nf-spectioand the Snakemake logger are released separately (architecture §2).
- "
-
Problem: a 0.3 runner on a login node against a 0.4 server, which is allowed to break, only gets a warning. Three version axes (SDK package, per-kind API, core) have no stated relation.
- Proposal: add architecture §12 "Compatibility between components": a table for CLI ↔ server, runner ↔ server, bridge ↔ ingest
schema_version(SR-001) and plugin ↔ SDK. Before 1.0, the runner and CLI must match the server's minor (otherwise refuse with exit 6 and an upgrade hint); from 1.0, N−1 minor. Plugins declare only the per-kind range; the SDK package version is independent. Question for Thomas (lag tolerance before 1.0). - Found by: spec-reviewer (c) SR-314
- Status: partly applied (APPLY1, 2026-10-27): admin §3.2; architecture §4, §12 (new); cli §1 (assumed — pending Thomas, inbox #28); pending: architecture §3.1 example dependency (inbox #25); bridge ↔ ingest
schema_versioncontract in api §14 (inbox #11)
SR-023 · major · Gate checks depend on the depictio catalogue, but 0.1 has no depictio¶
- Where: api-and-data-model.md §13.6 (rules 1 and 6); checking-scenarios.md §7, §11.2; depictio-ecosystem-reuse.md §0, §3.8; log 2026-10-26 ("MVP scope").
-
Evidence:
- "A check that has a catalogue binding uses it. The runner runs the recipe on the partial outputs at gate time … Spectio never re-implements a recipe that the catalogue has" (api §13.6 rule 1, l.352).
- The catalogue layer is "the source of gate checks:
depictio:<module>/<output>#<column>" (api §13.6, l.345). checking §7 has nodepictio:binding, and checking calls per-file recipes a future request to depictio (l.348). - "Running that campaign through Spectio, with the depictio hand-off at the end, is the first real test" (reuse §0, l.34).
- "automatic hand-off to depictio comes later, not in 0.1" (log, l.318).
-
Problem: for nf-core/rnaseq, rule 1 makes the 0.1 gates require a depictio recipe runtime on the runner. That runtime does not exist yet (reuse §3.8) and has no install path (DEP-T-016). Nothing says which binding wins when both exist.
- Proposal: 0.1 uses only the checking §7 bindings. Add
depictio:to checking §7 as optional, active when a recipe runtime is declared on the environment, with precedence "catalogue first when available". Rephrase rule 1 accordingly; reuse §0 labels the joint use case "after 0.1". Question for Thomas. - Found by: spec-reviewer (d) SR-413
- Status: inbox (TRIAGE1, 2026-10-27)
SR-024 · major · Tokens are specified twice, differently¶
- Where: api-and-data-model.md §5, §6, §7 vs authentication-and-access.md §1-§4; synthesis §7bis. Auth says "This spec owns the sign-in methods, sessions, tokens and links" (auth, l.8).
-
Evidence:
- Format: "Personal tokens, service-account tokens and agent tokens share one format (
spk_<kind>_<random>, stored hashed)" (api §6, l.155) vs "Access token … bearer JWT (EdDSA or RS256)" (auth §3, l.99) and "Refresh token … rotated on every use" (l.100). - Runner credentials: "rotating runner credential" (api §6, l.155) vs "Runner token | until revoked" (auth §3, l.103) (also SR-002).
- Scopes: api §6 list vs
principals:provision(auth §4, l.111) vsinterventions:resolve(synthesis §7bis, l.280); no ingest scope (SR-001). - Endpoints: api §5 lists only "
POST /auth/device+POST /auth/token(CLI device flow, phase 2)" (l.87). Missing:POST /auth/magic-links(auth l.65),POST /share-links(l.67),POST /principals:provision(l.112),GET /auth/config(l.52),/.well-known/jwks.json(l.99), and the login endpoint. - Table:
tokenshas "principal_id, hash, scopes (JSON), project_id (nullable), expires_at, last_used_at" (api §7, l.216): no name, kind, family / rotation, revoked_at or IP. Sessions (server-side rows, auth §3 l.98) and share links have no table.
- Format: "Personal tokens, service-account tokens and agent tokens share one format (
-
Problem: two specs give different formats, lifetimes and scope lists for the same credentials. Neither the token tables nor the OpenAPI can be written.
- Proposal: auth §3 owns token kinds, formats, lifetimes and a single scope registry (including the ingest scope of SR-001 and
principals:provision). api §6 "Tokens and scopes" becomes a link; api §5 "Session & me" lists auth's endpoints or links to auth §2; api §7 getstokens,sessions,refresh_tokens(family_id, rotated_from)andshare_linkscolumns taken from auth. Decide whether runner credentials rotate. - Found by: spec-reviewer (b) SR-206, (c) SR-302 (credential part)
- Status: inbox (TRIAGE1, 2026-10-27)
SR-025 · major · launcher and reviewer: rungs on a ladder or capability flags¶
- Where: api-and-data-model.md §6, §7 vs admin-and-operations.md §2.4 vs cli-and-shared-libraries.md §2 (
project share) and §4 (Role). -
Evidence:
- "role ∈
viewer < launcher < reviewer < editor < owner…launcherandreviewerare Spectio-only steps between viewer and editor" (api §6, l.140), with a cumulative table;project_grantsholds a singlerole(api §7, l.218). - "They appear as an 'Advanced' row of capabilities on top of Editor" (admin §2.4, l.114).
- "
share --user|--group … --role owner|editor|viewer [--launcher] [--reviewer]" (cli §2, l.51); "Role(owner / editor / viewer)" inbioplatform-models(cli §4, l.132).
- "role ∈
-
Problem: ladder vs flags. With the ladder, every reviewer can launch, so an external QC reviewer who must not launch on the cluster cannot be expressed.
--role viewer --reviewerhas no meaning in api §6, "on top of Editor" contradicts "between viewer and editor", and the sharedRolemodel cannot hold Spectio's grants. -
Proposal: api §6 decides; admin §2.4 and cli link to it. The reviewers disagree:
- (b): base role ∈ {viewer, editor, owner} as in depictio, plus capabilities
launchandreviewon viewer grants (editor and owner imply both);project_grants.capabilities(JSON); the depictio mirror carries the base role only. - (c): keep the five-step ladder; the CLI takes
--role viewer|launcher|reviewer|editor|owner; admin §2.4 says "between Viewer and Editor";bioplatform-modelscarries depictio's three roles plus a Spectio extension enum with the api §13.2 downgrade rule.
Question for Thomas.
- (b): base role ∈ {viewer, editor, owner} as in depictio, plus capabilities
-
Found by: spec-reviewer (b) SR-209, (c) SR-311
- Status: inbox (TRIAGE1, 2026-10-27)
SR-026 · major · Webhooks are both a project table and a notifier plugin instance¶
- Where: api-and-data-model.md §5, §6, §7, §8, §13.5 vs architecture §2, §3.3, §3.5, §9; admin-and-operations.md §1.
-
Evidence:
- "
webhooks,deliveries| project_id, url, secret_hash, event_types (JSON)" (api §7, l.232); the project owner manages webhooks (api §6, l.150). - "One delivery path. An outgoing webhook is just an instance of the built-in
webhooknotifier" (architecture §3.5, l.165); instances live inplugin_instances(architecture §3.3); the MVP lists "notifier (email, webhook)" (architecture §9, l.436). - Admin IA: "Events & webhooks" under Activity (admin §1, l.45) and "Notifications: notifier instances and routing" under Instance (l.52); api §13.5 puts "Webhooks" under Instance.
- "
-
Problem: two storage models, two permission models (project owner vs plugin-instance scope) and two UIs for one object; the outbox worker has two sources of subscriptions.
- Proposal: webhooks stay first-class (the
webhookstable and/webhooksAPI, project-scoped, owned by api §8) and the outbox worker delivers them. Remove thewebhooknotifier from architecture §2/§9, or define it as the delivery code that reads thewebhookstable. api §13.5 links to admin §1 (SR-039). - Found by: spec-reviewer (b) SR-212
- Status: applied (APPLY1, 2026-10-27): architecture §2 (Notifier row), §3.5 (assumed — pending Thomas, inbox #29)
SR-027 · major · The base install's "nothing else" dependency rule is contradicted by the specs' own choices¶
- Where: cli §0.3, §3, §5, §6; architecture §3.1, §4, §6, §7.3; api §5.
-
Evidence:
- "
pip install spectiois the CLI, the Python client and the runner: httpx, pydantic, typer, rich and nothing else" (cli §0.3, l.19); the same list in architecture §6. - The same specs also require: "Configuration has one layered model (pydantic-settings)" (architecture §7.3, l.336); YAML for
~/.config/spectio/servers.yaml(cli §3, l.106);token: keyring:spectio/embl(cli §3, l.115); "spectio plugin new… renders a Copier template" (architecture §4, l.204); a WebSocket channel (api §5, l.92);spectio-sdk, which the runner needs to load engine and launcher plugins (architecture §3.1); check providers on the runner (SR-003). - The runtime dependencies of
openapi-python-client's generated code (cli §5) are [to be validated].
- "
-
Problem: the base-install CI job and import-linter would encode a rule the design already breaks.
- Proposal: cli §6 lists an explicit allow-list (
spectio-sdk, pydantic, pydantic-settings, httpx, typer, rich, a YAML parser, and a WebSocket client if SR-002 picks WebSocket). keyring goes in[keyring]; Copier runs throughuvx copier; check-provider dependencies are named. The < 80 MB budget stays the testable rule. Architecture §6 links to the list. - Found by: spec-reviewer (c) SR-308
- Status: partly applied (APPLY1, 2026-10-27): architecture §4, §6; cli §0 item 3, §3, §6; pending: CI: base-install job and import-linter rule enforcing the allow-list; WebSocket client (inbox #12)
SR-028 · major · The TypeScript client handles bearer tokens for the UI, which should use HttpOnly cookies¶
- Where: cli §5 vs authentication-and-access.md §3; depictio-ecosystem-reuse.md §1.3.
-
Evidence:
- "The wrapper handles the bearer token, refresh on 401 and retry, as depictio's
authFetchdoes … Used by the UI, the embeddable elements and host plugins" (cli §5, l.163). - "HttpOnly, Secure,
SameSite=Laxcookie; a CSRF token on writes … Not readable by JavaScript, unlike depictio's localStorage bearer" (auth §3, l.98). - "
authFetch(bearer token, refresh on 401, retry) | Copy into@spectio/client" (reuse §1.3, l.80).
- "The wrapper handles the bearer token, refresh on 401 and retry, as depictio's
-
Problem: following cli §5 rebuilds depictio's token-in-JavaScript pattern, which auth §3 rejects.
- Proposal: cli §5 defines two modes:
session(same origin, cookies, CSRF header, no token in JavaScript; used by the UI) andbearer(embed tokens and host plugins). reuse §1.3 copies only the retry logic. - Found by: spec-reviewer (c) SR-316
- Status: partly applied (APPLY1, 2026-10-27): cli §5; pending: depictio-ecosystem-reuse §1.3
authFetchrow (inbox #26)
SR-029 · major · Project visibility has three values in the model and two in the UI¶
- Where: api-and-data-model.md §6, §12, §13.2 vs admin-and-operations.md §2.4.
-
Evidence:
- "Visibility
private(grants only),group(all members of the owning group) orinstance(everyone can read)" (api §6, l.139); "Default visibility for new projects (groupis proposed)" (api §12, l.282); "group↔group_viewersof the owning group" (api §13.2, l.306). - "Visibility. A Public / Private switch, with the same sentences as depictio" (admin §2.4, l.112).
- "Visibility
-
Problem: the proposed default,
group, cannot be selected or shown in the sharing UI. Becausegroupmirrors to a depictio group grant, it duplicates a viewer grant to the owning group: two ways to express the same access. - Proposal: two values,
privateandinstance, as depictio does. "Group" access becomes a default viewer grant to the owning group, created with the project. Update api §6, §12 Q3 and §13.2. Question for Thomas. - Found by: spec-reviewer (b) SR-208
- Status: inbox (TRIAGE1, 2026-10-27)
SR-030 · major · A restore rewinds the database under runs still executing; token handling is contradictory¶
- Where: admin-and-operations.md §4.3; authentication-and-access.md §3.
-
Evidence:
- "Tokens. As in depictio, they are not restored, so the admin's session survives a restore" (admin §4.3, l.247).
- "each table is wiped and replaced, with rollback if anything fails" (l.277).
- "A restored run whose directory is gone shows as archived" (l.246).
- Sessions are server-side rows (auth §3, l.98).
-
Problem:
- The admin's session survives only if
sessionsandtokensare not wiped, but neither is listed as excluded; kept tokens can then point to principals absent from the backup. - Into a fresh server, every runner credential, service-account token and run token is gone, so runners and LIMS integrations break silently.
- Runs launched after the backup are still executing; their events arrive for run IDs that no longer exist, and nothing says what happens.
- The admin's session survives only if
-
Proposal: list the tables preserved across a restore (
tokens,sessions,runners) and revoke rows whose principal is absent. The dry run reports runners and integrations that will need new credentials. A final restore step asks each runner for its live handles; unknown runs are adopted as "orphaned after restore" or cancelled, as chosen in the wizard. Ingest for an unknown run returns409with a problem type, and bridges keep buffering until adoption. Question for Thomas (default: adopt or cancel). - Found by: spec-reviewer (b) SR-216
- Status: inbox (TRIAGE1, 2026-10-27)
SR-031 · major · Single-user mode trusts loopback, but loopback is shared on a login node¶
- Where: api-and-data-model.md §1, §6; authentication-and-access.md §1, §6. To cross-check with security-reviewer (R5).
-
Evidence:
- "Personal |
spectio serveon a laptop or a login node, bound to127.0.0.1, auth modesingle" (api §1, l.18). - "Requests from
127.0.0.1/ a Unix socket without a token are treated as that user" (api §6, l.159). - "binds to
127.0.0.1by default. On any other interface it requires a token … (depictio's own risk note on shared login nodes)" (auth §1, l.43).
- "Personal |
-
Problem: on a multi-user login node any local account can connect to 127.0.0.1 and, through the local runner, submit jobs under the owner's cluster account. api §1 names the login node as a supported place for this mode.
- Proposal: in
singlemode, accept requests without a token only on a Unix socket in a 0700 directory, or after a peer-credential check (SO_PEERCRED, unix(7)); TCP loopback requires a cookie set from a one-time URL printed byspectio serve. Update the auth §6 tests. Or restrict the mode to laptops and service nodes. Question for Thomas. - Found by: spec-reviewer (b) SR-217
- Status: inbox (TRIAGE1, 2026-10-27)
SR-032 · major · Built-in plugins are separate distributions, yet one uv tool install spectio is said to be enough¶
- Where: architecture §0, §2, §3.1, §6, §7.3, §7.4, §7.6, §9; cli §6.
-
Evidence:
- "Built in: … local, slurm" (architecture §2, l.42);
plugins/holds "first-party plugins, each its own distribution" (engine-nextflow/ engine-snakemake/ launcher-slurm/ …, architecture §6, l.238-239), whilespectio/is the "CLI + generated Python client + runner daemon and local launcher" (l.233). - "a login node needs one
uv tool install spectio" (cli §6, l.175). - Extras: "
[postgres],[s3],[oidc](Authlib),[saml],[redis],[all]" (architecture §7.3, l.333) vs "[postgres],[s3],[oidc],[saml],[celery]" (cli §6, l.172). - The image runs
uv pip install "spectio[postgres,s3,oidc,saml]==X.Y.Z"(architecture §7.4, l.347), with no server extra, while cli §6 hasspectio[server](l.171) and architecture §9 ships a separatespectio-server(l.436). - The Celery plugin is "
spectio-plugin-celery" (architecture §7.6, l.402) and directorytasks-celery/(§6, l.243); the rule isspectio-plugin-<name>(§3.1, l.75). DEP-T-030 (R8b) covers only the depictio plugin.
- "Built in: … local, slurm" (architecture §2, l.42);
-
Problem: nobody can tell which wheels a login node or the image needs, whether an extra installs a library or a plugin distribution, or what the plugin packages are called. As written, the image contains no server.
- Proposal: in architecture §6, built-ins ship as modules inside
spectio(runner side) and the server package (server side) and register entry points there;plugins/holds optional plugins only. Each auth or backend extra pulls its plugin distribution (spectio[oidc]→spectio-plugin-oidc). Directory name =<name>. Align the extras in architecture §7.3 and cli §6, decide betweenspectio[server]andspectio-server, and fix the image line. - Found by: spec-reviewer (c) SR-307
- Status: applied (APPLY1, 2026-10-27): architecture §0, §2, §6, §7.3, §7.4, §8; cli §6 (assumed — pending Thomas, inbox #29)
SR-033 · major · on_fail: open_gate creates a gate with no items, policy or deciders¶
- Where: checking-scenarios.md §11.3 vs §7; api-and-data-model.md §6, §7.
-
Evidence:
- "
open_gate| A gate is opened at the end of the stage, even if the stage declares none, with the failed items preselected" (checking §11.3, l.320). - A declared gate needs
items.source/keyanddecide.humans/agents(checking §7);gatesrows carrypolicy (JSON)(api §7, l.227); "the decision endpoint checks both the role and the policy" (api §6, l.152).
- "
-
Problem: an implicit gate has no item set beyond the failed files, no policy and no view. Nobody can tell who may decide it, or whether agents may.
- Proposal: define the implicit gate in checking §11.3: items are the
{key}values seen by the watch; checks are the watch's checks; the view is the item table; the policy is "project reviewers and above,agents: none", overridable by the overlay's run-leveldecide. Store it withpolicy.source = implicit(see UX-111gate_source). - Found by: spec-reviewer (d) SR-405
- Status: inbox (TRIAGE1, 2026-10-27)
SR-034 · major · schedulers §8 defines tables, events and endpoints the API spec does not have¶
- Where: schedulers-and-monitoring.md §3.4, §3.5, §8 vs api-and-data-model.md §5, §7, §8.
-
Evidence:
- "links:
run_id,task_attempt_id" onscheduler_jobs(schedulers §8, l.231) vs "the parent job ID plus each array element … are stored n:m with engine attempts" (schedulers §3.4, l.104) and the n:mattempt_jobstable (api §7, l.224). environment_snapshots(l.237),spectio.task.waiting_changed(l.239),spectio.environment.capacity_low(l.241),GET /runs/{id}/scheduler,GET /environments/{id}/capacityandPOST /environments/{id}/preflight(l.245) appear nowhere in api §5, §7 or §8 (checked: zero occurrences). UX-121 asks for "a pre-flight endpoint" without knowing this one exists.failure_classvalues are prose only (schedulers §3.5).
- "links:
-
Problem: the single
task_attempt_idlink contradicts the n:m model. The API catalogue, which is the OpenAPI source, misses three endpoints, two events and a table. - Proposal: api §5, §7 and §8 own the contracts: add the three endpoints, the two events,
environment_snapshots, andfailure_classonspectio.task.failed. Droptask_attempt_idin favour ofattempt_jobs. schedulers §8 keeps the meaning and links to api. Definefailure_classas an enum:oom,timeout,preempted,node_failure,cancelled_external,image,tool_error,engine_fault. - Found by: spec-reviewer (d) SR-408
- Status: partly applied (APPLY1, 2026-10-27): api §5, §7, §8; schedulers §3.5, §8 (assumed — pending Thomas, inbox #29); pending:
GET /environments/{id}/capacityandPOST /environments/{id}/preflightin api §5 (inbox #20)
SR-035 · major · Push transport needs an inbound Kafka consumer the architecture does not have¶
- Where: schedulers-and-monitoring.md §0.3, §3.3, §9, §11 vs architecture §2, §7.6, §9.
-
Evidence:
- "Slurm's
jobcomp/kafkaread through Spectio's Kafka bridge" (schedulers §0.3, l.25); jobcomp records are Slurm job JSON with a "topic [that] defaults to the cluster name" (schedulers §3.3, l.92, citing https://slurm.schedmd.com/jobcomp_kafka.html). def stream(self, ctx) -> AsyncIterator[JobRecord] | None: ... # push transports (Kafka, …)on the runner-sideSchedulerObserver(schedulers §9, l.264).- "Bridges read from the same outbox as webhooks" (architecture §7.6, l.421): bridges are outbound, inbound is described only for MQTT robot signals; bridges run on the server (architecture §2) and come in phase 3 (architecture §9, l.439), while schedulers §11 puts Kafka in phase 2.
- "Slurm's
-
Problem: it is unclear whether the server bridge or the runner observer consumes the topic. The topic carries every user's jobs on the cluster and nothing filters them per tenant. The phases disagree.
- Proposal: in schedulers §3.3, make the Kafka consumer a transport of the runner's
SchedulerObserver, filtering to the runner's own user before anything leaves the cluster; it is not an event bridge. Align its stage in dev-env §15 (SR-007; reviewer (d) suggests unscheduled). - Found by: spec-reviewer (d) SR-409
- Status: inbox, assumed: the Kafka consumer is a transport of the runner's
SchedulerObserver, filtered to its own user; its stage follows SR-007 — pending Thomas (TRIAGE1, 2026-10-27); not applied (APPLY1): blocked by inbox #25 (schedulers §0 item 3 and §3.3)
SR-036 · major · The checks_as preset shape requested from depictio does not match Spectio's check syntax¶
- Where: depictio-ecosystem-reuse.md §1.4, §3.7 vs checking-scenarios.md §4, §7.
-
Evidence:
- "check presets such as
{kind: outlier, column: pct_mito, by: sample, k: 3}, validated againstOUTPUT_SCHEMAlikerenders_as. Spectio reads them as its presets (checking §4)" (reuse §3.7, l.153). - Checks use
{ id, from: "<binding>", min/max, severity, kind, scope }(checking §7);outlieris "robust deviation from the batch (median ± k·MAD), per group if given" (checking §4, l.84), with no key names. The presets table has no file format. - "evidence
matchglobs" (reuse §1.4) vsevidence: - { kind, path, per_item }(checking §7).
- "check presets such as
-
Problem: depictio would build and validate a shape Spectio cannot read (
columnvsfrom;byandkundefined). Changing a contract across two projects later is costly. - Proposal: define the keys of each check kind in checking §4/§7 (or the new §12, SR-004), for example
outlier: {k, by},relative: {against}, and the preset file format. Send depictio that exact shape, withoutfrom(it comes from the catalogue output). Fix "match" to "path" in reuse §1.4. - Found by: spec-reviewer (d) SR-414
- Status: partly applied (APPLY1, 2026-10-27): checking-scenarios §4.1 (new); depictio-ecosystem-reuse §3 row 7 (assumed — pending Thomas, inbox #27); pending: depictio-ecosystem-reuse §1.4
match→path(inbox #26); checking §7 example (inbox #16, #19); sending the request to depictio (Thomas, inbox #27)
SR-037 · major · SLURM job names: the head-job pattern and the Snakemake join do not work as written¶
- Where: schedulers-and-monitoring.md §3.1, §3.4.
-
Evidence:
- The head job is "named
spectio-<run_id>" (schedulers §3.1, l.64); reconciliation uses "squeue --me --name 'spectio-*'" (l.67). - "Spectio sets
--slurm-jobname-prefix spectio-<run_id>, thensacct --name/squeue --name" (schedulers §3.4, l.102). - The plugin joins prefix and UUID:
self.run_uuid = "_".join([jobname_prefix, self.run_uuid])(snakemake-executor-plugin-slurm8c2af56,snakemake_executor_plugin_slurm/__init__.py:481-496, cited by reviewer (d)). Task jobs are therefore namedspectio-<run_id>_<uuid4>. - "
-n, --name=<name_list>… a comma separated list of job names" (https://slurm.schedmd.com/squeue.html). Wildcards are not documented [to be validated on sind].
- The head job is "named
-
Problem:
--name spectio-<run_id>matches only the head job, and the UUID is known only from a log line.'spectio-*'probably matches nothing; if it did, it would also match Snakemake task jobs and treat them as head jobs. - Proposal: name head jobs
spectio-head-<run_id>. Reconcile from the batchedsqueue --me --json/sacct --jsonsnapshot, filtered client-side on the name prefix and on--comment=spectio:<run_id>. For Snakemake, join on the prefixspectio-<run_id>_client-side; do not use--name. Validate in T3. - Found by: spec-reviewer (d) SR-411
- Status: partly applied (APPLY1, 2026-10-27): schedulers §3.1 (head-job prefix, Runner restart); pending: none; the §3.4 Snakemake cell was superseded by FC-007
SR-038 · major · Maintenance mode does not say which writes still work¶
- Where: admin-and-operations.md §4.3, §4.4.
-
Evidence:
- "Choices: block new launches and gate decisions, or make the API read-only. Runners keep executing running jobs either way" (admin §4.4, l.306).
- "Used automatically by restore and migrations" (l.308).
- "maintenance mode turns on, runners stop picking up new launches" (admin §4.3, l.276).
-
Problem: "read-only" is not testable. Engines keep sending events, so it is undefined whether
POST /ingest/events, runner heartbeats and the runner channel,check.evaluated, robot signals (/gates/{id}/signals), sign-in, webhook delivery and the scheduled loops keep working; which status code a refused request gets; whether gate timeouts keep counting; and how long the bridges must buffer. - Proposal: add to admin §4.4 a table of endpoint families against the modes
normal,no-launch,read-onlyandrestoring. Ingest and the runner channel stay open in every mode exceptrestoring. Refused writes return503withRetry-Afterand problem type…/maintenance. Gate timeouts pause during maintenance. Bridges must buffer at least the announced maximum window (proposed 2 h; see SR-017). - Found by: spec-reviewer (b) SR-215
- Status: partly applied (APPLY1, 2026-10-27): admin §4.4; pending: restore wizard step → mode
restoring(inbox #24); bridge buffer bounds in api §14 (inbox #11)
Minors¶
SR-039 · minor · "Settings" leftovers next to Administration, with a different grouping in api §11/§13.5¶
- Where: api-and-data-model.md §11, §13.5; ui-spec.md §2, §4.5, §4.11; architecture §3.1, §4, §10; telemetry-and-analytics.md §0.4, §2; depictio-ecosystem-reuse.md §1.1; authentication-and-access.md §5. Owners: admin-and-operations.md §1 and ui-spec.md §4.9.
-
Evidence:
- "Settings tabs: Users & groups, Projects, Service accounts, Tokens, Webhooks, Plugins" (api §11, l.275); Tokens moved to Profile (log, l.134).
- "Activity (Runs, Events, Logs, Health) · Instance (Branding, AI & agents, Webhooks, Settings)" (api §13.5, l.335) vs admin §1 (l.43-55): Activity = Tasks, Runners, Events & webhooks, Logs, Health, Audit log; Instance adds Plugins, Notifications, Backups, Maintenance.
- "Settings → Plugins" three times in architecture; "Settings → Telemetry" (telemetry); "Settings → Version check" (reuse §1.1); "Settings → Sign-in" (auth §5). admin §4.5 lists none of these sub-panels.
- ui-spec: "Auto-approve rules (Settings)" (§4.5, l.100); the phone More sheet lists "Settings" (§4.11, l.164); a bare "settings" control in the top bar (§2, l.28). Auto-approve rules live in the gate's
decidepolicy, not in an admin page.
-
Proposal: write paths as "Administration →
<group>→<section>"; api §11 and §13.5 link to admin §1 and ui-spec §4.9 instead of listing tabs; admin §4.5 lists Sign-in, Telemetry and Version check sub-panels; ui-spec §4.5 says "(from the gate'sdecidepolicy)"; the phone More sheet and the top bar say "Administration" (admins only). - Found by: spec-reviewer (a) SR-113, (b) SR-218 (Settings part), (c) SR-318, (d) SR-418 (Settings part)
- Status: partly applied (APPLY1, 2026-10-27): admin §4.5; api §11, §13.5; architecture §3.1, §4, §10; auth §5; telemetry §0, §2.3; ui-spec §2, §4.5, §4.11; pending: depictio-ecosystem-reuse §1.1 (inbox #26); boards AppTopbar, MMore and admin boards titled Settings
SR-040 · minor · Stale names: agent for runner, perspectio, companion plugin, Duplicate¶
- Where: synthesis.md §1, §7quater, §8, §9; ui-spec.md §4.4, §5, §6; admin-and-operations.md §0.4.
-
Evidence:
- "Each engine has its own small agent" (synthesis §1, l.11); "server and agent run in the same process (
perspectio serve)", "via the agent", "outgoing agent" (§7quater, l.339-348); "Agents: disk buffer" and "the agent writes JSONL" (§8, l.367-369); "Snakemake agent", "Nextflow agent (V2 plugin)" (§9, l.377-378); "agents that heartbeat and claim 'Run now' requests" (admin §0.4, l.22). The log says "agent means AI agent only" (2026-10-25, l.101) andprincipals.kind=agentis AI only. - "
spectio runner connect <token>" (synthesis §7quater) vs "runner connect <server> --token …" (cli §2, architecture §7.3). - "shown as 'not scheduled' (companion plugin)" (ui-spec §5, l.181), although
nf-spectiois the only plugin. - Run detail action "Duplicate" (ui-spec §4.4, l.86; §6, l.208) vs "'Duplicate' becomes the secondary 'Copy to a new launch'" (§4.6, l.124).
- "Each engine has its own small agent" (synthesis §1, l.11); "server and agent run in the same process (
-
Proposal: "runner" for the Spectio process, "engine plugin" (
nf-spectio, Snakemake logger) for the in-engine reporters,spectio serve --with-runnerfor the combined process, the cli §2 syntax forrunner connect, "runners (depictio's watcher agents)" in admin §0.4, "nf-spectio" in ui-spec §5, and "Copy to a new launch" in ui-spec §4.4 and §6. - Found by: spec-reviewer (a) SR-112, (b) SR-218 (agent part), (c) SR-319, (d) SR-418 (agent part)
- Status: partly applied (APPLY1, 2026-10-27): admin §0; synthesis §1, §7quater, §8, §9; ui-spec §4.4, §5, §6; pending: boards RunDetail and Main still labelled 'Duplicate'
SR-041 · minor · Run and review screens are specified outside ui-spec; two cross-references are broken¶
- Where: ui-spec.md §4.4, §4.5, §10.2; schedulers-and-monitoring.md §3.1, §10; checking-scenarios.md §11.4; api-and-data-model.md §13.6.
-
Evidence:
- "Run detail → Scheduler tab" (schedulers §10, l.271); "The run detail shows a Live checks panel" (checking §11.4, l.335); a gate review "Dashboard" tab (api §13.6 rule 3, l.354). None is in ui-spec §4.4 (9 tabs) or §4.5.
- "Every pattern has the states of §3: empty, loading, error, permission" (ui-spec §10.2, l.303). §3 is the run status system and defines none of these.
- "No run is lost (synthesis §7 risk register)" (schedulers §3.1, l.67). The risks are in synthesis §10.
-
Proposal: add Scheduler and Live checks to ui-spec §4.4 and Dashboard (conditional) to §4.5, each linking to its owning spec; add ui-spec §11 "Component states" (empty, loading, error, permission, n/a) and point §10.2 to it; fix the schedulers reference to synthesis §10.
- Found by: spec-reviewer (a) SR-116
- Status: partly applied (APPLY1, 2026-10-27): schedulers §3.1; ui-spec §4.4, §4.5, §10.2, §11 (new) (assumed — pending Thomas, inbox #29); pending: boards RunDetail tab bar (Scheduler, Live checks), ReviewReport / ReviewDashboard tab bar (Dashboard)
SR-042 · minor · The built-in AI assistant has UI and a runner command but no API, data model or CLI entry¶
- Where: ui-spec.md §4.9; api-and-data-model.md §5, §7; cli §2; architecture §2 (AI provider kind).
-
Evidence:
- "the runner starts the model server as an ordinary GPU job (
spectio ai serve --env … --model … --gpus 1 --idle-stop 2h), registers it as an endpoint" (ui-spec §4.9, l.149). - "Lists: model endpoints (kind, where it runs, data policy, state), connected agents …, default limits for agents (… read evidence ≤ 50 MB …)" (l.151).
- No
aicommand in cli §2; no model-endpoint or agent-limit endpoint or table in api §5 or §7.
- "the runner starts the model server as an ordinary GPU job (
-
Proposal: architecture §2 (AI provider kind) owns model endpoints; add
/admin/ai/endpointsand agent-limit fields to api §5/§7 andspectio ai serveto cli §2 (SR-006). Or mark ui-spec §4.9 item 2 as post-1.0. Per-agent launch limits overlap UX-126. - Found by: spec-reviewer (a) SR-117
- Status: applied (APPLY1, 2026-10-27): admin §5; api §7; architecture §2; cli §2 (
airow); no stage claim (owned by dev-env §15) (assumed — pending Thomas, inbox #29)
SR-043 · minor · "v1" means both the API path and a release; the API rule conflicts with 0.x semver¶
- Where: api-and-data-model.md §4, §5; admin-and-operations.md §3.1, §4.2; dev-env §12, §14; log 2026-10-26 (versioning).
-
Evidence:
- "only additive changes within v1; breaking changes go to v2" (api §4, l.80) vs "a breaking change also bumps the minor (
bump-minor-pre-major)" (log, l.257) and the OpenAPI frozen only at 1.0 (dev-env §14, item 6). - "Kinds in v1: …
sink.depictio,sink.labid, …bridge.publish" (admin §3.1, l.134). The depictio hand-off is after 0.1 (log, l.318); LabID and bridges come in phases 2 and 3 (architecture §9).
- "only additive changes within v1; breaking changes go to v2" (api §4, l.80) vs "a breaking change also bumps the minor (
-
Proposal: api §4: "During 0.x,
/api/v1may break in a minor release, announced in the changelog; the additive-only rule starts at 1.0.0." Elsewhere write "API v1" for the path and "0.1" / "1.0" for releases. Tag each background-task kind with its stage (SR-007). - Found by: spec-reviewer (b) SR-221
- Status: partly applied (APPLY1, 2026-10-27): admin §3.1, §4.2; api §4, §5 heading, §12; architecture §11; pending: api §6 'Flat in v1' (inbox #13, #14, #15); stage tag per background-task kind (inbox #16)
SR-044 · minor · Superseded merge and staging rules remain in dev-env, map.md and auth¶
- Where: dev-env §0.6, §8; docs/map.md (item 10); authentication-and-access.md §2. Owners: documentation-system.md §8 and the log (2026-10-26, inbox #3).
-
Evidence:
- "Humans merge." (dev-env §0.6) and "A human merges." (dev-env §8) vs "On
autopilot/integration: auto-merge is always on" (documentation-system §8) and "Claude may merge intomainfor now" (log; inbox #3). - "eight reviewers and builders" (dev-env §8); CLAUDE.md lists twelve agents.
- "staging behind Tailscale Funnel" (map.md) and "For staging and demos" (auth §2, l.65). Staging was dropped (log, "Dev previews without a server").
- "Humans merge." (dev-env §0.6) and "A human merges." (dev-env §8) vs "On
-
Proposal: dev-env §0.6 and §8 say "Merges follow documentation-system §8" and link to the CLAUDE.md agent table; map.md says "dev previews (Cloudflare Pages, Codespaces), public instance from the beta"; auth §2 says "dev previews and demos".
- Found by: spec-reviewer (c) SR-322
- Status: partly applied (APPLY1, 2026-10-27): map (reading order 11); dev-env §0, §8; pending: auth §2 'For staging and demos' (inbox #20, #21)
SR-045 · minor · The event catalogue is incomplete, and gate notifications have two paths¶
- Where: api-and-data-model.md §8 vs §13.3, §13.4; architecture §3.4, §3.5; admin-and-operations.md §3.1.
-
Evidence:
spectio.run.dashboard_readyis emitted and bridged (api §13.3, l.321; §13.4, l.330) but missing from the §8 table.spectio.ext.<plugin>.*(architecture §3.4) and the SSE-onlycheck.evaluated(api §8, l.248) have no schema.- The
gate.notifybackground-task kind (admin §3.1, l.134) vs notifiers that subscribe through the outbox (architecture §3.5, l.164).
-
Proposal: api §8 lists every type (webhook, SSE-only, extension);
dashboard_readyis marked after 0.1; dropgate.notifyor define it as the outbox delivery to notifiers. See SR-052 for thecheck.evaluatedname. - Found by: spec-reviewer (b) SR-219
- Status: applied (APPLY1, 2026-10-27): admin §3.1; api §8
SR-046 · minor · Pipeline identifier and workflow version key: @ vs /, no column¶
- Where: cli §2, §4, §5; api-and-data-model.md §7, §13.4; depictio-ecosystem-reuse.md §2.4.
-
Evidence:
- "
launch <org/name@version>" andworkflow="nf-core/rnaseq@3.27.0"(cli §2, l.47; §5). - "
PipelineRef(<org>/<name>/<version>)" (cli §4); "Pipeline identifier:<org>/<name>/<version>everywhere" (api §13.4); depictio template IDs and Spectio workflow version keys are the same string (reuse §2.4). workflow_versionshas only "revision, commit" (api §7). Git, local and Snakemake-catalog workflows have no<org>.- The CLI takes names (
--env embl-slurm,--project liver-tc); the API takes prefixed IDs. How a name resolves is not specified.
- "
-
Proposal: canonical form
<org>/<name>/<version>; the CLI accepts@as input only and prints the canonical form. Addworkflow_versions.key(unique per project) with a defined form for git and local sources. Define name → ID resolution: a project or environment slug unique per instance, or an error listing the candidates. - Found by: spec-reviewer (c) SR-320, (d) SR-420
- Status: applied (APPLY1, 2026-10-27): api/index.md; api §7; cli §2, §5 (assumed — pending Thomas, inbox #29)
SR-047 · minor · Fixture workflows and step numbers in dev-env disagree with the playbook and with §10.1¶
- Where: dev-env §1, §3, §9, §10.1 vs docs/playbooks/next-phase.md (D4, T1, T2) and pipeline.yaml; checking-scenarios.md §11.5.
-
Evidence:
doctor.shruns "nextflow run tests/fixtures/workflows/nf-toy" (dev-env §1); §3 definesnf-toyandsmk-toywith stages "A → gate → B → C" (l.88).tests/fixtures/workflows/does not exist at3b209d3;tests/pipelines/synthetic/(§10.1, "qc→ gate →align→ gate →quant") exists and is verified.- "D4: build the fixture workflows and record the first golden fixtures" (dev-env §9) vs "D4 · CI and Claude in GitHub" and "T1 · Fixture workflows" / "T2 · Engine event capture" on
nf-toy(next-phase). - checking §11.5 validates the stop-file closure "on
nf-toy".
-
Proposal: declare the §10.1 synthetic pipelines the fixture workflows; §3 becomes a pointer and keeps its number.
doctor.sh, T1/T2 and checking §11.5 usetests/pipelines/synthetic. dev-env §9 links topipeline.yamlinstead of numbering steps itself. - Found by: spec-reviewer (c) SR-323
- Status: partly applied (APPLY1, 2026-10-27): next-phase T1–T4, P1; dev-env §1, §3, §9 (assumed — pending Thomas, inbox #28); pending: checking §11.3
nf-toy(inbox #19); tool:dev/doctor.shpaths
SR-048 · minor · Untestable thresholds: "head silent" and the 10,000-file watch limit¶
- Where: schedulers-and-monitoring.md §7; checking-scenarios.md §11.5; decision 0001 (Consequences).
-
Evidence:
- "When they stop while the head job is still
RUNNING, the run shows as 'head silent'" (schedulers §7, l.218); "It needs its own heartbeat" (0001, l.41), with no interval. - "A watch on 10,000 per-cell files is refused at save time" (checking §11.5). The number of matching files is unknown at save time.
- "When they stop while the head job is still
-
Proposal: bridges send a heartbeat every 60 s when idle, as the Tower model does (synthesis §2bis); "head silent" = no event for 5 min while the last
squeueshows the head jobRUNNING(put the heartbeat in api §14, SR-001). A watch is refused at save time when{key}binds to achildrenkind; at run time, evaluation stops after N files per watch (for example 2,000) with the state "suspended: too many files". - Found by: spec-reviewer (d) SR-417
- Status: partly applied (APPLY1, 2026-10-27): checking-scenarios §11.5; schedulers §7 (assumed — pending Thomas, inbox #28); pending: api §14 idle heartbeat (inbox #11)
SR-049 · minor · api §3 repeats the plugin-kind table with the stale "broker" kind and another engine contract¶
- Where: api-and-data-model.md §3 vs architecture §2, §3.6; log 2026-10-25.
-
Evidence:
- "adds the launcher, AI provider, file store, broker, API and CLI extension kinds" (api §3, l.57). Architecture §2 split the broker into
spectio.tasksandspectio.pubsub(plusspectio.bridge,spectio.backup,spectio.analytics). - api §3 gives the engine contract as "launch, stop at stage, resume, cancel, event source"; in architecture §3.6,
cancelbelongs toLauncher, andEnginehasdetect / describe / plan / plan_resume / collect / ingest.
- "adds the launcher, AI provider, file store, broker, API and CLI extension kinds" (api §3, l.57). Architecture §2 split the broker into
-
Proposal: replace the api §3 table with one sentence and a link to architecture §2; word the kinds as "task backend, pub/sub, event bridge". The log is append-only, so the "broker" wording of 2026-10-25 is corrected by a new log entry, not an edit.
- Found by: spec-reviewer (b) SR-218 (broker part), (c) SR-317
- Status: applied (APPLY1, 2026-10-27): api §3 (table removed, kinds owned by architecture §2); 2026-10-25 'broker' wording corrected in decisions/log.md (APPLY1 entry)
SR-050 · minor · The backup and restore contract differs between the CLI and admin specs¶
- Where: admin-and-operations.md §4.3, §4.4, §5 vs cli-and-shared-libraries.md §2.
-
Evidence:
- "
restore (--dry-run default, --tables, --force)", "validate" and "migrate project … --mode all|metadata|files" (cli §2, l.61-62). - vs "each table is wiped and replaced" (admin §4.3, l.277), "Verify" /
POST /backups/{id}/verify, and no mode on the project migration (l.290). - "the three wizards in §4.3" (admin §4.4, l.311) vs four migrations listed (l.287-290).
- "the manifest signature" (l.268), although the manifest (l.239) has no signature field or signing key.
- "
-
Proposal: decide whether partial restore by table exists (recommended: no, which removes
--tables); use one verb,verify; fix the wizard count; define the signature (Ed25519 with the instance key, verifiable without the archive's ownkeys/). - Found by: spec-reviewer (b) SR-220
- Status: partly applied (APPLY1, 2026-10-27): admin §4.3, §4.4; cli §2 (assumed — pending Thomas, inbox #24); pending: restore wizard steps and encryption rules, cli §2 backup example (inbox #24)
SR-051 · minor · Kubernetes RBAC differs between specs, and the Nextflow head pod has none¶
- Where: schedulers-and-monitoring.md §1, §4 vs architecture §7.5.
-
Evidence:
- "a Role that lets it create Jobs and Pods" (architecture §7.5).
- "
pods… get, list, watch;jobs: create, get, list, watch, delete" (schedulers §4). - Nextflow "creates one Kubernetes
Jobper task (default since 26.10;Podbefore)" (schedulers §1, l.43); dev-env also tests 25.10. That is done by the head pod, whose ServiceAccount is never specified. Nextflow's required permissions are [to be validated] (https://docs.seqera.io/nextflow/kubernetes); 25.10 needspods: create[to be validated on k8s-mini].
-
Proposal: schedulers §4 owns RBAC and defines two ServiceAccounts: the runner's (creates the head Job and watches) and the engine head's (create / delete / get / list / watch on pods and jobs,
pods/log, by Nextflow version), validated in T4. Architecture §7.5 links to it. - Found by: spec-reviewer (c) SR-321, (d) SR-419
- Status: applied (APPLY1, 2026-10-27): next-phase T4; architecture §7.5; schedulers §4
SR-052 · minor · Check-result vocabulary: state vs verdict, and how severity maps to them¶
- Where: checking-scenarios.md §4, §11.3, §11.4; api-and-data-model.md §7, §8, §13.6.
-
Evidence:
- "state (
ok,warn,fail,provisional,too_large,error)" (checking §11.4) vs "check_key … verdict (…)" (api §7). - Severities are
block,warn,info(checking §4); "When awarnorblockcheck fails" (checking §11.3). - The SSE event is "
check.evaluated" (api §8, l.248), while every other type isspectio.*.
- "state (
-
Proposal: store the outcome (
pass/fail/provisional/too_large/error) and the severity separately, and display warn / fail as outcome × severity. Name the columnverdictin both specs; rename the eventspectio.check.evaluated(SSE only). Extra states are covered by UX-103. - Found by: spec-reviewer (d) SR-415
- Status: applied (APPLY1, 2026-10-27): api §7, §8; checking-scenarios §11.1, §11.4 (assumed — pending Thomas, inbox #29)
SR-053 · minor · ui-spec contradicts the logged shell and list decisions without a new log entry¶
- Where: ui-spec.md §1.1, §2, §7 vs decision log 2026-10-25 "UI review round 2".
-
Evidence:
- "Shell: sidebar copied from depictio (logo on top, …, footer with theme, runners, server, profile), fixed and full height; top bar without logo" (log, l.102).
- "Top bar across the full width: animated logo (home) …, colour mode (only here)" and "Sidebar below it" (ui-spec §2, l.28-29). The AppTopbar board follows ui-spec.
- "Card grid dropped" (log, l.104; ui-spec §4.3) vs "list patterns (card grid / table toggle)" (ui-spec §1.1, l.8) and "List pattern: card/table toggle (
ViewPicker)" (§7, l.220).
-
Proposal: add a dated log entry recording the full-width top bar with logo and colour mode, and the sidebar below it. In ui-spec §1.1 and §7, say "table / rows toggle".
- Found by: spec-reviewer (a) SR-114
- Status: applied (APPLY1, 2026-10-27): ui-spec §1, §7; shell revision recorded in decisions/log.md (APPLY1 entry) (assumed — pending Thomas, inbox #29)
Questions for Thomas¶
These need a decision before the related findings can be applied. Reviewer recommendations are given where they agree.
- WES facade (SR-010): 0.1, private alpha, public beta, or unscheduled? All reviewers say not in 0.1; two recommend the public beta, one before the beta, one unscheduled. Same question for MCP and OIDC (SR-007).
- Stage contents (SR-007): is the Kubernetes launcher in 0.1 or the alpha? Are Postgres and OIDC needed for the design-partner alpha?
- Observed runs (SR-001): are terminal-started runs part of 0.1 or the alpha? Do they get a long-lived user token with an ingest scope on the login node, or must every observed run go through a wrapper (
spectio run nextflow …) so that it gets a run token? - Runner transport (SR-002): WebSocket (with long-poll fallback) or HTTPS long-poll / SSE? Does any EMBL proxy or SSH-tunnel constraint decide it?
- Snakemake steering (SR-008): may the runner launch Snakemake as a command-line head job (
--until,--forcerun), relaxing the "no Pythonsubprocess" constraint of the first session notes, or must it use the Python API inside the workflow's environment? - Nextflow boundary (SR-011): confirm that the generated
ext.whenconfig (no pipeline change) is the only mechanism and that--stagecooperation is dropped. - Pause (SR-018): is an immediate "stop now, keep the cache" in scope next to "pause after stage", and is either needed in 0.1?
- Roles (SR-025): may a reviewer decide gates without being allowed to launch (for example an external QC reviewer)? This decides ladder vs capability flags.
- Project visibility (SR-029): drop
groupand use depictio's two-value model? - Shared clusters (SR-014): does each user run their own runner, or is a site service account acceptable?
- Checks in 0.1 (SR-023): only Spectio's own bindings, or depictio catalogue recipes on the runner as well?
- Version skew before 1.0 (SR-022): may runners on clusters lag the server by one minor, at the cost of keeping the API backward compatible during 0.x?
- Restore (SR-030): when runs launched after the backup are found, adopt or cancel by default?
- Single-user mode on shared login nodes (SR-031): supported deployment, or laptops and service nodes only?
Proposed spikes¶
| Spike | Validates | Findings | Where |
|---|---|---|---|
| Extend T2 (engine event capture) | capture against a draft api §14 envelope; whether an exception in a TraceObserverV2 hook aborts the run; hook latency; Snakemake run UUID and Nextflow sessionId availability for the run handshake; idle heartbeat |
SR-001, SR-017, SR-048 | spikes/engine-events/ (T2 already planned) |
| Nextflow stage boundary | generated ext.when = false stops after a stage on 25.10 and 26.10; nf-core modules honour task.ext.when (source it); stop-file closure; rerun-from-stage through a generated ext key that enters the task hash |
SR-011, SR-018 | spikes/nf-stage-boundary/, on tests/pipelines/synthetic |
| Snakemake steering (only if Thomas wants evidence first) | CLI head job vs SnakemakeApi worker in the workflow environment: stop via SIGINT vs API, version coupling, logger hookup |
SR-008 | spikes/smk-steering/ |
| Runner transport | WebSocket upgrade and long-poll / SSE through the EMBL proxy and an SSH tunnel; streaming a large file both ways | SR-002 | needs EMBL access; otherwise a local proxy mock in spikes/runner-transport/ |
| Runner footprint with check bindings | install size of the base runner plus MultiQC, anndata and polars against the 80 MB budget; which bindings fit in an extra | SR-003, SR-027 | spikes/runner-footprint/ |
| Extend T3 (sind) | squeue --name with wildcards; the Snakemake SLURM job-name join; filtering on --comment |
SR-037 | T3 profiles |
| Extend T4 (kind) | the Nextflow head pod's minimal RBAC for 25.10 (Pods) and 26.10 (Jobs) | SR-051 | T4 profiles |