Skip to content

feat(owm): deterministic rich capture — headers, evolve, inertia, pipeline, method, custom phases (1/3) - #45

Open
formicoidea wants to merge 1 commit into
stagingfrom
claude/clever-robinson-b97dcf
Open

feat(owm): deterministic rich capture — headers, evolve, inertia, pipeline, method, custom phases (1/3)#45
formicoidea wants to merge 1 commit into
stagingfrom
claude/clever-robinson-b97dcf

Conversation

@formicoidea

@formicoidea formicoidea commented Aug 1, 2026

Copy link
Copy Markdown
Owner

PR 1/3 of the lint/deterministic split requested by the adversarial review (restructured branch — the lint and vision parts moved to stacked PRs).

Scope (deterministic OWM only)

  • // key: value header capture (unicode keys, French aliases, headers read past an evolution directive) → result.header + PurposeContext + map.context; emit:dsl re-emits // context: (never when empty).
  • evolveevolvesTo (component inertia mirrored onto the target, where the renderer reads it), inline inertia, pipeline→type pipeline + pipelineGeometry (render-valid per validateComponent), (build|buy|outsource)method, 4-label evolution directive→input-shape V3 renderConfig phases.
  • Byte-exact round-trip extended; dataset v2 LOSS_CONTRACT updated in the same change; --count 100 --seed 42 = 100% on the rebased tree.

Review blockers addressed here

  • B1: evolve refused for names embedding a decimal (vendored pattern rebinds the directive to the wrong component) or quote-wrapped names — insight, never silent. Same quote guard on pipeline lines.
  • B2: evolve maturity always carries a decimal point (11.0); empty context never emitted; non-natural evolveType noted.
  • B3: evolution directive ≠ 4 labels no longer crashes the parse; emit restricted to exactly 4 (other arities stay in the JSON path, noted).
  • B4: rebased on staging; LOSS_CONTRACT evolves with the projection (evolvesTo NOT LOST on owm; lossy injection targets only OWM-referenceable names).
  • Majors: accented French aliases really match now (test asserts future, not the default); schema-validity assertion restored; decorator-keyword substring hazard flagged.

Stacked: split/text-lint (2/3) → split/vision-decorators (3/3).

🤖 Generated with Claude Code

@formicoidea formicoidea changed the title docs: sync real-strategy counts (24 real / 61 mocks) feat(render): lint/deterministic split — study-context capture, text:lint:default, text-to-canonical recipe Aug 1, 2026

@formicoidea formicoidea left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recette adversariale — verdict : changements demandés

Trois revues indépendantes (contrat/architecture, LLM/prompts/recettes, tests/régressions), chaque finding reproduit par exécution, puis passe de réfutation avec ré-exécution indépendante des sondes décisives. Aucun bloquant n'a pu être réfuté.

Bloquants

B1 — Corruption silencieuse : evolve attribué au mauvais composant quand un nom contient un nombre.
owm/emit/dsl.mts:137 + owm/parse/dsl.mts:179-187. Sonde : HTTP (0.2) + HTTP 1.1 Gateway (0.4, evolvesTo 0.8) → emit écrit evolve HTTP 1.1 Gateway 0.8 ; au parse, le vendored découpe sur la première décimale → HTTP hérite d'un evolvesTo scalar 1 (le « 1.1 » du nom, clampé), le Gateway perd le sien, warnings ne contient rien d'utile. Donnée fausse et indétectable — rédhibitoire pour un socle de dataset.

B2 — Invariant round-trip byte-exact violé (ast-schema § 2.3.1 : bug bloquant).

  • evolvesTo scalar 0 ou 1 : emit écrit evolve X 1 (round2 sans point décimal), la regex du parseur (/\s[0-9]?\.[0-9]+/) ne matche pas → « dropped: not a declared component » → emit(parse(emit(m))) ≠ emit(m). owm-dsl.mts:218-225 + parse/dsl.mts:281-283.
  • context: '' (légal au schéma) : // context: émis, HEADER_COMMENT exige (.+) → perdu au retour, losses: []. owm-dsl.mts:128-134 + emit/dsl.mts:87-92.
  • evolveTypenatural : perdu sans note de perte, réinjecté natural. emit/dsl.mts:129-141.

B3 — Crash map: null sur une nomenclature d'axe ≠ 4 phases.
owm-dsl.mts:257-262 (signature relâchée en readonly string[]) + parse/dsl.mts:147-153 (.trim() sur undefined). Sonde : renderConfig à 2 labels — forme V3 valide, explicitement autorisée par le prompt du lint et utilisée par la propre fixture de text/lint/default.test.mts — → parsed: false, insight Cannot read properties of undefined (reading 'trim'), carte entièrement perdue. À 5 labels : troncature silencieuse à 4.

B4 — Le contrat de perte du dataset v2 casse au merge : 82 % au lieu de 100 %.
La branche est 2 commits derrière staging et ne voit pas e835393 (harnais v2). scripts/build-dataset.mts:442,601 (staging) exige l'insight evolvesTo targets are not projected que cette PR supprime en projetant evolve. Sur l'arbre mergé : --count 100 --seed 4282,0 % (18 échecs, signature unique) et build-dataset.test.mts 19/21. La table LOSS_CONTRACT doit évoluer dans le même changement que la projection.

B5 — La recette text-to-canonical échoue sur son chemin par défaut, et le chemin structured du lint ne peut pas refuser.

  • recipes/render/map/text-to-canonical.recipe.json:15-19 : avec target: 'json' (défaut), le lint sort dsl: null ; l'étape owm:parse:dsl reçoit un input invalide → $.output.result = { map: null, parsed: false } + insight mensonger « upstream step not yet promoted », alors que la carte est dans $.linted.result.map.
  • text/lint/default.mts:205-224 : le chemin structuré passe outputFormat: json_schema — le modèle est contraint de produire une carte, il ne peut ni émettre NOT_A_VALUE_CHAIN ni refuser. {text:"écris-moi un poème"} → carte inventée, linted: true. L'invariant annoncé en tête de fichier (« the deterministic layer stays the only producer ») est faux sur ce chemin.

Majeurs

  • Décorateurs projetés mais morts au rendu : pipelineGeometry posé sans type: 'pipeline' (invalide au validateMap du renderer, bande jamais dessinée) — parse/dsl.mts:244,267-276 et png.mts:243-250 ; component.inertia jamais lu par le renderer (la barre vient de evolvesTo[].inertia) ; method sans renderConfig.style.decorators → marqueur jamais dessiné.
  • Couleur → noir : les prompts demandent un nom CSS (red), resolveColor ne connaît que hex + palette Tailwind → #000000 sans warning. prompts/render-image-parse-png.system.md:89-91, render-text-lint.system.md:47.
  • Décorateurs inventés par détection en sous-chaîne : component inertia dampener re-parse avec inertia: true et re-émet … inertia ; (build tools) Xmethod: build. emit/dsl.mts:160-176 + vendored setInertia/methodDecorator.
  • Alias français accentués = code mort : parseHeaderComments (owm-dsl.mts:129) n'accepte pas les accents (\w), donc temporalité/granularité/portée/périmètre ne matchent jamais ; le test passe en assertant la valeur par défaut. parse/dsl.mts:52-61, parse/dsl.test.mts:190-204.
  • Assertion supprimée : assert.ok(WardleyMapSchema.safeParse(map).success) retirée de owm/parse/dsl.test.mts au commit qui élargit la sortie du parseur. À restaurer.
  • // context: perdu si evolution précède les en-têtes — ordre que le prompt du lint encourage. owm-dsl.mts:153.
  • Hors catalogue AST : le sous-domaine text et la commande lint n'existent pas dans la spec normative (ast-schema.md:242-257, domaine déclaré exhaustif) ; la recette invente render:map comme namespace (clé de feature-flag PostHog incluse).
  • JSON Schema envoyé au provider non contraignant : z.toJSONSchema(WardleyMapSchema, {unrepresentable:'any'})scalar: {} (tout accepté), evolveType requis en contradiction avec le prompt ; échec avalé par catch {} + dégradation. default.mts:60-68,199.
  • Injection via le document linté : source interpolée brute, parseDelimitedBlock prend le premier bloc LINT_START (un bloc injecté gagne), payload.includes('NOT_A_VALUE_CHAIN') matche n'importe où. default.mts:255-268.
  • docs/functional/tools-reference.md:259 : compteurs faux (70/24) non corrigés par le commit de sync.

À porter au crédit

Aucune fixture trafiquée ; compteurs de boot exacts (25 réelles / 86) ; règle prompts system/user respectée (0 {{ dans les system) ; tests sans appel LLM réel ; typecheck vert.

Recommandation

Scinder en trois : (1) l'élargissement OWM déterministe, mergeable après correction des round-trips B1-B3 + mise à jour du LOSS_CONTRACT dans le même changement (rebase sur staging obligatoire) ; (2) le linter + recette, après re-conception du chemin par défaut et de la capacité de refus ; (3) les décorateurs vision, après que la projection produise des cartes valides au rendu (validateMap en garde de sortie serait le bon oracle).

🤖 Generated with Claude Code

…eline, method, custom phases

Review-hardened deterministic enlargement of the OWM dialect (PR 1/3 of
the lint/deterministic split):

- parse:dsl captures `// key: value` headers (unicode keys, French
  aliases folded onto canonical English ones, headers still read after an
  evolution directive) into result.header + PurposeContext + map.context;
  emit:dsl re-emits `// context:` (never when empty — the header grammar
  requires a value).
- parse:dsl projects evolve->evolvesTo (component inertia mirrored onto
  the target, where the renderer reads it), inline inertia, pipeline->
  type 'pipeline' + pipelineGeometry (validateComponent refuses the
  geometry elsewhere), (build|buy|outsource)->method, and a 4-label
  evolution directive->input-shape V3 renderConfig phases.
- emit:dsl is the exact inverse, with grammar-hazard guards: evolve
  refused for names embedding a decimal (vendored pattern rebinds the
  directive) or quote-wrapped names; maturities always carry a decimal
  point; decorator-keyword substrings flagged; non-4 phase arities and
  non-natural evolveTypes dropped with notes. Byte-exact round-trip holds
  on the emitted dialect.
- dataset v2 LOSS_CONTRACT updated in the same change: evolvesTo is NOT
  LOST on owm; the lossy injection only targets OWM-referenceable names.
  --count 100 --seed 42 = 100%.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@formicoidea
formicoidea force-pushed the claude/clever-robinson-b97dcf branch from 3569ed8 to b5006a4 Compare August 1, 2026 20:23
@formicoidea formicoidea changed the title feat(render): lint/deterministic split — study-context capture, text:lint:default, text-to-canonical recipe feat(owm): deterministic rich capture — headers, evolve, inertia, pipeline, method, custom phases (1/3) Aug 1, 2026
@formicoidea

Copy link
Copy Markdown
Owner Author

Revue traitée — tous les bloquants et majeurs adressés, et la recommandation de scission appliquée :

Détail des sondes de la revue rejouées en tests unitaires : HTTP 1.1 Gateway (B1), maturité 0/1 (B2), directive à 2 labels (B3), inertia dampener (sous-chaîne), temporalité: future (alias accentués non-vacueux), refus structuré sur prose libre, injection LINT_START.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant