MOJ: o pacote de problema (formato canônico) — MOJ docs

MOJ: o pacote de problema (formato canônico)

Este documento é a fonte única do formato do pacote de problema do MOJ. Explica o que é um pacote, o que faz cada arquivo dentro dele, o que são os metadados (.moj-meta.json e .moj-id), o que são orgs e coleções, e como um problema sai de rascunho e chega ao aluno.

Quem monta um pacote na prática (passo a passo, com os comandos) deve ler o README.md do mojtools, que tem o roteiro. Aqui está a referência: o que cada coisa é e por quê. As rotas da API que leem e escrevem o pacote estão em API.md.

Doc atrasada = bug. Mudou o pacote (arquivo novo, campo novo, layout, de onde vem o título)? Atualize este documento no mesmo commit. Os outros lugares (o CLAUDE.md do cdmoj, do mojtools e do moj-cli) apontam para cá em vez de repetir o formato.

Sumário

  1. O que é um pacote
  2. Onde os pacotes moram
  3. Layout canônico
  4. Arquivo por arquivo
  5. .moj-meta.json: os metadados do problema
  6. .moj-id: o ponteiro local da CLI
  7. ORG: quem pode mexer
  8. COLEÇÃO: como os problemas são agrupados
  9. ORG x COLEÇÃO
  10. Ciclo de vida de um problema
  11. Perguntas frequentes

1. O que é um pacote

Um pacote é um diretório que descreve um problema por inteiro: o enunciado, os testes, as soluções de referência e os limites de execução. Não existe banco de dados de problemas: o pacote é o problema.

Três coisas valem saber desde já:

2. Onde os pacotes moram

moj-problems/<org>/<prob>/        # o pacote (raiz do repo git local daquele problema)

A raiz moj-problems/ é configurável pela variável MOJ_PROBLEMS_DIR. No checkout de desenvolvimento ela fica ao lado do cdmoj/.

Um pacote não contém o placar, o histórico de submissões, nem os tempos-limite calibrados. Isso tudo vive fora dele:

Coisa Onde fica Quem escreve
Tempos-limite calibrados run/tl/<id>.json os juízes, ao calibrar
Relatório de validação run/validation/<id>.json validate-problem.sh
Índice servido ao aluno contests/treino/var/jsons/<id>.json gen-problem-json.sh
Registro de orgs contests/treino/var/orgs.json a API (lib/orgs.sh)
Registro de coleções contests/treino/var/collections.json a API (lib/problems.sh)

3. Layout canônico

Árvore de um pacote completo. A coluna da direita mostra em quantos dos 453 pacotes do acervo atual cada item aparece, para dar noção do que é rotina e do que é exceção.

moj-problems/<org>/<prob>/
├── .git/                     repo git local do problema                     453  (sempre)
├── .moj-meta.json            metadados (título, público, coleções, …)       453  (sempre)
├── author                    autor(es) do problema                          453  (obrigatório)
├── tags                      assuntos, uma tag por linha                    453
├── conf                      limites e ajustes de execução                  453
├── docs/
│   ├── enunciado.md          o enunciado (também aceita .org e .tex)        453  (obrigatório)
│   ├── sample-notes.json     explicação de cada exemplo                     opcional
│   └── solucao.md            editorial, só para o autor                     opcional
├── tests/
│   ├── input/sample1         exemplo (aparece no enunciado)                 obrigatório, >= 1
│   ├── output/sample1        resposta do exemplo
│   ├── input/<nome>          teste oculto (corrige a submissão)
│   ├── output/<nome>         resposta do teste oculto
│   └── score                 grupos de pontuação (subtarefas)               254  (opcional)
├── sols/
│   ├── good/                 soluções corretas                              453  (obrigatório, >= 1)
│   ├── wrong/                soluções erradas de propósito                    18  (opcional)
│   ├── slow/                 soluções lentas de propósito                      7  (opcional)
│   ├── pass/                 soluções que devem passar raspando               3  (opcional)
│   └── upcoming/             soluções em rascunho                              1  (opcional)
└── scripts/                  correção especial                               79  (opcional)
    ├── compare.sh            comparador próprio (checker)                    18
    └── <lang>/compile.sh     compilação própria (submissão de função)       201

Dois arquivos aparecem no acervo mas não fazem parte do formato:

4. Arquivo por arquivo

docs/enunciado.md

O texto do problema. Aceita três formatos, procurados nesta ordem: enunciado.md, enunciado.org, enunciado.tex. O .md é o canônico e o recomendado.

Três regras que o portão de qualidade cobra:

  1. As seções ## Entrada e ## Saída são obrigatórias. Sem elas o problema não passa na validação. (O validador também aceita ## Input e ## Output, e de um a três #.)
  2. O título não vai no texto. Uma primeira linha % Título do problema é legado: o renderizador a remove. O título verdadeiro é o campo display_title do .moj-meta.json (seção 5), e o renderizador injeta um <h1> a partir dele.
  3. Os exemplos não vão no texto. Eles são montados a partir de tests/input/sample* e tests/output/sample* e injetados no fim do HTML. Se você escrever um exemplo à mão dentro do enunciado, ele vai aparecer duplicado. (A validação avisa, mas não bloqueia.)

Imagens devem ser embutidas em base64. O renderizador roda com --embed-resources, então o HTML servido ao aluno é autocontido, sem depender de arquivo externo.

Quem renderiza é um script só: mojtools/render-statement.sh. O botão "Pré-visualizar" do editor, o HTML que o aluno lê e o HTML que a validação confere são exatamente o mesmo. Não existe segundo renderizador, e não se deve criar um.

docs/sample-notes.json

Opcional. Um array JSON de textos, um por exemplo, na ordem dos exemplos:

["No primeiro exemplo, os dois times empatam, então a saída é 0.",
 "Aqui o segundo time vence por 3 pontos."]

Cada nota é renderizada em markdown e aparece logo abaixo do exemplo correspondente.

docs/solucao.md

Opcional. É o editorial: a explicação da ideia da solução, para o autor e para quem for reusar o problema. O aluno nunca vê este arquivo. O gen-problem-json.sh o ignora de propósito. É o lugar certo para escrever "a solução é uma DP em O(n log n)" sem medo.

Não confundir com a mecânica da correção especial, que é assunto do scripts/ e está documentada em mojtools/docs/correcao-especial.md.

tests/input/ e tests/output/

Todo arquivo em tests/input/ precisa ter um arquivo de mesmo nome em tests/output/. Isso é checado na validação, nos dois sentidos (input sem output e output sem input reprovam).

O nome do arquivo decide o papel do teste:

Nome Papel
sample1, sample2, … exemplo: aparece no enunciado, e também corrige
qualquer outro nome teste oculto: só corrige, o aluno nunca vê

Os exemplos são todos os arquivos que começam com sample, ordenados por ls -1v (ou seja, sample2 vem antes de sample10, e não depois). É preciso ter pelo menos um par de teste, e na prática pelo menos um exemplo.

O nome dos testes ocultos é livre. As convenções que aparecem no acervo são test-001, test-002 (estilo APC) e <prob>_1_1, <prob>_1_2 (estilo OBI, que agrupa por subtarefa; ver tests/score).

tests/score

Opcional. Liga a pontuação por grupos (subtarefas). Sem este arquivo, a nota do problema é a porcentagem de testes que passaram.

O formato é texto puro, uma linha por grupo:

sample* - 0 pontos
2015f2p1_capitais_1_*, 2015f2p1_capitais_2_* - 40 pontos
2015f2p1_capitais_3_*, 2015f2p1_capitais_4_*, 2015f2p1_capitais_5_* - 60 pontos

Lendo a linha: um ou mais globs de nome de teste, depois -, depois o peso do grupo.

Regras:

Quem interpreta é o mojtools/score-summary.sh, no juiz.

sols/

As soluções de referência, separadas por categoria. A extensão do arquivo é o que define a linguagem (sol.c é C, sol.cpp é C++, Main.java é Java, e assim por diante).

Diretório O que é Para que serve
good/ soluções corretas obrigatório, pelo menos uma. É o que a calibração roda para descobrir o tempo-limite, e o que a validação exige que seja aceito
wrong/ soluções erradas de propósito conferir que os testes pegam o erro
slow/ soluções lentas de propósito conferir que o tempo-limite realmente reprova a solução ruim
pass/ soluções que devem passar raspando conferir que o tempo-limite não é apertado demais
upcoming/ rascunhos não entram na conferência

Na prática, ponha uma good em cada linguagem que você quer que o aluno possa usar. O tempo-limite é calibrado por linguagem, e uma linguagem sem solução good aceita simplesmente não ganha tempo-limite naquele juiz (o aluno não consegue usá-la).

scripts/ (correção especial)

Opcional. É como o problema customiza a compilação, a execução ou a comparação. O build-and-test.sh procura os arquivos do problema antes dos padrões de mojtools/lang/<lang>/, então qualquer coisa que você ponha aqui vence o comportamento normal.

Os usos mais comuns:

Arquivo Uso Quantos no acervo
scripts/<lang>/compile.sh submissão de função: o aluno entrega só a função, e este script injeta o main que lê a entrada, chama a função e imprime o resultado 201
scripts/compare.sh checker: a resposta não é única (tolerância de ponto flutuante, várias respostas válidas), então o problema traz o próprio comparador 18
scripts/checker.cpp o fonte do checker quando ele é testlib (padrão Polygon/Maratona). Vem junto de um compare.sh de 10 linhas — o stub — instalado por mojtools/testlib/install-checker.sh. O testlib.h NÃO vai no pacote (é vendorado no mojtools) e o binário do checker nunca é commitado (a bridge do mojtools o compila no juiz, sob demanda, e cacheia FORA de scripts/).
scripts/arbitro.{cpp,py,sh} + scripts/c/{prep,run}.sh problema interativo (mojtools/interactive/install-interactive.sh)

O contrato do comparador: recebe $1 = saída do aluno, $2 = saída esperada, $3 = entrada, e responde pelo código de saída (4 = aceito, 5 = aceito com erro de formatação, 6 = resposta errada, qualquer outro = erro de juiz).

Stub, não cópia. O que roda no host do juizscripts/compare.sh, scripts/<lang>/prep.sh, scripts/summary.sh — vai no pacote como um stub que chama o driver canônico do mojtools; só o que entra na jaula (scripts/<lang>/run.sh, compile.sh) é cópia de verdade. É o que permite consertar um bug do driver em um lugar só: quando cada pacote levava a sua cópia da bridge do checker, um bug nela nasceu replicado em 198 pacotes (e derrubava todos os testes de quem o usasse). Um problema pode, claro, trocar o stub pelo seu próprio comparador (é o caso dos 18 do acervo, todos escritos à mão).

Todo .sh em scripts/ precisa do bit de execução (chmod +x) — e o bit viaja (o moj push/clone e o upload preservam). Sem ele o juiz recebe Permission denied ao executar o script: compare.sh/prep.sh rodam no host (fora da jaula) e viram erro de juiz (UE) em todos os testes; run.sh/compile.sh são montados na jaula e viram Compilation Error. O validate-problem.sh reprova o pacote (scripts_exec) antes que isso aconteça.

Modo dos arquivos: 644 (ou 755 com +x), sempre. O servidor normaliza em toda escrita, pelos dois caminhos (moj push e moj upload) — não é o umask do processo que decide. Isso importa porque o tl-checksum inclui o modo de scripts/*: se o mesmo conteúdo entrar com modo diferente conforme o caminho, o juiz vê "pacote mudou" e recalibra à toa.

Mexer em scripts/ obriga a recalibrar (seção 10).

O guia completo (submissão de função, proibir funções da biblioteca, checker com testlib, problema interativo) está em mojtools/docs/correcao-especial.md.

conf

Os limites e ajustes de execução. É um arquivo de shell, lido com source, então nunca interpole nele conteúdo vindo de usuário.

Um conf típico do acervo é curto:

TLMOD[calibrafactor]=1.35
TLMOD[java.drift]=0.02
TLMOD[spim.sum]=1
ULIMITS[-u]=10000
ALLOWPARALLELTEST=y

Todas as chaves que o build-and-test.sh entende:

Chave Default O que faz Uso hoje
TLMOD[calibrafactor] 1.35 multiplicador aplicado ao tempo da solução good para virar o tempo-limite. Subir dá folga ao aluno 453
TLMOD[<lang>.drift] 0 tolerância de variação de tempo naquela linguagem antes de dar TLE 404 (java)
TLMOD[<lang>.sum] 0 soma um valor fixo (em segundos) ao tempo-limite daquela linguagem 405 (spim)
TLMOD[<lang>.mult] 1 multiplica o tempo-limite daquela linguagem 0
ULIMITS[-u] 1024 número máximo de processos. Java e outras runtimes precisam de mais (o acervo usa 10000) 453
ULIMITS[-s] 131072 (128 MB, em KB) tamanho da pilha. Prefira STACKLIMITMB 0
ULIMITS[-f] 256000 tamanho máximo de arquivo que o programa pode escrever 0
ALLOWPARALLELTEST ligado n força os testes a rodarem um de cada vez (necessário quando o problema é sensível a tempo) 453
STACKLIMITMB 128 pilha em MB. Vence o ULIMITS[-s]. A JVM espelha isso no -Xss 0
MEMLIMITMB sem limite por RSS limite de memória em MB, medido pelo pico de RSS. Ligar isso desliga o limite de memória virtual (que penalizaria injustamente JVM e Go). A JVM usa este valor no -Xmx 0
COMPILEMEMLIMIT 2048 memória em MB liberada para a compilação (o kotlinc passa de 600 MB) 0
MAXPARALLELTESTS nº de CPUs teto de testes em paralelo 0
STOPWHEN_WA não para y interrompe no primeiro Wrong Answer 0
STOPWHEN_TLE não para y interrompe no primeiro Time Limit Exceeded 0
STOPWHEN_RE não para y interrompe no primeiro Runtime Error 0
TLERERUN y repete o teste uma vez antes de confirmar um TLE (evita TLE por ruído da máquina) 0
CALIBRATIONTL 5 tempo-limite usado durante a calibração, antes de existir um TL real 0

A coluna "uso hoje" conta em quantos dos 453 conf do acervo a chave aparece. Um zero não quer dizer que a chave não funciona: quer dizer que o default serve para quase todo problema. Mexa só quando tiver um motivo (um problema que exige muita memória, ou uma linguagem que precisa de folga).

PUBLIC=no no conf é legado. Hoje quem decide se o problema é público é o campo public do .moj-meta.json.

author

Texto livre, um autor por linha. É servido ao aluno verbatim (as linhas são juntadas com ", "). Não separe por vírgula esperando que o sistema divida: a vírgula já aparece dentro das linhas ("Fulano, adaptado por Beltrano").

O arquivo é obrigatório: sem ele, a validação reprova.

tags

Os assuntos do problema, uma tag por linha, começando com #, em minúsculas:

#grafos
#bfs
#matriz

As tags alimentam a busca do treino e o sorteio de problemas na criação de contest.

Dificuldade não é uma tag e não existe no pacote. Ela é calculada a partir da taxa de acerto real dos alunos (fácil se pelo menos metade acerta, difícil se menos de 20% acerta, desconhecida se ninguém tentou). Não adianta procurar um campo de dificuldade para preencher.

tl e tl.<host>

Você não escreve estes arquivos. Eles são gerados pela calibração, no juiz. Ver a seção 10.

5. .moj-meta.json: os metadados do problema

É o metadado canônico do problema: o que não cabe em nenhum dos arquivos acima. Fica dentro do pacote e é commitado junto com ele.

Quem escreve é o servidor, sempre (função write_meta, em server/api/v1/lib/problems.sh). Nem o autor nem a CLI editam este arquivo à mão: eles mandam os campos pela API, e o servidor grava.

No moj upload (o pacote sobe num tar), o servidor separa os campos em dois grupos:

Exemplo real (moj-problems/apc/seno/.moj-meta.json):

{
  "public": true,
  "collections": ["problemas-apc"],
  "display_title": "Seno por série de Taylor",
  "owner": "ribas.admin",
  "gitea": { "owner": "ribas.admin", "repo": "apc" },
  "languages": ["c", "cpp", "java", "py", "rs"]
}

Campo a campo:

Campo Tipo O que é
display_title texto O título do problema. É a fonte única. Se o autor não mandar um título e o campo ainda não existir, o servidor deriva um (do % do enunciado, do #+title: do org, do \section{} do tex, ou, em último caso, do nome do diretório). Por isso o campo nunca fica vazio
owner login o dono do problema
public booleano se true, o problema entra no treino livre. Publicar exige que a org permita (seção 7)
collections lista de textos as coleções em que o problema está (seção 8). Pode estar em várias
languages lista de ids as linguagens de submissão permitidas neste problema. Vazio ou ausente = todas as linguagens padrão. É o que permite um problema só-PDDL, por exemplo. O servidor normaliza (minúsculas, py2/py3 viram py, sem repetidos)
public_at epoch quando o problema foi publicado pela primeira vez. Fica lá mesmo se despublicarem depois. Alimenta a estatística de entrada de problemas públicos
migrated_at epoch quando o problema veio de uma migração. Só informativo

Dois campos são legado e não devem ser usados em código novo:

Quem lê o .moj-meta.json: o gen-problem-json.sh (para montar o índice do aluno), o gen-problem-owners.sh (para montar o índice de donos), e a API, ao devolver o problema ao editor e à CLI.

6. .moj-id: o ponteiro local da CLI

Atenção, porque este é o ponto que mais confunde: .moj-id não faz parte do pacote. Repare também que ele não tem extensão .json (não existe nenhum arquivo .moj-id.json no MOJ), mesmo que o conteúdo seja JSON.

Ele é criado pelo moj-cli, na sua máquina, quando você roda moj clone ou moj new. Serve para o clone local lembrar de qual problema ele é, e para carregar os campos editáveis do metadado de ida e volta. O moj push exclui este arquivo do que sobe.

{ "id": "apc#seno", "repo": "apc", "prob": "seno", "title": "Seno por série de Taylor",
  "format": "md", "collections": ["problemas-apc"], "public": true }
Campo O que é
id, repo, prob qual problema este diretório é (<org>#<prob>)
title espelho local do display_title. Editar aqui e dar push muda o título no servidor. O push recusa enviar com o título vazio
format md, org ou tex, o formato do enunciado deste clone
collections, languages, public espelhos locais dos campos do .moj-meta.json, com ida e volta pelo push
scripts_rt marca que este clone sabe fazer ida e volta de scripts/ e tests/score. Sem essa marca, o push não tem permissão de apagar esses arquivos no servidor (protege clones antigos de destruir a correção especial sem querer)

Resumindo a diferença:

.moj-meta.json .moj-id
Onde vive dentro do pacote, no servidor no clone local do autor
Quem escreve o servidor o moj-cli
Vai para o servidor? é o do servidor não, é excluído do envio
Para que serve ser o metadado canônico lembrar de qual problema é o diretório e levar os campos de ida e volta

Os 336 .moj-id que aparecem hoje dentro de moj-problems/ são resíduo de migrações antigas que copiaram diretórios inteiros. O servidor os ignora.

7. ORG: quem pode mexer

Uma org é um grupo de acesso. Ela é a parte antes do # no id do problema (apc#fatorial está na org apc), e é ela que decide quem pode editar o problema.

O registro fica em contests/treino/var/orgs.json, e o código em server/api/v1/lib/orgs.sh.

{
  "monitores": {
    "created_by": "ribas.admin",
    "title": "monitores",
    "members": ["ribas.admin", "ryshim.admin"],
    "admins":  ["ribas.admin"],
    "public_allowed": true,
    "at": 1783051935
  },
  "ribas.admin": {
    "created_by": "ribas.admin", "title": "ribas.admin",
    "members": ["ribas.admin"], "admins": ["ribas.admin"],
    "public_allowed": false, "implicit": true, "at": 1783515797
  }
}
Campo O que é
members quem escreve nos problemas da org. Ser membro de uma org dá acesso de edição a todos os problemas dela
admins quem gere os membros e mexe na trava public_allowed
public_allowed se false (o default), nenhum problema da org pode ficar público
implicit marca a org pessoal de um usuário (ver abaixo)
created_by, title, at quem criou, rótulo de exibição, quando

As regras que valem a pena guardar:

Um problema pode ser movido de org enquanto for rascunho (moj mv, ou pelo editor). Isso muda o id, então o MOJ recusa mover problema que já é público ou que já está em uso em algum contest.

Rotas: /orgs/* em API.md. Pela CLI: moj org list|create|members|public|rm e moj share <org> <login>.

8. COLEÇÃO: como os problemas são agrupados

Uma coleção é um rótulo de agrupamento, e nada mais. problemas-apc, obi2016, obi2016-fase2-senior são coleções.

O registro fica em contests/treino/var/collections.json:

{
  "problemas-apc":         { "owner": "ribas.admin", "created_by": "ribas.admin", "at": 1782519704 },
  "obi2016-fase2-senior":  { "owner": "ribas.admin", "created_by": "ribas.admin", "at": 1782927032 }
}

O que um problema está em quais coleções, isso mora no .moj-meta.json dele, no campo collections (uma lista, porque um problema pode estar em várias coleções ao mesmo tempo, e elas podem ser de orgs diferentes).

Pontos importantes:

Para que servem, na prática:

  1. Navegação no treino: o aluno filtra os problemas por coleção.
  2. Sorteio de problemas na criação de um contest: você pede "5 problemas da coleção X, com a tag grafos, dificuldade média", e o sistema sorteia (de forma reproduzível, a partir de uma semente).

Rotas: /problems/collection* em API.md. Pela CLI: moj collection ls|show|create|add|remove|rename|delete.

9. ORG x COLEÇÃO

Este é o par que mais gera confusão, então vale a tabela. Os dois são ortogonais: um problema tem exatamente uma org e pode ter várias coleções.

ORG COLEÇÃO
Para que serve acesso (quem edita, quem vê) agrupamento (navegar, sortear)
Quantas por problema exatamente uma várias, ou nenhuma
Aparece no id? sim, é o <org> de <org>#<prob> não
Atravessa orgs? não faz sentido sim, uma coleção junta problemas de orgs diferentes
Tem membros? sim (members, admins) não
Controla publicação? sim (public_allowed) não
Onde é registrada contests/treino/var/orgs.json contests/treino/var/collections.json
Onde o problema a declara no próprio id no .moj-meta.json, campo collections

Em uma frase: a org diz quem manda no problema, a coleção diz onde ele aparece.

10. Ciclo de vida de um problema

  rascunho  ──►  validação  ──►  calibração  ──►  público
 (org privada)   (portão)        (nos juízes)    (treino livre)

Rascunho

O problema nasce na sua org (a pessoal, se você não escolher outra). Ele é privado: ninguém além dos membros da org vê que ele existe.

Validação (o portão de qualidade)

Roda mojtools/validate-problem.sh, que grava um relatório em run/validation/<id>.json. Todas as checagens abaixo precisam passar (não existe checagem "opcional" que reprove pela metade):

Checagem O que exige
has_author existe o arquivo author
has_statement existe docs/enunciado.{md,org,tex}
html_builds o pandoc consegue renderizar o enunciado
secao_entrada o enunciado tem ## Entrada
secao_saida o enunciado tem ## Saída
examples_present existe pelo menos um par input/output
tests_paired todo input tem seu output, e vice-versa
has_good_sol existe pelo menos uma solução em sols/good/
good_sol_accepts toda solução good é aceita

Alguns avisos são informativos e não reprovam: LaTeX vazando na prosa do enunciado, exemplo escrito à mão dentro do texto, e checker commitado como binário (padrão antigo, deprecado: mande o fonte scripts/checker.cpp e deixe a bridge compilar).

Sobre o good_sol_accepts: rodar as soluções exige um sandbox de verdade. Na máquina de desenvolvimento o bwrap é um no-op (fbwrap), então a validação adia essa checagem para a calibração, que roda num juiz real. Isso não é bug.

Se a validação passa, ela indexa o problema (chama o gen-problem-json.sh), que gera o JSON que o aluno de fato consome, com o enunciado já em HTML.

Calibração (de onde vem o tempo-limite)

O tempo-limite não é escrito à mão no pacote. Ele é medido.

Um juiz baixa o pacote, roda cada solução de sols/good/, pega o pior tempo de cada linguagem, multiplica pelo TLMOD[calibrafactor] (1.35 por padrão) e reporta o resultado para o servidor. O resultado fica em run/tl/<id>.json, guardado por máquina:

{ "id": "apc#ajude_simplificado", "checksum": "df7f628e84bfc6c3", "updated_at": 1783534737,
  "hosts": {
    "cpu1": { "tl": { "c": ".0335", "cpp": ".0335", "java": ".3710", "py": ".1685",
                      "default": ".0335" }, "at": 1783534737 },
    "cpu2": { "tl": { "…": "…" }, "at": 1783534733 } } }

O tempo-limite servido ao aluno é o maior entre as máquinas, para que a submissão não seja reprovada por ter caído num juiz mais lento. Uma linguagem só ganha tempo-limite se alguma solução good naquela linguagem foi aceita em algum juiz. Sem tempo-limite, a linguagem não fica disponível.

O checksum, e o que dispara recalibração

O campo checksum acima é o que amarra o TL ao pacote. Ele é calculado pelo tl-checksum.sh e cobre só o que pode mudar o tempo de execução:

Entra no checksum Não entra
conf docs/enunciado.*
tests/input/* tags
sols/good/* author
scripts/* (conteúdo e bit de execução) tests/output/*

Se o checksum do pacote deixa de bater com o guardado, o TL é considerado velho e some (o problema passa a aparecer como "precisa recalibrar"). Ou seja: corrigir um typo no enunciado não força recalibração; trocar um teste, uma solução good, o conf ou um script força.

Publicação

Publicar (moj publish, ou o botão no editor) faz o servidor validar e calibrar. O problema só entra no treino livre se os dois passarem. E, antes de tudo isso, a org precisa ter public_allowed: true (seção 7).

11. Perguntas frequentes

Onde eu ponho o título? No campo display_title do .moj-meta.json, e na prática você o edita pelo editor web ou pelo campo title do .moj-id (a CLI). Nunca no texto do enunciado.

Como eu escrevo o tempo-limite? Você não escreve. Ele é medido pela calibração. O que você pode ajustar é a folga, pelo TLMOD[calibrafactor] no conf.

Quero que o problema só aceite Python. Ponha ["py"] no campo languages do .moj-meta.json (pelo editor ou pelo .moj-id).

Meu problema tem várias respostas certas. Você precisa de um checker: scripts/compare.sh. Ver mojtools/docs/correcao-especial.md e o guia de testlib em mojtools/docs/checker-testlib.md.

O aluno vai entregar só uma função, não o programa inteiro. É a submissão de função: scripts/<lang>/compile.sh. Mesmo guia.

Editei o enunciado. Preciso recalibrar? Não. O enunciado não entra no checksum.

Onde fica a dificuldade do problema? Em lugar nenhum do pacote. Ela é calculada da taxa de acerto real dos alunos.

Qual é a diferença entre .moj-meta.json e .moj-id? Ver a tabela no fim da seção 6. Em uma frase: o primeiro é o metadado do servidor, o segundo é um bilhete que a CLI deixa no seu diretório local e que nunca sobe.


Ponteiros