@ybotok/loam 0.1.0-beta.1 → 0.1.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +6 -1
  3. package/SCHEMA.md +22 -4
  4. package/dist/cli.js +4 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/commands/adopt.js +17 -3
  7. package/dist/commands/adopt.js.map +1 -1
  8. package/dist/commands/archive.js +24 -8
  9. package/dist/commands/archive.js.map +1 -1
  10. package/dist/commands/delta.js +74 -47
  11. package/dist/commands/delta.js.map +1 -1
  12. package/dist/commands/dependencies.js +7 -2
  13. package/dist/commands/dependencies.js.map +1 -1
  14. package/dist/commands/docs-repo-gate.js +104 -0
  15. package/dist/commands/docs-repo-gate.js.map +1 -0
  16. package/dist/commands/explore.js +195 -0
  17. package/dist/commands/explore.js.map +1 -0
  18. package/dist/commands/format.js +17 -0
  19. package/dist/commands/format.js.map +1 -0
  20. package/dist/commands/gherkin.js +87 -48
  21. package/dist/commands/gherkin.js.map +1 -1
  22. package/dist/commands/init.js +3 -3
  23. package/dist/commands/init.js.map +1 -1
  24. package/dist/commands/instructions.js +80 -0
  25. package/dist/commands/instructions.js.map +1 -0
  26. package/dist/commands/list.js +10 -76
  27. package/dist/commands/list.js.map +1 -1
  28. package/dist/commands/migrate-openspec.js +45 -28
  29. package/dist/commands/migrate-openspec.js.map +1 -1
  30. package/dist/commands/new.js +35 -34
  31. package/dist/commands/new.js.map +1 -1
  32. package/dist/commands/rebase.js +2 -4
  33. package/dist/commands/rebase.js.map +1 -1
  34. package/dist/commands/show.js +26 -31
  35. package/dist/commands/show.js.map +1 -1
  36. package/dist/commands/status.js +17 -25
  37. package/dist/commands/status.js.map +1 -1
  38. package/dist/commands/unarchive.js +12 -5
  39. package/dist/commands/unarchive.js.map +1 -1
  40. package/dist/commands/validate.js +306 -142
  41. package/dist/commands/validate.js.map +1 -1
  42. package/dist/commands/verify.js +33 -17
  43. package/dist/commands/verify.js.map +1 -1
  44. package/dist/commands/vouch.js +156 -60
  45. package/dist/commands/vouch.js.map +1 -1
  46. package/dist/core/agent.js +392 -42
  47. package/dist/core/agent.js.map +1 -1
  48. package/dist/core/agents-stamp.js +47 -10
  49. package/dist/core/agents-stamp.js.map +1 -1
  50. package/dist/core/arch.js +28 -2
  51. package/dist/core/arch.js.map +1 -1
  52. package/dist/core/asyncapi.js +253 -0
  53. package/dist/core/asyncapi.js.map +1 -0
  54. package/dist/core/brief.js +28 -6
  55. package/dist/core/brief.js.map +1 -1
  56. package/dist/core/coherence.js +37 -13
  57. package/dist/core/coherence.js.map +1 -1
  58. package/dist/core/concurrency.js +51 -0
  59. package/dist/core/concurrency.js.map +1 -0
  60. package/dist/core/config.js +10 -2
  61. package/dist/core/config.js.map +1 -1
  62. package/dist/core/delta.js +21 -2
  63. package/dist/core/delta.js.map +1 -1
  64. package/dist/core/dependencies.js +46 -42
  65. package/dist/core/dependencies.js.map +1 -1
  66. package/dist/core/docs.js +65 -3
  67. package/dist/core/docs.js.map +1 -1
  68. package/dist/core/doctor.js +79 -27
  69. package/dist/core/doctor.js.map +1 -1
  70. package/dist/core/document-bytes.js +59 -0
  71. package/dist/core/document-bytes.js.map +1 -0
  72. package/dist/core/explore.js +225 -0
  73. package/dist/core/explore.js.map +1 -0
  74. package/dist/core/fleet-context.js +29 -63
  75. package/dist/core/fleet-context.js.map +1 -1
  76. package/dist/core/frontmatter.js +1 -5
  77. package/dist/core/frontmatter.js.map +1 -1
  78. package/dist/core/gherkin.js +3 -61
  79. package/dist/core/gherkin.js.map +1 -1
  80. package/dist/core/health.js +1 -5
  81. package/dist/core/health.js.map +1 -1
  82. package/dist/core/ids.js +34 -5
  83. package/dist/core/ids.js.map +1 -1
  84. package/dist/core/json.js +8 -1
  85. package/dist/core/json.js.map +1 -1
  86. package/dist/core/likec4.js +19 -4
  87. package/dist/core/likec4.js.map +1 -1
  88. package/dist/core/maturity.js +66 -0
  89. package/dist/core/maturity.js.map +1 -0
  90. package/dist/core/openapi-merge.js +39 -6
  91. package/dist/core/openapi-merge.js.map +1 -1
  92. package/dist/core/openapi.js +17 -5
  93. package/dist/core/openapi.js.map +1 -1
  94. package/dist/core/openspec-inventory.js +64 -27
  95. package/dist/core/openspec-inventory.js.map +1 -1
  96. package/dist/core/path-safety.js +59 -0
  97. package/dist/core/path-safety.js.map +1 -1
  98. package/dist/core/provenance.js +102 -10
  99. package/dist/core/provenance.js.map +1 -1
  100. package/dist/core/records.js +33 -0
  101. package/dist/core/records.js.map +1 -0
  102. package/dist/core/repo.js +77 -1
  103. package/dist/core/repo.js.map +1 -1
  104. package/dist/core/report.js +9 -0
  105. package/dist/core/report.js.map +1 -1
  106. package/dist/core/results.js +1 -3
  107. package/dist/core/results.js.map +1 -1
  108. package/dist/core/spec.js +28 -4
  109. package/dist/core/spec.js.map +1 -1
  110. package/dist/core/staging.js +124 -17
  111. package/dist/core/staging.js.map +1 -1
  112. package/dist/core/status.js +152 -35
  113. package/dist/core/status.js.map +1 -1
  114. package/dist/core/steps.js +72 -0
  115. package/dist/core/steps.js.map +1 -0
  116. package/dist/core/verify.js +18 -4
  117. package/dist/core/verify.js.map +1 -1
  118. package/dist/core/version.js +17 -1
  119. package/dist/core/version.js.map +1 -1
  120. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { loadConfig } from \"../core/config.js\";\nimport { emitJson, fail, repoPath, reportNoConfig } from \"../core/json.js\";\nimport { loadFile, serviceResolver } from \"../core/likec4.js\";\nimport {\n DocsRepoUnavailableError,\n compareIds,\n landscapePath,\n listFeatures,\n listServices,\n servicePaths,\n type FeatureEntry,\n type ServiceEntry,\n} from \"../core/repo.js\";\nimport {\n featureChecklist,\n readVerification,\n tallyRecord,\n verificationVerdict,\n type VerificationVerdict,\n} from \"../core/verify.js\";\nimport { docsRepoReady, reportDocsRepoError } from \"./validate.js\";\n\ntype Section = \"services\" | \"features\";\nconst SECTIONS: Section[] = [\"services\", \"features\"];\n\ninterface ListOptions {\n json?: boolean;\n archived?: boolean;\n needsWork?: boolean;\n}\n\nexport function registerList(program: Command): void {\n program\n .command(\"list\")\n .argument(\"[section]\", \"services | features (default: both)\")\n .description(\"List the services and features in the docs repo\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .option(\"--archived\", \"include archived features\")\n .option(\n \"--needs-work\",\n \"services only: the adoption worklist — every service below `vouched`, with what it is missing\",\n )\n .action(async (section: string | undefined, opts: ListOptions) => {\n const json = opts.json === true;\n const wanted = opts.needsWork\n ? SECTIONS.filter((s) => s === \"services\")\n : section\n ? SECTIONS.filter((s) => s === section)\n : SECTIONS;\n if (section && !SECTIONS.includes(section as Section)) {\n // `invalid-option`, same as show's bad --type: one mistake class, one code.\n fail(json, \"invalid-option\", `Unknown section '${section}'. Expected: ${SECTIONS.join(\" | \")}.`);\n return;\n }\n if (opts.needsWork && section === \"features\") {\n fail(json, \"invalid-option\", \"--needs-work is the service adoption worklist; drop the 'features' section.\");\n return;\n }\n\n const config = await loadConfig();\n if (!config) {\n reportNoConfig(json);\n return;\n }\n const { docsDir } = config;\n // A docsDir that is not a docs repo is refused, never rendered as an empty\n // fleet — the whole point of the gate (see validate.ts's docsRepoReady).\n // `list features` alone does not need services/, so it asks for less.\n if (!docsRepoReady(json, docsDir, wanted.includes(\"services\") ? \"services\" : \"docs\")) return;\n\n try {\n const services = wanted.includes(\"services\") ? await listServices(docsDir) : undefined;\n const views = services ? await serviceViews(docsDir, services, config.service) : undefined;\n const features = wanted.includes(\"features\")\n ? await listFeatures(docsDir, { includeArchived: opts.archived })\n : undefined;\n const verification = features\n ? await Promise.all(features.map((f) => featureVerification(docsDir, f)))\n : undefined;\n\n const worklist = views?.filter((v) => v.maturity !== \"vouched\");\n\n if (json) {\n emitJson({\n docsDir,\n ...(views\n ? {\n services: (opts.needsWork ? worklist! : views).map((v) => serviceJson(docsDir, v)),\n maturity: maturityRollup(views),\n }\n : {}),\n ...(features\n ? { features: features.map((f, i) => featureJson(docsDir, f, verification![i] ?? null)) }\n : {}),\n });\n return;\n }\n\n if (opts.needsWork) {\n printWorklist(worklist!, views!.length);\n return;\n }\n if (views) printServices(views);\n if (views && features) console.log(\"\");\n if (features) printFeatures(features, verification!);\n } catch (err) {\n if (err instanceof DocsRepoUnavailableError) {\n reportDocsRepoError(json, err);\n return;\n }\n // One unreadable file used to escape as a stack trace (`internal` in\n // --json), naming nothing. The enumeration is all-or-nothing — it reads\n // every service's frontmatter to build one table — so the honest answer\n // is a refusal that says WHICH path could not be read.\n const path = (err as NodeJS.ErrnoException).path;\n if (path === undefined) throw err;\n fail(\n json,\n \"repository-unavailable\",\n `${path} could not be read, so the listing would be missing a service. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* The per-service view */\n/* ------------------------------------------------------------------ */\n\n/**\n * A service entry plus the two things the enumeration cannot know on its own:\n * whether an API is EXPECTED of it, and whether anyone standing here could\n * check its `sources`. Both change what the maturity rung means, and both are\n * fleet-level facts — they need the landscape and loam.json, not the directory.\n */\ninterface ServiceView {\n entry: ServiceEntry;\n /** `arch.spec.md` — the architecture-obligations axis, absent from ServiceEntry.has. */\n archSpec: boolean;\n /**\n * Does anything in the fleet call an operation on this service? True unless\n * the landscape PROVES otherwise, exactly as `validate`'s no-openapi grace\n * reads it: a missing or unparseable landscape proves nothing.\n */\n apiExpected: boolean;\n /** True when this service's `sources` can only be resolved from its own repo. */\n unverifiableFromHere: boolean;\n maturity: Maturity;\n /** What stands between this service and the next rung, in fix order. */\n missing: string[];\n}\n\n/**\n * Read the living landscape ONCE and decide, per service, whether an API is\n * expected of it. `serviceResolver` is handed the real service ids so an edge\n * drawn into a modelled container (`paymentService.api`) counts for the service\n * that owns it — the same resolution `validate` uses, so the two commands\n * cannot disagree about who is called.\n */\nasync function serviceViews(\n docsDir: string,\n services: ServiceEntry[],\n boundService: string | undefined,\n): Promise<ServiceView[]> {\n const known = new Set(services.map((s) => s.id));\n const lp = landscapePath(docsDir);\n const land = existsSync(lp) ? await loadFile(lp) : null;\n const called = new Set<string>();\n // Positive evidence only: with no landscape, or one that does not parse, we\n // know nothing about who is called and every service is assumed to have an\n // API — the conservative direction, because claiming a service needs no\n // contract is how a real one goes undocumented.\n const proven = land !== null && land.errors.length === 0;\n if (proven) {\n const svcOf = serviceResolver(land.elements, known);\n for (const r of land.relationships) {\n if (r.op !== undefined) called.add(svcOf(r.target));\n }\n }\n\n return services.map((entry) => {\n const archSpec = existsSync(servicePaths(docsDir, entry.id).archSpec);\n const apiExpected = !proven || called.has(entry.id);\n const view = {\n entry,\n archSpec,\n apiExpected,\n unverifiableFromHere: entry.sources.declared && boundService !== entry.id,\n };\n const missing = gaps(view);\n return { ...view, maturity: maturity(view), missing };\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* JSON */\n/* ------------------------------------------------------------------ */\n\nfunction serviceJson(docsDir: string, v: ServiceView): Record<string, unknown> {\n const s = v.entry;\n return {\n id: s.id,\n path: repoPath(docsDir, s.dir),\n has: { ...s.has, archSpec: v.archSpec },\n adrs: s.adrs,\n status: s.status,\n maturity: v.maturity,\n missing: v.missing,\n apiExpected: v.apiExpected,\n // Never omitted when true: a consumer that filters this table into a\n // worklist has to be able to tell \"checked and fine\" from \"not checkable\n // from here\", and absence reads as the first one.\n ...(v.unverifiableFromHere ? { provenance: \"unverifiable-from-here\" } : {}),\n };\n}\n\nfunction featureJson(\n docsDir: string,\n f: FeatureEntry,\n verification: VerificationCell | null,\n): Record<string, unknown> {\n return {\n id: f.id,\n dirName: f.dirName,\n path: repoPath(docsDir, f.dir),\n archived: f.archived,\n services: f.services,\n has: f.has,\n verification,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Maturity — the adoption campaign's dial */\n/* ------------------------------------------------------------------ */\n\n/** The adoption-maturity ladder, in order. Each rung stands on every rung below it. */\nconst MATURITY_LADDER = [\"empty\", \"partial\", \"documented\", \"sourced\", \"vouched\"] as const;\ntype Maturity = (typeof MATURITY_LADDER)[number];\n\n/**\n * One monotone word for how far a service's documentation has got. Derived\n * from artifact PRESENCE and provenance state only — the data list already\n * holds — never from what the artifacts say. COMPLETENESS of adopted docs is\n * explicitly on the unchecked list (brief.ts): a service with one endpoint\n * documented out of thirty climbs this ladder exactly as fast as a thorough\n * one, which is why no rung is called \"adopted\".\n *\n * empty services/<id>/ exists, no artifact is in it\n * partial some artifacts, but not the required set\n * documented the artifacts the adopt brief marks required are present\n * sourced the living spec declares `sources` — something ties it to code\n * vouched status: verified with a sources_digest behind it — a person\n * stamped it. `verified` with no digest is a claim with nothing\n * behind it and stays below this rung.\n *\n * `openapi.yaml` is required ONLY where an API is expected. The rung used to\n * demand it of everything, which permanently pinned every worker, cron and\n * consumer in the fleet at `partial` — services that are fully documented and\n * vouched for, reported as unfinished forever, and a rollup that therefore said\n * a correctly-adopted fleet was half-done. The evidence is the same one\n * `validate` uses to keep `service.no-openapi` quiet, so a service cannot be\n * green in one command and unfinished in the other.\n */\nfunction maturity(v: Omit<ServiceView, \"maturity\" | \"missing\">): Maturity {\n const s = v.entry;\n if (!Object.values(s.has).some(Boolean) && !v.archSpec && s.adrs === 0) return \"empty\";\n if (!(s.has.model && s.has.spec && (!v.apiExpected || s.has.openapi))) return \"partial\";\n if (!s.sources.declared) return \"documented\";\n if (!(s.status === \"verified\" && s.sources.stamped)) return \"sourced\";\n return \"vouched\";\n}\n\n/**\n * What stands between this service and `vouched`, named as the thing to go and\n * do. One rung's worth at a time: telling somebody at `empty` that they also\n * need a vouch is noise, and the vouch is not even possible yet.\n */\nfunction gaps(v: Omit<ServiceView, \"maturity\" | \"missing\">): string[] {\n const s = v.entry;\n const files = [\n ...(s.has.model ? [] : [\"model.likec4\"]),\n ...(s.has.spec ? [] : [\"spec.md\"]),\n ...(v.apiExpected && !s.has.openapi ? [\"openapi.yaml\"] : []),\n ];\n if (files.length > 0) return files;\n if (!s.sources.declared) return [\"sources: in the spec.md frontmatter\"];\n if (!(s.status === \"verified\" && s.sources.stamped)) return [`\\`loam vouch --service ${s.id}\\``];\n return [];\n}\n\n/** Counts per rung, every rung present — a stable shape a fleet dashboard can diff. */\nfunction maturityRollup(views: ServiceView[]): Record<Maturity, number> {\n const out = Object.fromEntries(MATURITY_LADDER.map((m) => [m, 0])) as Record<Maturity, number>;\n for (const v of views) out[v.maturity] += 1;\n return out;\n}\n\n/* ------------------------------------------------------------------ */\n/* Verification */\n/* ------------------------------------------------------------------ */\n\n/** What the features table says about verification without N `loam verify` runs. */\ninterface VerificationCell {\n state: \"recorded\" | \"stale\";\n /** The day the record was written. */\n recorded: string;\n /**\n * `verify --json`'s own three-valued verdict, through `verificationVerdict` —\n * not a fourth opinion computed here. `attested` is the one this column got\n * wrong: a scenario confirmed on an agent's word printed as `11/11` under a\n * heading that said `verified`, and `list --json` is how the fleet is graded.\n */\n verdict: VerificationVerdict;\n /** Both counts are `tallyRecord`'s — the record's `claims[]`, never its `summary:` block. */\n confirmed: number;\n claims: number;\n /** Of the confirmed, the scenario claims on an agent's word (`attestedClaims`). */\n attested: number;\n}\n\n/**\n * The verification column. `readVerification` is one file read; the checklist\n * is derived only when there is a record to judge — on a fleet-sized repo most\n * features have none, and deriving N checklists to print N dashes is the cost\n * that would get this column dropped.\n *\n * An archived feature's record is frozen history (see verify.ts): archive\n * merged the feature's operations into the living openapi, so a re-derived\n * checklist can only mismatch — the record is reported as recorded, never\n * judged stale.\n */\nasync function featureVerification(\n docsDir: string,\n f: FeatureEntry,\n): Promise<VerificationCell | null> {\n const v = await readVerification(f.dir);\n if (v === null) return null;\n const stale = f.archived\n ? false\n : (await featureChecklist(docsDir, f.dir, f.id)).digest !== v.checklist;\n const tally = tallyRecord(v);\n return {\n state: stale ? \"stale\" : \"recorded\",\n recorded: v.recorded,\n verdict: verificationVerdict(tally, stale),\n confirmed: tally.confirmed,\n claims: tally.claims,\n attested: tally.attested,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Text */\n/* ------------------------------------------------------------------ */\n\n/**\n * Fixed-width presence flags. `a` and `A` are deliberately the same letter in\n * two cases: the arch spec and the API are the two things a reader most often\n * mistakes for each other, and one is lowercase because it is optional.\n */\nfunction serviceFlags(v: ServiceView): string {\n const s = v.entry;\n return [\n s.has.model ? \"M\" : \"-\",\n s.has.spec ? \"S\" : \"-\",\n v.archSpec ? \"a\" : \"-\",\n s.has.openapi ? \"A\" : \"-\",\n s.has.runbook ? \"R\" : \"-\",\n s.has.health ? \"H\" : \"-\",\n ].join(\" \");\n}\n\nfunction printServices(views: ServiceView[]): void {\n console.log(\n `services (${views.length}) [M]odel [S]pec [a]rch-spec [A]pi [R]unbook [H]ealth`,\n );\n const width = Math.max(0, ...views.map((v) => v.entry.id.length));\n const rungWidth = Math.max(0, ...views.map((v) => v.maturity.length));\n for (const v of views) {\n const s = v.entry;\n const adrs = s.adrs > 0 ? ` (${s.adrs} adr${s.adrs === 1 ? \"\" : \"s\"})` : \"\";\n // The rung per service, not only in the rollup: \"12 partial\" tells a reader\n // the fleet is unfinished and nothing about which twelve, which is the one\n // question the line is read to answer.\n console.log(\n ` ${serviceFlags(v)} ${s.id.padEnd(width)} ${v.maturity.padEnd(rungWidth)}${adrs}`.trimEnd(),\n );\n }\n // How much of the fleet anyone has actually vouched for. On 100+ services this\n // is the number that says whether the docs can be trusted at all.\n if (views.length > 0) {\n const counted = new Map<string, number>();\n for (const v of views) {\n const key = v.entry.status ?? \"unmarked\";\n counted.set(key, (counted.get(key) ?? 0) + 1);\n }\n const parts = [...counted.entries()]\n .sort((a, b) => compareIds(a[0], b[0]))\n .map(([status, n]) => `${n} ${status}`);\n console.log(` status: ${parts.join(\" · \")}`);\n // The campaign dial next to the trust dial: rungs in ladder order, so the\n // line reads as progress left to right. Presence and provenance state only\n // — completeness is unchecked, so this line never says \"adopted\".\n const rollup = maturityRollup(views);\n const rungs = MATURITY_LADDER.filter((m) => rollup[m] > 0).map((m) => `${rollup[m]} ${m}`);\n console.log(` maturity: ${rungs.join(\" · \")}`);\n }\n}\n\n/**\n * The one-shot adoption worklist. Onboarding ten legacy services means asking\n * \"what is left\" once a day for a month, and the answer used to require reading\n * a presence table and a rollup and joining them by eye. A service whose\n * provenance cannot be judged from here is LISTED, tagged, never dropped:\n * omitting it would read as done.\n */\nfunction printWorklist(views: ServiceView[], total: number): void {\n if (views.length === 0) {\n console.log(`nothing to do — all ${total} service(s) are vouched`);\n return;\n }\n console.log(`${views.length} of ${total} service(s) need work`);\n const width = Math.max(0, ...views.map((v) => v.entry.id.length));\n const rungWidth = Math.max(0, ...views.map((v) => v.maturity.length));\n for (const v of views) {\n const note = v.unverifiableFromHere ? \" (provenance: unverifiable-from-here)\" : \"\";\n console.log(\n ` ${v.entry.id.padEnd(width)} ${v.maturity.padEnd(rungWidth)} missing: ${v.missing.join(\", \")}${note}`,\n );\n }\n}\n\n/** Narrow verification cell: confirmed/claims when a record answers, one word when it does not. */\nfunction verificationMark(v: VerificationCell | null): string {\n if (v === null) return \"-\";\n if (v.state === \"stale\") return \"stale\";\n // `11/11` and `11/11 attested` are different facts — the first is a\n // digest-matched green run, the second is somebody's word about one. Without\n // the suffix a complete count is the same glyph either way, which is exactly\n // the reading `verify`, `status` and the JSON envelope stopped giving.\n return `${v.confirmed}/${v.claims}${v.verdict === \"attested\" ? \" attested\" : \"\"}`;\n}\n\nfunction printFeatures(features: FeatureEntry[], verification: (VerificationCell | null)[]): void {\n const active = features.filter((f) => !f.archived).length;\n const archived = features.length - active;\n const counts = `${active} active${archived > 0 ? `, ${archived} archived` : \"\"}`;\n // Not `verified`: the column reports three verdicts and only one of them is\n // that one. A heading that names the strong verdict makes every other cell\n // read as it.\n console.log(`features (${counts}) [I]ntent [D]elta verification`);\n const width = Math.max(0, ...features.map((f) => f.id.length));\n const cells = verification.map(verificationMark);\n const cellWidth = Math.max(0, ...cells.map((c) => c.length));\n for (const [i, f] of features.entries()) {\n const flags = `${f.has.intent ? \"I\" : \"-\"} ${f.has.delta ? \"D\" : \"-\"}`;\n const svcs = f.services.length > 0 ? f.services.join(\", \") : \"—\";\n const tag = f.archived ? \" (archived)\" : \"\";\n console.log(` ${flags} ${f.id.padEnd(width)} ${cells[i]!.padEnd(cellWidth)} ${svcs}${tag}`);\n }\n}\n"]}
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { loadConfig } from \"../core/config.js\";\nimport { emitJson, fail, repoPath, reportNoConfig } from \"../core/json.js\";\nimport { loadFile, serviceResolver } from \"../core/likec4.js\";\nimport {\n MATURITY_LADDER,\n maturityGaps,\n maturityRollup,\n serviceMaturity,\n type Maturity,\n type MaturityInput,\n} from \"../core/maturity.js\";\nimport {\n DocsRepoUnavailableError,\n compareIds,\n landscapePath,\n listFeatures,\n listServices,\n servicePaths,\n type FeatureEntry,\n type ServiceEntry,\n} from \"../core/repo.js\";\nimport {\n featureChecklist,\n readVerification,\n tallyRecord,\n verificationVerdict,\n type VerificationVerdict,\n} from \"../core/verify.js\";\nimport { docsRepoReady, reportDocsRepoError, reportRepositoryUnavailable } from \"./docs-repo-gate.js\";\n\ntype Section = \"services\" | \"features\";\nconst SECTIONS: Section[] = [\"services\", \"features\"];\n\ninterface ListOptions {\n json?: boolean;\n archived?: boolean;\n needsWork?: boolean;\n}\n\nexport function registerList(program: Command): void {\n program\n .command(\"list\")\n .argument(\"[section]\", \"services | features (default: both)\")\n .description(\"List the services and features in the docs repo\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .option(\"--archived\", \"include archived features\")\n .option(\n \"--needs-work\",\n \"services only: the adoption worklist — every service below `vouched`, with what it is missing\",\n )\n .action(async (section: string | undefined, opts: ListOptions) => {\n const json = opts.json === true;\n const wanted = opts.needsWork\n ? SECTIONS.filter((s) => s === \"services\")\n : section\n ? SECTIONS.filter((s) => s === section)\n : SECTIONS;\n if (section && !SECTIONS.includes(section as Section)) {\n // `invalid-option`, same as show's bad --type: one mistake class, one code.\n fail(json, \"invalid-option\", `Unknown section '${section}'. Expected: ${SECTIONS.join(\" | \")}.`);\n return;\n }\n if (opts.needsWork && section === \"features\") {\n fail(json, \"invalid-option\", \"--needs-work is the service adoption worklist; drop the 'features' section.\");\n return;\n }\n\n const config = await loadConfig();\n if (!config) {\n reportNoConfig(json);\n return;\n }\n const { docsDir } = config;\n // A docsDir that is not a docs repo is refused, never rendered as an empty\n // fleet — the whole point of the gate (see docs-repo-gate.ts).\n // `list features` alone does not need services/, so it asks for less.\n if (!docsRepoReady(json, docsDir, wanted.includes(\"services\") ? \"services\" : \"docs\")) return;\n\n try {\n const services = wanted.includes(\"services\") ? await listServices(docsDir) : undefined;\n const views = services ? await serviceViews(docsDir, services, config.service) : undefined;\n const features = wanted.includes(\"features\")\n ? await listFeatures(docsDir, { includeArchived: opts.archived })\n : undefined;\n const verification = features\n ? await Promise.all(features.map((f) => featureVerification(docsDir, f)))\n : undefined;\n\n const worklist = views?.filter((v) => v.maturity !== \"vouched\");\n\n if (json) {\n emitJson({\n docsDir,\n ...(views\n ? {\n services: (opts.needsWork ? worklist! : views).map((v) => serviceJson(docsDir, v)),\n maturity: maturityRollup(views),\n }\n : {}),\n ...(features\n ? { features: features.map((f, i) => featureJson(docsDir, f, verification![i] ?? null)) }\n : {}),\n });\n return;\n }\n\n if (opts.needsWork) {\n printWorklist(worklist!, views!.length);\n return;\n }\n if (views) printServices(views);\n if (views && features) console.log(\"\");\n if (features) printFeatures(features, verification!);\n } catch (err) {\n if (err instanceof DocsRepoUnavailableError) {\n reportDocsRepoError(json, err);\n return;\n }\n // One unreadable file used to escape as a stack trace (`internal` in\n // --json), naming nothing. The enumeration is all-or-nothing — it reads\n // every service's frontmatter to build one table — so the honest answer\n // is a refusal that says WHICH path could not be read.\n reportRepositoryUnavailable(json, err, \"the listing would be missing a service\", docsDir);\n }\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* The per-service view */\n/* ------------------------------------------------------------------ */\n\n/**\n * The graded view: the rung's own inputs (core/maturity.ts) plus the one fact\n * only this command knows — whether anyone standing here could check the\n * service's `sources`, which needs loam.json's binding, not the directory.\n */\ninterface ServiceView extends MaturityInput {\n /** True when this service's `sources` can only be resolved from its own repo. */\n unverifiableFromHere: boolean;\n maturity: Maturity;\n /** What stands between this service and the next rung, in fix order. */\n missing: string[];\n}\n\n/**\n * Read the living landscape ONCE and decide, per service, whether an API is\n * expected of it. `serviceResolver` is handed the real service ids so an edge\n * drawn into a modelled container (`paymentService.api`) counts for the service\n * that owns it — the same resolution `validate` uses, so the two commands\n * cannot disagree about who is called.\n */\nasync function serviceViews(\n docsDir: string,\n services: ServiceEntry[],\n boundService: string | undefined,\n): Promise<ServiceView[]> {\n const known = new Set(services.map((s) => s.id));\n const lp = landscapePath(docsDir);\n const land = existsSync(lp) ? await loadFile(lp) : null;\n const called = new Set<string>();\n // Positive evidence only: with no landscape, or one that does not parse, we\n // know nothing about who is called and every service is assumed to have an\n // API — the conservative direction, because claiming a service needs no\n // contract is how a real one goes undocumented.\n const proven = land !== null && land.errors.length === 0;\n if (proven) {\n const svcOf = serviceResolver(land.elements, known);\n for (const r of land.relationships) {\n if (r.op !== undefined) called.add(svcOf(r.target));\n }\n }\n\n return services.map((entry) => {\n const archSpec = existsSync(servicePaths(docsDir, entry.id).archSpec);\n const apiExpected = !proven || called.has(entry.id);\n const view = {\n entry,\n archSpec,\n apiExpected,\n unverifiableFromHere: entry.sources.declared && boundService !== entry.id,\n };\n const missing = maturityGaps(view);\n return { ...view, maturity: serviceMaturity(view), missing };\n });\n}\n\n/* ------------------------------------------------------------------ */\n/* JSON */\n/* ------------------------------------------------------------------ */\n\nfunction serviceJson(docsDir: string, v: ServiceView): Record<string, unknown> {\n const s = v.entry;\n return {\n id: s.id,\n path: repoPath(docsDir, s.dir),\n has: { ...s.has, archSpec: v.archSpec },\n adrs: s.adrs,\n status: s.status,\n maturity: v.maturity,\n missing: v.missing,\n apiExpected: v.apiExpected,\n // Never omitted when true: a consumer that filters this table into a\n // worklist has to be able to tell \"checked and fine\" from \"not checkable\n // from here\", and absence reads as the first one.\n ...(v.unverifiableFromHere ? { provenance: \"unverifiable-from-here\" } : {}),\n };\n}\n\nfunction featureJson(\n docsDir: string,\n f: FeatureEntry,\n verification: VerificationCell | null,\n): Record<string, unknown> {\n return {\n id: f.id,\n dirName: f.dirName,\n path: repoPath(docsDir, f.dir),\n archived: f.archived,\n services: f.services,\n has: f.has,\n verification,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Verification */\n/* ------------------------------------------------------------------ */\n\n/** What the features table says about verification without N `loam verify` runs. */\ninterface VerificationCell {\n state: \"recorded\" | \"stale\";\n /** The day the record was written. */\n recorded: string;\n /**\n * `verify --json`'s own three-valued verdict, through `verificationVerdict` —\n * not a fourth opinion computed here. `attested` is the one this column got\n * wrong: a scenario confirmed on an agent's word printed as `11/11` under a\n * heading that said `verified`, and `list --json` is how the fleet is graded.\n */\n verdict: VerificationVerdict;\n /** Both counts are `tallyRecord`'s — the record's `claims[]`, never its `summary:` block. */\n confirmed: number;\n claims: number;\n /** Of the confirmed, the scenario claims on an agent's word (`attestedClaims`). */\n attested: number;\n}\n\n/**\n * The verification column. `readVerification` is one file read; the checklist\n * is derived only when there is a record to judge — on a fleet-sized repo most\n * features have none, and deriving N checklists to print N dashes is the cost\n * that would get this column dropped.\n *\n * An archived feature's record is frozen history (see verify.ts): archive\n * merged the feature's operations into the living openapi, so a re-derived\n * checklist can only mismatch — the record is reported as recorded, never\n * judged stale.\n */\nasync function featureVerification(\n docsDir: string,\n f: FeatureEntry,\n): Promise<VerificationCell | null> {\n const v = await readVerification(f.dir);\n if (v === null) return null;\n const stale = f.archived\n ? false\n : (await featureChecklist(docsDir, f.dir, f.id)).digest !== v.checklist;\n const tally = tallyRecord(v);\n return {\n state: stale ? \"stale\" : \"recorded\",\n recorded: v.recorded,\n verdict: verificationVerdict(tally, stale),\n confirmed: tally.confirmed,\n claims: tally.claims,\n attested: tally.attested,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Text */\n/* ------------------------------------------------------------------ */\n\n/**\n * Fixed-width presence flags. `a` and `A` are deliberately the same letter in\n * two cases: the arch spec and the API are the two things a reader most often\n * mistakes for each other, and one is lowercase because it is optional.\n */\nfunction serviceFlags(v: ServiceView): string {\n const s = v.entry;\n return [\n s.has.model ? \"M\" : \"-\",\n s.has.spec ? \"S\" : \"-\",\n v.archSpec ? \"a\" : \"-\",\n s.has.openapi ? \"A\" : \"-\",\n // The async contract, lowercase like the arch spec and for the same reason:\n // it is optional. A fleet where most services own no topic must not read as\n // a fleet with a column of gaps in it.\n s.has.asyncapi ? \"e\" : \"-\",\n s.has.runbook ? \"R\" : \"-\",\n s.has.health ? \"H\" : \"-\",\n ].join(\" \");\n}\n\nfunction printServices(views: ServiceView[]): void {\n console.log(\n `services (${views.length}) [M]odel [S]pec [a]rch-spec [A]pi [R]unbook [H]ealth`,\n );\n const width = Math.max(0, ...views.map((v) => v.entry.id.length));\n const rungWidth = Math.max(0, ...views.map((v) => v.maturity.length));\n for (const v of views) {\n const s = v.entry;\n const adrs = s.adrs > 0 ? ` (${s.adrs} adr${s.adrs === 1 ? \"\" : \"s\"})` : \"\";\n // The rung per service, not only in the rollup: \"12 partial\" tells a reader\n // the fleet is unfinished and nothing about which twelve, which is the one\n // question the line is read to answer.\n console.log(\n ` ${serviceFlags(v)} ${s.id.padEnd(width)} ${v.maturity.padEnd(rungWidth)}${adrs}`.trimEnd(),\n );\n }\n // How much of the fleet anyone has actually vouched for. On 100+ services this\n // is the number that says whether the docs can be trusted at all.\n if (views.length > 0) {\n const counted = new Map<string, number>();\n for (const v of views) {\n const key = v.entry.status ?? \"unmarked\";\n counted.set(key, (counted.get(key) ?? 0) + 1);\n }\n const parts = [...counted.entries()]\n .sort((a, b) => compareIds(a[0], b[0]))\n .map(([status, n]) => `${n} ${status}`);\n console.log(` status: ${parts.join(\" · \")}`);\n // The campaign dial next to the trust dial: rungs in ladder order, so the\n // line reads as progress left to right. Presence and provenance state only\n // — completeness is unchecked, so this line never says \"adopted\".\n const rollup = maturityRollup(views);\n const rungs = MATURITY_LADDER.filter((m) => rollup[m] > 0).map((m) => `${rollup[m]} ${m}`);\n console.log(` maturity: ${rungs.join(\" · \")}`);\n }\n}\n\n/**\n * The one-shot adoption worklist. Onboarding ten legacy services means asking\n * \"what is left\" once a day for a month, and the answer used to require reading\n * a presence table and a rollup and joining them by eye. A service whose\n * provenance cannot be judged from here is LISTED, tagged, never dropped:\n * omitting it would read as done.\n */\nfunction printWorklist(views: ServiceView[], total: number): void {\n if (views.length === 0) {\n console.log(`nothing to do — all ${total} service(s) are vouched`);\n return;\n }\n console.log(`${views.length} of ${total} service(s) need work`);\n const width = Math.max(0, ...views.map((v) => v.entry.id.length));\n const rungWidth = Math.max(0, ...views.map((v) => v.maturity.length));\n for (const v of views) {\n const note = v.unverifiableFromHere ? \" (provenance: unverifiable-from-here)\" : \"\";\n console.log(\n ` ${v.entry.id.padEnd(width)} ${v.maturity.padEnd(rungWidth)} missing: ${v.missing.join(\", \")}${note}`,\n );\n }\n}\n\n/** Narrow verification cell: confirmed/claims when a record answers, one word when it does not. */\nfunction verificationMark(v: VerificationCell | null): string {\n if (v === null) return \"-\";\n if (v.state === \"stale\") return \"stale\";\n // `11/11` and `11/11 attested` are different facts — the first is a\n // digest-matched green run, the second is somebody's word about one. Without\n // the suffix a complete count is the same glyph either way, which is exactly\n // the reading `verify`, `status` and the JSON envelope stopped giving.\n return `${v.confirmed}/${v.claims}${v.verdict === \"attested\" ? \" attested\" : \"\"}`;\n}\n\nfunction printFeatures(features: FeatureEntry[], verification: (VerificationCell | null)[]): void {\n const active = features.filter((f) => !f.archived).length;\n const archived = features.length - active;\n const counts = `${active} active${archived > 0 ? `, ${archived} archived` : \"\"}`;\n // Not `verified`: the column reports three verdicts and only one of them is\n // that one. A heading that names the strong verdict makes every other cell\n // read as it.\n console.log(`features (${counts}) [I]ntent [D]elta verification`);\n const width = Math.max(0, ...features.map((f) => f.id.length));\n const cells = verification.map(verificationMark);\n const cellWidth = Math.max(0, ...cells.map((c) => c.length));\n for (const [i, f] of features.entries()) {\n const flags = `${f.has.intent ? \"I\" : \"-\"} ${f.has.delta ? \"D\" : \"-\"}`;\n const svcs = f.services.length > 0 ? f.services.join(\", \") : \"—\";\n const tag = f.archived ? \" (archived)\" : \"\";\n console.log(` ${flags} ${f.id.padEnd(width)} ${cells[i]!.padEnd(cellWidth)} ${svcs}${tag}`);\n }\n}\n"]}
@@ -4,10 +4,11 @@ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "nod
4
4
  import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
5
5
  import { findConfigPath, parseConfig } from "../core/config.js";
6
6
  import { DOCS_SUBDIRS, docsRepoFiles } from "../core/docs.js";
7
- import { decodeDocument, NotUtf8DocumentError } from "../core/fleet-context.js";
7
+ import { decodeDocument, NotUtf8DocumentError } from "../core/document-bytes.js";
8
8
  import { serviceIdProblem } from "../core/ids.js";
9
9
  import { fail, emitJson } from "../core/json.js";
10
- import { createOpenSpecMappingSkeleton, inventoryOpenSpec, OpenSpecRootError, } from "../core/openspec-inventory.js";
10
+ import { createOpenSpecMappingSkeleton, inventoryOpenSpec, isOpenSpecArtifactDisposition, OpenSpecRootError, } from "../core/openspec-inventory.js";
11
+ import { asRecord, dictionary, ownValue } from "../core/records.js";
11
12
  import { parseRequirements, requirementIdProblems, serializeRequirements, } from "../core/spec.js";
12
13
  import { message, planWrite, rollbackError, rollbackStaged, stageWrites, swapStaged, } from "../core/staging.js";
13
14
  class OpenSpecCommandError extends Error {
@@ -138,21 +139,18 @@ function reportCommandError(json, error) {
138
139
  }
139
140
  throw error;
140
141
  }
141
- function asRecord(value) {
142
- return typeof value === "object" && value !== null && !Array.isArray(value)
143
- ? value
144
- : null;
145
- }
146
- function dictionary() {
147
- return Object.create(null);
148
- }
149
- function ownValue(record, key) {
150
- return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;
142
+ /**
143
+ * `Array.isArray` narrows an `unknown` to `any[]`, so the element check below it
144
+ * proved nothing to tsc and the elements had to be asserted back to `string` at
145
+ * the point of use. One predicate makes the narrowing carry the check.
146
+ */
147
+ function isStringArray(value) {
148
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
151
149
  }
152
150
  function stringList(value, label) {
153
151
  if (typeof value === "string")
154
152
  return value.trim() === "" ? [] : [value.trim()];
155
- if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
153
+ if (!isStringArray(value)) {
156
154
  throw new OpenSpecCommandError("invalid-option", `${label} must be a string or an array of service ids.`);
157
155
  }
158
156
  return [...new Set(value.map((item) => item.trim()).filter(Boolean))];
@@ -305,6 +303,10 @@ async function readMapping(path) {
305
303
  renames[key] = requirementId.trim();
306
304
  }
307
305
  }
306
+ // Recorded as written. Naming the disposition union here only meant asserting
307
+ // an unreviewed string into it: `mapping.invalid-artifact-disposition` is what
308
+ // actually grades this value, and it has to see what the human typed to be
309
+ // able to name it back to them.
308
310
  const artifacts = dictionary();
309
311
  if (document.artifacts !== undefined) {
310
312
  const artifactsNode = asRecord(document.artifacts);
@@ -448,7 +450,12 @@ function normalizedMapping(inventory, mapping) {
448
450
  decision.change,
449
451
  {
450
452
  feature: ownValue(mapping.changes, decision.change)?.feature ?? null,
451
- title: ownValue(mapping.changes, decision.change)?.title ?? decision.title,
453
+ // The decision's title, which is the mapping's own title trimmed.
454
+ // `readMapping` trims `feature` but not `title`, and materialization
455
+ // writes the trimmed one into the frontmatter, the H1 and the directory
456
+ // slug — so recording the raw one made the plan disagree with the files
457
+ // beside it about what the feature is called.
458
+ title: decision.title,
452
459
  },
453
460
  ])),
454
461
  renames: Object.fromEntries(inventory.renamed
@@ -585,8 +592,16 @@ function docsRepoScaffold(target) {
585
592
  }).map(([rel, content]) => planWrite(join(target, rel), content));
586
593
  }
587
594
  async function planMigrationWrites(inventory, mapping, target) {
588
- const livingWrites = await materializeLivingSpecs(inventory, mapping, target);
589
- const activeWrites = await materializeActiveChanges(inventory, mapping, target);
595
+ // One reading of the living corpus for both materializers. They each read and
596
+ // parsed the whole of it independently, which is twice the work and, worse,
597
+ // two readings: a rename resolved against one of them was written beside a
598
+ // living spec built from the other.
599
+ const livingByCapability = new Map();
600
+ for (const capability of inventory.living.capabilities) {
601
+ livingByCapability.set(capability.id, parseRequirements(await readSourceArtifact(inventory.root, capability.files[0])));
602
+ }
603
+ const livingWrites = await materializeLivingSpecs(inventory, mapping, target, livingByCapability);
604
+ const activeWrites = await materializeActiveChanges(inventory, mapping, target, livingByCapability);
590
605
  const legacyWrites = await copyLivingTree(inventory, target);
591
606
  assertDistinctPlannedPaths([...livingWrites, ...activeWrites, ...legacyWrites]);
592
607
  return { livingWrites, activeWrites, legacyWrites };
@@ -636,7 +651,7 @@ function assertMaterializedRequirementIds(where, requirements) {
636
651
  : `Requirement-ID '${first.id}' is shared by ${first.requirements.map((name) => `'${name}'`).join(", ")}`;
637
652
  throw new OpenSpecCommandError("invalid-option", `${where} would materialize an invalid loam spec: ${detail}. Repair the source or refine routing before apply.`);
638
653
  }
639
- async function materializeLivingSpecs(inventory, mapping, target) {
654
+ async function materializeLivingSpecs(inventory, mapping, target, livingByCapability) {
640
655
  const byService = new Map();
641
656
  const renameIds = new Map(inventory.renamed
642
657
  .filter((rename) => rename.scope === "active" && rename.from !== null && rename.requirementId !== null)
@@ -645,14 +660,13 @@ async function materializeLivingSpecs(inventory, mapping, target) {
645
660
  const selected = ownValue(mapping.capabilities, capability.id);
646
661
  if (selected === undefined)
647
662
  continue; // readiness prevents this on --apply
648
- const raw = await readSourceArtifact(inventory.root, capability.files[0]);
649
- const requirements = parseRequirements(raw);
650
- for (const parsed of requirements) {
663
+ for (const parsed of livingByCapability.get(capability.id) ?? []) {
651
664
  const renamedId = renameIds.get(`${capability.id}\0${parsed.name}`);
652
665
  const requirement = renamedId === undefined ? parsed : { ...parsed, id: renamedId };
653
- const services = selected.services.length === 1
654
- ? selected.services
655
- : ownValue(selected.requirementServices, requirement.name) ?? [];
666
+ // The one spelling of the routing rule. Written out again here, it drifted
667
+ // from the copy the delta side uses, so a split capability could route a
668
+ // living requirement and its own delta to different services.
669
+ const services = selectedServices(mapping, capability.id, requirement.name);
656
670
  for (const service of services) {
657
671
  const existing = byService.get(service) ?? [];
658
672
  const identity = requirement.id === undefined ? `heading '${requirement.name}'` : `Requirement-ID '${requirement.id}'`;
@@ -715,12 +729,8 @@ function safeArtifactRelative(artifactPath, prefix, owner) {
715
729
  }
716
730
  return segments;
717
731
  }
718
- async function materializeActiveChanges(inventory, mapping, target) {
732
+ async function materializeActiveChanges(inventory, mapping, target, livingByCapability) {
719
733
  const writes = [];
720
- const livingByCapability = new Map();
721
- for (const capability of inventory.living.capabilities) {
722
- livingByCapability.set(capability.id, parseRequirements(await readSourceArtifact(inventory.root, capability.files[0])));
723
- }
724
734
  const inventoryArtifactsByPath = new Map(inventory.artifacts.map((artifact) => [artifact.path, artifact]));
725
735
  for (const change of inventory.changes.active) {
726
736
  const decision = inventory.changeDecisions.find((item) => item.change === change.id);
@@ -742,6 +752,13 @@ async function materializeActiveChanges(inventory, mapping, target) {
742
752
  const disposition = ownValue(mapping.artifacts, artifactDecision.path);
743
753
  if (disposition === undefined)
744
754
  continue; // readiness prevents this on --apply
755
+ // The mapping holds the authored string; everything below compares it
756
+ // against disposition literals, so this is where the value has to become
757
+ // one of them or stop being routed. `mapping.invalid-artifact-disposition`
758
+ // already refuses an unknown one, so readiness prevents this too — but a
759
+ // silent skip is the right failure for a value nothing here can act on.
760
+ if (!isOpenSpecArtifactDisposition(disposition))
761
+ continue;
745
762
  authored.push({
746
763
  path: artifactDecision.path,
747
764
  kind: artifactDecision.kind,