@ybotok/loam 0.2.0-alpha.5 → 0.2.0-alpha.6
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.
- package/CHANGELOG.md +901 -0
- package/MIGRATING-from-OpenSpec.md +7 -4
- package/QUICKSTART.md +8 -3
- package/README.md +13 -7
- package/ROADMAP.md +264 -11
- package/SCHEMA.md +439 -38
- package/WORKFLOW.md +23 -10
- package/dist/commands/adopt/render.js +47 -8
- package/dist/commands/adopt/render.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +45 -1
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/run.js +5 -2
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/context/print.js +11 -1
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/doctor.js +46 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explore.js +12 -2
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/list/views.js +5 -1
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/seed/plan.js +97 -3
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +7 -2
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/feature.js +2 -1
- package/dist/commands/show/feature.js.map +1 -1
- package/dist/commands/show/marks.js +3 -5
- package/dist/commands/show/marks.js.map +1 -1
- package/dist/commands/show/service.js +39 -18
- package/dist/commands/show/service.js.map +1 -1
- package/dist/commands/subsystem/sync.js +128 -74
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +124 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +10 -3
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +113 -16
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +16 -9
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +30 -77
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/vocabulary.js +4 -19
- package/dist/commands/validate/checks/vocabulary.js.map +1 -1
- package/dist/commands/validate/feature.js +1 -1
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +11 -10
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +127 -119
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/load.js +66 -0
- package/dist/commands/validate/fleet/load.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +103 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +96 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +298 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +56 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +49 -17
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +13 -9
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/projects.js +258 -70
- package/dist/commands/validate/fleet/views/projects.js.map +1 -1
- package/dist/commands/validate/fleet/views/root-documents.js +97 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +2 -2
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +110 -34
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +39 -5
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +41 -3
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +10 -24
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/core/agent/agents-md/artifacts.js +1 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +18 -4
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/cycle.js +24 -9
- package/dist/core/agent/agents-md/cycle.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +51 -11
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +45 -3
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md.js +14 -4
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/support/report.js +39 -5
- package/dist/core/agent/support/report.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +123 -14
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +35 -20
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +3 -1
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/brief/brief.js +63 -11
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/checks.js +133 -7
- package/dist/core/brief/checks.js.map +1 -1
- package/dist/core/brief/landscape.js +212 -129
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +81 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +284 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +30 -29
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +12 -2
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/likec4.js +23 -1
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/parsed/deployment.js +5 -3
- package/dist/core/c4/parsed/deployment.js.map +1 -1
- package/dist/core/c4/parsed/view-ids.js +39 -1
- package/dist/core/c4/parsed/view-ids.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +142 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +52 -4
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +9 -4
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +77 -38
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +46 -12
- package/dist/core/c4/project/staged.js.map +1 -1
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/service.js +8 -17
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/resolve/steps.js +18 -0
- package/dist/core/c4/resolve/steps.js.map +1 -1
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +126 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-scan.js +26 -0
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +60 -13
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/contract.js.map +1 -1
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +17 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -1
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +154 -100
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +140 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +14 -4
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/workspace.js +2 -1
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/coherence/coherence.js +7 -0
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/delta/delta.js +9 -0
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/deployment/delta.js +4 -0
- package/dist/core/deployment/delta.js.map +1 -1
- package/dist/core/diff/base-state.js +21 -5
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/victims.js +10 -1
- package/dist/core/diff/victims.js.map +1 -1
- package/dist/core/docs.js +29 -24
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/config.js +7 -3
- package/dist/core/doctor/config.js.map +1 -1
- package/dist/core/doctor/doctor.js +36 -8
- package/dist/core/doctor/doctor.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/explain/refusals.js +1 -1
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explore/explore.js +44 -9
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +47 -0
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/partners.js +5 -9
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/pack/living.js +47 -13
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/pack/pack.js +9 -6
- package/dist/core/pack/pack.js.map +1 -1
- package/dist/core/projection/arch-slice.js +2 -2
- package/dist/core/projection/arch-slice.js.map +1 -1
- package/dist/core/repo/paths.js +11 -9
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/tree/render/projects.js +93 -35
- package/dist/core/repo/tree/render/projects.js.map +1 -1
- package/dist/core/repo/tree/render/stale.js +2 -3
- package/dist/core/repo/tree/render/stale.js.map +1 -1
- package/dist/core/repo/tree/render/views.js +51 -3
- package/dist/core/repo/tree/render/views.js.map +1 -1
- package/dist/core/repo/tree/walk.js +45 -2
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/scaffold/landscape.js +219 -9
- package/dist/core/scaffold/landscape.js.map +1 -1
- package/dist/core/staging/writes.js.map +1 -1
- package/dist/core/usecases/delta/claims.js +1 -0
- package/dist/core/usecases/delta/claims.js.map +1 -1
- package/dist/core/usecases/delta/overlay.js +4 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -1
- package/dist/core/usecases/fleet.js +18 -6
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/core/usecases/operations.js +7 -0
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +161 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +10 -0
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/examples/README.md +24 -6
- package/examples/docs/architecture/landscape.likec4 +41 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +5 -2
- package/examples/docs/likec4.config.json +0 -1
- package/examples/docs/services/checkout-web/model.likec4 +39 -56
- package/examples/docs/services/order-service/arch.spec.md +13 -6
- package/examples/docs/services/order-service/model.likec4 +53 -67
- package/examples/docs/services/payment-service/arch.spec.md +7 -4
- package/examples/docs/services/payment-service/model.likec4 +32 -35
- package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +29 -33
- package/examples/docs/services/platform/notification-service/health.yaml +8 -3
- package/examples/docs/services/platform/notification-service/model.likec4 +39 -59
- package/package.json +1 -1
- package/examples/docs/services/checkout-web/likec4.config.json +0 -4
- package/examples/docs/services/order-service/likec4.config.json +0 -4
- package/examples/docs/services/payment-service/likec4.config.json +0 -4
- package/examples/docs/services/platform/identity-service/likec4.config.json +0 -4
- package/examples/docs/services/platform/notification-service/likec4.config.json +0 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/validate/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam validate` — argument grammar, target selection, and the run's one\n * filesystem snapshot.\n *\n * The checks themselves live beside it, one module per target kind\n * (`landscape.ts`, `service/`, `feature/`) over the document checks they share\n * (`requirements.ts`). Every one of them produces findings and none of them\n * print: printing is `report.ts`'s, and it happens once, after the last target\n * is graded.\n */\nimport type { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { agentsStaleFinding, binaryBehindFinding } from \"../../core/agent/agents-stamp.js\";\nimport { inOrder } from \"../../core/kernel/concurrency.js\";\nimport type { RawServiceId } from \"../../core/kernel/ids/service.js\";\nimport { resolveServiceTarget } from \"../../core/repo/service-target.js\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { emitJson, fail, NO_SERVICE_MESSAGE, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { agentsPath as agentsFile, featurePaths, landscapePath as landscapeFile, servicePathsAt } from \"../../core/repo/paths.js\";\nimport { listFeatures, listServices, missingFeatureMessage, resolveFeature } from \"../../core/repo/repo.js\";\nimport {\n countSeverity,\n reportValid,\n targetJson,\n targetValid,\n type TargetReport,\n} from \"../../core/vocabulary/report.js\";\nimport { LOAM_VERSION } from \"../../core/envelope/version.js\";\nimport { FleetContext } from \"../../core/fleet-context.js\";\nimport { fixesFor } from \"../policy/format.js\";\nimport {\n docsRepoReady,\n reportDocsRepoError,\n reportRepositoryUnavailable,\n} from \"../policy/gate.js\";\nimport { interruptedCommitFinding } from \"../../core/staging/recovery/finding.js\";\nimport { scopeJson, scopeLine, scopeSince, type ValidateScope } from \"../../core/diff/scope/changed-paths.js\";\nimport { validateLandscape } from \"./fleet/landscape.js\";\nimport { loadArchitecture } from \"../../core/c4/project/architecture.js\";\nimport { readLandscape } from \"./fleet/load.js\";\nimport { buildScorecard } from \"./fleet/scorecard/scorecard.js\";\nimport { printScorecard } from \"./fleet/scorecard/print.js\";\nimport { validateFeature } from \"./feature.js\";\nimport { validateService } from \"./service/service.js\";\nimport { ambiguousTarget, capDetails, guarded, renderText, summary, unverifiableSubjects } from \"./report.js\";\n\ninterface ValidateOptions {\n service?: string;\n feature?: string;\n all?: boolean;\n base?: string;\n strict?: boolean;\n errorsOnly?: boolean;\n json?: boolean;\n}\n\nexport function registerValidate(program: Command): void {\n program\n .command(\"validate\")\n .argument(\"[target]\", \"service or feature id (a feature wins when both match; --service/--feature force the reading)\")\n .description(\"Validate a service (C4 + requirement coverage) or a feature (delta + coverage)\")\n .option(\"--service <id>\", \"service to validate (defaults to the configured service)\")\n .option(\"--feature <id>\", \"validate a feature delta instead of a service\")\n .option(\"--all\", \"validate every service and every active feature\")\n .option(\"--base <ref>\", \"with --all: grade only the targets changed since a base git ref of the docs repo — the adoption ratchet\")\n .option(\"--strict\", \"exit 1 on any warning too — a per-invocation CI lever; the report and --json payload do not change\")\n .option(\"--errors-only\", \"print only errors and warnings — a rendering lever; the --json payload does not change\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (target: string | undefined, opts: ValidateOptions) => {\n const json = opts.json === true;\n\n if (target !== undefined && (opts.all || opts.service || opts.feature)) {\n fail(json, \"invalid-option\", `'${target}' already names the target; drop --all/--service/--feature.`);\n return;\n }\n if (opts.all && (opts.service || opts.feature)) {\n fail(json, \"invalid-option\", \"--all validates everything; drop --service/--feature.\");\n return;\n }\n // Two targets is no target: silently validating only the feature taught\n // callers that --service had been honoured when it had been dropped.\n if (opts.service && opts.feature) {\n fail(json, \"invalid-option\", \"--service and --feature name different targets; pass one or the other.\");\n return;\n }\n // `--base` NARROWS a whole-fleet run; it does not name one. Beside a\n // positional, `--service` or `--feature` it is a scope over a scope — a\n // contradiction rather than a narrowing, whose \"this service if it\n // changed\" reading nobody could tell apart from a green over a service\n // never looked at. `--base` and not `--since`: `--base <ref>` is already\n // loam's word for a base git ref of the docs repo on diff and vouch.\n if (opts.base !== undefined && opts.all !== true) {\n fail(\n json,\n \"invalid-option\",\n target !== undefined || opts.service || opts.feature\n ? \"--base narrows --all to what changed since a ref; a named target is already a scope. Pass one or the other.\"\n : \"--base narrows --all to what changed since a ref — pass --all with it.\",\n );\n return;\n }\n\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const config = loaded.config;\n const { docsDir } = config;\n // Before anything is enumerated: a docsDir that is not a docs repo must\n // refuse, not report an empty fleet. See docsRepoReady. `--feature` is the\n // one mode that never enumerates services, so it asks for less.\n if (!docsRepoReady(json, docsDir, opts.feature ? \"docs\" : \"services\")) return;\n // One invocation, one filesystem snapshot. Nothing is global: a later\n // command gets a fresh index and therefore cannot observe stale files.\n const fleet = new FleetContext();\n\n // `sources` are paths into a service's own repository, so they only mean\n // something when loam is standing in that repository — which is exactly\n // what loam.json's `service` records.\n const repoOf = (service: string): string | undefined =>\n config.service === service ? process.cwd() : undefined;\n\n /** One service target, from a name the enumeration or the grammar approved. */\n const serviceTarget = (id: RawServiceId): Promise<TargetReport> =>\n guarded({ kind: \"service\", id }, () =>\n validateService({ docsDir, service: id, repoDir: repoOf(id), gherkinDir: config.gherkinDir, contracts: config.contracts, fleet }),\n );\n\n const targets: TargetReport[] = [];\n /** What the positional argument turned out to name, for the JSON payload. */\n let resolvedKind: \"service\" | \"feature\" | undefined;\n /** The `--base` narrowing, once it is known. Null on every unscoped run — including every run without --base. */\n let scope: ValidateScope | null = null;\n\n try {\n if (opts.all) {\n // ONE LikeC4 workspace for the whole run. The per-path load pays a\n // fresh Langium workspace per document (~100ms each even warm), which\n // made the fleet's main CI command O(documents) workspace spins —\n // 13.7s median over the 120-service benchmark (docs/BENCHMARKS.md).\n // So --all enumerates its documents up front — the landscape, every\n // service model, every active feature's delta — and batch-parses\n // them into the fleet context's memo; every loadLikeC4 below, the\n // landscape read included, is then a seeded hit. The enumerations are\n // the same memoized promises the target loops reuse. If the batch\n // CANNOT run (a sandbox denying tmpdir writes), prefetch seeds\n // nothing and every load falls back to today's per-path parse:\n // identical findings, the old speed. Single-service validate and\n // list keep their untouched code paths on purpose — the ≤10%\n // regression bound in docs/BENCHMARKS.md holds by construction.\n const lp = landscapeFile(docsDir);\n const enumerated = await listServices(docsDir, fleet);\n const active = await listFeatures(docsDir, {}, fleet);\n // `--base` narrows the enumerations and nothing else: a kept target is\n // graded by exactly the checks `--all` would have run on it, at the\n // same severities, through the same `--strict`. It matches through the\n // ENUMERATIONS' own directories — changed-paths.ts says why a split\n // on \"/\" silently drops every filed service.\n if (opts.base !== undefined) {\n const narrowed = await scopeSince({ docsDir, ref: opts.base, services: enumerated, features: active });\n if (narrowed.kind === \"refused\") {\n fail(json, narrowed.code, narrowed.message);\n return;\n }\n scope = narrowed;\n }\n const services = scope === null ? enumerated : scope.services;\n const features = scope === null ? active : scope.features;\n await fleet.prefetchLikeC4([\n ...(existsSync(lp) ? [lp] : []),\n ...services.filter((svc) => svc.has.model).map((svc) => servicePathsAt(svc.dir).model),\n ...features.filter((feat) => feat.has.delta).map((feat) => featurePaths(feat.dir).delta),\n ]);\n // Read whether or not the landscape is a TARGET: every service check\n // below joins against it, so a scoped run needs the map in hand even\n // when it does not grade the map itself.\n const land = existsSync(lp) ? await readLandscape(() => loadArchitecture(docsDir)) : null;\n // The fleet-level cross-check first: it frames everything below it, and a\n // service nobody drew is worth knowing before its own findings scroll past.\n // Under `--base` it is a target only when `architecture/` changed — the\n // landscape owns no service directory, so that is its whole footprint.\n if (scope === null || scope.landscape) {\n const landscape = await validateLandscape(docsDir, land, fleet);\n targets.push(landscape);\n // The agent contract check, --all only: AGENTS.md is written once and\n // never refreshed (the ownership contract), so the one thing the\n // docs-repo-wide mode owes it is detection — a stamp older than the\n // binary means agents are branching on tables the binary no longer\n // honours. It grades the repo, not any service, so it rides on the\n // landscape target.\n const agentsPath = agentsFile(docsDir);\n const agentsText = existsSync(agentsPath) ? await readFile(agentsPath, \"utf8\") : null;\n const agents = agentsStaleFinding(agentsText, LOAM_VERSION);\n if (agents !== null) landscape.findings.push(agents);\n // The other direction, and the one that changes what a PASS means:\n // this binary predates the corpus, so a directive it cannot parse is\n // read as prose and produces no join to fail.\n const behind = binaryBehindFinding(agentsText, LOAM_VERSION);\n if (behind !== null) landscape.findings.push(behind);\n }\n targets.push(\n ...(await inOrder(services, (svc) =>\n guarded({ kind: \"service\", id: svc.id }, () =>\n validateService({\n docsDir,\n service: svc.id,\n repoDir: repoOf(svc.id),\n preloaded: land,\n gherkinDir: config.gherkinDir,\n contracts: config.contracts,\n fleet,\n landscapeReported: true,\n }),\n ),\n )),\n );\n targets.push(\n ...(await inOrder(features, (feat) =>\n guarded({ kind: \"feature\", id: feat.id }, () =>\n validateFeature(docsDir, feat, land, fleet),\n ),\n )),\n );\n } else if (opts.feature) {\n const feature = await resolveFeature(docsDir, opts.feature, \"exclude\", fleet);\n if (!feature) {\n fail(json, \"unknown-target\", await missingFeatureMessage(docsDir, opts.feature, fleet));\n return;\n }\n targets.push(\n await guarded({ kind: \"feature\", id: feature.id }, () =>\n validateFeature(docsDir, feature, undefined, fleet),\n ),\n );\n } else if (target !== undefined) {\n // The positional reads the way `show` reads one: try the feature first\n // (ids like FEAT-101 are distinctive, service names are arbitrary), then\n // the service. --service/--feature stay as the explicit spellings for a\n // name that could be both — and when both readings exist, the run says\n // so out loud instead of silently taking one (`target.ambiguous`).\n const feature = await resolveFeature(docsDir, target, \"exclude\", fleet);\n const isService = (await listServices(docsDir, fleet)).some((s) => s.id === target);\n if (feature) {\n resolvedKind = \"feature\";\n const report = await guarded({ kind: \"feature\", id: feature.id }, () =>\n validateFeature(docsDir, feature, undefined, fleet),\n );\n if (isService) report.findings.unshift(ambiguousTarget(target, \"feature\"));\n targets.push(report);\n } else {\n // Neither reading exists. An archived feature is its own diagnosis\n // (\"already archived\", not \"no such thing\"); anything else reads as a\n // service, so the did-you-mean hints in service.unknown fire.\n if (!isService && (await resolveFeature(docsDir, target, \"only\", fleet)) !== null) {\n fail(json, \"unknown-target\", await missingFeatureMessage(docsDir, target, fleet));\n return;\n }\n resolvedKind = \"service\";\n const resolved = await resolveServiceTarget(docsDir, target, \"target\", fleet);\n if (!resolved.ok) return fail(json, \"invalid-option\", resolved.problem);\n targets.push(await serviceTarget(resolved.id));\n }\n } else {\n const service = opts.service ?? config.service;\n if (!service) {\n fail(json, \"invalid-option\", NO_SERVICE_MESSAGE);\n return;\n }\n const resolved = await resolveServiceTarget(docsDir, service, \"--service\", fleet);\n if (!resolved.ok) return fail(json, \"invalid-option\", resolved.problem);\n targets.push(await serviceTarget(resolved.id));\n }\n } catch (err) {\n // The docs repo went away between the gate above and the enumeration.\n if (err instanceof DocsRepoUnavailableError) {\n reportDocsRepoError(json, err);\n return;\n }\n // An IO failure that `guarded` could not localise to one target — it\n // happened in the ENUMERATION, which reads every living spec's\n // frontmatter to build the service list. There is no partial report to\n // give: without the list, no service was checked, including the ones\n // that are fine. Say which file, and refuse; the one thing that must\n // not happen is a stack trace on stdout's sibling stream and an\n // `internal` envelope that names nothing.\n reportRepositoryUnavailable(\n json,\n err,\n \"the service list itself is unknown and nothing was validated\",\n docsDir,\n );\n return;\n }\n\n // By subject, not by finding — the rule lives with the rollup in report.ts.\n const unverifiable = unverifiableSubjects(targets);\n // A journal in the repo outranks everything graded above: the docs may\n // be half-merged, and in CI a green over them merges. Led, not appended\n // — it is the reason nothing below can be trusted — and attached to the\n // first target because a finding lives in one.\n const interrupted = await interruptedCommitFinding(docsDir);\n if (interrupted !== null && targets.length > 0) targets[0]!.findings.unshift(interrupted);\n\n // The fleet scorecard, --all only: recomputed per invocation off the same\n // memoized reads this run already made — loam stores no history — and it\n // fails closed per axis, never whole (fleet/scorecard/scorecard.ts).\n //\n // Suppressed under `--base`: its denominators are the graded targets, so\n // over a narrowed set it reads \"2 of 2 services documented\" for a fleet\n // where ten more are not — and its axes license report.ts's grouping,\n // which would drop real warnings because an unlooked-at axis reads zero.\n const scorecard =\n opts.all && scope === null\n ? await buildScorecard({ docsDir, targets, fleet, boundService: config.service })\n : null;\n\n const valid = reportValid(targets);\n const capped = targets.map(capDetails);\n if (json) {\n emitJson({\n command: \"validate\",\n valid,\n summary: summary(targets),\n ...(resolvedKind === undefined ? {} : { resolvedKind }),\n // What this run looked at. Only under `--base`, so an unscoped payload\n // is today's document and its ABSENCE says `summary` counts the whole\n // fleet — scopeJson has why a scoped one may not stay silent.\n ...(scope === null ? {} : { scope: scopeJson(scope) }),\n // Emitted in every mode now that it is derived per service: a\n // single-service run knows exactly as much about its own blind spot\n // as `--all` knows about the fleet's.\n sourcesUnverifiableFromHere: unverifiable,\n ...(scorecard === null ? {} : { scorecard }),\n // What to do about every code this run raised — the one thing the\n // payload could not previously answer. `validate` is step 1 of every\n // generated protocol and the command an agent reads first, and until\n // now it replied in prose: a finding names a code and says what is\n // wrong, and nothing in it said that `loam explain <code>` knows what\n // to do next.\n //\n // A top-level MAP, not a field on each finding, for the reason\n // report.ts's DETAIL_LIMIT gives about evidence: a hundred-service\n // fleet raising one code a hundred times would ship the same\n // sentence a hundred times, in the interface an agent pipes into a\n // context window. The consumer joins `findings[].code` to\n // `fixes[code]` — one lookup, no round trip, no repetition.\n //\n // Keyed ONLY by codes a non-`ok` finding raised. A confirmation has\n // nothing to fix, and on a clean fleet the `ok` codes are the\n // overwhelming majority of findings; attaching fixes to them would\n // pay the whole vocabulary's byte cost to tell a reader that nothing\n // is wrong. `targets` is read here rather than `capped` because\n // capping truncates evidence, not findings — the two raise the same\n // codes, and reading the uncapped set keeps this rollup computed off\n // the same targets as `summary()`.\n //\n // Not behind a flag, deliberately. It is additive, so no consumer\n // that ignores it is affected; it is small, because it carries only\n // the handful of codes this run actually raised rather than the\n // 227-row vocabulary; and a flag would mean an agent has to already\n // know the fixes exist in order to ask for them — which is the exact\n // gap being closed. It is emitted on a green run too, as `{}`, so a\n // consumer never has to branch on the key's presence before looking\n // a code up in it.\n fixes: fixesFor(\n targets.flatMap((t) => t.findings.filter((f) => f.severity !== \"ok\").map((f) => f.code)),\n ),\n targets: capped.map(targetJson),\n });\n } else {\n // The scope FIRST: a reader has to know what the report below is a\n // report ABOUT, and in the zero-target case there is nothing below at\n // all — printed after the findings, the one run that most needs words\n // would read as a green over the whole system.\n if (scope !== null) console.log(scopeLine(scope));\n renderText(capped, {\n all: opts.all === true,\n errorsOnly: opts.errorsOnly === true,\n unverifiable,\n scorecard,\n });\n if (scorecard !== null) printScorecard(scorecard);\n }\n // --strict is a per-invocation CI lever: it fails the run on any error or\n // warning (ok-severity confirmations never trip it — virtually every\n // clean target emits some), and changes nothing else — `valid` keeps meaning \"no\n // errors\" in text and JSON alike, so two pipelines reading the same repo\n // may grade the same report differently and both are telling the truth.\n const strictFailed =\n opts.strict === true &&\n countSeverity(targets, \"error\") + countSeverity(targets, \"warn\") > 0;\n if (!valid || strictFailed) process.exitCode = 1;\n });\n}\n\nexport { targetValid };\n"]}
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/commands/validate/validate.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam validate` — argument grammar, target selection, and the run's one\n * filesystem snapshot.\n *\n * The checks themselves live beside it, one module per target kind\n * (`landscape.ts`, `service/`, `feature/`) over the document checks they share\n * (`requirements.ts`). Every one of them produces findings and none of them\n * print: printing is `report.ts`'s, and it happens once, after the last target\n * is graded.\n */\nimport type { Command } from \"commander\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { agentsStaleFinding, binaryBehindFinding } from \"../../core/agent/agents-stamp.js\";\nimport { inOrder } from \"../../core/kernel/concurrency.js\";\nimport type { RawServiceId } from \"../../core/kernel/ids/service.js\";\nimport { resolveServiceTarget } from \"../../core/repo/service-target.js\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { emitJson, fail, NO_SERVICE_MESSAGE, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { agentsPath as agentsFile, landscapePath as landscapeFile } from \"../../core/repo/paths.js\";\nimport { listFeatures, listServices, missingFeatureMessage, resolveFeature } from \"../../core/repo/repo.js\";\nimport {\n countSeverity,\n reportValid,\n targetJson,\n targetValid,\n type TargetReport,\n} from \"../../core/vocabulary/report.js\";\nimport { LOAM_VERSION } from \"../../core/envelope/version.js\";\nimport { FleetContext } from \"../../core/fleet-context.js\";\nimport { fixesFor } from \"../policy/format.js\";\nimport {\n docsRepoReady,\n reportDocsRepoError,\n reportRepositoryUnavailable,\n} from \"../policy/gate.js\";\nimport { interruptedCommitFinding } from \"../../core/staging/recovery/finding.js\";\nimport { scopeJson, scopeLine, scopeSince, type ValidateScope } from \"../../core/diff/scope/changed-paths.js\";\nimport { validateLandscape } from \"./fleet/landscape.js\";\nimport { prefetchFleetDocuments, readLandscape } from \"./fleet/load.js\";\nimport { buildScorecard } from \"./fleet/scorecard/scorecard.js\";\nimport { printScorecard } from \"./fleet/scorecard/print.js\";\nimport { validateFeature } from \"./feature.js\";\nimport { validateService } from \"./service/service.js\";\nimport { ambiguousTarget, capDetails, guarded, renderText, summary, unverifiableSubjects } from \"./report.js\";\n\ninterface ValidateOptions {\n service?: string;\n feature?: string;\n all?: boolean;\n base?: string;\n strict?: boolean;\n errorsOnly?: boolean;\n json?: boolean;\n}\n\nexport function registerValidate(program: Command): void {\n program\n .command(\"validate\")\n .argument(\"[target]\", \"service or feature id (a feature wins when both match; --service/--feature force the reading)\")\n .description(\"Validate a service (C4 + requirement coverage) or a feature (delta + coverage)\")\n .option(\"--service <id>\", \"service to validate (defaults to the configured service)\")\n .option(\"--feature <id>\", \"validate a feature delta instead of a service\")\n .option(\"--all\", \"validate every service and every active feature\")\n .option(\"--base <ref>\", \"with --all: grade only the targets changed since a base git ref of the docs repo — the adoption ratchet\")\n .option(\"--strict\", \"exit 1 on any warning too — a per-invocation CI lever; the report and --json payload do not change\")\n .option(\"--errors-only\", \"print only errors and warnings — a rendering lever; the --json payload does not change\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (target: string | undefined, opts: ValidateOptions) => {\n const json = opts.json === true;\n\n if (target !== undefined && (opts.all || opts.service || opts.feature)) {\n fail(json, \"invalid-option\", `'${target}' already names the target; drop --all/--service/--feature.`);\n return;\n }\n if (opts.all && (opts.service || opts.feature)) {\n fail(json, \"invalid-option\", \"--all validates everything; drop --service/--feature.\");\n return;\n }\n // Two targets is no target: silently validating only the feature taught\n // callers that --service had been honoured when it had been dropped.\n if (opts.service && opts.feature) {\n fail(json, \"invalid-option\", \"--service and --feature name different targets; pass one or the other.\");\n return;\n }\n // `--base` NARROWS a whole-fleet run; it does not name one. Beside a\n // positional, `--service` or `--feature` it is a scope over a scope — a\n // contradiction rather than a narrowing, whose \"this service if it\n // changed\" reading nobody could tell apart from a green over a service\n // never looked at. `--base` and not `--since`: `--base <ref>` is already\n // loam's word for a base git ref of the docs repo on diff and vouch.\n if (opts.base !== undefined && opts.all !== true) {\n fail(\n json,\n \"invalid-option\",\n target !== undefined || opts.service || opts.feature\n ? \"--base narrows --all to what changed since a ref; a named target is already a scope. Pass one or the other.\"\n : \"--base narrows --all to what changed since a ref — pass --all with it.\",\n );\n return;\n }\n\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const config = loaded.config;\n const { docsDir } = config;\n // Before anything is enumerated: a docsDir that is not a docs repo must\n // refuse, not report an empty fleet. See docsRepoReady. `--feature` is the\n // one mode that never enumerates services, so it asks for less.\n if (!docsRepoReady(json, docsDir, opts.feature ? \"docs\" : \"services\")) return;\n // One invocation, one filesystem snapshot. Nothing is global: a later\n // command gets a fresh index and therefore cannot observe stale files.\n const fleet = new FleetContext();\n\n // `sources` are paths into a service's own repository, so they only mean\n // something when loam is standing in that repository — which is exactly\n // what loam.json's `service` records.\n const repoOf = (service: string): string | undefined =>\n config.service === service ? process.cwd() : undefined;\n\n /** One service target, from a name the enumeration or the grammar approved. */\n const serviceTarget = (id: RawServiceId): Promise<TargetReport> =>\n guarded({ kind: \"service\", id }, () =>\n validateService({ docsDir, service: id, repoDir: repoOf(id), gherkinDir: config.gherkinDir, contracts: config.contracts, fleet }),\n );\n\n const targets: TargetReport[] = [];\n /** What the positional argument turned out to name, for the JSON payload. */\n let resolvedKind: \"service\" | \"feature\" | undefined;\n /** The `--base` narrowing, once it is known. Null on every unscoped run — including every run without --base. */\n let scope: ValidateScope | null = null;\n\n try {\n if (opts.all) {\n // ONE workspace per document kind for the whole run — the block moved\n // to `fleet/load.ts` (`prefetchFleetDocuments`), which is where the\n // rule about which shape parses in which workspace belongs.\n const lp = landscapeFile(docsDir);\n const enumerated = await listServices(docsDir, fleet);\n const active = await listFeatures(docsDir, {}, fleet);\n // `--base` narrows the enumerations and nothing else: a kept target is\n // graded by exactly the checks `--all` would have run on it, at the\n // same severities, through the same `--strict`. It matches through the\n // ENUMERATIONS' own directories — changed-paths.ts says why a split\n // on \"/\" silently drops every filed service.\n if (opts.base !== undefined) {\n const narrowed = await scopeSince({ docsDir, ref: opts.base, services: enumerated, features: active });\n if (narrowed.kind === \"refused\") {\n fail(json, narrowed.code, narrowed.message);\n return;\n }\n scope = narrowed;\n }\n const services = scope === null ? enumerated : scope.services;\n const features = scope === null ? active : scope.features;\n await prefetchFleetDocuments({ docsDir, fleet, services, features });\n // Read whether or not the landscape is a TARGET: every service check\n // below joins against it, so a scoped run needs the map in hand even\n // when it does not grade the map itself. Through the fleet index, so\n // the single-service path — which now reads the same project — answers\n // out of the same memo rather than parsing it a second time.\n const land = existsSync(lp) ? await readLandscape(() => fleet.architecture(docsDir)) : null;\n // The fleet-level cross-check first: it frames everything below it, and a\n // service nobody drew is worth knowing before its own findings scroll past.\n // Under `--base` it is a target only when `architecture/` changed — the\n // landscape owns no service directory, so that is its whole footprint.\n if (scope === null || scope.landscape) {\n const landscape = await validateLandscape(docsDir, land, fleet);\n targets.push(landscape);\n // The agent contract check, --all only: AGENTS.md is written once and\n // never refreshed (the ownership contract), so the one thing the\n // docs-repo-wide mode owes it is detection — a stamp older than the\n // binary means agents are branching on tables the binary no longer\n // honours. It grades the repo, not any service, so it rides on the\n // landscape target.\n const agentsPath = agentsFile(docsDir);\n const agentsText = existsSync(agentsPath) ? await readFile(agentsPath, \"utf8\") : null;\n const agents = agentsStaleFinding(agentsText, LOAM_VERSION);\n if (agents !== null) landscape.findings.push(agents);\n // The other direction, and the one that changes what a PASS means:\n // this binary predates the corpus, so a directive it cannot parse is\n // read as prose and produces no join to fail.\n const behind = binaryBehindFinding(agentsText, LOAM_VERSION);\n if (behind !== null) landscape.findings.push(behind);\n }\n targets.push(\n ...(await inOrder(services, (svc) =>\n guarded({ kind: \"service\", id: svc.id }, () =>\n validateService({\n docsDir,\n service: svc.id,\n repoDir: repoOf(svc.id),\n preloaded: land,\n gherkinDir: config.gherkinDir,\n contracts: config.contracts,\n fleet,\n landscapeReported: true,\n }),\n ),\n )),\n );\n targets.push(\n ...(await inOrder(features, (feat) =>\n guarded({ kind: \"feature\", id: feat.id }, () =>\n validateFeature(docsDir, feat, land, fleet),\n ),\n )),\n );\n } else if (opts.feature) {\n const feature = await resolveFeature(docsDir, opts.feature, \"exclude\", fleet);\n if (!feature) {\n fail(json, \"unknown-target\", await missingFeatureMessage(docsDir, opts.feature, fleet));\n return;\n }\n targets.push(\n await guarded({ kind: \"feature\", id: feature.id }, () =>\n validateFeature(docsDir, feature, undefined, fleet),\n ),\n );\n } else if (target !== undefined) {\n // The positional reads the way `show` reads one: try the feature first\n // (ids like FEAT-101 are distinctive, service names are arbitrary), then\n // the service. --service/--feature stay as the explicit spellings for a\n // name that could be both — and when both readings exist, the run says\n // so out loud instead of silently taking one (`target.ambiguous`).\n const feature = await resolveFeature(docsDir, target, \"exclude\", fleet);\n const isService = (await listServices(docsDir, fleet)).some((s) => s.id === target);\n if (feature) {\n resolvedKind = \"feature\";\n const report = await guarded({ kind: \"feature\", id: feature.id }, () =>\n validateFeature(docsDir, feature, undefined, fleet),\n );\n if (isService) report.findings.unshift(ambiguousTarget(target, \"feature\"));\n targets.push(report);\n } else {\n // Neither reading exists. An archived feature is its own diagnosis\n // (\"already archived\", not \"no such thing\"); anything else reads as a\n // service, so the did-you-mean hints in service.unknown fire.\n if (!isService && (await resolveFeature(docsDir, target, \"only\", fleet)) !== null) {\n fail(json, \"unknown-target\", await missingFeatureMessage(docsDir, target, fleet));\n return;\n }\n resolvedKind = \"service\";\n const resolved = await resolveServiceTarget(docsDir, target, \"target\", fleet);\n if (!resolved.ok) return fail(json, \"invalid-option\", resolved.problem);\n targets.push(await serviceTarget(resolved.id));\n }\n } else {\n const service = opts.service ?? config.service;\n if (!service) {\n fail(json, \"invalid-option\", NO_SERVICE_MESSAGE);\n return;\n }\n const resolved = await resolveServiceTarget(docsDir, service, \"--service\", fleet);\n if (!resolved.ok) return fail(json, \"invalid-option\", resolved.problem);\n targets.push(await serviceTarget(resolved.id));\n }\n } catch (err) {\n // The docs repo went away between the gate above and the enumeration.\n if (err instanceof DocsRepoUnavailableError) {\n reportDocsRepoError(json, err);\n return;\n }\n // An IO failure that `guarded` could not localise to one target — it\n // happened in the ENUMERATION, which reads every living spec's\n // frontmatter to build the service list. There is no partial report to\n // give: without the list, no service was checked, including the ones\n // that are fine. Say which file, and refuse; the one thing that must\n // not happen is a stack trace on stdout's sibling stream and an\n // `internal` envelope that names nothing.\n reportRepositoryUnavailable(\n json,\n err,\n \"the service list itself is unknown and nothing was validated\",\n docsDir,\n );\n return;\n }\n\n // By subject, not by finding — the rule lives with the rollup in report.ts.\n const unverifiable = unverifiableSubjects(targets);\n // A journal in the repo outranks everything graded above: the docs may\n // be half-merged, and in CI a green over them merges. Led, not appended\n // — it is the reason nothing below can be trusted — and attached to the\n // first target because a finding lives in one.\n const interrupted = await interruptedCommitFinding(docsDir);\n if (interrupted !== null && targets.length > 0) targets[0]!.findings.unshift(interrupted);\n\n // The fleet scorecard, --all only: recomputed per invocation off the same\n // memoized reads this run already made — loam stores no history — and it\n // fails closed per axis, never whole (fleet/scorecard/scorecard.ts).\n //\n // Suppressed under `--base`: its denominators are the graded targets, so\n // over a narrowed set it reads \"2 of 2 services documented\" for a fleet\n // where ten more are not — and its axes license report.ts's grouping,\n // which would drop real warnings because an unlooked-at axis reads zero.\n const scorecard =\n opts.all && scope === null\n ? await buildScorecard({ docsDir, targets, fleet, boundService: config.service })\n : null;\n\n const valid = reportValid(targets);\n const capped = targets.map(capDetails);\n if (json) {\n emitJson({\n command: \"validate\",\n valid,\n summary: summary(targets),\n ...(resolvedKind === undefined ? {} : { resolvedKind }),\n // What this run looked at. Only under `--base`, so an unscoped payload\n // is today's document and its ABSENCE says `summary` counts the whole\n // fleet — scopeJson has why a scoped one may not stay silent.\n ...(scope === null ? {} : { scope: scopeJson(scope) }),\n // Emitted in every mode now that it is derived per service: a\n // single-service run knows exactly as much about its own blind spot\n // as `--all` knows about the fleet's.\n sourcesUnverifiableFromHere: unverifiable,\n ...(scorecard === null ? {} : { scorecard }),\n // What to do about every code this run raised — the one thing the\n // payload could not previously answer. `validate` is step 1 of every\n // generated protocol and the command an agent reads first, and until\n // now it replied in prose: a finding names a code and says what is\n // wrong, and nothing in it said that `loam explain <code>` knows what\n // to do next.\n //\n // A top-level MAP, not a field on each finding, for the reason\n // report.ts's DETAIL_LIMIT gives about evidence: a hundred-service\n // fleet raising one code a hundred times would ship the same\n // sentence a hundred times, in the interface an agent pipes into a\n // context window. The consumer joins `findings[].code` to\n // `fixes[code]` — one lookup, no round trip, no repetition.\n //\n // Keyed ONLY by codes a non-`ok` finding raised. A confirmation has\n // nothing to fix, and on a clean fleet the `ok` codes are the\n // overwhelming majority of findings; attaching fixes to them would\n // pay the whole vocabulary's byte cost to tell a reader that nothing\n // is wrong. `targets` is read here rather than `capped` because\n // capping truncates evidence, not findings — the two raise the same\n // codes, and reading the uncapped set keeps this rollup computed off\n // the same targets as `summary()`.\n //\n // Not behind a flag, deliberately. It is additive, so no consumer\n // that ignores it is affected; it is small, because it carries only\n // the handful of codes this run actually raised rather than the\n // 227-row vocabulary; and a flag would mean an agent has to already\n // know the fixes exist in order to ask for them — which is the exact\n // gap being closed. It is emitted on a green run too, as `{}`, so a\n // consumer never has to branch on the key's presence before looking\n // a code up in it.\n fixes: fixesFor(\n targets.flatMap((t) => t.findings.filter((f) => f.severity !== \"ok\").map((f) => f.code)),\n ),\n targets: capped.map(targetJson),\n });\n } else {\n // The scope FIRST: a reader has to know what the report below is a\n // report ABOUT, and in the zero-target case there is nothing below at\n // all — printed after the findings, the one run that most needs words\n // would read as a green over the whole system.\n if (scope !== null) console.log(scopeLine(scope));\n renderText(capped, {\n all: opts.all === true,\n errorsOnly: opts.errorsOnly === true,\n unverifiable,\n scorecard,\n });\n if (scorecard !== null) printScorecard(scorecard);\n }\n // --strict is a per-invocation CI lever: it fails the run on any error or\n // warning (ok-severity confirmations never trip it — virtually every\n // clean target emits some), and changes nothing else — `valid` keeps meaning \"no\n // errors\" in text and JSON alike, so two pipelines reading the same repo\n // may grade the same report differently and both are telling the truth.\n const strictFailed =\n opts.strict === true &&\n countSeverity(targets, \"error\") + countSeverity(targets, \"warn\") > 0;\n if (!valid || strictFailed) process.exitCode = 1;\n });\n}\n\nexport { targetValid };\n"]}
|
|
@@ -46,6 +46,7 @@ services/<svc>/
|
|
|
46
46
|
arch.spec.md its living ARCHITECTURE requirements (outbox, retries, alerts)
|
|
47
47
|
openapi.yaml its API contract
|
|
48
48
|
asyncapi.yaml its AsyncAPI 3 event contract
|
|
49
|
+
usecases/<name>.likec4 optional flows INSIDE this boundary — dynamic views over its containers, graded when tagged #req- (any .likec4 beside model.likec4 is read the same way)
|
|
49
50
|
adrs/ runbook.md health.yaml why it is like this, how to run it
|
|
50
51
|
features/<FEAT>/ a change in flight
|
|
51
52
|
intent.md why, in business terms
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqMxB,CAAC","sourcesContent":["/**\n * The document's opening arc: what the docs repo HOLDS — the layout, how its\n * documents link to each other, the glossary, architectural obligations, and\n * the `loam.json` wiring every repository commits.\n *\n * The three sections that used to close this file — the architecture spec\n * axis, the generated Gherkin suite, and the frontmatter/vouch chain — are now\n * the `loam-authoring` reference page (../workflows/reference/authoring.ts),\n * printed by `loam instructions loam-authoring` rather than written into\n * AGENTS.md. They are grammars consulted while writing ONE document, and the\n * file they were in is auto-loaded on every session by hosts that truncate it\n * silently; ./command-map.ts's header carries the measurement that decided it.\n * What is left here is what an agent must know before it can form a question\n * at all.\n *\n * One section of the AGENTS.md template. ../agents-md.ts assembles the\n * document by PLAIN CONCATENATION — no join separator — so every section\n * starts at the first character of its opening line and ends with the newline\n * that closes its last one. Keep that shape when editing, or two sections glue\n * onto one line in every docs repo loam scaffolds from now on.\n */\nexport const ARTIFACTS = `# Working in this docs repo\n\nThis is a **loam** docs repo: the shared source of truth for a governed software\nsystem — its architecture, requirements, contracts and evidence. Everything here\nis plain files. \\`loam\\` reads and writes them; delete \\`loam\\` and the docs remain.\n\n**The bar this artifact set aims at is reproducibility**: a reader should be able\nto answer, from these files alone — what each governed boundary exposes, what it\nreaches, what shapes it exchanges, how it is run, and what pages whom —\nwithout opening the code. \\`loam validate\\` grades form and joins, never depth:\ngreen means the files agree with each other, and the bar is what \"done\" is\nmeasured against — a thin baseline that validates is thin, not done.\n\n## Layout\n\n\\`\\`\\`\narchitecture/landscape.likec4 the living C4 model of the whole system\narchitecture/permissions.yaml optional system-wide authorization vocabulary\narchitecture/obligations.yaml optional ARCHITECTURAL obligations (#obl-<name> on the map)\narchitecture/adrs/NNNN-*.md optional SYSTEM-level decisions (MADR) — only their links are graded\nglossary/<term>.md optional domain vocabulary — one file per term, nesting allowed\nservices/<svc>/\n model.likec4 this governed boundary's C4\n spec.md its living requirements (current state)\n arch.spec.md its living ARCHITECTURE requirements (outbox, retries, alerts)\n openapi.yaml its API contract\n asyncapi.yaml its AsyncAPI 3 event contract\n adrs/ runbook.md health.yaml why it is like this, how to run it\nfeatures/<FEAT>/ a change in flight\n intent.md why, in business terms\n delta.likec4 the architecture change, tagged #<FEAT>\n specs/<svc>/spec.md the requirement change for one governed boundary\n specs/<svc>/arch.spec.md the architectural requirement change, same delta grammar\n specs/<svc>/openapi.yaml the endpoints this feature adds\n specs/<svc>/asyncapi.yaml the event-contract delta (optional; a complete AsyncAPI 3 document)\n verification.yaml what was checked once the code was built\nfeatures/archive/<FEAT>/ shipped changes — the evolution history\n\\`\\`\\`\n\n## Linking between documents\n\nDocuments here link to each other with **standard markdown links**, and the\ntarget is a relative path to the file:\n\n\\`\\`\\`markdown\n[0001 — transactional outbox](../../architecture/adrs/0001-transactional-outbox.md)\n\\`\\`\\`\n\nTwo reasons, and the second is the one that decides it. A markdown link renders\nas a link in pull-request review, which is where these documents are actually\nread, while \\`[[0001 transactional outbox]]\\` renders there as the literal\nbrackets somebody typed. And its target is a real relative path, so \"does this\nlink resolve\" is a filesystem question with a yes-or-no answer — where resolving\na wikilink means reimplementing Obsidian's shortest-unique-path search across the\nwhole repo, which is guessing, and loam refuses and names rather than guessing.\n\nYou lose nothing by it. Obsidian reads a repo written this way with no\nintegration at all — graph view, backlinks and search all work on markdown links\n— and its per-vault \\`Use [[Wikilinks]]\\` setting turns OFF, after which its own\nautocomplete and rename-tracking produce markdown links too. The authoring\ncomfort is a toggle in somebody's editor, not a decision this repo carries.\n\n**\\`loam validate\\` resolves these links** (\\`link.unresolved\\`, error): a relative\ntarget that names nothing is a broken join, reported once per document with\nevery bad link and its line. A link here is a **join**, not decoration — a\nrequirement that names a term wants that term's document linked, and an ADR that\nsupersedes another wants to say which, the same kind of relationship\n\\`Operations:\\` and \\`Covers:\\` already state.\n\nThree things are deliberately NOT graded, so write them freely: a target outside\nthis repository (\\`../../some-service/README.md\\` — that tree may not be checked\nout beside these documents), a link to a heading (\\`#section\\`), and any link\ninside a fenced code block or an inline code span, which is how a document shows\nthe convention without being convicted for it.\n\nCASE **is** graded, and deliberately: \\`[Order](Order.md)\\` beside a file called\n\\`order.md\\` resolves on Windows and macOS and 404s on GitHub and every Linux\nrunner, so the message names the stored spelling on all of them alike.\n\n## The glossary — the system's domain words\n\n\\`glossary/<term>.md\\`, one file per term, nesting allowed\n(\\`glossary/payments/authorization.md\\` is the term \\`payments/authorization\\`). There is\nno \\`glossary.yaml\\`: a definition is prose, and the DIRECTORY is the list. The\ndirectory's existence is the opt-in — a system without one hears nothing.\n\n**A term is checkable because a link is a join.** Cite it from the document that\nuses the word — a requirement, a capability document, a feature's intent — with an\nordinary relative link:\n\n\\`\\`\\`markdown\nAn [Order](../../glossary/order.md) is what a customer has confirmed.\n\\`\\`\\`\n\nA citation that does not resolve is \\`link.unresolved\\` like any other; a term nothing\noutside \\`glossary/\\` cites is \\`glossary.unlinked\\` (warn). Terms citing each other is\nnormal and does NOT count as adoption — a glossary is a network of definitions, and\ntwo terms defining each other say nothing about whether the system uses either word.\n\\`loam list glossary\\` prints every term with the documents that cite it.\n\n**A feature may bring a new word with it**: write it at\n\\`features/<FEAT>/glossary/<term>.md\\` and \\`loam archive\\` copies it into \\`glossary/\\`,\n\\`loam unarchive\\` takes it back out. This route is CREATE-ONLY — a term the living\nglossary already defines is \\`glossary.term-exists\\`, which \\`--approve\\` does not\noverride, because the merge is a whole-file copy and would replace an authored\ndefinition wholesale. To CHANGE a definition, edit \\`glossary/<term>.md\\` directly in\nthe same pull request, where git produces an ordinary conflict.\n\nCite the new word at its FUTURE living path (\\`../../../../glossary/order.md\\` from a\n\\`specs/<svc>/\\` delta) — that link resolves while the feature is in flight, and the\nmerge re-expresses it from wherever the text lands, so it keeps resolving afterwards.\n\nWrite the definition for a reader who knows the business and not this system: what the\nword means, and what it is NOT (an order is not a cart). Never which service owns it —\nthat is the system map's question and it changes.\n\n\n## Architectural obligations — what the architect hands the team\n\nAn architect has always had one checked channel here: an edge carrying\n\\`metadata { op 'authorizePayment' }\\` obliges the provider to define that operationId,\nor \\`spine.op-undefined\\` fails the gate. Obligations are the same handoff for the rules\nthat VARY — an outbox on this publisher and not that one, a circuit breaker on two\nedges out of five — and they are three separate things on purpose:\n\n- an **ADR** in \\`architecture/adrs/\\` says WHAT was decided, as thin or as thick as the\n decision needs;\n- a **\\`#obl-<name>\\` tag** on an element or an edge in \\`architecture/landscape.likec4\\`\n says WHERE it applies, so one ADR governs three edges and not the fourth without the\n document forking;\n- **\\`architecture/obligations.yaml\\`** declares the names, so a mistyped tag is an error\n rather than a word nobody notices.\n\n\\`\\`\\`yaml\nobligations:\n outbox:\n description: Publishers write the event and the state change in one transaction.\n adr: architecture/adrs/0001-transactional-outbox.md # relative to the docs repo root\n\\`\\`\\`\n\n**Your side of it is \\`Covers:\\`**. A tagged object with no living requirement covering it\nis \\`obligation.uncovered\\` (warn), and the finding names the service, the object and the\nexact line to write — \\`Covers: <element>\\` or \\`Covers: <source> -> <target>\\` in that\nservice's \\`arch.spec.md\\`, with a scenario that proves it. An id is its own tag suffix,\nso it may hold letters, digits, \\`_\\` and \\`-\\` only.\n\n## \\`loam.json\\` — the wiring, in every repo\n\nA governed system is **N + 1 repositories**: this docs repo, and one per governed\nimplementation boundary. Paths and commands call that boundary a \\`service\\`; it\nmay be a modular monolith, a network service, a CLI or a worker. Every repo\ncommits its own \\`loam.json\\`, so an agent, human or CI runner can find the rest\nof the system. There is no global config; without a \\`loam.json\\`, commands refuse\nwith \\`no-config\\` rather than guessing.\n\n\\`\\`\\`json\n{ \"docsDir\": \"../docs-repo\", \"service\": \"payment-service\", \"gherkinDir\": \"features\" }\n\\`\\`\\`\n\n- \\`docsDir\\` — where the docs repo is, **stored exactly as it was passed** and\n resolved against the directory holding the \\`loam.json\\`. So \\`../docs-repo\\`\n keeps working on every machine that checks the repos out side by side, which\n is the point of committing the file. An absolute path is a warning\n (\\`doctor.docs-absolute\\`): it resolves only on the machine that ran \\`loam init\\`.\n The docs repo's own \\`loam.json\\` says \\`\"docsDir\": \".\"\\`.\n- \\`service\\` — the canonical id of the governed boundary THIS repo contains, i.e. the\n \\`services/<id>/\\` directory it is allowed to speak for. \\`loam vouch\\`,\n \\`loam gherkin\\` and \\`loam verify --service\\` when writing with \\`--record\\`,\n \\`--results\\` or \\`--contract-results\\` bind to it; without it they refuse\n (\\`repository-unavailable\\`) rather than write another boundary's documents\n from a repo that is not that boundary's. A read-only verify checklist needs no\n binding and works from the docs repo.\n- \\`gherkinDir\\` — optional, default \\`features\\`: the directory \\`loam gherkin\\`\n writes its own \\`loam/\\` subtree into.\n- \\`agentTools\\` — optional: the agent tools \\`loam init\\` has written command and\n skill files for here, accumulated across runs. Written by \\`init\\`, read by\n \\`loam doctor\\`; nothing else depends on it, and a config without it loads.\n\n**Step 0 of everything below, once per repo:**\n\n\\`\\`\\`sh\nloam init --docs ../docs-repo --service payment-service # in EACH service repo\nloam doctor # before you trust any of it\n\\`\\`\\`\n\n\\`loam init --docs <dir>\\` **joins** an existing docs repo; creating a new one\ntakes \\`--create\\`, so a mistyped path cannot quietly scaffold a second source of\ntruth beside the real one. \\`loam doctor\\` is the read-only preflight: it reads\nloam.json defensively, resolves \\`docsDir\\`, probes access, checks \\`services/\\` and\nthe system map, and reports the service binding — run it first when anything\nbehaves as though the system were empty.\n\n**Living vs delta.** \\`services/<svc>/spec.md\\` is the complete current state.\n\\`features/<FEAT>/specs/<svc>/spec.md\\` is a diff against it, reviewed as a diff, with\nrequirements grouped under \\`## ADDED\\`, \\`## MODIFIED\\` or \\`## REMOVED Requirements\\`.\n\\`loam archive\\` folds the delta into the living state.\n\n`;\n"]}
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsMxB,CAAC","sourcesContent":["/**\n * The document's opening arc: what the docs repo HOLDS — the layout, how its\n * documents link to each other, the glossary, architectural obligations, and\n * the `loam.json` wiring every repository commits.\n *\n * The three sections that used to close this file — the architecture spec\n * axis, the generated Gherkin suite, and the frontmatter/vouch chain — are now\n * the `loam-authoring` reference page (../workflows/reference/authoring.ts),\n * printed by `loam instructions loam-authoring` rather than written into\n * AGENTS.md. They are grammars consulted while writing ONE document, and the\n * file they were in is auto-loaded on every session by hosts that truncate it\n * silently; ./command-map.ts's header carries the measurement that decided it.\n * What is left here is what an agent must know before it can form a question\n * at all.\n *\n * One section of the AGENTS.md template. ../agents-md.ts assembles the\n * document by PLAIN CONCATENATION — no join separator — so every section\n * starts at the first character of its opening line and ends with the newline\n * that closes its last one. Keep that shape when editing, or two sections glue\n * onto one line in every docs repo loam scaffolds from now on.\n */\nexport const ARTIFACTS = `# Working in this docs repo\n\nThis is a **loam** docs repo: the shared source of truth for a governed software\nsystem — its architecture, requirements, contracts and evidence. Everything here\nis plain files. \\`loam\\` reads and writes them; delete \\`loam\\` and the docs remain.\n\n**The bar this artifact set aims at is reproducibility**: a reader should be able\nto answer, from these files alone — what each governed boundary exposes, what it\nreaches, what shapes it exchanges, how it is run, and what pages whom —\nwithout opening the code. \\`loam validate\\` grades form and joins, never depth:\ngreen means the files agree with each other, and the bar is what \"done\" is\nmeasured against — a thin baseline that validates is thin, not done.\n\n## Layout\n\n\\`\\`\\`\narchitecture/landscape.likec4 the living C4 model of the whole system\narchitecture/permissions.yaml optional system-wide authorization vocabulary\narchitecture/obligations.yaml optional ARCHITECTURAL obligations (#obl-<name> on the map)\narchitecture/adrs/NNNN-*.md optional SYSTEM-level decisions (MADR) — only their links are graded\nglossary/<term>.md optional domain vocabulary — one file per term, nesting allowed\nservices/<svc>/\n model.likec4 this governed boundary's C4\n spec.md its living requirements (current state)\n arch.spec.md its living ARCHITECTURE requirements (outbox, retries, alerts)\n openapi.yaml its API contract\n asyncapi.yaml its AsyncAPI 3 event contract\n usecases/<name>.likec4 optional flows INSIDE this boundary — dynamic views over its containers, graded when tagged #req- (any .likec4 beside model.likec4 is read the same way)\n adrs/ runbook.md health.yaml why it is like this, how to run it\nfeatures/<FEAT>/ a change in flight\n intent.md why, in business terms\n delta.likec4 the architecture change, tagged #<FEAT>\n specs/<svc>/spec.md the requirement change for one governed boundary\n specs/<svc>/arch.spec.md the architectural requirement change, same delta grammar\n specs/<svc>/openapi.yaml the endpoints this feature adds\n specs/<svc>/asyncapi.yaml the event-contract delta (optional; a complete AsyncAPI 3 document)\n verification.yaml what was checked once the code was built\nfeatures/archive/<FEAT>/ shipped changes — the evolution history\n\\`\\`\\`\n\n## Linking between documents\n\nDocuments here link to each other with **standard markdown links**, and the\ntarget is a relative path to the file:\n\n\\`\\`\\`markdown\n[0001 — transactional outbox](../../architecture/adrs/0001-transactional-outbox.md)\n\\`\\`\\`\n\nTwo reasons, and the second is the one that decides it. A markdown link renders\nas a link in pull-request review, which is where these documents are actually\nread, while \\`[[0001 transactional outbox]]\\` renders there as the literal\nbrackets somebody typed. And its target is a real relative path, so \"does this\nlink resolve\" is a filesystem question with a yes-or-no answer — where resolving\na wikilink means reimplementing Obsidian's shortest-unique-path search across the\nwhole repo, which is guessing, and loam refuses and names rather than guessing.\n\nYou lose nothing by it. Obsidian reads a repo written this way with no\nintegration at all — graph view, backlinks and search all work on markdown links\n— and its per-vault \\`Use [[Wikilinks]]\\` setting turns OFF, after which its own\nautocomplete and rename-tracking produce markdown links too. The authoring\ncomfort is a toggle in somebody's editor, not a decision this repo carries.\n\n**\\`loam validate\\` resolves these links** (\\`link.unresolved\\`, error): a relative\ntarget that names nothing is a broken join, reported once per document with\nevery bad link and its line. A link here is a **join**, not decoration — a\nrequirement that names a term wants that term's document linked, and an ADR that\nsupersedes another wants to say which, the same kind of relationship\n\\`Operations:\\` and \\`Covers:\\` already state.\n\nThree things are deliberately NOT graded, so write them freely: a target outside\nthis repository (\\`../../some-service/README.md\\` — that tree may not be checked\nout beside these documents), a link to a heading (\\`#section\\`), and any link\ninside a fenced code block or an inline code span, which is how a document shows\nthe convention without being convicted for it.\n\nCASE **is** graded, and deliberately: \\`[Order](Order.md)\\` beside a file called\n\\`order.md\\` resolves on Windows and macOS and 404s on GitHub and every Linux\nrunner, so the message names the stored spelling on all of them alike.\n\n## The glossary — the system's domain words\n\n\\`glossary/<term>.md\\`, one file per term, nesting allowed\n(\\`glossary/payments/authorization.md\\` is the term \\`payments/authorization\\`). There is\nno \\`glossary.yaml\\`: a definition is prose, and the DIRECTORY is the list. The\ndirectory's existence is the opt-in — a system without one hears nothing.\n\n**A term is checkable because a link is a join.** Cite it from the document that\nuses the word — a requirement, a capability document, a feature's intent — with an\nordinary relative link:\n\n\\`\\`\\`markdown\nAn [Order](../../glossary/order.md) is what a customer has confirmed.\n\\`\\`\\`\n\nA citation that does not resolve is \\`link.unresolved\\` like any other; a term nothing\noutside \\`glossary/\\` cites is \\`glossary.unlinked\\` (warn). Terms citing each other is\nnormal and does NOT count as adoption — a glossary is a network of definitions, and\ntwo terms defining each other say nothing about whether the system uses either word.\n\\`loam list glossary\\` prints every term with the documents that cite it.\n\n**A feature may bring a new word with it**: write it at\n\\`features/<FEAT>/glossary/<term>.md\\` and \\`loam archive\\` copies it into \\`glossary/\\`,\n\\`loam unarchive\\` takes it back out. This route is CREATE-ONLY — a term the living\nglossary already defines is \\`glossary.term-exists\\`, which \\`--approve\\` does not\noverride, because the merge is a whole-file copy and would replace an authored\ndefinition wholesale. To CHANGE a definition, edit \\`glossary/<term>.md\\` directly in\nthe same pull request, where git produces an ordinary conflict.\n\nCite the new word at its FUTURE living path (\\`../../../../glossary/order.md\\` from a\n\\`specs/<svc>/\\` delta) — that link resolves while the feature is in flight, and the\nmerge re-expresses it from wherever the text lands, so it keeps resolving afterwards.\n\nWrite the definition for a reader who knows the business and not this system: what the\nword means, and what it is NOT (an order is not a cart). Never which service owns it —\nthat is the system map's question and it changes.\n\n\n## Architectural obligations — what the architect hands the team\n\nAn architect has always had one checked channel here: an edge carrying\n\\`metadata { op 'authorizePayment' }\\` obliges the provider to define that operationId,\nor \\`spine.op-undefined\\` fails the gate. Obligations are the same handoff for the rules\nthat VARY — an outbox on this publisher and not that one, a circuit breaker on two\nedges out of five — and they are three separate things on purpose:\n\n- an **ADR** in \\`architecture/adrs/\\` says WHAT was decided, as thin or as thick as the\n decision needs;\n- a **\\`#obl-<name>\\` tag** on an element or an edge in \\`architecture/landscape.likec4\\`\n says WHERE it applies, so one ADR governs three edges and not the fourth without the\n document forking;\n- **\\`architecture/obligations.yaml\\`** declares the names, so a mistyped tag is an error\n rather than a word nobody notices.\n\n\\`\\`\\`yaml\nobligations:\n outbox:\n description: Publishers write the event and the state change in one transaction.\n adr: architecture/adrs/0001-transactional-outbox.md # relative to the docs repo root\n\\`\\`\\`\n\n**Your side of it is \\`Covers:\\`**. A tagged object with no living requirement covering it\nis \\`obligation.uncovered\\` (warn), and the finding names the service, the object and the\nexact line to write — \\`Covers: <element>\\` or \\`Covers: <source> -> <target>\\` in that\nservice's \\`arch.spec.md\\`, with a scenario that proves it. An id is its own tag suffix,\nso it may hold letters, digits, \\`_\\` and \\`-\\` only.\n\n## \\`loam.json\\` — the wiring, in every repo\n\nA governed system is **N + 1 repositories**: this docs repo, and one per governed\nimplementation boundary. Paths and commands call that boundary a \\`service\\`; it\nmay be a modular monolith, a network service, a CLI or a worker. Every repo\ncommits its own \\`loam.json\\`, so an agent, human or CI runner can find the rest\nof the system. There is no global config; without a \\`loam.json\\`, commands refuse\nwith \\`no-config\\` rather than guessing.\n\n\\`\\`\\`json\n{ \"docsDir\": \"../docs-repo\", \"service\": \"payment-service\", \"gherkinDir\": \"features\" }\n\\`\\`\\`\n\n- \\`docsDir\\` — where the docs repo is, **stored exactly as it was passed** and\n resolved against the directory holding the \\`loam.json\\`. So \\`../docs-repo\\`\n keeps working on every machine that checks the repos out side by side, which\n is the point of committing the file. An absolute path is a warning\n (\\`doctor.docs-absolute\\`): it resolves only on the machine that ran \\`loam init\\`.\n The docs repo's own \\`loam.json\\` says \\`\"docsDir\": \".\"\\`.\n- \\`service\\` — the canonical id of the governed boundary THIS repo contains, i.e. the\n \\`services/<id>/\\` directory it is allowed to speak for. \\`loam vouch\\`,\n \\`loam gherkin\\` and \\`loam verify --service\\` when writing with \\`--record\\`,\n \\`--results\\` or \\`--contract-results\\` bind to it; without it they refuse\n (\\`repository-unavailable\\`) rather than write another boundary's documents\n from a repo that is not that boundary's. A read-only verify checklist needs no\n binding and works from the docs repo.\n- \\`gherkinDir\\` — optional, default \\`features\\`: the directory \\`loam gherkin\\`\n writes its own \\`loam/\\` subtree into.\n- \\`agentTools\\` — optional: the agent tools \\`loam init\\` has written command and\n skill files for here, accumulated across runs. Written by \\`init\\`, read by\n \\`loam doctor\\`; nothing else depends on it, and a config without it loads.\n\n**Step 0 of everything below, once per repo:**\n\n\\`\\`\\`sh\nloam init --docs ../docs-repo --service payment-service # in EACH service repo\nloam doctor # before you trust any of it\n\\`\\`\\`\n\n\\`loam init --docs <dir>\\` **joins** an existing docs repo; creating a new one\ntakes \\`--create\\`, so a mistyped path cannot quietly scaffold a second source of\ntruth beside the real one. \\`loam doctor\\` is the read-only preflight: it reads\nloam.json defensively, resolves \\`docsDir\\`, probes access, checks \\`services/\\` and\nthe system map, and reports the service binding — run it first when anything\nbehaves as though the system were empty.\n\n**Living vs delta.** \\`services/<svc>/spec.md\\` is the complete current state.\n\\`features/<FEAT>/specs/<svc>/spec.md\\` is a diff against it, reviewed as a diff, with\nrequirements grouped under \\`## ADDED\\`, \\`## MODIFIED\\` or \\`## REMOVED Requirements\\`.\n\\`loam archive\\` folds the delta into the living state.\n\n`;\n"]}
|
|
@@ -163,6 +163,7 @@ The map:
|
|
|
163
163
|
`;
|
|
164
164
|
const MAP_REST = `- \`loam validate --service <id>\` grades one service's own axes: \`service.unknown\`,
|
|
165
165
|
\`service.no-model\`, \`service.no-spec\`, \`service.no-openapi\`, \`c4.invalid\`,
|
|
166
|
+
\`c4.declaration-diverged\`, \`c4.element-unowned\`,
|
|
166
167
|
\`c4.no-relationships\`, \`requirements.missing-scenarios\`,
|
|
167
168
|
\`requirements.stepless-scenario\`, \`requirements.assertionless-scenario\`,
|
|
168
169
|
\`requirements.examples-unbound\`, \`requirements.examples-unreferenced\`,
|
|
@@ -220,9 +221,21 @@ const MAP_REST = `- \`loam validate --service <id>\` grades one service's own ax
|
|
|
220
221
|
\`landscape.platform-candidate\`, \`landscape.datastore-private\` and
|
|
221
222
|
\`landscape.datastore-shared\`, \`service.id-invalid\` (fleet scope only, and
|
|
222
223
|
graded before the map is opened, so it stands even when the landscape is
|
|
223
|
-
missing or unreadable),
|
|
224
|
-
|
|
225
|
-
|
|
224
|
+
missing or unreadable), the four renderer-wiring warnings a
|
|
225
|
+
\`loam subsystem sync\` repairs — \`service.likec4-config-missing\` (a model that
|
|
226
|
+
STANDS ALONE, declaring its own \`specification\`, with no
|
|
227
|
+
\`likec4.config.json\` beside it: it renders nowhere from the docs root),
|
|
228
|
+
\`service.likec4-config-stray\` (that file beside a model that EXTENDS the map,
|
|
229
|
+
where it registers a project that CLAIMS the model, out of the root project
|
|
230
|
+
where the map's kinds are),
|
|
231
|
+
\`service.model-excluded\` (the root \`likec4.config.json\` excludes an extending
|
|
232
|
+
model's directory, so the renderer never loads it) and
|
|
233
|
+
\`service.model-unexcluded\` (it does NOT exclude a standalone model's, so the
|
|
234
|
+
renderer merges that model into the map and calls every declaration a
|
|
235
|
+
duplicate) — plus \`c4.fleet-project-invalid\` (warn: every document reads clean
|
|
236
|
+
where loam grades it and the ONE project the renderer builds out of the map and
|
|
237
|
+
every extending model does not, because something is declared in two of them),
|
|
238
|
+
a per-service \`sources.unverifiable-from-here\`, and
|
|
226
239
|
one check on the docs repo's own AGENTS.md, \`agents.stale\`. That last one is
|
|
227
240
|
the reason to distrust THAT file rather than this page: it fires when its
|
|
228
241
|
version stamp on line 1 (\`<!-- generated by loam vX.Y.Z -->\`) is missing or
|
|
@@ -302,7 +315,8 @@ const MAP_REST = `- \`loam validate --service <id>\` grades one service's own ax
|
|
|
302
315
|
"who calls whom" is the one thing no generator can read off a repository.
|
|
303
316
|
The seeded landscape carries a line-1 stamp; while it stands unedited,
|
|
304
317
|
editing fleet.yaml and re-running regenerates the map, and the first hand
|
|
305
|
-
edit
|
|
318
|
+
edit anywhere in the file, including above the stub, makes it yours — seed
|
|
319
|
+
then refuses \`seed-landscape-edited\`
|
|
306
320
|
rather than overwrite. Then adopt each service: \`loam adopt --service <id>\`.
|
|
307
321
|
- \`loam instructions [<page>] [args...]\` prints one of the six workflow
|
|
308
322
|
protocols — \`loam-adopt\`, \`loam-feature\`, \`loam-implement\`, \`loam-check\`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"command-map.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/command-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuB7B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B9B,CAAC;AAEF;;;GAGG;AACH,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BjB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2JhB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC","sourcesContent":["/**\n * Reading loam's output, in its two deliveries.\n *\n * {@link READING_OUTPUT} and {@link REFERENCE_PAGES} are what AGENTS.md keeps:\n * the `--json` envelope, the rule to branch on codes rather than prose, and the\n * index of the pages this file no longer carries. {@link CODE_MAP} is the\n * code-by-code map of `status`, `validate`, `doctor`, `rebase`, `dependencies`,\n * `explore`, `seed` and `instructions` — the part `loam instructions loam-codes`\n * prints. ../workflows/reference/codes.ts composes it with `./map/`,\n * `./map/lenses/` and `./refusals.ts`, in exactly the order ../agents-md.ts used\n * to concatenate them, so the assembled page is the section byte for byte.\n *\n * WHY THE MAP LEFT THE FILE, given that this package's whole subject is a file.\n * AGENTS.md is auto-loaded from the working directory by every agents.md-aware\n * host, on every session, and `loam init` writes it once and never refreshes it.\n * It reached 109,399 bytes; Codex truncates the AGENTS.md chain at 32,768 bytes\n * and Windsurf caps a workspace rule file at 12,000 characters, both silently.\n * Roughly seventy percent of the document was being dropped with no error and no\n * way for the reader to tell which half it held — and this section alone was\n * 44,433 of those bytes, 41% of the file. It is also the half a reader consults\n * at a moment it can name (a run reported something) rather than the half it\n * needs to form a question at all, which is what decided which side of the split\n * it went. ../workflows/reference/reference.ts carries the rest of that argument.\n *\n * The move is a move and not a deletion: every byte is still shipped, still in\n * the same corpus test/codes-drift.test.ts reads (AGENTS_MD + PROTOCOLS), and\n * still one command away rather than one file away.\n *\n * WHAT THE MAP IS, AND WHAT IT DELIBERATELY IS NOT. The unique content is which\n * codes which INVOCATION can raise: nothing else in the corpus says that, and an\n * agent choosing what to run needs it. What it does not carry is a per-code\n * gloss of what each code MEANS. That half used to be written twice — once here,\n * once in the /loam-check fix tables — in two independently worded places, in a\n * file `loam init` writes once and never refreshes, so the two drifted with\n * nothing able to say which had rotted. `loam explain <code>` now answers\n * meaning, severity and fix for every code named below, out of the running\n * binary. test/agent-contract.test.ts holds that pointer honest: every code\n * backticked in the corpus must resolve through `explainSubject`, so a family\n * added here without an explanation fails by name. Keep the code list; add the\n * gloss only where it says something `explain` cannot — a condition on when the\n * invocation raises it at all, or a cross-reference between two codes.\n *\n * ONE PARAGRAPH THE MOVE MADE FALSE, and the reason to look for others like it.\n * The `agents.stale` entry read \"one check on this very file … the reason to\n * distrust what you are reading\", which was true while these bytes WERE the\n * scaffolded AGENTS.md. On a page printed by the binary it is exactly backwards\n * — this page cannot be stale, and the file it warns about is somewhere else —\n * so the entry names AGENTS.md instead. A section that talks about its own\n * document does not survive being moved to another one; that is the class to\n * check for whenever anything else leaves this file.\n *\n * READING_OUTPUT and REFERENCE_PAGES are sections of the AGENTS.md template.\n * ../agents-md.ts assembles the document by PLAIN CONCATENATION — no join\n * separator — so every section starts at the first character of its opening line\n * and ends with the newline that closes its last one. Keep that shape when\n * editing, or two sections glue onto one line in every docs repo loam scaffolds\n * from now on. CODE_MAP owes the same shape for the same reason, one level up:\n * reference/codes.ts concatenates it with the modules listed above.\n */\nimport { STATUS_COMMAND } from \"./map/status.js\";\n\n/**\n * The section AGENTS.md keeps. Three facts an agent needs BEFORE it can form a\n * question — that every command speaks JSON, that the envelope survives a bad\n * invocation, and that codes are the contract and prose is not — plus the two\n * places the detail went.\n */\nexport const READING_OUTPUT = `## Reading loam's output\n\nEvery command takes \\`--json\\`, and the envelope holds even when the INVOCATION\nis wrong: with \\`--json\\` anywhere in the arguments, an unknown flag, unknown\ncommand or missing argument still yields \\`{ ok: false, error: { code:\n\"invalid-option\" } }\\` on stdout with exit 1 (commander's own diagnostic goes\nto stderr; \\`--help\\` and \\`--version\\` output pass through untouched). Without\n\\`--json\\` the same refusal is plain text on stderr with nothing on stdout.\n\nBranch on \\`findings[].code\\`, never on the prose — the wording changes, the codes do\nnot.\n\n**What a code MEANS is one command away**, and the answer describes the loam you\nare running rather than the one that scaffolded this repo. \\`loam explain <code>\\`\ngives one code's meaning, its severity in each scope that grades it, and its fix;\n\\`loam explain --codes\\` lists the whole vocabulary and \\`loam explain --codes --json\\`\nis the machine-readable form. Reach for it rather than for a generated pointer:\nthis page is printed by the binary that defines the codes.\n\n**Which codes an INVOCATION can raise** is the other half, and it is the one\nthing nothing else carries. It is a reference page rather than a section here:\n\\`loam instructions loam-codes\\`.\n\n`;\n\n/**\n * The index. A reference nobody can find is content deleted with extra steps,\n * so the exact command is spelled per page rather than described — and\n * test/agents.test.ts asserts that every name in REFERENCES appears here inside\n * its own `loam instructions` line, which is what makes a renamed page fail\n * loudly instead of leaving a pointer at nothing.\n */\nexport const REFERENCE_PAGES = `## The reference pages\n\nThis file is the orientation: the layout, the cycle, what gates and what only\nadvises, and what the words mean. Four things it does NOT carry — the grammars\nyou consult while writing ONE document, and the inventory of what each command\ncan report — are **reference pages**, printed by the binary rather than written\nhere. That is why: this file is auto-loaded on every session and never\nrefreshed, while a page out of the binary describes the loam you are actually\nrunning, and is read at the one moment it is needed.\n\n- \\`loam instructions loam-codes\\` — which codes each invocation can raise:\n \\`validate --service\\` / \\`--feature\\` / \\`--all\\`, \\`status\\`, \\`doctor\\`, \\`gate\\`,\n \\`context\\`, \\`diff\\`, \\`explore\\`, \\`dependencies\\`, \\`rebase\\`, \\`seed\\`, \\`subsystem\\`,\n \\`mcp\\`, the use-case views, the containment refusals, the error envelope, and\n the OpenSpec migration surface.\n- \\`loam instructions loam-spine\\` — the ID spine: every join between the\n artifacts (\\`operationId\\`, message name, \\`Covers:\\`, \\`Requires:\\`,\n \\`Capability:\\`, \\`Realizes:\\`), the \\`Based-On:\\` baseline pins on both the\n requirement and the contract axis, how to draw a shared broker, and how to\n declare a message produced outside the fleet.\n- \\`loam instructions loam-authoring\\` — the grammars you author against:\n the architecture spec axis (\\`arch.spec.md\\` and its \\`Covers:\\` line), the\n generated Gherkin suite, and frontmatter with the vouch chain behind it.\n- \\`loam instructions loam-done-check\\` — the done-check: how \\`loam verify\\`\n derives its claims, the three channels that may answer them, the federated\n recording form, and what separates **verified** from **attested**.\n\nEach takes no arguments and prints whole. \\`loam instructions\\` with no argument\nlists them beside the six workflow protocols; \\`loam explain <code>\\` answers any\nsingle code without opening a page at all.\n\n`;\n\n/**\n * The reference page's own opening: what the map is, where the /loam-check fix\n * tables sit beside it, and the one family `loam explain` cannot answer.\n */\nconst MAP_INTRO = `**What this page is.** It says which codes an INVOCATION can raise. It does\nNOT say what they mean: that half is one command away and describes the loam you\nare running rather than the one that scaffolded this repo. \\`loam explain <code>\\`\ngives one code's meaning, its severity in each scope that grades it, and its fix;\n\\`loam explain --codes\\` lists the whole vocabulary and \\`loam explain --codes --json\\`\nis the machine-readable form. The one family \\`explain\\` does not answer\nis the OpenSpec migration surface (\\`openspec.*\\`, \\`mapping.*\\`) — those commands run\nbefore a repository has a governed loop to look a code up from — so those entries\nalone keep their notes here.\n\nThe code-by-code fix table is a different document again: it lives in the\n\\`/loam-check\\` command \\`loam init\\` lays\ndown. \\`init\\` writes that body twice for every tool it configures: once as a slash\ncommand in the tool's own command directory (you type it), and once as an Agent\nSkill at \\`<tool-dir>/skills/loam-check/SKILL.md\\` (the model loads it by itself when\nthe task matches the skill's description). Same body, two ways in.\n\nWhich tools get them is detected from the repo: \\`loam init\\` scans for the\ndot-directories of the tools it knows (\\`.claude\\`, \\`.cursor\\`, \\`.gemini\\`, …) and\nwrites for the ones it finds, falling back to Claude Code when it finds none.\n\\`loam init --tools <ids|all>\\` overrides the scan — an unknown id is refused\n(\\`invalid-option\\`) rather than skipped — and \\`--no-commands\\` / \\`--no-skills\\`\neach suppress one delivery. The tools written for are recorded in\n\\`loam.json\\` as \\`agentTools\\`, which is how \\`loam doctor\\` tells a file missing\nbecause the binary grew a new command from one missing because nobody ever\nselected that tool.\n\nThe map:\n\n`;\n\nconst MAP_REST = `- \\`loam validate --service <id>\\` grades one service's own axes: \\`service.unknown\\`,\n \\`service.no-model\\`, \\`service.no-spec\\`, \\`service.no-openapi\\`, \\`c4.invalid\\`,\n \\`c4.no-relationships\\`, \\`requirements.missing-scenarios\\`,\n \\`requirements.stepless-scenario\\`, \\`requirements.assertionless-scenario\\`,\n \\`requirements.examples-unbound\\`, \\`requirements.examples-unreferenced\\`,\n \\`spec.merge-conflict\\`, \\`spec.duplicate-requirement\\`, \\`spec.no-requirements\\`,\n \\`spec.repeated-operations\\`, \\`spec.repeated-covers\\`, \\`openapi.invalid\\`,\n \\`openapi.duplicate-operationid\\`, \\`openapi.response-undescribed\\`,\n \\`openapi.ref-unresolved\\`, \\`api.ungoverned\\`, \\`api.ops-unlinked\\`,\n \\`api.requirement-deprecated\\`, \\`spec-api.op-undefined\\`,\n \\`spine.landscape-invalid\\`, \\`spine.op-undefined\\`, \\`spine.op-link-missing\\`,\n \\`spine.op-deprecated\\`; the async contract axis (AsyncAPI 3):\n \\`service.no-asyncapi\\`, \\`asyncapi.invalid\\`, \\`asyncapi.duplicate-message\\`,\n \\`asyncapi.payload-undescribed\\`, \\`asyncapi.ref-unresolved\\`,\n \\`spine.message-undefined\\`, \\`spec-event.message-undefined\\`,\n \\`spine.message-unproduced\\`, \\`spine.message-external\\`,\n \\`asyncapi.message-contested\\`, \\`event.messages-unlinked\\`, \\`event.ungoverned\\`,\n \\`event.covered\\`; and the architecture spec axis: \\`covers.unknown\\`,\n \\`health.invalid\\`, \\`health.uncovered\\`, \\`health.dependency-unmodelled\\`.\n Run inside the service's own repo, once a generated suite exists under\n \\`<gherkinDir>/loam/\\`, it also grades that suite against the living specs:\n \\`gherkin.missing\\`, \\`gherkin.stale\\`, \\`gherkin.orphaned\\`. A service that never\n ran \\`loam gherkin\\` stays quiet — that whole trio is conditional on the suite\n existing here — and a file tagged with a feature still in flight answers to\n that feature, not to the living spec it has not merged into yet.\n- \\`loam validate --feature <id>\\` grades a change's three axes against each other and\n against the fleet in flight: \\`delta.invalid\\`, \\`delta.nothing-tagged\\`,\n \\`delta.service-unknown\\`, \\`delta.service-id-invalid\\`, \\`spec-api.op-undefined\\`,\n \\`spec-api.op-pending\\`, \\`c4-api.op-undefined\\`, \\`c4-api.op-pending\\`,\n \\`c4-api.op-deprecated\\`, \\`c4.op-ungoverned\\`, \\`c4.op-link-missing\\`,\n \\`c4.service-binding-invalid\\`, \\`api.op-unconsumed\\`,\n \\`service.no-requirement-delta\\`, \\`archedge.uncovered\\`, and — the same four\n codes service scope raises, graded here on the feature's own spec.md and\n arch.spec.md deltas, because every one of those breaches merges into the\n living document — \\`spec.repeated-operations\\`, \\`spec.repeated-covers\\`,\n \\`spec.merge-conflict\\` and \\`requirements.stepless-scenario\\`. Then the\n architecture spec axis (\\`c4.uncovered\\`, plus \\`covers.unknown\\` on the\n feature's arch.spec.md deltas), the delta-shape group:\n \\`delta.unknown-section\\`, \\`delta.no-delta-sections\\`,\n \\`delta.requirement-not-merged\\`, \\`delta.modified-unknown\\`, \\`delta.removed-unknown\\`,\n \\`delta.added-duplicate\\`, \\`delta.added-near-duplicate\\`, \\`delta.modified-pending\\`,\n \\`delta.removed-pending\\`, \\`delta.added-conflict\\`, \\`delta.modified-conflict\\`,\n \\`delta.living-duplicate-requirement\\`, and the API-removal group:\n \\`openapi.remove-marker-anonymous\\`, \\`openapi.remove-op-consumed\\`.\n The event axis is graded in feature scope too — the \\`asyncapi.*\\`\n baseline/removal/conflict codes plus \\`c4-event.*\\` and \\`spec-event.*\\`.\n Where a finding names another feature in flight (\\`delta.*-pending\\`,\n \\`delta.added-conflict\\`, \\`delta.modified-conflict\\`, \\`spec-api.op-pending\\`,\n \\`c4-api.op-pending\\`) the ORDER is the answer, and \\`loam dependencies --json\\`\n is what computes it: \\`order\\` is a dependency-first sequence, \\`conflicts\\`\n the pairs no ordering fixes, \\`cycles\\` the ones that need a human.\n- \\`loam validate --all\\` runs both of those for everything and adds the fleet\n cross-check: \\`landscape.missing\\`, \\`landscape.invalid\\`,\n \\`landscape.merge-conflict\\`, \\`landscape.service-unmodelled\\`,\n \\`landscape.service-undocumented\\`, \\`landscape.binding-unknown\\`,\n \\`landscape.binding-duplicate\\`, the fleet-shape advisories\n \\`landscape.platform-candidate\\`, \\`landscape.datastore-private\\` and\n \\`landscape.datastore-shared\\`, \\`service.id-invalid\\` (fleet scope only, and\n graded before the map is opened, so it stands even when the landscape is\n missing or unreadable), \\`service.likec4-config-missing\\` (warn, per\n service: a model with no \\`likec4.config.json\\` beside it renders nowhere from\n the docs root — \\`loam subsystem sync\\` writes the file), a per-service \\`sources.unverifiable-from-here\\`, and\n one check on the docs repo's own AGENTS.md, \\`agents.stale\\`. That last one is\n the reason to distrust THAT file rather than this page: it fires when its\n version stamp on line 1 (\\`<!-- generated by loam vX.Y.Z -->\\`) is missing or\n older than the running binary, which is exactly when what it says may name a\n loam that no longer exists. It is never refreshed automatically — your edits\n outrank the template, so detection is all loam does, and a hand-curated file\n silences it the same way, by keeping the stamp current. This page has no such\n failure mode: it is printed by the binary it describes.\n \\`loam validate --all\\`'s \\`--json\\` payload also carries the additive \\`scorecard\\` key — per-axis ceiling-vs-actual fleet\n aggregates, the text report appending the same table; derived per run and never stored, so week-over-week is the pipeline's job: capture the key per run into a metrics store.\n \\`scorecard.adoption\\` counts the services PARTICIPATING in each contract axis\n (requirements, arch, openapi, asyncapi, permissions, capabilities; the\n denominator is \\`scorecard.services\\`) — an axis at 0 of N reads \"not started\",\n which is expected during staged adoption and distinct from partially adopted.\n Text mode folds the warnings such an axis alone causes under one banner per\n axis and says so; \\`--json\\` carries every finding unchanged, and the summary\n counts, exit codes and \\`--strict\\` are identical either way.\n- \\`loam doctor\\` is read-only local/fleet preflight — the first thing to run in a\n repo that behaves as though the fleet were empty. Every finding carries a\n \\`fix\\` field naming the exact command or edit, so this is the one family you\n rarely need \\`loam explain\\` for. Its blockers are \\`doctor.config-missing\\`,\n \\`doctor.config-invalid\\`, \\`doctor.docs-missing\\`, \\`doctor.services-missing\\`, and\n the three that say the fleet map cannot be read at all —\n \\`doctor.landscape-merge-conflict\\`, \\`doctor.landscape-invalid\\` and\n \\`doctor.landscape-unreadable\\`. It also grades what a WRITE that did not finish\n left in the docs repo, reported as \\`writePath\\` beside the findings:\n \\`doctor.docs-locked\\`, \\`doctor.commit-interrupted\\`, \\`doctor.commit-unreadable\\`\n and \\`doctor.staging-temps\\`. When this repo is a service repo that same scan\n covers \\`<gherkinDir>/loam/\\`, the root \\`loam gherkin\\` commits into.\n Accessibility, portability and incomplete binding stay warnings:\n \\`doctor.docs-unreadable\\`, \\`doctor.docs-readonly\\`, \\`doctor.docs-absolute\\`,\n \\`doctor.inventory-unreadable\\`, \\`doctor.landscape-missing\\`,\n \\`doctor.service-unbound\\` (never raised inside the docs repo itself, where\n having no service binding is the correct state), \\`doctor.service-unknown\\`\n (the same state \\`loam status\\` reports as \\`next.adopt-bound\\`),\n \\`doctor.likec4-config-missing\\`, and the two about this repo's own generated\n command and skill files: \\`doctor.agent-files-missing\\` and\n \\`doctor.agent-files-stale\\`.\n EXPECT the second one on the first \\`loam doctor\\` after an upgrade. It is not\n evidence that anything was edited or broken: staleness reads the version\n stamp only. Re-running \\`loam init\\` refreshes an unchanged pointer only when\n its current bytes still match the digest recorded in \\`loam.json\\`; an\n unrecorded or customized file stays in place for a human to review.\n- \\`loam rebase <FEAT>\\` writes the baseline pins: \\`Based-On:\\` under every\n MODIFIED/REMOVED requirement in the feature's spec deltas, and\n \\`x-loam-based-on\\` on every operation in its openapi.yaml, from the living text\n as it stands right now. Run it when you finish authoring a delta and again\n after you resolve a collision — it is the one mechanism standing between two\n features in flight and silently reverting each other's landed work. It refuses\n rather than inventing a pin, and re-pinning is not resolving: see\n \"The requirement baseline\".\n- \\`loam dependencies [<FEAT>]\\` derives the ordering of the features in flight\n from the artifacts themselves — requirement identities and OpenAPI\n operationIds, never from validator prose. It is the answer to every\n \"another feature in flight does this first\" finding, and to\n \\`delta.added-conflict\\` / \\`delta.modified-conflict\\`, which no ordering fixes.\n- \\`loam explore [<service>...]\\` reads the fleet around a change nobody has\n written down yet, and writes nothing. It exists because \\`loam new\\`'s\n \\`--touches\\` list is the hardest call in the cycle and the only one nothing\n downstream catches: a list short by one service produces a feature that\n validates, archives and ships with a consumer nobody updated. What it derives\n is mechanical — the one-hop ring, each service's rung, its living operations,\n who already calls whom, and which active features cover the same services. It\n does NOT decide which of those neighbours you actually change; that is a\n judgement about intent, and loam does not make those. \\`--op <operationId>\\`\n seeds from the operation's defining service; \\`--capability <id>\\` (repeatable)\n seeds from a declared capability's realizing services, and an id that seeds\n nothing lands in the additive \\`unresolvedCapabilities\\` — beside\n \\`loam list capabilities\\`, the rollup those seeds are read from.\n- \\`loam seed --from fleet.yaml\\` is the onboarding entry point for an empty\n fleet: a tiny human-authored YAML — a \\`services:\\` list of ids, optional\n \\`subsystems:\\`, \\`externals:\\` and \\`calls:\\` lines like\n \\`checkout -> payments\\` — templated mechanically into\n architecture/landscape.likec4 (one bound element per service, plain edges, no\n guessed operationIds) plus one services/<id>/ directory per service, in one\n journaled transaction. Not an extractor: the human stated every fact, and\n \"who calls whom\" is the one thing no generator can read off a repository.\n The seeded landscape carries a line-1 stamp; while it stands unedited,\n editing fleet.yaml and re-running regenerates the map, and the first hand\n edit makes the file yours — seed then refuses \\`seed-landscape-edited\\`\n rather than overwrite. Then adopt each service: \\`loam adopt --service <id>\\`.\n- \\`loam instructions [<page>] [args...]\\` prints one of the six workflow\n protocols — \\`loam-adopt\\`, \\`loam-feature\\`, \\`loam-implement\\`, \\`loam-check\\`,\n \\`loam-verify\\`, \\`loam-ship\\` — with \\`$1\\`, \\`$2\\` filled in from the arguments you\n pass, or one of the four reference pages — \\`loam-codes\\`, \\`loam-spine\\`,\n \\`loam-authoring\\`, \\`loam-done-check\\` — which take no arguments. With no\n argument at all it lists both sets. The pages ship inside the binary, so they\n describe the loam you are about to run rather than the one that scaffolded the\n repository; the command and skill files \\`loam init\\` writes are pointers at it,\n and so is AGENTS.md's own \"The reference pages\" section. It reads no\n \\`loam.json\\` and no docs repo, deliberately: \\`loam-adopt\\`'s own first step is\n to run \\`loam init\\` when there is no config, so it cannot be the step that\n requires one.\n`;\n\n/**\n * The reference page's body, up to the modules that continue it. The bullets\n * are ordered so `status` — the orientation command, the one to run when you\n * have lost the session — is read first.\n */\nexport const CODE_MAP = MAP_INTRO + STATUS_COMMAND + MAP_REST;\n"]}
|
|
1
|
+
{"version":3,"file":"command-map.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/command-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0DG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG;;;;;;;;;;;;;;;;;;;;;;;CAuB7B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+B9B,CAAC;AAEF;;;GAGG;AACH,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BjB,CAAC;AAEF,MAAM,QAAQ,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyKhB,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,GAAG,cAAc,GAAG,QAAQ,CAAC","sourcesContent":["/**\n * Reading loam's output, in its two deliveries.\n *\n * {@link READING_OUTPUT} and {@link REFERENCE_PAGES} are what AGENTS.md keeps:\n * the `--json` envelope, the rule to branch on codes rather than prose, and the\n * index of the pages this file no longer carries. {@link CODE_MAP} is the\n * code-by-code map of `status`, `validate`, `doctor`, `rebase`, `dependencies`,\n * `explore`, `seed` and `instructions` — the part `loam instructions loam-codes`\n * prints. ../workflows/reference/codes.ts composes it with `./map/`,\n * `./map/lenses/` and `./refusals.ts`, in exactly the order ../agents-md.ts used\n * to concatenate them, so the assembled page is the section byte for byte.\n *\n * WHY THE MAP LEFT THE FILE, given that this package's whole subject is a file.\n * AGENTS.md is auto-loaded from the working directory by every agents.md-aware\n * host, on every session, and `loam init` writes it once and never refreshes it.\n * It reached 109,399 bytes; Codex truncates the AGENTS.md chain at 32,768 bytes\n * and Windsurf caps a workspace rule file at 12,000 characters, both silently.\n * Roughly seventy percent of the document was being dropped with no error and no\n * way for the reader to tell which half it held — and this section alone was\n * 44,433 of those bytes, 41% of the file. It is also the half a reader consults\n * at a moment it can name (a run reported something) rather than the half it\n * needs to form a question at all, which is what decided which side of the split\n * it went. ../workflows/reference/reference.ts carries the rest of that argument.\n *\n * The move is a move and not a deletion: every byte is still shipped, still in\n * the same corpus test/codes-drift.test.ts reads (AGENTS_MD + PROTOCOLS), and\n * still one command away rather than one file away.\n *\n * WHAT THE MAP IS, AND WHAT IT DELIBERATELY IS NOT. The unique content is which\n * codes which INVOCATION can raise: nothing else in the corpus says that, and an\n * agent choosing what to run needs it. What it does not carry is a per-code\n * gloss of what each code MEANS. That half used to be written twice — once here,\n * once in the /loam-check fix tables — in two independently worded places, in a\n * file `loam init` writes once and never refreshes, so the two drifted with\n * nothing able to say which had rotted. `loam explain <code>` now answers\n * meaning, severity and fix for every code named below, out of the running\n * binary. test/agent-contract.test.ts holds that pointer honest: every code\n * backticked in the corpus must resolve through `explainSubject`, so a family\n * added here without an explanation fails by name. Keep the code list; add the\n * gloss only where it says something `explain` cannot — a condition on when the\n * invocation raises it at all, or a cross-reference between two codes.\n *\n * ONE PARAGRAPH THE MOVE MADE FALSE, and the reason to look for others like it.\n * The `agents.stale` entry read \"one check on this very file … the reason to\n * distrust what you are reading\", which was true while these bytes WERE the\n * scaffolded AGENTS.md. On a page printed by the binary it is exactly backwards\n * — this page cannot be stale, and the file it warns about is somewhere else —\n * so the entry names AGENTS.md instead. A section that talks about its own\n * document does not survive being moved to another one; that is the class to\n * check for whenever anything else leaves this file.\n *\n * READING_OUTPUT and REFERENCE_PAGES are sections of the AGENTS.md template.\n * ../agents-md.ts assembles the document by PLAIN CONCATENATION — no join\n * separator — so every section starts at the first character of its opening line\n * and ends with the newline that closes its last one. Keep that shape when\n * editing, or two sections glue onto one line in every docs repo loam scaffolds\n * from now on. CODE_MAP owes the same shape for the same reason, one level up:\n * reference/codes.ts concatenates it with the modules listed above.\n */\nimport { STATUS_COMMAND } from \"./map/status.js\";\n\n/**\n * The section AGENTS.md keeps. Three facts an agent needs BEFORE it can form a\n * question — that every command speaks JSON, that the envelope survives a bad\n * invocation, and that codes are the contract and prose is not — plus the two\n * places the detail went.\n */\nexport const READING_OUTPUT = `## Reading loam's output\n\nEvery command takes \\`--json\\`, and the envelope holds even when the INVOCATION\nis wrong: with \\`--json\\` anywhere in the arguments, an unknown flag, unknown\ncommand or missing argument still yields \\`{ ok: false, error: { code:\n\"invalid-option\" } }\\` on stdout with exit 1 (commander's own diagnostic goes\nto stderr; \\`--help\\` and \\`--version\\` output pass through untouched). Without\n\\`--json\\` the same refusal is plain text on stderr with nothing on stdout.\n\nBranch on \\`findings[].code\\`, never on the prose — the wording changes, the codes do\nnot.\n\n**What a code MEANS is one command away**, and the answer describes the loam you\nare running rather than the one that scaffolded this repo. \\`loam explain <code>\\`\ngives one code's meaning, its severity in each scope that grades it, and its fix;\n\\`loam explain --codes\\` lists the whole vocabulary and \\`loam explain --codes --json\\`\nis the machine-readable form. Reach for it rather than for a generated pointer:\nthis page is printed by the binary that defines the codes.\n\n**Which codes an INVOCATION can raise** is the other half, and it is the one\nthing nothing else carries. It is a reference page rather than a section here:\n\\`loam instructions loam-codes\\`.\n\n`;\n\n/**\n * The index. A reference nobody can find is content deleted with extra steps,\n * so the exact command is spelled per page rather than described — and\n * test/agents.test.ts asserts that every name in REFERENCES appears here inside\n * its own `loam instructions` line, which is what makes a renamed page fail\n * loudly instead of leaving a pointer at nothing.\n */\nexport const REFERENCE_PAGES = `## The reference pages\n\nThis file is the orientation: the layout, the cycle, what gates and what only\nadvises, and what the words mean. Four things it does NOT carry — the grammars\nyou consult while writing ONE document, and the inventory of what each command\ncan report — are **reference pages**, printed by the binary rather than written\nhere. That is why: this file is auto-loaded on every session and never\nrefreshed, while a page out of the binary describes the loam you are actually\nrunning, and is read at the one moment it is needed.\n\n- \\`loam instructions loam-codes\\` — which codes each invocation can raise:\n \\`validate --service\\` / \\`--feature\\` / \\`--all\\`, \\`status\\`, \\`doctor\\`, \\`gate\\`,\n \\`context\\`, \\`diff\\`, \\`explore\\`, \\`dependencies\\`, \\`rebase\\`, \\`seed\\`, \\`subsystem\\`,\n \\`mcp\\`, the use-case views, the containment refusals, the error envelope, and\n the OpenSpec migration surface.\n- \\`loam instructions loam-spine\\` — the ID spine: every join between the\n artifacts (\\`operationId\\`, message name, \\`Covers:\\`, \\`Requires:\\`,\n \\`Capability:\\`, \\`Realizes:\\`), the \\`Based-On:\\` baseline pins on both the\n requirement and the contract axis, how to draw a shared broker, and how to\n declare a message produced outside the fleet.\n- \\`loam instructions loam-authoring\\` — the grammars you author against:\n the architecture spec axis (\\`arch.spec.md\\` and its \\`Covers:\\` line), the\n generated Gherkin suite, and frontmatter with the vouch chain behind it.\n- \\`loam instructions loam-done-check\\` — the done-check: how \\`loam verify\\`\n derives its claims, the three channels that may answer them, the federated\n recording form, and what separates **verified** from **attested**.\n\nEach takes no arguments and prints whole. \\`loam instructions\\` with no argument\nlists them beside the six workflow protocols; \\`loam explain <code>\\` answers any\nsingle code without opening a page at all.\n\n`;\n\n/**\n * The reference page's own opening: what the map is, where the /loam-check fix\n * tables sit beside it, and the one family `loam explain` cannot answer.\n */\nconst MAP_INTRO = `**What this page is.** It says which codes an INVOCATION can raise. It does\nNOT say what they mean: that half is one command away and describes the loam you\nare running rather than the one that scaffolded this repo. \\`loam explain <code>\\`\ngives one code's meaning, its severity in each scope that grades it, and its fix;\n\\`loam explain --codes\\` lists the whole vocabulary and \\`loam explain --codes --json\\`\nis the machine-readable form. The one family \\`explain\\` does not answer\nis the OpenSpec migration surface (\\`openspec.*\\`, \\`mapping.*\\`) — those commands run\nbefore a repository has a governed loop to look a code up from — so those entries\nalone keep their notes here.\n\nThe code-by-code fix table is a different document again: it lives in the\n\\`/loam-check\\` command \\`loam init\\` lays\ndown. \\`init\\` writes that body twice for every tool it configures: once as a slash\ncommand in the tool's own command directory (you type it), and once as an Agent\nSkill at \\`<tool-dir>/skills/loam-check/SKILL.md\\` (the model loads it by itself when\nthe task matches the skill's description). Same body, two ways in.\n\nWhich tools get them is detected from the repo: \\`loam init\\` scans for the\ndot-directories of the tools it knows (\\`.claude\\`, \\`.cursor\\`, \\`.gemini\\`, …) and\nwrites for the ones it finds, falling back to Claude Code when it finds none.\n\\`loam init --tools <ids|all>\\` overrides the scan — an unknown id is refused\n(\\`invalid-option\\`) rather than skipped — and \\`--no-commands\\` / \\`--no-skills\\`\neach suppress one delivery. The tools written for are recorded in\n\\`loam.json\\` as \\`agentTools\\`, which is how \\`loam doctor\\` tells a file missing\nbecause the binary grew a new command from one missing because nobody ever\nselected that tool.\n\nThe map:\n\n`;\n\nconst MAP_REST = `- \\`loam validate --service <id>\\` grades one service's own axes: \\`service.unknown\\`,\n \\`service.no-model\\`, \\`service.no-spec\\`, \\`service.no-openapi\\`, \\`c4.invalid\\`,\n \\`c4.declaration-diverged\\`, \\`c4.element-unowned\\`,\n \\`c4.no-relationships\\`, \\`requirements.missing-scenarios\\`,\n \\`requirements.stepless-scenario\\`, \\`requirements.assertionless-scenario\\`,\n \\`requirements.examples-unbound\\`, \\`requirements.examples-unreferenced\\`,\n \\`spec.merge-conflict\\`, \\`spec.duplicate-requirement\\`, \\`spec.no-requirements\\`,\n \\`spec.repeated-operations\\`, \\`spec.repeated-covers\\`, \\`openapi.invalid\\`,\n \\`openapi.duplicate-operationid\\`, \\`openapi.response-undescribed\\`,\n \\`openapi.ref-unresolved\\`, \\`api.ungoverned\\`, \\`api.ops-unlinked\\`,\n \\`api.requirement-deprecated\\`, \\`spec-api.op-undefined\\`,\n \\`spine.landscape-invalid\\`, \\`spine.op-undefined\\`, \\`spine.op-link-missing\\`,\n \\`spine.op-deprecated\\`; the async contract axis (AsyncAPI 3):\n \\`service.no-asyncapi\\`, \\`asyncapi.invalid\\`, \\`asyncapi.duplicate-message\\`,\n \\`asyncapi.payload-undescribed\\`, \\`asyncapi.ref-unresolved\\`,\n \\`spine.message-undefined\\`, \\`spec-event.message-undefined\\`,\n \\`spine.message-unproduced\\`, \\`spine.message-external\\`,\n \\`asyncapi.message-contested\\`, \\`event.messages-unlinked\\`, \\`event.ungoverned\\`,\n \\`event.covered\\`; and the architecture spec axis: \\`covers.unknown\\`,\n \\`health.invalid\\`, \\`health.uncovered\\`, \\`health.dependency-unmodelled\\`.\n Run inside the service's own repo, once a generated suite exists under\n \\`<gherkinDir>/loam/\\`, it also grades that suite against the living specs:\n \\`gherkin.missing\\`, \\`gherkin.stale\\`, \\`gherkin.orphaned\\`. A service that never\n ran \\`loam gherkin\\` stays quiet — that whole trio is conditional on the suite\n existing here — and a file tagged with a feature still in flight answers to\n that feature, not to the living spec it has not merged into yet.\n- \\`loam validate --feature <id>\\` grades a change's three axes against each other and\n against the fleet in flight: \\`delta.invalid\\`, \\`delta.nothing-tagged\\`,\n \\`delta.service-unknown\\`, \\`delta.service-id-invalid\\`, \\`spec-api.op-undefined\\`,\n \\`spec-api.op-pending\\`, \\`c4-api.op-undefined\\`, \\`c4-api.op-pending\\`,\n \\`c4-api.op-deprecated\\`, \\`c4.op-ungoverned\\`, \\`c4.op-link-missing\\`,\n \\`c4.service-binding-invalid\\`, \\`api.op-unconsumed\\`,\n \\`service.no-requirement-delta\\`, \\`archedge.uncovered\\`, and — the same four\n codes service scope raises, graded here on the feature's own spec.md and\n arch.spec.md deltas, because every one of those breaches merges into the\n living document — \\`spec.repeated-operations\\`, \\`spec.repeated-covers\\`,\n \\`spec.merge-conflict\\` and \\`requirements.stepless-scenario\\`. Then the\n architecture spec axis (\\`c4.uncovered\\`, plus \\`covers.unknown\\` on the\n feature's arch.spec.md deltas), the delta-shape group:\n \\`delta.unknown-section\\`, \\`delta.no-delta-sections\\`,\n \\`delta.requirement-not-merged\\`, \\`delta.modified-unknown\\`, \\`delta.removed-unknown\\`,\n \\`delta.added-duplicate\\`, \\`delta.added-near-duplicate\\`, \\`delta.modified-pending\\`,\n \\`delta.removed-pending\\`, \\`delta.added-conflict\\`, \\`delta.modified-conflict\\`,\n \\`delta.living-duplicate-requirement\\`, and the API-removal group:\n \\`openapi.remove-marker-anonymous\\`, \\`openapi.remove-op-consumed\\`.\n The event axis is graded in feature scope too — the \\`asyncapi.*\\`\n baseline/removal/conflict codes plus \\`c4-event.*\\` and \\`spec-event.*\\`.\n Where a finding names another feature in flight (\\`delta.*-pending\\`,\n \\`delta.added-conflict\\`, \\`delta.modified-conflict\\`, \\`spec-api.op-pending\\`,\n \\`c4-api.op-pending\\`) the ORDER is the answer, and \\`loam dependencies --json\\`\n is what computes it: \\`order\\` is a dependency-first sequence, \\`conflicts\\`\n the pairs no ordering fixes, \\`cycles\\` the ones that need a human.\n- \\`loam validate --all\\` runs both of those for everything and adds the fleet\n cross-check: \\`landscape.missing\\`, \\`landscape.invalid\\`,\n \\`landscape.merge-conflict\\`, \\`landscape.service-unmodelled\\`,\n \\`landscape.service-undocumented\\`, \\`landscape.binding-unknown\\`,\n \\`landscape.binding-duplicate\\`, the fleet-shape advisories\n \\`landscape.platform-candidate\\`, \\`landscape.datastore-private\\` and\n \\`landscape.datastore-shared\\`, \\`service.id-invalid\\` (fleet scope only, and\n graded before the map is opened, so it stands even when the landscape is\n missing or unreadable), the four renderer-wiring warnings a\n \\`loam subsystem sync\\` repairs — \\`service.likec4-config-missing\\` (a model that\n STANDS ALONE, declaring its own \\`specification\\`, with no\n \\`likec4.config.json\\` beside it: it renders nowhere from the docs root),\n \\`service.likec4-config-stray\\` (that file beside a model that EXTENDS the map,\n where it registers a project that CLAIMS the model, out of the root project\n where the map's kinds are),\n \\`service.model-excluded\\` (the root \\`likec4.config.json\\` excludes an extending\n model's directory, so the renderer never loads it) and\n \\`service.model-unexcluded\\` (it does NOT exclude a standalone model's, so the\n renderer merges that model into the map and calls every declaration a\n duplicate) — plus \\`c4.fleet-project-invalid\\` (warn: every document reads clean\n where loam grades it and the ONE project the renderer builds out of the map and\n every extending model does not, because something is declared in two of them),\n a per-service \\`sources.unverifiable-from-here\\`, and\n one check on the docs repo's own AGENTS.md, \\`agents.stale\\`. That last one is\n the reason to distrust THAT file rather than this page: it fires when its\n version stamp on line 1 (\\`<!-- generated by loam vX.Y.Z -->\\`) is missing or\n older than the running binary, which is exactly when what it says may name a\n loam that no longer exists. It is never refreshed automatically — your edits\n outrank the template, so detection is all loam does, and a hand-curated file\n silences it the same way, by keeping the stamp current. This page has no such\n failure mode: it is printed by the binary it describes.\n \\`loam validate --all\\`'s \\`--json\\` payload also carries the additive \\`scorecard\\` key — per-axis ceiling-vs-actual fleet\n aggregates, the text report appending the same table; derived per run and never stored, so week-over-week is the pipeline's job: capture the key per run into a metrics store.\n \\`scorecard.adoption\\` counts the services PARTICIPATING in each contract axis\n (requirements, arch, openapi, asyncapi, permissions, capabilities; the\n denominator is \\`scorecard.services\\`) — an axis at 0 of N reads \"not started\",\n which is expected during staged adoption and distinct from partially adopted.\n Text mode folds the warnings such an axis alone causes under one banner per\n axis and says so; \\`--json\\` carries every finding unchanged, and the summary\n counts, exit codes and \\`--strict\\` are identical either way.\n- \\`loam doctor\\` is read-only local/fleet preflight — the first thing to run in a\n repo that behaves as though the fleet were empty. Every finding carries a\n \\`fix\\` field naming the exact command or edit, so this is the one family you\n rarely need \\`loam explain\\` for. Its blockers are \\`doctor.config-missing\\`,\n \\`doctor.config-invalid\\`, \\`doctor.docs-missing\\`, \\`doctor.services-missing\\`, and\n the three that say the fleet map cannot be read at all —\n \\`doctor.landscape-merge-conflict\\`, \\`doctor.landscape-invalid\\` and\n \\`doctor.landscape-unreadable\\`. It also grades what a WRITE that did not finish\n left in the docs repo, reported as \\`writePath\\` beside the findings:\n \\`doctor.docs-locked\\`, \\`doctor.commit-interrupted\\`, \\`doctor.commit-unreadable\\`\n and \\`doctor.staging-temps\\`. When this repo is a service repo that same scan\n covers \\`<gherkinDir>/loam/\\`, the root \\`loam gherkin\\` commits into.\n Accessibility, portability and incomplete binding stay warnings:\n \\`doctor.docs-unreadable\\`, \\`doctor.docs-readonly\\`, \\`doctor.docs-absolute\\`,\n \\`doctor.inventory-unreadable\\`, \\`doctor.landscape-missing\\`,\n \\`doctor.service-unbound\\` (never raised inside the docs repo itself, where\n having no service binding is the correct state), \\`doctor.service-unknown\\`\n (the same state \\`loam status\\` reports as \\`next.adopt-bound\\`),\n \\`doctor.likec4-config-missing\\`, and the two about this repo's own generated\n command and skill files: \\`doctor.agent-files-missing\\` and\n \\`doctor.agent-files-stale\\`.\n EXPECT the second one on the first \\`loam doctor\\` after an upgrade. It is not\n evidence that anything was edited or broken: staleness reads the version\n stamp only. Re-running \\`loam init\\` refreshes an unchanged pointer only when\n its current bytes still match the digest recorded in \\`loam.json\\`; an\n unrecorded or customized file stays in place for a human to review.\n- \\`loam rebase <FEAT>\\` writes the baseline pins: \\`Based-On:\\` under every\n MODIFIED/REMOVED requirement in the feature's spec deltas, and\n \\`x-loam-based-on\\` on every operation in its openapi.yaml, from the living text\n as it stands right now. Run it when you finish authoring a delta and again\n after you resolve a collision — it is the one mechanism standing between two\n features in flight and silently reverting each other's landed work. It refuses\n rather than inventing a pin, and re-pinning is not resolving: see\n \"The requirement baseline\".\n- \\`loam dependencies [<FEAT>]\\` derives the ordering of the features in flight\n from the artifacts themselves — requirement identities and OpenAPI\n operationIds, never from validator prose. It is the answer to every\n \"another feature in flight does this first\" finding, and to\n \\`delta.added-conflict\\` / \\`delta.modified-conflict\\`, which no ordering fixes.\n- \\`loam explore [<service>...]\\` reads the fleet around a change nobody has\n written down yet, and writes nothing. It exists because \\`loam new\\`'s\n \\`--touches\\` list is the hardest call in the cycle and the only one nothing\n downstream catches: a list short by one service produces a feature that\n validates, archives and ships with a consumer nobody updated. What it derives\n is mechanical — the one-hop ring, each service's rung, its living operations,\n who already calls whom, and which active features cover the same services. It\n does NOT decide which of those neighbours you actually change; that is a\n judgement about intent, and loam does not make those. \\`--op <operationId>\\`\n seeds from the operation's defining service; \\`--capability <id>\\` (repeatable)\n seeds from a declared capability's realizing services, and an id that seeds\n nothing lands in the additive \\`unresolvedCapabilities\\` — beside\n \\`loam list capabilities\\`, the rollup those seeds are read from.\n- \\`loam seed --from fleet.yaml\\` is the onboarding entry point for an empty\n fleet: a tiny human-authored YAML — a \\`services:\\` list of ids, optional\n \\`subsystems:\\`, \\`externals:\\` and \\`calls:\\` lines like\n \\`checkout -> payments\\` — templated mechanically into\n architecture/landscape.likec4 (one bound element per service, plain edges, no\n guessed operationIds) plus one services/<id>/ directory per service, in one\n journaled transaction. Not an extractor: the human stated every fact, and\n \"who calls whom\" is the one thing no generator can read off a repository.\n The seeded landscape carries a line-1 stamp; while it stands unedited,\n editing fleet.yaml and re-running regenerates the map, and the first hand\n edit anywhere in the file, including above the stub, makes it yours — seed\n then refuses \\`seed-landscape-edited\\`\n rather than overwrite. Then adopt each service: \\`loam adopt --service <id>\\`.\n- \\`loam instructions [<page>] [args...]\\` prints one of the six workflow\n protocols — \\`loam-adopt\\`, \\`loam-feature\\`, \\`loam-implement\\`, \\`loam-check\\`,\n \\`loam-verify\\`, \\`loam-ship\\` — with \\`$1\\`, \\`$2\\` filled in from the arguments you\n pass, or one of the four reference pages — \\`loam-codes\\`, \\`loam-spine\\`,\n \\`loam-authoring\\`, \\`loam-done-check\\` — which take no arguments. With no\n argument at all it lists both sets. The pages ship inside the binary, so they\n describe the loam you are about to run rather than the one that scaffolded the\n repository; the command and skill files \\`loam init\\` writes are pointers at it,\n and so is AGENTS.md's own \"The reference pages\" section. It reads no\n \\`loam.json\\` and no docs repo, deliberately: \\`loam-adopt\\`'s own first step is\n to run \\`loam init\\` when there is no config, so it cannot be the step that\n requires one.\n`;\n\n/**\n * The reference page's body, up to the modules that continue it. The bullets\n * are ordered so `status` — the orientation command, the one to run when you\n * have lost the session — is read first.\n */\nexport const CODE_MAP = MAP_INTRO + STATUS_COMMAND + MAP_REST;\n"]}
|
|
@@ -11,11 +11,15 @@
|
|
|
11
11
|
* scrolls looking for it concludes the file is truncated — which, on the two
|
|
12
12
|
* hosts that truncate silently, is a conclusion they cannot check.
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* Not a section of the scaffolded AGENTS.md any more: that document carries a
|
|
15
|
+
* condensed cycle of its own (../agents-md.ts), sized for a host that loads it
|
|
16
|
+
* on every turn. This constant is the long teaching, and it is DELIVERED
|
|
17
|
+
* through `loam explain`'s term paragraphs — ../../explain/terms.ts pins
|
|
18
|
+
* verbatim phrases of it, so rewording a sentence here breaks the pairing
|
|
19
|
+
* loudly instead of letting a term drift away from what loam ships. Two
|
|
20
|
+
* consequences for an editor: a claim written here is read by an agent through
|
|
21
|
+
* `loam explain <term>` and must stay true, and a phrase a pin names cannot be
|
|
22
|
+
* reworded on one side alone.
|
|
19
23
|
*/
|
|
20
24
|
export const CYCLE = `## The cycle
|
|
21
25
|
|
|
@@ -91,12 +95,23 @@ wrong quietly, and \`loam validate\` passing means nothing about any of it.
|
|
|
91
95
|
|
|
92
96
|
One of the targets is not under \`services/<id>/\`: \`architecture/landscape.likec4\`,
|
|
93
97
|
the fleet map, carried with \`action: "edit"\` and a \`landscape.instruction\`
|
|
94
|
-
spelling out the
|
|
95
|
-
|
|
96
|
-
it
|
|
98
|
+
spelling out the write this service owes it. That target appears while nothing
|
|
99
|
+
in the map resolves to the service, and again while the element that does has
|
|
100
|
+
no edge touching it — \`landscape.touched\` says which, and \`landscape.attested\`
|
|
101
|
+
lists the calls the service's own model.likec4 declares across its boundary,
|
|
102
|
+
which are the edges the map owes. **Add to that file; never rewrite it** —
|
|
103
|
+
every other service's elements and edges are in there. A service that is
|
|
97
104
|
fully documented and undrawn is \`landscape.service-unmodelled\` (error) and is
|
|
98
105
|
invisible to every cross-service check: no edge into it can be graded against
|
|
99
|
-
its openapi.yaml, and no feature can draw a call to it.
|
|
106
|
+
its openapi.yaml, and no feature can draw a call to it. A drawn, bound,
|
|
107
|
+
edgeless service whose model reaches other systems is
|
|
108
|
+
\`landscape.service-isolated\` (warn): drawn, and invisible to every
|
|
109
|
+
cross-service check all the same. One whose model attests no such call is
|
|
110
|
+
silent there — the brief's \`landscape.touched: false\` is the only place that
|
|
111
|
+
state is named, so read it before the fleet run rather than hoping for it in it.
|
|
112
|
+
And one edge closes the state; the check is touched/untouched, not a set
|
|
113
|
+
difference, so draw every attested call in one pass — nothing names the ones
|
|
114
|
+
left out.
|
|
100
115
|
|
|
101
116
|
An adoption ends with two runs, not one: \`loam validate --service <id> --json\`
|
|
102
117
|
for the baseline, then \`loam validate --all --json\` in the docs repo — the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cycle.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/cycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgJpB,CAAC","sourcesContent":["/**\n * What an agent DOES: the cycle step by step, adopting a service, what is\n * authored versus derived, and the rules the validator enforces.\n *\n * The done-check itself is no longer here — it is `loam instructions\n * loam-done-check` (../workflows/reference/done-check.ts). Steps 4 and 7 used\n * to end `See \"The requirement baseline\"` and `See \"The done-check\"`, naming\n * headings that were further down this same file; they now name the COMMAND\n * that prints them. That is not a rewording for its own sake: a section\n * reference to a section that left is a pointer at nothing, and a reader who\n * scrolls looking for it concludes the file is truncated — which, on the two\n * hosts that truncate silently, is a conclusion they cannot check.\n *\n * One section of the AGENTS.md template. ../agents-md.ts assembles the\n * document by PLAIN CONCATENATION — no join separator — so every section\n * starts at the first character of its opening line and ends with the newline\n * that closes its last one. Keep that shape when editing, or two sections glue\n * onto one line in every docs repo loam scaffolds from now on.\n */\nexport const CYCLE = `## The cycle\n\n0. **Wire the repo** — \\`loam init --docs <path-to-docs-repo> --service <id>\\` in\n each service repo, then \\`loam doctor\\`. Once per repository, before anything\n else; see \"\\`loam.json\\` — the wiring\" above. Every step below runs in a repo\n that has been through this one.\n1. **Adopt** — a service with no documentation at all starts at\n \\`loam adopt --service <id> --json\\`, which briefs you on the baseline to write.\n See \"Adopting a service\" below. Once per service, not once per feature.\n2. **Understand** — \\`loam status --json\\` first if you joined halfway or lost the\n session: it says what is in flight and what the next step is, for the fleet or\n for one feature (\\`loam status FEAT-101 --json\\`). Then \\`loam list --json\\` and\n \\`loam show <service> --json\\`.\n Then \\`loam explore <service> --json\\` around the services you believe are\n involved — it writes nothing and answers the one question the next step takes\n as an argument: which services this change actually touches. It reports the\n ring one hop out in the fleet map (\\`neighbours\\`), how far each service's\n documentation has got (\\`maturity\\`), what each already exposes, the features\n already in flight over the same ground (\\`overlaps\\`), and the \\`loam new\\` line\n the seeds imply (\\`scaffold\\`). \\`--op <operationId>\\` seeds from an operation\n when you know the call but not who owns it.\n Never propose a change to a service you have not read.\n3. **Scaffold** — \\`loam new FEAT-101 --title \"...\" --touches <existing> --new-service <new>\\`.\n The scaffold leaves a \\`delta.likec4\\` whose context elements are commented out —\n a requirements-only feature should DELETE that file rather than ship an empty\n one — and gives every \\`--new-service\\` a \\`specs/<svc>/arch.spec.md\\` alongside.\n \\`--capability <id>\\` (repeatable, and it composes with \\`--touches\\`) scaffolds a\n capability delta instead of a service one — the inversion of this step, for a\n change whose BUSINESS side is what is known: open the promise that changes and\n derive the service work from it. An id the fleet has never named is scaffolded\n rather than refused, with the close spellings printed beside it; the archive\n is what creates the living \\`capabilities/<id>/spec.md\\`.\n4. **Author** the four files the scaffold left as TODO: intent, delta.likec4,\n a spec.md per service, an openapi.yaml per new service. Finish with\n \\`loam rebase FEAT-101\\`: it pins every MODIFIED/REMOVED requirement and every\n operation in the contract delta to the living version you wrote it against.\n On the contract axis run it even when you changed nothing but one endpoint —\n that is exactly what marks the REST of the document as quotation the merge\n must not write. See \\`loam instructions loam-spine\\` — \"The requirement baseline\".\n5. **Check** — \\`loam validate FEAT-101 --json\\`. Fix every error before writing code.\n \\`loam dependencies --json\\` says whether another feature in flight has to\n archive first.\n6. **Build** — \\`loam delta FEAT-101 --service <svc> --json\\` is the task for one service:\n intent, its requirement delta with scenarios verbatim, and the edges around it.\n In the service's own repo, \\`loam gherkin FEAT-101\\` then emits those scenarios as\n \\`.feature\\` files under \\`<gherkinDir>/loam/\\` — write step definitions against them\n **first**, outside \\`loam/\\`, and implement until they pass.\n If \\`architecture.errors\\` is non-empty the payload keeps \\`ok: true\\` (the command\n ran) but the exit code is 1: the C4 slice is empty because delta.likec4 did not\n parse, not because the feature changes no architecture — do not build on it.\n7. **Verify** — \\`loam verify FEAT-101 --json\\` turns the feature's own promises into a\n checklist. The scenario claims are answered by the cucumber report\n (\\`--results report.json\\`); answer the rest with evidence and record them\n (\\`--record answers.json --service <id>\\`), **from each affected service's own\n repo**. See \\`loam instructions loam-done-check\\`.\n8. **Ship** — \\`loam archive FEAT-101\\` once the code is merged. \\`--dry-run\\` shows\n every file the merge would write, and writes none of them.\n\n## Adopting a service\n\n\\`loam adopt --service <id>\\` does not read code and never will. Nothing\ndeterministic can look at a legacy service and say what its architecture MEANS,\nand a guessed model is worse than none: everybody downstream has to re-derive it\nto know whether to believe it. So loam takes the half of the job that is\nmechanical — stating the work, and checking the result — and you do the reading.\n\nThe brief names every file to write, the grammar each must be in, what the\nlandscape already says about the service (bind to those elements, do not draw a\nparallel fleet), the frontmatter, and the checks that follow. It also lists what\n**no** check will ever catch. Read that list: everything on it is a way to be\nwrong quietly, and \\`loam validate\\` passing means nothing about any of it.\n\nOne of the targets is not under \\`services/<id>/\\`: \\`architecture/landscape.likec4\\`,\nthe fleet map, carried with \\`action: \"edit\"\\` and a \\`landscape.instruction\\`\nspelling out the block this service owes it. That target appears only while\nnothing in the map resolves to the service. **Add to that file; never rewrite\nit** — every other service's elements and edges are in there. A service that is\nfully documented and undrawn is \\`landscape.service-unmodelled\\` (error) and is\ninvisible to every cross-service check: no edge into it can be graded against\nits openapi.yaml, and no feature can draw a call to it.\n\nAn adoption ends with two runs, not one: \\`loam validate --service <id> --json\\`\nfor the baseline, then \\`loam validate --all --json\\` in the docs repo — the\nfleet cross-check the first invocation does not perform is exactly where a\nlandscape edit that did not land shows up. Done, stated once: \\`--service\\`\nclean when run from inside the service's own repo, and \\`--all\\` reporting no\n\\`landscape.*\\` finding. The fleet run is never SILENT — \\`sources.unverifiable-from-here\\`\n(severity ok) appears per service as a confirmation, not work — so \"keep going\nuntil validation is quiet\" is the wrong loop; the two runs above are the test.\n\nTwo rules the brief repeats and this file will too. An artifact that already\nexists is reported as \\`action: \"diff\"\\` — read it and report what disagrees;\nnever replace it, because a document somebody wrote is evidence. And everything\nyou write is \\`status: draft\\`: promotion is \\`loam vouch\\`, run by a person in the\nservice's own repo — \\`loam vouch --pack --service <id>\\` (read-only) preps that read.\n\n## What you author, what loam derives\n\nAuthored by hand: \\`intent.md\\`, \\`delta.likec4\\`, \\`specs/<svc>/spec.md\\`,\n\\`specs/<svc>/arch.spec.md\\`, \\`specs/<svc>/openapi.yaml\\`, ADRs, runbooks, health.\n\nWritten by loam: the merge into \\`services/<svc>/spec.md\\`, \\`services/<svc>/arch.spec.md\\`,\n\\`services/<svc>/openapi.yaml\\` and \\`architecture/landscape.likec4\\` at archive time.\n\n**Do not hand-edit the living landscape to add a feature's changes.** Put them in a\ndelta and archive it — otherwise the change has no intent, no requirement and no\nhistory behind it.\n\n## Rules the validator enforces\n\n- every requirement has at least one \\`#### Scenario:\\` — scenarios are the acceptance\n criteria and the source for tests;\n- every operationId a requirement governs exists in that service's OpenAPI;\n- every C4 edge's \\`op\\` resolves to an operation the target actually exposes;\n- every operation is governed by some requirement (warning);\n- a \"Calls\" edge with no \\`metadata { op }\\` is unlinked (warning);\n- **the map is complete**: every \\`services/<svc>/\\` has an element in the landscape,\n and every element that looks like a service has a directory (warning) or is\n tagged \\`#external\\`;\n- **the diff applies**: a \\`MODIFIED\\` or \\`REMOVED\\` requirement exists in the living\n spec, an \\`ADDED\\` one does not, and a section heading matches the grammar exactly;\n- a \\`Requirement-ID: <id>\\` is optional, but when present it is valid and unique;\n archive selects by it, so carry the same ID through \\`MODIFIED\\` to rename a heading;\n- **every requirement in a delta is under a delta section**: one under a prose heading\n (\\`## Behavior\\`) is documentation as far as the merge is concerned and is dropped\n (warning). \\`## Requirements\\` is exempt — quoting the living state is legal.\n\nThat last pair of rules exists because each of its failures used to be silent.\n\\`MODIFIED\\` of a requirement that does not exist merged as a creation; \\`ADDED\\` of one\nthat does exist REPLACED it, scenarios and all; a near-miss heading like\n\\`## ADDED Requirement\\` (singular) parses as plain prose, so archive merged nothing and\nsaid nothing; and a requirement under \\`## Behavior\\` vanished the same way.\n\nWrite the delta section heading on its own line exactly as \\`## ADDED Requirements\\`.\nThe heading is the only thing that gives a requirement its kind: without a matching\none, archive merges the requirement as nothing.\n\nSeverity and gating are two different questions. An ERROR means the document is\ninvalid — \\`loam validate\\` fails. A finding with \\`gates: true\\` means \\`loam archive\\`\nwill refuse — the merge is unsafe. They usually agree (errors gate, warnings do\nnot), and where they diverge the \\`--json\\` output says so: \\`delta.requirement-not-merged\\`\nis a warning (the shape is legal OpenSpec) that gates (the merge would drop the\nrequirement). Leave a warning standing only deliberately.\n\n`;\n"]}
|
|
1
|
+
{"version":3,"file":"cycle.js","sourceRoot":"","sources":["../../../../src/core/agent/agents-md/cycle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2JpB,CAAC","sourcesContent":["/**\n * What an agent DOES: the cycle step by step, adopting a service, what is\n * authored versus derived, and the rules the validator enforces.\n *\n * The done-check itself is no longer here — it is `loam instructions\n * loam-done-check` (../workflows/reference/done-check.ts). Steps 4 and 7 used\n * to end `See \"The requirement baseline\"` and `See \"The done-check\"`, naming\n * headings that were further down this same file; they now name the COMMAND\n * that prints them. That is not a rewording for its own sake: a section\n * reference to a section that left is a pointer at nothing, and a reader who\n * scrolls looking for it concludes the file is truncated — which, on the two\n * hosts that truncate silently, is a conclusion they cannot check.\n *\n * Not a section of the scaffolded AGENTS.md any more: that document carries a\n * condensed cycle of its own (../agents-md.ts), sized for a host that loads it\n * on every turn. This constant is the long teaching, and it is DELIVERED\n * through `loam explain`'s term paragraphs — ../../explain/terms.ts pins\n * verbatim phrases of it, so rewording a sentence here breaks the pairing\n * loudly instead of letting a term drift away from what loam ships. Two\n * consequences for an editor: a claim written here is read by an agent through\n * `loam explain <term>` and must stay true, and a phrase a pin names cannot be\n * reworded on one side alone.\n */\nexport const CYCLE = `## The cycle\n\n0. **Wire the repo** — \\`loam init --docs <path-to-docs-repo> --service <id>\\` in\n each service repo, then \\`loam doctor\\`. Once per repository, before anything\n else; see \"\\`loam.json\\` — the wiring\" above. Every step below runs in a repo\n that has been through this one.\n1. **Adopt** — a service with no documentation at all starts at\n \\`loam adopt --service <id> --json\\`, which briefs you on the baseline to write.\n See \"Adopting a service\" below. Once per service, not once per feature.\n2. **Understand** — \\`loam status --json\\` first if you joined halfway or lost the\n session: it says what is in flight and what the next step is, for the fleet or\n for one feature (\\`loam status FEAT-101 --json\\`). Then \\`loam list --json\\` and\n \\`loam show <service> --json\\`.\n Then \\`loam explore <service> --json\\` around the services you believe are\n involved — it writes nothing and answers the one question the next step takes\n as an argument: which services this change actually touches. It reports the\n ring one hop out in the fleet map (\\`neighbours\\`), how far each service's\n documentation has got (\\`maturity\\`), what each already exposes, the features\n already in flight over the same ground (\\`overlaps\\`), and the \\`loam new\\` line\n the seeds imply (\\`scaffold\\`). \\`--op <operationId>\\` seeds from an operation\n when you know the call but not who owns it.\n Never propose a change to a service you have not read.\n3. **Scaffold** — \\`loam new FEAT-101 --title \"...\" --touches <existing> --new-service <new>\\`.\n The scaffold leaves a \\`delta.likec4\\` whose context elements are commented out —\n a requirements-only feature should DELETE that file rather than ship an empty\n one — and gives every \\`--new-service\\` a \\`specs/<svc>/arch.spec.md\\` alongside.\n \\`--capability <id>\\` (repeatable, and it composes with \\`--touches\\`) scaffolds a\n capability delta instead of a service one — the inversion of this step, for a\n change whose BUSINESS side is what is known: open the promise that changes and\n derive the service work from it. An id the fleet has never named is scaffolded\n rather than refused, with the close spellings printed beside it; the archive\n is what creates the living \\`capabilities/<id>/spec.md\\`.\n4. **Author** the four files the scaffold left as TODO: intent, delta.likec4,\n a spec.md per service, an openapi.yaml per new service. Finish with\n \\`loam rebase FEAT-101\\`: it pins every MODIFIED/REMOVED requirement and every\n operation in the contract delta to the living version you wrote it against.\n On the contract axis run it even when you changed nothing but one endpoint —\n that is exactly what marks the REST of the document as quotation the merge\n must not write. See \\`loam instructions loam-spine\\` — \"The requirement baseline\".\n5. **Check** — \\`loam validate FEAT-101 --json\\`. Fix every error before writing code.\n \\`loam dependencies --json\\` says whether another feature in flight has to\n archive first.\n6. **Build** — \\`loam delta FEAT-101 --service <svc> --json\\` is the task for one service:\n intent, its requirement delta with scenarios verbatim, and the edges around it.\n In the service's own repo, \\`loam gherkin FEAT-101\\` then emits those scenarios as\n \\`.feature\\` files under \\`<gherkinDir>/loam/\\` — write step definitions against them\n **first**, outside \\`loam/\\`, and implement until they pass.\n If \\`architecture.errors\\` is non-empty the payload keeps \\`ok: true\\` (the command\n ran) but the exit code is 1: the C4 slice is empty because delta.likec4 did not\n parse, not because the feature changes no architecture — do not build on it.\n7. **Verify** — \\`loam verify FEAT-101 --json\\` turns the feature's own promises into a\n checklist. The scenario claims are answered by the cucumber report\n (\\`--results report.json\\`); answer the rest with evidence and record them\n (\\`--record answers.json --service <id>\\`), **from each affected service's own\n repo**. See \\`loam instructions loam-done-check\\`.\n8. **Ship** — \\`loam archive FEAT-101\\` once the code is merged. \\`--dry-run\\` shows\n every file the merge would write, and writes none of them.\n\n## Adopting a service\n\n\\`loam adopt --service <id>\\` does not read code and never will. Nothing\ndeterministic can look at a legacy service and say what its architecture MEANS,\nand a guessed model is worse than none: everybody downstream has to re-derive it\nto know whether to believe it. So loam takes the half of the job that is\nmechanical — stating the work, and checking the result — and you do the reading.\n\nThe brief names every file to write, the grammar each must be in, what the\nlandscape already says about the service (bind to those elements, do not draw a\nparallel fleet), the frontmatter, and the checks that follow. It also lists what\n**no** check will ever catch. Read that list: everything on it is a way to be\nwrong quietly, and \\`loam validate\\` passing means nothing about any of it.\n\nOne of the targets is not under \\`services/<id>/\\`: \\`architecture/landscape.likec4\\`,\nthe fleet map, carried with \\`action: \"edit\"\\` and a \\`landscape.instruction\\`\nspelling out the write this service owes it. That target appears while nothing\nin the map resolves to the service, and again while the element that does has\nno edge touching it — \\`landscape.touched\\` says which, and \\`landscape.attested\\`\nlists the calls the service's own model.likec4 declares across its boundary,\nwhich are the edges the map owes. **Add to that file; never rewrite it** —\nevery other service's elements and edges are in there. A service that is\nfully documented and undrawn is \\`landscape.service-unmodelled\\` (error) and is\ninvisible to every cross-service check: no edge into it can be graded against\nits openapi.yaml, and no feature can draw a call to it. A drawn, bound,\nedgeless service whose model reaches other systems is\n\\`landscape.service-isolated\\` (warn): drawn, and invisible to every\ncross-service check all the same. One whose model attests no such call is\nsilent there — the brief's \\`landscape.touched: false\\` is the only place that\nstate is named, so read it before the fleet run rather than hoping for it in it.\nAnd one edge closes the state; the check is touched/untouched, not a set\ndifference, so draw every attested call in one pass — nothing names the ones\nleft out.\n\nAn adoption ends with two runs, not one: \\`loam validate --service <id> --json\\`\nfor the baseline, then \\`loam validate --all --json\\` in the docs repo — the\nfleet cross-check the first invocation does not perform is exactly where a\nlandscape edit that did not land shows up. Done, stated once: \\`--service\\`\nclean when run from inside the service's own repo, and \\`--all\\` reporting no\n\\`landscape.*\\` finding. The fleet run is never SILENT — \\`sources.unverifiable-from-here\\`\n(severity ok) appears per service as a confirmation, not work — so \"keep going\nuntil validation is quiet\" is the wrong loop; the two runs above are the test.\n\nTwo rules the brief repeats and this file will too. An artifact that already\nexists is reported as \\`action: \"diff\"\\` — read it and report what disagrees;\nnever replace it, because a document somebody wrote is evidence. And everything\nyou write is \\`status: draft\\`: promotion is \\`loam vouch\\`, run by a person in the\nservice's own repo — \\`loam vouch --pack --service <id>\\` (read-only) preps that read.\n\n## What you author, what loam derives\n\nAuthored by hand: \\`intent.md\\`, \\`delta.likec4\\`, \\`specs/<svc>/spec.md\\`,\n\\`specs/<svc>/arch.spec.md\\`, \\`specs/<svc>/openapi.yaml\\`, ADRs, runbooks, health.\n\nWritten by loam: the merge into \\`services/<svc>/spec.md\\`, \\`services/<svc>/arch.spec.md\\`,\n\\`services/<svc>/openapi.yaml\\` and \\`architecture/landscape.likec4\\` at archive time.\n\n**Do not hand-edit the living landscape to add a feature's changes.** Put them in a\ndelta and archive it — otherwise the change has no intent, no requirement and no\nhistory behind it.\n\n## Rules the validator enforces\n\n- every requirement has at least one \\`#### Scenario:\\` — scenarios are the acceptance\n criteria and the source for tests;\n- every operationId a requirement governs exists in that service's OpenAPI;\n- every C4 edge's \\`op\\` resolves to an operation the target actually exposes;\n- every operation is governed by some requirement (warning);\n- a \"Calls\" edge with no \\`metadata { op }\\` is unlinked (warning);\n- **the map is complete**: every \\`services/<svc>/\\` has an element in the landscape,\n and every element that looks like a service has a directory (warning) or is\n tagged \\`#external\\`;\n- **the diff applies**: a \\`MODIFIED\\` or \\`REMOVED\\` requirement exists in the living\n spec, an \\`ADDED\\` one does not, and a section heading matches the grammar exactly;\n- a \\`Requirement-ID: <id>\\` is optional, but when present it is valid and unique;\n archive selects by it, so carry the same ID through \\`MODIFIED\\` to rename a heading;\n- **every requirement in a delta is under a delta section**: one under a prose heading\n (\\`## Behavior\\`) is documentation as far as the merge is concerned and is dropped\n (warning). \\`## Requirements\\` is exempt — quoting the living state is legal.\n\nThat last pair of rules exists because each of its failures used to be silent.\n\\`MODIFIED\\` of a requirement that does not exist merged as a creation; \\`ADDED\\` of one\nthat does exist REPLACED it, scenarios and all; a near-miss heading like\n\\`## ADDED Requirement\\` (singular) parses as plain prose, so archive merged nothing and\nsaid nothing; and a requirement under \\`## Behavior\\` vanished the same way.\n\nWrite the delta section heading on its own line exactly as \\`## ADDED Requirements\\`.\nThe heading is the only thing that gives a requirement its kind: without a matching\none, archive merges the requirement as nothing.\n\nSeverity and gating are two different questions. An ERROR means the document is\ninvalid — \\`loam validate\\` fails. A finding with \\`gates: true\\` means \\`loam archive\\`\nwill refuse — the merge is unsafe. They usually agree (errors gate, warnings do\nnot), and where they diverge the \\`--json\\` output says so: \\`delta.requirement-not-merged\\`\nis a warning (the shape is legal OpenSpec) that gates (the merge would drop the\nrequirement). Leave a warning standing only deliberately.\n\n`;\n"]}
|
|
@@ -16,9 +16,10 @@ export const CONTEXT_COMMAND = `- \`loam context <service>\` assembles the docs
|
|
|
16
16
|
requirements and arch requirements VERBATIM (bodies and scenarios included),
|
|
17
17
|
the OpenAPI operations with the requirements governing each, the AsyncAPI
|
|
18
18
|
messages with their send/receive direction, the fleet edges one hop out with
|
|
19
|
-
the map's own health beside them (\`landscape.present
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
the map's own health beside them (\`landscape.present\` is the FILE,
|
|
20
|
+
\`landscape.parses\` is the whole \`architecture/\` project the renderer loads,
|
|
21
|
+
as \`loam adopt\` reads it — an empty edge list under a map that does not parse
|
|
22
|
+
is "nobody could look", never "nobody calls this"), the \`Requires:\` permissions resolved against the
|
|
22
23
|
vocabulary (an undeclared entry is carried with \`declared: false\`, never
|
|
23
24
|
refused — and when the vocabulary ITSELF does not read, its parse failure
|
|
24
25
|
rides beside them, so \`declared: false\` there means nobody could look, not
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../../../src/core/agent/agents-md/map/lenses/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../../../../src/core/agent/agents-md/map/lenses/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4B9B,CAAC","sourcesContent":["/**\n * The `loam context` entry of the command map — one of the three consumer\n * LENSES this package holds (the agent briefing here, `./gate.ts`'s deploy\n * pipeline, `./diff.ts`'s PR review), the family carved out of `../` when the\n * map package hit its own five-file cap: command-map.ts sits against the\n * file-line limit, so the pack's documentation lives down here and is\n * concatenated after the map.\n *\n * Same assembly contract as every section: ../../../agents-md.ts concatenates\n * with NO join separator, so this string starts at the first character of its\n * opening line and ends with the newline that closes its last one.\n */\nexport const CONTEXT_COMMAND = `- \\`loam context <service>\\` assembles the docs slice bound to one service as a\n single deterministic briefing — the pack an agent loads before working in\n that service's repository. It writes nothing. One payload carries the living\n requirements and arch requirements VERBATIM (bodies and scenarios included),\n the OpenAPI operations with the requirements governing each, the AsyncAPI\n messages with their send/receive direction, the fleet edges one hop out with\n the map's own health beside them (\\`landscape.present\\` is the FILE,\n \\`landscape.parses\\` is the whole \\`architecture/\\` project the renderer loads,\n as \\`loam adopt\\` reads it — an empty edge list under a map that does not parse\n is \"nobody could look\", never \"nobody calls this\"), the \\`Requires:\\` permissions resolved against the\n vocabulary (an undeclared entry is carried with \\`declared: false\\`, never\n refused — and when the vocabulary ITSELF does not read, its parse failure\n rides beside them, so \\`declared: false\\` there means nobody could look, not\n that the claim is wrong), the capabilities this service realizes with the\n capability vocabulary's own health beside them, maturity and provenance,\n presence pointers for the runbook/health/ADRs, and every ACTIVE feature's\n delta over this service in \\`loam delta\\`'s own shapes. \\`--feature <FEAT>\\`\n narrows the in-flight section to that one feature and is echoed back as the\n \\`feature\\` key, so a narrowed pack says it is one; a known feature that does\n not touch the service still projects, with empty sections and its own\n services list. Exit 1 with \\`ok: true\\` means a document behind the pack did\n not parse — the fleet map, a living contract, a fleet vocabulary, another\n service's spec during the capability join, or an included feature's document\n (a feature whose delta.likec4 does not parse is still INCLUDED, its errors\n in the payload, because a change nobody can read is in flight, not absent)\n — and the empty section beside the flag IS the parse failure, not \"nothing\n here\". Identical state yields identical bytes, so packs are diffable across\n runs.\n`;\n"]}
|