Un rapport affiche quatre lignes alors que son fichier de configuration indique limit: 6, et on vous demande pourquoi. Vous découvrez ce dépôt. Il contient une CLI, un chargeur de configuration, quelques services et un dossier de tests. Tout lire finirait par vous donner la réponse. Suivre la valeur qui détermine le nombre de lignes est bien plus rapide.
Préciser la question
« Comprendre le module de rapports » n’a pas de limite claire. Une question précise, si :
La configuration indique
limit: 6et l’environnement contientREPORT_LIMIT=4. Le rapport affiche quatre lignes. Quelle valeur a pris le dessus, et que se passe-t-il siREPORT_LIMITest une chaîne vide ?
Notez la commande exécutée, le répertoire et le commit. Vérifiez aussi que l’entrée contient plus de quatre enregistrements. Si la source n’a que quatre lignes, en obtenir quatre ne prouve rien sur la limite.
Trouver un premier fichier à partir de votre indice
Le premier fichier utile peut être un lanceur, un formateur ou un test, sans être la fonction qui choisit la limite. Partez de l’indice que vous pouvez reproduire pour atteindre cette fonction, et notez les liens réellement vérifiés.
Téléchargez le laboratoire sur le point d’entrée du rapport, décompressez-le et entrez dans report-entry-lab. Ce petit projet a été créé pour ce tutoriel. Il ajoute une vraie commande, une table de dispatch et des chargeurs de fixtures locales aux règles de priorité présentées ci-dessous. Il faut Node.js 22 ou ultérieur, npm et ripgrep (rg), sans installation de dépendances ni compte de modèle. Les commandes shell fonctionnent sous macOS et Linux.
REPORT_LIMIT=4 npm run --silent report
Report rows: 4
Aster
Birch
Clover
Dahlia
La fixture de configuration contient limit: 6 ; celle des données a huit lignes. La première ligne de sortie est un en-tête, suivi de quatre lignes de données. L’écart est donc réel et ne vient pas d’un fichier d’entrée trop court. Le programme lit uniquement les fixtures locales incluses et écrit dans le terminal ; ses tests lancent des processus Node locaux, sans requête réseau ni écriture de fichier.
| Votre indice | Point de départ | Ce qui reste à vérifier |
|---|---|---|
| Une commande reproduit le comportement | Le script du paquet ou l’exécutable appelé | Quel argument sélectionne quel gestionnaire |
| Un texte de sortie ou d’erreur distinctif | Le code qui le construit | Si le résultat est un producteur, une fixture ou une assertion, et qui appelle le producteur |
| Un test identifié | Son import et l’appel dans le test | S’il lance la vraie commande ou fournit des dépendances de remplacement |
| Une clé de configuration ou une variable d’environnement | La lecture et la conversion de cette valeur | Quel appelant y mène et quel chargeur fournit la configuration |
Lire le même laboratoire dans Yenpo
Utilisez le dossier report-entry-lab téléchargé pour répondre à « Quel point d’entrée a produit ces quatre lignes ? ». La lecture doit aboutir à une courte note indiquant la commande de lancement, le gestionnaire choisi, les fichiers d’entrée et l’appel de sortie.
- Ouvrez le dossier extrait
report-entry-labdans Yenpo en choisissant la racine contenantpackage.json. Utilisez Command-P (Aller au fichier…) pour ouvrirpackage.json, puissrc/cli.mjsetsrc/commands.mjs. Vérifiez le script de lancement et le gestionnaire enregistré pourreport. - Dans la barre latérale, utilisez Rechercher dans tous les fichiers pour chercher
Report rows:en désactivant Regex. Lisezsrc/format-report.mjsavec les résultats dans les tests : l’un construit le texte, les autres vérifient un résultat attendu. Suivez l’import et l’appel du formateur danssrc/report.mjsavant de le rattacher à cette commande. - Gardez
src/report.mjs,src/limits.mjset le test concerné ouverts dans des onglets. Notez le fichier et la ligne qui étayent chaque étape, puis utilisez les vérifications Terminal ci-dessous pour distinguer un test direct de fonction d’une exécution par la vraie CLI.
La navigation dans les fichiers et la recherche textuelle ne nécessitent ni connexion à un modèle ni serveur de langage JavaScript. Pour essayer, téléchargez Yenpo pour Mac et ouvrez le même dossier extrait ; l’aide à la lecture du code explique les deux outils de recherche. Le ZIP contient des sources, sans historique Git : cet exercice porte donc sur les fichiers, pas sur une comparaison de commits figée.
Vous avez la commande du terminal
Inspectez le script avant de déduire le point d’entrée du nom d’un dossier :
npm pkg get scripts.report
rg -n 'process.argv|commands\[command\]' src/cli.mjs
rg -n 'report:|runReport|report-config.json' src/commands.mjs
La première commande affiche "node src/cli.mjs report". Dans cli.mjs, process.argv.slice(2) fait de report le nom de commande ; les arguments restants vont au gestionnaire choisi. commands[command] est une recherche dans une table : trouver le lanceur ne suffit donc pas. Ouvrez commands.mjs : sa propriété report appelle runReport avec des chargeurs pour report-config.json et rows.json. La propriété voisine help renvoie plutôt le texte d’aide.
Effectuez maintenant une modification contrôlée via le même lanceur :
REPORT_LIMIT=4 npm run --silent report -- --limit 2
Cela affiche Report rows: 2, puis Aster et Birch. npm transmet au script les arguments placés après le séparateur à deux tirets. Lisez la recherche dans la table et le gestionnaire enregistré pour établir le chemin ; la sortie modifiée vérifie ensuite que cette commande atteint le comportement de limitation. La sortie seule ne permettrait pas d’identifier tous les appels intermédiaires.
Vous n’avez qu’un texte de sortie
rg -n -F 'Report rows:' src tests
rg -n 'renderReport|runReport' src
La première recherche trouve format-report.mjs et des assertions de tests. Le formateur construit l’en-tête ; les tests comparent le texte attendu. Aucun de ces résultats n’est automatiquement un point d’entrée de commande. Dans report.mjs, vérifiez l’import de renderReport et l’appel qui lui transmet les noms choisis. Remontez ensuite de runReport à l’enregistrement report dans commands.mjs, puis du gestionnaire choisi à l’écriture sur stdout dans cli.mjs.
Vous obtenez ainsi un parcours à vérifier avec la commande ci-dessus. Si la sortie réelle est assemblée en plusieurs morceaux, cherchez un fragment stable puis examinez la construction de l’expression autour. Si un formateur partagé a plusieurs appelants, gardez-les comme candidats jusqu’à ce que les arguments de lancement ou un test ciblé en désignent un ; ne les fusionnez pas en un seul chemin d’exécution.
Vous avez un nom de test
rg -n -F 'environment wins over config' tests
node --test --test-name-pattern='environment wins over config' tests/report.test.mjs
Le test trouvé importe directement runReport et fournit son propre environnement ainsi que ses chargeurs de configuration et de lignes. Il confirme que quatre l’emporte sur six dans cette fonction, mais ne lance jamais cli.mjs et ne lit aucun fichier de configuration. Il ne dit pas quel fichier une vraie commande charge.
Suivez l’import pour trouver le comportement, puis inspectez la liaison réelle commands.report. Ce test distinct franchit la frontière manquante :
node --test --test-name-pattern='CLI uses REPORT_LIMIT' tests/cli.test.mjs
Il lance la vraie CLI dans un processus enfant avec REPORT_LIMIT=4 et vérifie son code de sortie et stdout. Les deux tests sélectionnés passent. Conservez cette distinction dans vos notes : l’un choisit ses dépendances, l’autre exerce le lancement et les adaptateurs de fichiers. La réussite d’un test direct de fonction ne remplace pas le second.
Vous avez le nom de la configuration
rg -n -F 'REPORT_LIMIT' src tests
rg -n 'resolveLimit|loadConfig|report-config.json' src
La lecture de la valeur se trouve dans limits.mjs ; les autres résultats préparent des entrées de test. Suivez l’appel de resolveLimit dans report.mjs, puis vérifiez la fonction loadConfig fournie par commands.report. Son new URL(..., import.meta.url) choisit la fixture incluse relativement au module. Le nom du fichier à lui seul ne prouve pas que ce gestionnaire l’utilise.
Vous avez maintenant le point de départ nécessaire pour suivre la valeur ci-dessous. Laissez de côté help et les tests sans rapport : vous avez vérifié la commande, le gestionnaire choisi, les vrais fichiers d’entrée et le point de sortie. Si la commande réelle utilise un autre checkout, un wrapper ou une autre source d’environnement, résolvez cet écart avant d’élargir la recherche. Sinon, la prochaine question porte sur la priorité de la valeur, pas sur le reste du dépôt.
Suivre le gestionnaire choisi
Le fichier report.mjs du laboratoire analyse les arguments, charge la configuration, choisit une limite, charge les lignes, puis appelle renderReport pour ajouter l’en-tête. La CLI écrit la chaîne renvoyée. L’exemple autonome antérieur ci-dessous ne conserve que les lignes de données, pour examiner la valeur sans le raccordement de la commande. Les chargeurs sont des arguments dans les deux versions, ce qui permet aux tests d’observer l’ordre sans lire de fichiers :
export async function runReport({ args, env, loadConfig, loadRows }) {
const { values } = parseArgs({
args,
options: { limit: { type: 'string' } },
strict: true,
});
const config = await loadConfig();
const limit = resolveLimit(values, env, config);
const rows = await loadRows();
return rows
.slice(0, limit)
.map((row) => row.name)
.join('\n');
}
Avant même d’ouvrir une fonction auxiliaire, celle-ci donne déjà l’ordre : analyser les arguments, charger la configuration, choisir la limite, charger les lignes, afficher. Elle révèle aussi un détail facile à manquer : resolveLimit() ne s’exécute que si loadConfig() réussit. Cela comptera plus loin.
Dans une vraie base de code, suivez les imports. Une fonction nommée loadConfig peut lire un fichier JSON, en fusionner plusieurs ou appeler un service distant. Son nom ne permet pas de trancher.
Comment la limite est choisie
export function resolveLimit(cli, env, config) {
const raw = cli.limit ?? env.REPORT_LIMIT ?? config.limit ?? 10;
const limit = Number(raw);
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100) {
throw new Error('limit must be an integer from 1 to 100');
}
return limit;
}
Trois opérations ont lieu : choisir une source, convertir en nombre, vérifier la plage. Séparez-les dans vos notes. Écrire seulement « l’environnement prime sur la configuration » peut faire croire qu’une valeur d’environnement invalide déclenche un repli vers le fichier. Ce code ne le fait jamais.
CLI --limit |
REPORT_LIMIT |
Configuration limit |
Résultat |
|---|---|---|---|
2 |
4 |
6 |
2, depuis la ligne de commande |
| absent | 4 |
6 |
4, depuis l’environnement |
| absent | absent | 6 |
6, depuis le fichier |
| absent | absent | absent | valeur par défaut 10 |
| absent | chaîne vide | 6 |
erreur de validation |
0 |
4 |
6 |
erreur de validation |
?? ignore seulement null et undefined. Une chaîne vide reste une valeur, donc REPORT_LIMIT='' l’emporte. Number('') vaut 0, la vérification de plage lève une erreur et la fonction ne consulte jamais la valeur du fichier de configuration.
Remplacer ?? par || laisserait passer les chaînes vides, mais traiterait aussi 0 comme « non défini ». Cela change les règles ; ce n’est pas un simple nettoyage. Décidez d’abord du comportement voulu : une mauvaise valeur définie volontairement doit-elle produire une erreur ou déclencher discrètement un repli ?
Suivre la valeur jusqu’à son utilisation
Une limite correcte ne garantit pas une sortie correcte. Suivez limit jusqu’à rows.slice(0, limit), puis regardez d’où vient rows.
Ici, loadRows() renvoie toutes les lignes et le gestionnaire garde les premières. La source n’effectue ni tri, ni filtre, ni pagination. La limite plafonne donc les lignes affichées, pas la quantité de données lues ou conservées en mémoire.
Cela compte si le problème signalé est différent. Si l’on dit « le rapport épuise la mémoire même avec --limit 2 », les règles de priorité ne sont pas le bon endroit. Il faut examiner loadRows et vérifier si la limite doit parvenir jusqu’à la source de données. Même gestionnaire, autre question, autre fichier à lire ensuite.
Provoquer une panne volontairement
Essayez maintenant un fichier de configuration invalide avec --limit 2. La ligne de commande a la priorité la plus haute : la commande devrait donc fonctionner quand même, non ?
Non. La configuration est chargée avant le choix de la limite ; si loadConfig() lève une erreur, rien ne s’exécute ensuite. La priorité détermine la valeur utilisée. Elle ne dit rien sur ce qui doit réussir avant ce choix.
Le cas inverse mérite aussi un test : la configuration se charge, mais la limite choisie est invalide. Les lignes ne doivent alors jamais être lues. Comptez les lectures pour le vérifier :
let reads = 0;
await assert.rejects(
runReport({
args: [],
env: { REPORT_LIMIT: '' },
loadConfig: async () => ({ limit: 6 }),
loadRows: async () => {
reads++;
return [];
},
}),
/integer/,
);
assert.equal(reads, 0);
Si vous vérifiiez seulement qu’une erreur est levée, une version qui lit toutes les lignes avant de rejeter la limite passerait aussi. C’est reads === 0 qui fixe l’ordre.
Exécuter l’exemple
Téléchargez configuration-flow.mjs et exécutez-le avec Node.js 22 ou ultérieur. Il n’a aucune dépendance :
node --test configuration-flow.mjs
Ce téléchargement original en un seul fichier reste disponible. Ses six tests couvrent l’ordre de priorité, les valeurs vides et invalides, la sortie affichée, l’absence de lecture des lignes après une entrée incorrecte et la configuration invalide. Ils exercent les fonctions isolément ; dans votre projet, il faut encore vérifier comment la vraie CLI charge son environnement et affiche les erreurs.
Le nouveau laboratoire couvre aussi le raccordement de la commande. Depuis son dossier, exécutez :
node --test tests/*.test.mjs
REPORT_LIMIT='' npm run --silent report
Les neuf tests passent. La deuxième commande se termine volontairement avec le code 1, écrit limit must be an integer from 1 to 100 sur stderr et ne produit rien sur stdout. Le test unitaire compte aussi les lectures de lignes : le cas de la valeur vide vérifie donc l’ordre décrit plus haut. Le ZIP contient un manifeste SHA-256 ; l’archive et les tests extraits ont été vérifiés.
Noter ce que vous avez trouvé
Une courte note suffit, et se relira bien plus vite que le code la prochaine fois :
runReport
parseArgs → loadConfig → resolveLimit → loadRows → slice → output
limit: command line > environment > config > 10
invalid selected value: error; no fallback; rows are not loaded
config read failure: stops even when --limit is present
scope: limit bounds output, not the row loader's work
Dans une vraie base de code, ajoutez le fichier et la ligne à chaque étape et listez les points non vérifiés : quel fichier lit loadConfig, si un processus parent définit REPORT_LIMIT, comment la CLI présente les erreurs. Dès que vous pouvez expliquer les quatre lignes et nommer ces questions ouvertes, vous pouvez vous arrêter. Il n’est pas encore nécessaire de comprendre le reste du projet.
Faire vérifier la transmission par une autre personne
Une note de lecture est plus utile si quelqu’un peut la reproduire sans l’historique de votre conversation. Essayez le ZIP de transmission poster-desk et sa courte fiche de transmission. Ce petit projet hors ligne et ses affirmations ont été créés à des fins pédagogiques ; il ne s’agit ni d’une application réellement générée par IA ni d’une vraie transmission.
La tâche de réception consiste à vérifier quatre promesses sur un instantané fixe des sources : les cartes locales sont lisibles par un nouveau processus, les répétitions séquentielles identiques réutilisent un enregistrement, les reçus ne sont que des aperçus de fixtures et la conservation lors du remplacement d’un déploiement reste inconnue. « Implémenté » couvre les conditions testées ; les répétitions séquentielles ne prouvent pas la sûreté en concurrence, le mock n’envoie rien et le paquet ne fournit aucune preuve sur le stockage du déploiement.
Suivez la fiche, copiez RECEIVER.md hors du paquet extrait, puis renseignez cette copie avec vos commandes, résultats, emplacements dans le code et questions ouvertes. Gardez le modèle livré intact, puis vérifiez à nouveau le paquet original.
SHA-256 du ZIP
c39d19b210c05f4667cd74db4934459a079408d14c5e7678c24cd087e1df5185
Dans Yenpo, Aller au fichier… et la recherche dans le projet permettent de garder le gestionnaire, le résolveur et les tests ouverts côte à côte. Avec le lecteur de code IA, posez une question sur une seule valeur : « Suis REPORT_LIMIT depuis sa lecture jusqu’à son utilisation, avec les références de lignes. » Vous obtiendrez un chemin vérifiable étape par étape plutôt qu’un autre résumé du projet.
Choisissez la prochaine tâche de lecture selon les éléments dont vous disposez :
- Une réponse serveur surprenante : suivez une requête HTTP de sa route jusqu’à la requête de données.
- Des tests verts après un correctif IA : vérifiez si les assertions modifiées protègent encore le comportement initial.
- Une vérification apparemment redondante : utilisez l’historique Git et les tests de régression pour comprendre sa raison d’être.
- Une fonction va changer : vérifiez quels consommateurs cassent, lesquels gardent leurs résultats et lesquels restent à tester.
- Du code non testé doit être remanié : observez et enregistrez son comportement actuel avant de changer sa structure.