feat(renderable): add decodeDocument API for live documentation#44
feat(renderable): add decodeDocument API for live documentation#44darko-mijic merged 2 commits intomainfrom
Conversation
Add decodeDocument() and decodeDocumentSafe() — the codec decode step without markdown rendering. Interactive consumers (Studio desktop, MCP clients) use these to receive typed RenderableDocument blocks for native UI rendering instead of parsing static markdown. Also fix prepublishOnly to guarantee clean builds: pnpm clean runs first (removing stale tsbuildinfo), and a new verify:exports script checks all 34 declared export paths exist in dist/ before publish proceeds. New public API from @libar-dev/architect/renderable: - decodeDocument(type, dataset, options?) → RenderableDocument - decodeDocumentSafe(type, dataset, options?) → Result<RenderableDocument> - type CodecOptions (codec-specific option union) - type GenerationError (structured decode/render error)
📝 WalkthroughWalkthroughAdded two new decoding entry points in Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/renderable/generate.ts`:
- Around line 398-406: The JSDoc example passes an invalid DocumentType
("design-review") which is not in DOCUMENT_TYPES and will break consumers;
update the example to use a valid type (e.g., "architecture" or "patterns") for
the call to decodeDocumentSafe, removing the invalid per-document mapping and
calling decodeDocumentSafe("architecture", patternGraph) (referencing the
decodeDocumentSafe function and DOCUMENT_TYPES/RenderableDocument types in the
file) so the example compiles and returns a proper RenderableDocument.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 78be219c-3df5-47f2-b71a-df147a8889db
⛔ Files ignored due to path filters (2)
package.jsonis excluded by none and included by nonescripts/verify-exports.mjsis excluded by none and included by none
📒 Files selected for processing (2)
src/renderable/generate.tssrc/renderable/index.ts
Multi-agent review findings: - Fix JSDoc example using invalid "design-review" DocumentType - Add path containment guard in verify-exports.mjs (prevents traversal) - Handle pkg.bin string shorthand (was silently skipped) - Guard nested conditional exports (skip with warning vs misleading error) - Include available types in "no codec registered" error messages
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/renderable/generate.ts (1)
393-393:⚠️ Potential issue | 🟡 MinorJSDoc still references an invalid
DocumentType(design-review).The options param example text mentions
design-review, which is not present inDOCUMENT_TYPES. Please replace with an existing type (e.g.,architectureorpr-changes) to avoid misleading consumers.📝 Suggested doc fix
- * `@param` options - Optional codec-specific options (e.g., patternName for design-review) + * `@param` options - Optional codec-specific options (e.g., changedFiles for pr-changes)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderable/generate.ts` at line 393, JSDoc for the options parameter in src/renderable/generate.ts incorrectly references a non-existent DocumentType "design-review"; update the docstring to mention a valid DOCUMENT_TYPES value (for example "architecture" or "pr-changes") and ensure the `@param` description for options accurately reflects supported codec-specific option names (reference DOCUMENT_TYPES and the options param in the generate function to confirm available types).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/renderable/generate.ts`:
- Around line 462-486: The decodeDocument function currently throws on missing
codec and returns decoded value directly; change it to follow the project's
Result-monad convention by returning Result.ok(decoded) or Result.error(err)
instead of throwing: use resolveCodec and if undefined return Result.error with
a message that includes CodecRegistry.getRegisteredTypes(); wrap the
codec.decode(dataset) call so its success returns Result.ok and any runtime
error returns Result.error; preserve context enrichment behavior around
setCodecContextEnrichment and clearCodecContextEnrichment but ensure cleanup
still runs and that errors are captured and converted to Result.error rather
than thrown (refer to decodeDocument, resolveCodec,
CodecRegistry.getRegisteredTypes, setCodecContextEnrichment,
clearCodecContextEnrichment, and codec.decode for locations to change).
---
Duplicate comments:
In `@src/renderable/generate.ts`:
- Line 393: JSDoc for the options parameter in src/renderable/generate.ts
incorrectly references a non-existent DocumentType "design-review"; update the
docstring to mention a valid DOCUMENT_TYPES value (for example "architecture" or
"pr-changes") and ensure the `@param` description for options accurately reflects
supported codec-specific option names (reference DOCUMENT_TYPES and the options
param in the generate function to confirm available types).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: e9747e70-dcbd-4ba4-8794-36e203c95530
⛔ Files ignored due to path filters (1)
scripts/verify-exports.mjsis excluded by none and included by none
📒 Files selected for processing (1)
src/renderable/generate.ts
| export function decodeDocument( | ||
| type: DocumentType, | ||
| dataset: PatternGraph, | ||
| options?: CodecOptions, | ||
| contextEnrichment?: CodecContextEnrichment | ||
| ): RenderableDocument { | ||
| const codec = resolveCodec(type, options); | ||
| if (codec === undefined) { | ||
| throw new Error( | ||
| `No codec registered for document type: "${type}". Available types: ${CodecRegistry.getRegisteredTypes().join(', ')}` | ||
| ); | ||
| } | ||
|
|
||
| if (contextEnrichment) { | ||
| setCodecContextEnrichment(contextEnrichment); | ||
| } | ||
|
|
||
| try { | ||
| return codec.decode(dataset) as RenderableDocument; | ||
| } finally { | ||
| if (contextEnrichment) { | ||
| clearCodecContextEnrichment(); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
New/updated throw paths conflict with the repository’s Result-based error-handling rule.
decodeDocument() is introduced as exception-based, and the touched generateDocument() path still throws. This diverges from the project’s required Result-monad convention.
♻️ Suggested direction
-export function decodeDocument(
+export function decodeDocument(
type: DocumentType,
dataset: PatternGraph,
options?: CodecOptions,
contextEnrichment?: CodecContextEnrichment
-): RenderableDocument {
- const codec = resolveCodec(type, options);
- if (codec === undefined) {
- throw new Error(
- `No codec registered for document type: "${type}". Available types: ${CodecRegistry.getRegisteredTypes().join(', ')}`
- );
- }
-
- if (contextEnrichment) {
- setCodecContextEnrichment(contextEnrichment);
- }
-
- try {
- return codec.decode(dataset) as RenderableDocument;
- } finally {
- if (contextEnrichment) {
- clearCodecContextEnrichment();
- }
- }
+): Result<RenderableDocument, GenerationError> {
+ return decodeDocumentSafe(type, dataset, options, contextEnrichment);
}As per coding guidelines, Use Result monad for explicit error handling: functions should return Result.ok(value) or Result.error(err) instead of throwing exceptions.
Also applies to: 605-607
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/renderable/generate.ts` around lines 462 - 486, The decodeDocument
function currently throws on missing codec and returns decoded value directly;
change it to follow the project's Result-monad convention by returning
Result.ok(decoded) or Result.error(err) instead of throwing: use resolveCodec
and if undefined return Result.error with a message that includes
CodecRegistry.getRegisteredTypes(); wrap the codec.decode(dataset) call so its
success returns Result.ok and any runtime error returns Result.error; preserve
context enrichment behavior around setCodecContextEnrichment and
clearCodecContextEnrichment but ensure cleanup still runs and that errors are
captured and converted to Result.error rather than thrown (refer to
decodeDocument, resolveCodec, CodecRegistry.getRegisteredTypes,
setCodecContextEnrichment, clearCodecContextEnrichment, and codec.decode for
locations to change).
There was a problem hiding this comment.
Not applicable — the dual-API pattern is deliberate and pre-existing.
This codebase provides paired variants throughout:
generateDocumentSafe()→Result<OutputFile[], GenerationError>generateDocument()→ throws, returnsOutputFile[]
The new decode functions mirror this exact convention:
decodeDocumentSafe()→Result<RenderableDocument, GenerationError>decodeDocument()→ throws, returnsRenderableDocument
The Safe suffix is the naming contract that distinguishes Result-based from throwing variants. The Result monad itself includes unwrap() (converts Result back to throwing), confirming both patterns are valid.
Making decodeDocument return Result would make it identical to decodeDocumentSafe, eliminating consumer choice and breaking the established Foo/FooSafe API symmetry that shipped in PR #40.
There was a problem hiding this comment.
@darko-mijic, you're absolutely right — I missed the established Foo / FooSafe dual-API convention. Converting decodeDocument() to return Result would collapse it into decodeDocumentSafe(), eliminating the throwing variant that some consumers prefer. My suggestion was incorrect; the symmetry is correct as-is.
ʕ •ᴥ•ʔ (learning noted for future reviews)
✏️ Learnings added
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 44
File: src/renderable/generate.ts:462-486
Timestamp: 2026-04-04T09:22:47.625Z
Learning: In libar-dev/architect, the codebase deliberately provides paired API variants throughout `src/renderable/generate.ts`:
- The throwing variant (e.g., `generateDocument()`, `decodeDocument()`) returns the value directly and throws on error.
- The `Safe` suffixed variant (e.g., `generateDocumentSafe()`, `decodeDocumentSafe()`) returns `Result<T, GenerationError>` for explicit error handling.
This `Foo` / `FooSafe` naming contract is intentional and must not be collapsed into a single Result-returning function. Do NOT flag the throwing variants as violating the Result monad convention — both patterns are valid by design.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
🧠 Learnings used
Learnt from: CR
Repo: libar-dev/architect PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T02:23:21.646Z
Learning: Applies to src/{generators,renderable}/**/*.ts : Use Codec-Based Rendering: generators in `src/generators/` must use codecs to transform data to markdown via Zod codecs
Learnt from: CR
Repo: libar-dev/architect PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T02:23:21.646Z
Learning: Applies to src/renderable/codecs/**/*.ts : TypeScript files that implement codecs must use Zod schemas for transformation. Codecs transform data structures to markdown using schema definitions.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/codecs/validation-rules.ts:232-235
Timestamp: 2026-04-01T14:42:40.489Z
Learning: In `src/renderable/codecs/validation-rules.ts`, `ValidationRulesCodec` intentionally ignores the `CodecContext` (passed as `_context`) because it generates documentation for static, built-in `RULE_DEFINITIONS` (Process Guard validation rules), not for user-extracted source data. The TODO comment in the file explicitly documents this design decision.
Learnt from: CR
Repo: libar-dev/architect PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-04-02T02:23:21.646Z
Learning: Applies to **/*.{ts,tsx} : Use Result monad for explicit error handling: functions should return `Result.ok(value)` or `Result.error(err)` instead of throwing exceptions
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/codecs/validation-rules.ts:232-235
Timestamp: 2026-04-01T14:42:29.625Z
Learning: When referencing a function by name in review feedback (or proposing a call site), don’t only check that the function exists—verify the proposed invocation matches the function’s actual exported signature. Confirm argument order and the expected parameter types (and any overloaded variants) against the definition. For example, in src/renderable/codecs/validation-rules.ts, composeRationaleIntoRules expects (rules: readonly RuleDefinition[], conventionContent: ReadonlyMap<string, {...}>)—so calls should pass rules first and the convention map second, not a CodecContext as the second argument.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/codecs/types/base.ts:206-224
Timestamp: 2026-04-01T14:42:08.890Z
Learning: When reviewing JavaScript/Node.js code, do NOT suggest thread-safety or race-condition warnings for code that is explicitly synchronous and runs on the main single-threaded JS execution model. In particular, module-level or shared mutable state that is used only within a synchronous generation/decode pipeline (e.g., set codec context before a synchronous decode call, then cleared immediately after) does not imply a race condition under the stated synchronous execution contract. Avoid “speculative” warnings about hypothetical future async/worker scenarios; follow the project philosophy of not adding error handling, fallbacks, or validation for scenarios that cannot happen. If the code already documents the synchronous execution guarantee (e.g., via JSDoc), treat that as sufficient justification.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/codecs/pr-changes.ts:6-6
Timestamp: 2026-04-01T14:42:07.229Z
Learning: In this repository, scanner opt-in and runtime dependency annotations must use the `architect` prefix (e.g., `architect`). Do NOT suggest or add deprecated/invalid tags such as `libar-docs` or `libar-docs-uses`. For TypeScript files, opt into scanning by placing `architect` in the JSDoc header; if runtime dependency annotations are present, they should follow the same `architect` prefix convention.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/render-options.ts:21-21
Timestamp: 2026-04-01T14:42:10.736Z
Learning: In the `architect` TypeScript codebase (especially `src/renderable/**/*.ts`), do not suggest or introduce `Object.freeze` for empty default objects typed via `readonly` properties (e.g., `DEFAULT_SIZE_BUDGET: SizeBudget = {}`). If the interface/type already uses `readonly` and the object has no mutable runtime fields, freezing an empty object provides no meaningful runtime protection (effectively a no-op). Reserve `Object.freeze` for objects that contain actual mutable properties that must be protected at runtime.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/taxonomy/arch-values.ts:1-9
Timestamp: 2026-04-01T14:42:13.881Z
Learning: In this repository (libar-dev/architect), the documentation-scanner opt-in marker is `architect` (used in a file’s JSDoc header). Do not suggest or add the old `libar-docs` prefix—this rebrand marker no longer exists in the codebase. If a file already has `architect` in its JSDoc header, it is correctly opted in for documentation scanning and should not be flagged for opt-in/marker issues.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: tests/features/doc-generation/index-codec.feature:1-6
Timestamp: 2026-04-01T14:42:18.034Z
Learning: In the libar-dev/architect repository, the old documentation tag prefix `libar-docs-*` no longer exists (it was renamed during a rebrand). Do NOT flag missing or incorrect `libar-docs-*` tags in this repo. Instead, expect the `architect-*` tag prefix in both feature files and TypeScript sources (e.g., `architect-pattern`, `architect-status`, `architect-product-area`, `architect-unlock-reason`, etc.).
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/split.ts:72-105
Timestamp: 2026-04-01T14:42:14.584Z
Learning: When reviewing heuristic or budget-based logic (e.g., line-count/document splitting or other approximate heuristics), treat measurement imprecision within the intended heuristic bounds as expected behavior, not a bug. Only flag violations that are true hard correctness requirements (must-never conditions); distinguish them from soft heuristics that are approximate by design to avoid false positives.
Learnt from: darko-mijic
Repo: libar-dev/architect PR: 40
File: src/renderable/codecs/validation-rules.ts:232-235
Timestamp: 2026-04-01T14:42:29.625Z
Learning: When reviewing the Architect codebase and proposing changes to a codec or function, first scan nearby code for TODO comments or inline documentation that explicitly explains intentional behavior/design decisions (e.g., unused parameters preserved for interface consistency). If the ignored/unused parameter (or similar behavior) is explicitly documented as intentional, do not raise it as a problem—treat it as a likely false positive.
Summary
decodeDocument()anddecodeDocumentSafe()— codec decode without markdown rendering. ReturnsRenderableDocumentas structured JSON for native UI rendering in Studio.CodecOptionsandGenerationErrortypes for typed consumer usage.prepublishOnlyto guarantee clean builds:pnpm cleanruns first (removes staletsbuildinfo), newverify:exportsscript checks all 34 declared paths exist indist/.Context
The Live Documentation API needs a way to invoke codecs and get structured
RenderableDocumentback instead of markdown strings. The existinggenerateDocument()always flattens to markdown —decodeDocument()stops after the decode step, returning the intermediate format that Studio can render natively (tables, Mermaid diagrams, collapsibles).The publish safety fix prevents the stale
tsbuildinfoissue that caused incompletedist/in pre.5.New public API (
@libar-dev/architect/renderable)Review hardening (938a6a3)
Multi-agent review (code quality + security + silent failure analysis) identified and fixed:
"design-review"DocumentType in example with"architecture"verify-exports.mjsnow rejects export paths that resolve outside project rootpkg.binpolymorphism: handles both string ("./cli.js") and object ({ "cmd": "./cli.js" }) forms — string form was silently skippedTest plan
verify:exportscatches missing dist/ (tested withrm -rf dist)Summary by CodeRabbit
New Features
Bug Fixes / Improvements