akm-cli 0.9.30 → 0.10.261001-beta
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 +438 -0
- package/README.md +10 -10
- package/ROADMAP.md +112 -0
- package/STABILITY.md +99 -57
- package/dist/api-node.mjs +20 -0
- package/dist/api.d.ts +23 -0
- package/dist/api.js +45 -0
- package/dist/assets/hints/cli-hints-full.md +15 -29
- package/dist/assets/hints/cli-hints-short.md +2 -2
- package/dist/assets/improve-strategies/default.json +3 -3
- package/dist/assets/prompts/consolidate-pair.md +9 -7
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/cli/shared.js +31 -48
- package/dist/cli/unknown-flags.js +6 -43
- package/dist/cli.js +8 -34
- package/dist/commands/agent/contribute-cli.js +1 -1
- package/dist/commands/completions.js +1 -2
- package/dist/commands/config-cli.js +5 -28
- package/dist/commands/env/env-cli.js +5 -5
- package/dist/commands/env/secret-cli.js +2 -2
- package/dist/commands/feedback-cli.js +75 -49
- package/dist/commands/health/checks.js +41 -16
- package/dist/commands/health/plugin-staleness.js +52 -22
- package/dist/commands/improve/autonomy-gate.js +5 -3
- package/dist/commands/improve/consolidate/chunking.js +3 -10
- package/dist/commands/improve/consolidate/continuity-check.js +4 -4
- package/dist/commands/improve/consolidate/pair-pass.js +29 -10
- package/dist/commands/improve/consolidate.js +10 -65
- package/dist/commands/improve/distill/lesson-update.js +91 -0
- package/dist/commands/improve/distill-guards.js +1 -43
- package/dist/commands/improve/distill.js +148 -21
- package/dist/commands/improve/eligibility.js +14 -1
- package/dist/commands/improve/extract-cli.js +1 -1
- package/dist/commands/improve/extract-prompt.js +17 -7
- package/dist/commands/improve/extract.js +5 -7
- package/dist/commands/improve/improve-cli.js +125 -118
- package/dist/commands/improve/improve-strategies.js +8 -12
- package/dist/commands/improve/improve.js +134 -52
- package/dist/commands/improve/loop-stages.js +18 -5
- package/dist/commands/improve/planner.js +0 -1
- package/dist/commands/improve/preparation.js +40 -99
- package/dist/commands/improve/proactive-maintenance.js +2 -2
- package/dist/commands/improve/reflect-noise.js +3 -55
- package/dist/commands/improve/reflect.js +29 -34
- package/dist/commands/improve/retrieval-queries.js +37 -0
- package/dist/commands/improve/retrieval-scope.js +2 -2
- package/dist/commands/improve/salience.js +2 -9
- package/dist/commands/improve/session-asset.js +4 -1
- package/dist/commands/improve/stage.js +23 -12
- package/dist/commands/lint/index.js +5 -20
- package/dist/commands/observability-cli.js +3 -9
- package/dist/commands/proposal/drain.js +43 -6
- package/dist/commands/proposal/proposal-cli.js +11 -31
- package/dist/commands/proposal/repository.js +20 -14
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -3
- package/dist/commands/read/knowledge.js +3 -3
- package/dist/commands/read/remember-cli.js +0 -13
- package/dist/commands/read/search-cli.js +29 -97
- package/dist/commands/read/search.js +0 -11
- package/dist/commands/read/show.js +0 -19
- package/dist/commands/sources/plugin-upgrade.js +164 -101
- package/dist/commands/sources/sources-cli.js +1 -15
- package/dist/commands/sources/stash-cli.js +6 -14
- package/dist/commands/tasks/tasks-cli.js +4 -115
- package/dist/commands/workflow/plan.js +11 -33
- package/dist/commands/workflow-cli.js +2 -7
- package/dist/core/adapter/adapter-ids.js +1 -2
- package/dist/core/adapter/adapters/agent-skills-adapter.js +0 -4
- package/dist/core/adapter/adapters/akm-adapter.js +9 -48
- package/dist/core/adapter/adapters/akm-lint.js +10 -26
- package/dist/core/adapter/adapters/akm-metadata.js +2 -72
- package/dist/core/adapter/adapters/akm-task-adapter.js +0 -5
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +9 -28
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -20
- package/dist/core/adapter/adapters/generic-files-adapter.js +0 -10
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +0 -4
- package/dist/core/adapter/adapters/tool-dir-shared.js +0 -24
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -4
- package/dist/core/adapter/recognize-match.js +3 -4
- package/dist/core/common.js +18 -2
- package/dist/core/config/config-schema.js +12 -15
- package/dist/core/config/config-types.js +6 -15
- package/dist/core/config/config-walker.js +6 -23
- package/dist/core/config/config.js +17 -80
- package/dist/core/config/engine-semantics.js +7 -3
- package/dist/core/config/schema/engines.js +7 -7
- package/dist/core/config/schema/improve-processes.js +10 -63
- package/dist/core/config/schema/improve.js +2 -21
- package/dist/core/config/schema/index-config.js +6 -39
- package/dist/core/env-secret-ref.js +2 -45
- package/dist/core/errors.js +1 -2
- package/dist/core/extra-params.js +2 -86
- package/dist/core/file-lock.js +12 -7
- package/dist/core/improve-result.js +13 -1
- package/dist/core/mutation-target.js +2 -2
- package/dist/core/paths.js +4 -0
- package/dist/core/recognition-util.js +4 -5
- package/dist/core/run-lock.js +1 -1
- package/dist/core/subprocess.js +49 -0
- package/dist/core/warn.js +21 -4
- package/dist/core/write-source.js +3 -3
- package/dist/execution/target-ref.js +1 -2
- package/dist/indexer/indexer.js +15 -6
- package/dist/indexer/passes/memory-inference.js +15 -6
- package/dist/indexer/search/db-search.js +49 -36
- package/dist/indexer/search/fts-query.js +0 -19
- package/dist/indexer/search/ranking.js +29 -1
- package/dist/indexer/usage/usage-events.js +21 -16
- package/dist/integrations/agent/engine-resolution.js +5 -2
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +41 -98
- package/dist/integrations/agent/request-lowering.js +3 -3
- package/dist/integrations/harnesses/aider/index.js +5 -0
- package/dist/integrations/harnesses/amazonq/index.js +1 -0
- package/dist/integrations/harnesses/claude/config-import.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +5 -0
- package/dist/integrations/harnesses/codex/index.js +1 -0
- package/dist/integrations/harnesses/copilot/index.js +1 -0
- package/dist/integrations/harnesses/gemini/index.js +1 -0
- package/dist/integrations/harnesses/index.js +18 -39
- package/dist/integrations/harnesses/opencode/agent-builder.js +60 -35
- package/dist/integrations/harnesses/opencode/config-import.js +121 -52
- package/dist/integrations/harnesses/opencode/index.js +22 -0
- package/dist/integrations/harnesses/opencode/plugin-layout.js +68 -0
- package/dist/integrations/harnesses/opencode/session-log-types.js +12 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +72 -0
- package/dist/integrations/harnesses/opencode/session-log-v2.js +140 -0
- package/dist/integrations/harnesses/opencode/session-log.js +104 -115
- package/dist/integrations/harnesses/opencode/version.js +98 -0
- package/dist/integrations/harnesses/opencode-sdk/{harness.js → index.js} +5 -17
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +105 -206
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +199 -0
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +254 -0
- package/dist/integrations/harnesses/opencode-sdk/wire.js +66 -0
- package/dist/integrations/harnesses/openhands/index.js +1 -0
- package/dist/integrations/harnesses/pi/index.js +1 -0
- package/dist/integrations/harnesses/shared.js +2 -0
- package/dist/integrations/harnesses/types.js +2 -0
- package/dist/llm/client.js +74 -14
- package/dist/output/cli-hints.js +1 -1
- package/dist/output/context.js +10 -19
- package/dist/output/format-exempt.js +5 -8
- package/dist/output/shapes/helpers.js +1 -22
- package/dist/output/shapes/passthrough.js +0 -1
- package/dist/output/shapes.js +3 -31
- package/dist/output/stdout.js +5 -1
- package/dist/output/text/command-format.js +6 -1
- package/dist/output/text/workflow-format.js +4 -22
- package/dist/scripts/akm-migrate-node.js +15769 -16731
- package/dist/scripts/akm-migrate.js +16339 -17297
- package/dist/setup/detect.js +10 -4
- package/dist/setup/harness-config-import.js +5 -14
- package/dist/setup/setup.js +1 -1
- package/dist/setup/steps/tasks.js +12 -13
- package/dist/sources/providers/git-stash.js +94 -13
- package/dist/storage/repositories/index-utility-repository.js +2 -32
- package/dist/storage/repositories/index-vec-repository.js +4 -0
- package/dist/storage/repositories/task-history-repository.js +0 -5
- package/dist/storage/repositories/workflow-runs-repository.js +5 -15
- package/dist/tasks/embedded.js +2 -1
- package/dist/tasks/run/run-command-task.js +9 -1
- package/dist/tasks/run/run-workflow-task.js +4 -3
- package/dist/tasks/run/task-history.js +0 -2
- package/dist/tasks/run/task-log.js +38 -1
- package/dist/tasks/schedule-gates.js +39 -0
- package/dist/tasks/scheduler-binding.js +0 -16
- package/dist/tasks/scheduler-sync.js +3 -97
- package/dist/tasks/source/bounded-document.js +1 -1
- package/dist/tasks/source/task-source-v4.js +2 -12
- package/dist/tasks/task-run-reserved-flags.js +2 -31
- package/dist/workflows/authoring/authoring.js +6 -6
- package/dist/workflows/compile.js +8 -65
- package/dist/workflows/exec/child-workflow.js +22 -3
- package/dist/workflows/exec/native-executor.js +12 -147
- package/dist/workflows/exec/run-workflow.js +31 -103
- package/dist/workflows/exec/step-work.js +9 -178
- package/dist/workflows/exec/unit-dispatch.js +0 -10
- package/dist/workflows/freeze/environment.js +3 -44
- package/dist/workflows/freeze/freeze.js +8 -41
- package/dist/workflows/freeze/targets/child-workflow.js +27 -63
- package/dist/workflows/freeze/targets/command.js +2 -16
- package/dist/workflows/freeze/targets/shell.js +0 -2
- package/dist/workflows/freeze/task-bindings.js +2 -28
- package/dist/workflows/ir/params.js +12 -2
- package/dist/workflows/parser.js +82 -232
- package/dist/workflows/plan.js +1 -1
- package/dist/workflows/renderer.js +10 -19
- package/dist/workflows/runtime/run-plan.js +11 -53
- package/dist/workflows/runtime/runs.js +4 -27
- package/dist/workflows/source-files.js +12 -16
- package/dist/workflows/source-semantics.js +1 -93
- package/docs/README.md +43 -42
- package/docs/agents/README.md +15 -0
- package/docs/agents/agent-install.md +14 -0
- package/docs/architecture/0.10-process-rules.md +827 -0
- package/docs/architecture/README.md +67 -0
- package/docs/architecture/adapters.md +258 -0
- package/docs/architecture/akm-architecture-decision-history.md +2055 -0
- package/docs/architecture/akm-core-principles.md +126 -0
- package/docs/architecture/architecture.md +578 -0
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +550 -0
- package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +72 -0
- package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +142 -0
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +189 -0
- package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +97 -0
- package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +108 -0
- package/docs/architecture/decisions/0006-task-source-version-routing.md +124 -0
- package/docs/architecture/decisions/0007-workflow-composition-bounds.md +83 -0
- package/docs/architecture/decisions/0008-task-binding-normalization.md +88 -0
- package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +80 -0
- package/docs/architecture/decisions/0010-driver-protocol-cut.md +36 -0
- package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +125 -0
- package/docs/architecture/decisions/README.md +62 -0
- package/docs/architecture/improvement.md +479 -0
- package/docs/architecture/internals/classification.md +154 -0
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +40 -0
- package/docs/architecture/internals/functional-contract-patterns.md +340 -0
- package/docs/architecture/internals/health-advisories.md +110 -0
- package/docs/architecture/internals/improve-workflow.md +719 -0
- package/docs/architecture/internals/indexing.md +498 -0
- package/docs/architecture/internals/registry-network-boundary.md +57 -0
- package/docs/architecture/internals/search.md +248 -0
- package/docs/architecture/internals/storage-locations.md +943 -0
- package/docs/architecture/persisted-data-compat.md +68 -0
- package/docs/architecture/reviews/env-secret-access.md +319 -0
- package/docs/architecture/runtime-boundary-design.md +153 -0
- package/docs/architecture/specs/0.9.0-close-out-plan.md +361 -0
- package/docs/architecture/specs/0.9.0-decisions.md +532 -0
- package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +745 -0
- package/docs/architecture/specs/0.9.0-open-items-register.md +135 -0
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +740 -0
- package/docs/architecture/specs/0.9.0-release-surface-review.md +636 -0
- package/docs/architecture/specs/agent-command-engine-model-design.md +513 -0
- package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +501 -0
- package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +291 -0
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +2059 -0
- package/docs/architecture/specs/di-seams-plan.md +539 -0
- package/docs/architecture/specs/driver-protocol-keep-or-cut.md +275 -0
- package/docs/architecture/specs/fact-asset-type.md +142 -0
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +634 -0
- package/docs/architecture/specs/okf-support.md +148 -0
- package/docs/architecture/specs/ref.md +329 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/README.md +72 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +152 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +352 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +300 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +402 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +758 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +645 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +602 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +27 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +74 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +15 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +132 -0
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +147 -0
- package/docs/architecture/specs/stash-conventions-code-spec.md +275 -0
- package/docs/architecture/specs/stash-organization-conventions.md +377 -0
- package/docs/architecture/specs/task-workflow-format-unification.md +721 -0
- package/docs/architecture/specs/workflow-engine-buy-vs-build.md +231 -0
- package/docs/architecture/specs/workflow-format-unification.md +432 -0
- package/docs/architecture/testing/manual-testing-checklist.md +3411 -0
- package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +924 -0
- package/docs/architecture/testing/task-workflow-manual-tests.md +1720 -0
- package/docs/architecture/testing/testing-workflow.md +446 -0
- package/docs/architecture/workflow-engine.md +223 -0
- package/docs/guides/README.md +33 -0
- package/docs/guides/author-bundles.md +310 -0
- package/docs/guides/author-workflows.md +490 -0
- package/docs/guides/bundles.md +323 -0
- package/docs/guides/capture-knowledge.md +136 -0
- package/docs/guides/claude-code-vs-akm-workflows.md +29 -0
- package/docs/guides/concepts.md +93 -0
- package/docs/guides/discover-and-load.md +158 -0
- package/docs/guides/getting-started.md +240 -0
- package/docs/guides/improve-the-library.md +247 -0
- package/docs/guides/knowledge-management.md +18 -0
- package/docs/guides/recipes/headless-install.md +97 -0
- package/docs/guides/recipes/website-source.md +28 -0
- package/docs/guides/run-workflows.md +279 -0
- package/docs/guides/scheduling.md +131 -0
- package/docs/guides/use-with-any-agent.md +174 -0
- package/docs/guides/wikis.md +81 -0
- package/docs/integration/bundling-akm.md +7 -6
- package/docs/maintainers/README.md +19 -0
- package/docs/maintainers/curate-workmap.md +335 -0
- package/docs/maintainers/eval.md +3 -0
- package/docs/maintainers/local-development.md +108 -0
- package/docs/maintainers/release-checklist.md +135 -0
- package/docs/migration/README.md +4 -2
- package/docs/migration/release-notes/0.0.13.md +1 -1
- package/docs/migration/release-notes/0.1.0.md +1 -1
- package/docs/migration/release-notes/0.10.0.md +201 -0
- package/docs/migration/release-notes/0.2.0.md +1 -1
- package/docs/migration/release-notes/0.3.0.md +1 -1
- package/docs/migration/release-notes/0.5.0.md +1 -1
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.7.3.md +2 -2
- package/docs/migration/release-notes/0.7.4.md +1 -1
- package/docs/migration/release-notes/0.7.5.md +1 -1
- package/docs/migration/release-notes/0.8.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +1 -1
- package/docs/migration/release-notes/0.9.14.md +1 -1
- package/docs/migration/release-notes/0.9.15.md +1 -1
- package/docs/migration/release-notes/0.9.16.md +1 -1
- package/docs/migration/release-notes/0.9.17.md +1 -1
- package/docs/migration/release-notes/0.9.19.md +1 -1
- package/docs/migration/release-notes/0.9.2.md +1 -1
- package/docs/migration/release-notes/README.md +28 -31
- package/docs/migration/v0.5-to-v0.6.md +759 -0
- package/docs/migration/v0.8-to-v0.9.md +1 -1
- package/docs/migration/v0.9-to-v0.10.md +507 -0
- package/docs/plans/0.9.2-agent-command-workflow-plan.md +423 -0
- package/docs/posts/README.md +30 -0
- package/docs/posts/akm-command-tour.md +495 -0
- package/docs/posts/akm-logo-sized.webp +0 -0
- package/docs/posts/belief-aware-memory-12.md +139 -0
- package/docs/posts/config-v2-lessons-16.md +191 -0
- package/docs/posts/improve-loop-autonomous-10.md +225 -0
- package/docs/posts/improve-pipeline-debugging-0803.md +179 -0
- package/docs/posts/intro-part-01.md +76 -0
- package/docs/posts/intro-part-02.md +221 -0
- package/docs/posts/intro-part-03.md +190 -0
- package/docs/posts/intro-part-04.md +221 -0
- package/docs/posts/llm-mode-reflect-13.md +166 -0
- package/docs/posts/openpalm-built-on-akm.md +86 -0
- package/docs/posts/progressive-disclosure-06.md +129 -0
- package/docs/posts/proposal-safety-net-15.md +112 -0
- package/docs/posts/release-0.5.0.md +247 -0
- package/docs/posts/release-0.6.0.md +117 -0
- package/docs/posts/release-0.7.0.md +159 -0
- package/docs/posts/release-0.8.0.md +332 -0
- package/docs/posts/scattered-skills-05.md +100 -0
- package/docs/posts/task-assets-persistent-workflows-11.md +222 -0
- package/docs/posts/team-skills-07.md +198 -0
- package/docs/posts/wiki-agent-knowledge-08.md +223 -0
- package/docs/posts/workflows-vaults-09.md +321 -0
- package/docs/product-surface.md +54 -0
- package/docs/reference/README.md +2 -2
- package/docs/reference/api.md +65 -0
- package/docs/reference/asset-types.md +166 -0
- package/docs/reference/bundle-types.md +2 -4
- package/docs/reference/cli.md +163 -192
- package/docs/reference/configuration.md +101 -20
- package/docs/reference/data-and-telemetry.md +2 -2
- package/docs/reference/env-and-secrets.md +126 -0
- package/docs/reference/memory.md +124 -0
- package/docs/reference/refs.md +156 -0
- package/docs/reference/registry.md +489 -0
- package/docs/reference/supported-formats.md +3 -4
- package/docs/reference/tasks.md +12 -19
- package/docs/reference/website-sources.md +141 -0
- package/docs/reference/workflow-schema.md +89 -317
- package/docs/reference/workflows.md +20 -48
- package/package.json +23 -16
- package/schemas/akm-config.json +2 -243
- package/schemas/akm-task.json +2 -3
- package/schemas/akm-workflow.json +47 -84
- package/dist/assets/improve-strategies/catchup.json +0 -41
- package/dist/assets/improve-strategies/proactive-maintenance.json +0 -24
- package/dist/assets/improve-strategies/quick.json +0 -17
- package/dist/assets/improve-strategies/reflect-distill.json +0 -29
- package/dist/assets/improve-strategies/thorough.json +0 -49
- package/dist/assets/prompts/retrieval-relevance-judge.md +0 -6
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +0 -6
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +0 -4
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +0 -4
- package/dist/cli/retired-commands.js +0 -118
- package/dist/commands/improve/retrieval-gate.js +0 -132
- package/dist/commands/tasks/validate.js +0 -176
- package/dist/core/config/legacy-source-shape-shim.js +0 -117
- package/dist/indexer/feedback/utility-policy.js +0 -75
- package/dist/integrations/harnesses/ids.js +0 -28
- package/dist/tasks/source/task-source-v3-frozen.js +0 -424
- package/dist/tasks/source/task-to-v4.js +0 -863
- package/dist/workflows/exec/worktree.js +0 -372
- package/dist/workflows/freeze/child-output-references.js +0 -83
- package/dist/workflows/freeze/identity.js +0 -22
- package/dist/workflows/freeze/targets/script.js +0 -50
- package/dist/workflows/freeze/targets/task.js +0 -124
- package/dist/workflows/github-yaml.js +0 -506
- package/dist/workflows/runtime/run-outputs.js +0 -80
|
@@ -0,0 +1,602 @@
|
|
|
1
|
+
# Review #3 — `task-workflow-format-unification.md` (v7) + the implementation it builds on
|
|
2
|
+
|
|
3
|
+
Reviewer: independent reviewer #3 of 3.
|
|
4
|
+
Repo: `/home/user/akm` @ `claude/akm-markdown-tasks-history-75l6du` (baselined on `claude/release-0-9-0-polish-d6sycl`).
|
|
5
|
+
Scope: the spec end-to-end, every factual claim it makes about the code, and the readiness of the
|
|
6
|
+
code it plans to build on.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 0. Summary judgement
|
|
11
|
+
|
|
12
|
+
The **direction** is right and the grounding (§1) is sound: `uses:`/`run:`, the prose rule, and
|
|
13
|
+
"steps are tasks" genuinely reduce concept count, and the target-key XOR really does make a whole
|
|
14
|
+
error class structurally impossible. The `.yml` task format is, on inspection, worse than the spec
|
|
15
|
+
says it is (see F-04) and deserves to die.
|
|
16
|
+
|
|
17
|
+
The **v7 configuration section (§3.4) and the non-goals (§10) do not survive contact with the
|
|
18
|
+
code.** Three load-bearing claims are false:
|
|
19
|
+
|
|
20
|
+
1. Freeze's "layer cascade" the spec says it is merely *exposing* does **not** include a config
|
|
21
|
+
defaults layer for anything but `engine` — `defaults.model` does not exist in the config schema
|
|
22
|
+
and is read nowhere, so the spec's own worked example silently does nothing today.
|
|
23
|
+
2. The "kind-gated hard error" the spec says `llm:` exists to scope is **dead code** in
|
|
24
|
+
`freeze.ts`. The workflow surface already silently drops `llm` overrides on agent engines.
|
|
25
|
+
3. §10's "no changes to IR, freeze, journal, leases, or replay" is contradicted by §3.4/§3.6/§3.7 on
|
|
26
|
+
at least six counts (agent persona → system prompt/tool policy; shell units without an engine;
|
|
27
|
+
`env` list-of-mappings; `cwd`/`shell`/`params` at dispatch; non-empty-`instructions` invariant;
|
|
28
|
+
the unit input-hash preimage). This is not authoring-surface-only work; it is an IR v3 schema +
|
|
29
|
+
hash-version change.
|
|
30
|
+
|
|
31
|
+
Plus two silent-loss bugs the plan would bake in: deleting `unit.output` conflates two
|
|
32
|
+
*semantically different* schemas (F-05), and moving `command:` argv → `run:` shell text destroys
|
|
33
|
+
the `akm`-binary resolution seam every shipped template depends on (F-06).
|
|
34
|
+
|
|
35
|
+
Recommendation: **do not sign off decision 14 as written.** §3.4 needs a config-layer reality pass
|
|
36
|
+
and §10 needs to be rewritten to admit an IR change. §3.3/§3.6 need the input-hash and
|
|
37
|
+
`instructions` invariants addressed before anyone starts.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 1. Findings table
|
|
42
|
+
|
|
43
|
+
| # | Sev | Title | Evidence |
|
|
44
|
+
|---|---|---|---|
|
|
45
|
+
| F-01 | critical | Cascade's "config defaults" layer does not exist; the worked example is a silent no-op | `config-schema.ts:102-108`, `freeze.ts:169-171,193-209` |
|
|
46
|
+
| F-02 | critical | §10 "no IR/freeze changes" is false — §3.4/§3.6/§3.7 all require IR v3 schema changes | `ir/schema.ts:417-451`, `unit-dispatch.ts:9-31`, `native-executor.ts:1026-1027` |
|
|
47
|
+
| F-03 | critical | Shell (`run:`) units cannot exist in the current IR: no engine, empty instructions, no runner kind | `freeze.ts:52-62`, `ir/schema.ts:434-441`, `native-executor.ts:1104+` |
|
|
48
|
+
| F-04 | critical | Unit input-hash preimage is unaddressed — `run:`/`uses:`/`cwd`/`shell`/`params` would not re-dispatch | `step-work.ts:376-392` |
|
|
49
|
+
| F-05 | major | Deleting the `unit:` bag conflates two distinct `output` schemas and loses per-item validation on `map` | `program/schema.ts:125,186`, `compile.ts:204,229`, `native-executor.ts:54-56,663` |
|
|
50
|
+
| F-06 | major | `command:` argv → `run:` shell text destroys `resolveNestedAkmCommand` / akm-bin resolution | `runner.ts:263,343-348`, `command-executable.ts:18-22`, `src/assets/tasks/**` |
|
|
51
|
+
| F-07 | major | The "kind-gated hard error" §3.4 argues against is dead code; workflows already drop `llm` silently | `freeze.ts:67-73` |
|
|
52
|
+
| F-08 | major | `agent:` as a cascade selector requires system-prompt + tool-policy plumbing that does not exist | `native-executor.ts:1026-1027`, `renderers.ts:252-262`, `IrInvocation` `ir/schema.ts:78-84` |
|
|
53
|
+
| F-09 | major | `params:` now means three different things; §5 claims this as a simplification | §3.2 vs §5 vs `renderers.ts:164-176`, `ir/params.ts:34-56` |
|
|
54
|
+
| F-10 | major | Command-template filling is undefined for the actual placeholder grammar (`$ARGUMENTS`, `$1`..`$9`) | `renderers.ts:164-176`, `indexer/walk/matchers.ts:126` |
|
|
55
|
+
| F-11 | major | `env:` list-of-mappings breaks the IR `string[]` contract and the "names only" hash invariant | `ir/schema.ts:448`, `step-work.ts:353-357,387` |
|
|
56
|
+
| F-12 | major | Prose-optional on `uses:`/`run:` steps collides with the non-empty-`instructions` invariant | `workflows/parser.ts:281-296`, `ir/schema.ts:434-441` |
|
|
57
|
+
| F-13 | major | Migrator depends on the live task parser; yml→md is a path-changing content step in a journaled plan | `task-target-ref-migration.ts:27,44-58` |
|
|
58
|
+
| F-14 | major | Markdown tasks silently inherit the whole markdown lint/OKF/`improve` surface — including body rewrites of live prompts | `akm-adapter.ts:388-434`, `asset-placement.ts:157-169` |
|
|
59
|
+
| F-15 | minor | Model aliases are *not* portable to LLM endpoints or non-claude/opencode platforms | `model-aliases.ts:45-104` |
|
|
60
|
+
| F-16 | minor | Gate judges are outside the cascade; §3.4 never says whether that stays | `freeze.ts:109,263-278` |
|
|
61
|
+
| F-17 | minor | `on_error` is called steps-only in §3.4 but already exists at document defaults | §3.4 vs `program/schema.ts:210`, `compile.ts:231` |
|
|
62
|
+
| F-18 | minor | Adapter story for `.md` tasks is underspecified and partly contradicts `okf-support.md` | `adapters/index.ts:73-88`, `akm-workflow-adapter.ts:141-155`, `okf-support.md:47-63` |
|
|
63
|
+
| F-19 | minor | `status: draft` adds a second, orthogonal installation gate next to `enabled:` | §4 vs `tasks.ts:400-445` |
|
|
64
|
+
| F-20 | minor | `task_history.target_kind` is a persisted enum the new target vocabulary outgrows | `runner.ts:823-830,870-899` |
|
|
65
|
+
| F-21 | minor | Embedded-template enumeration fails *silently* on format change | `embedded.ts:91-97` |
|
|
66
|
+
| F-22 | minor | Composition loses single-file provenance (`IrUnitNode.source`) and can blow the 256 KiB instruction cap | `ir/schema.ts:444-445`, `compile.ts:186` |
|
|
67
|
+
| F-23 | minor | 0.7 md → 0.8 yml → 0.9 md whiplash; the existing collision guard must be inverted | `tasks.ts:154-163` |
|
|
68
|
+
| F-24 | minor | `prompt: agents/x` sends raw file bytes (frontmatter included) — worse than §3.5 describes | `runner.ts:592-593` |
|
|
69
|
+
|
|
70
|
+
Claims I checked and found **accurate**: `parser.ts` is 368 lines; `akm-task.json` is 87 lines and
|
|
71
|
+
loaded by nothing at runtime (`tests/integration/tasks-schema.test.ts:8` only); `start`/`next`/
|
|
72
|
+
`complete` are gone (`workflow-cli.ts:522-531`); `runWorkflowTask()` → `runWorkflowSteps()` works
|
|
73
|
+
(`runner.ts:352-416`); `UnitDispatchRequest` carries prompt/engine/timeoutMs/env/cwd/
|
|
74
|
+
sensitiveValues and results carry `failureReason` (`unit-dispatch.ts:9-43`); `output` really is
|
|
75
|
+
declared twice in `akm-workflow.json` (`:232,344`); command assets really do read an `agent:`
|
|
76
|
+
frontmatter key (`renderers.ts:235`); agent assets really are model-hint-only
|
|
77
|
+
(`renderers.ts:260`); `temperature` on an agent-kind engine really is a config error
|
|
78
|
+
(`engines.ts:105-120`); `resolveModel()` really is a one-level four-tier chain
|
|
79
|
+
(`model-aliases.ts:89-104`).
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 2. Critical
|
|
84
|
+
|
|
85
|
+
### F-01 — The cascade's far layer does not exist. The worked example is a silent no-op.
|
|
86
|
+
|
|
87
|
+
§2 and §3.4 rest on: *"Freeze already implements a configuration cascade … §3.4 exposes this
|
|
88
|
+
existing mechanism."* The mechanism exists **for the two document layers only**.
|
|
89
|
+
|
|
90
|
+
`freeze.ts:50` builds `layers = [documentDefaults, unit]`. Resolution:
|
|
91
|
+
|
|
92
|
+
- engine — `selectedEngine()` walks layers nearest-first, then falls back to
|
|
93
|
+
`config.defaults?.engine` (`freeze.ts:151-155`). ✅ config layer exists.
|
|
94
|
+
- model — `exactModel()` walks layers, then `engine.model` (`freeze.ts:169-171`). **`config.defaults.model` is never consulted.**
|
|
95
|
+
- timeout — `effectiveTimeout()` walks layers, then `engine.timeoutMs`, then a builtin constant (`freeze.ts:193-209`). **No config-defaults timeout.**
|
|
96
|
+
- llm overrides — `mergedLlmOverrides()` deep-merges layers only (`freeze.ts:211-216`). No engine-node or config-defaults participation (the engine's own `temperature`/`maxTokens` go into the *snapshot*, `freeze.ts:231-236`, a different path).
|
|
97
|
+
|
|
98
|
+
And the config schema has no such key at all:
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
// src/core/config/config-schema.ts:102-108
|
|
102
|
+
export const DefaultsSchema = z.object({
|
|
103
|
+
engine: engineName.optional(),
|
|
104
|
+
llmEngine: engineName.optional(),
|
|
105
|
+
improveStrategy: engineName.optional(),
|
|
106
|
+
}).passthrough();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`.passthrough()` means the spec's literal worked example —
|
|
110
|
+
`{ "defaults": { "engine": "claude", "model": "sonnet" } }` (§3.4) — **validates today and does
|
|
111
|
+
absolutely nothing.** A user following the spec's teaching example gets silent configuration loss,
|
|
112
|
+
the exact failure mode `config-schema.ts:117-120` says the strict schema exists to prevent.
|
|
113
|
+
|
|
114
|
+
So the honest framing is the opposite of the spec's: freeze implements a *two-layer* nearest-wins
|
|
115
|
+
resolution with per-field engine fallbacks. §3.4 proposes a **five-layer** cascade. Three of those
|
|
116
|
+
five layers (config defaults, engine node as a uniform layer, persona node) do not exist as layers
|
|
117
|
+
and must be built, each with its own schema surface.
|
|
118
|
+
|
|
119
|
+
**Recommendation.** Rewrite §2's third bullet and §3.4's opening to say what is true: "freeze
|
|
120
|
+
resolves two document layers nearest-wins; §3.4 generalizes that to five." Then add an explicit
|
|
121
|
+
sub-section enumerating the *new config schema surface* (`defaults.model`, `defaults.timeout`,
|
|
122
|
+
`defaults.env`, …) with `.strict()` on it, plus a migration note that a pre-existing
|
|
123
|
+
passthrough `defaults.model` would change meaning from inert to load-bearing — which violates §8's
|
|
124
|
+
"No key survives with a changed meaning."
|
|
125
|
+
|
|
126
|
+
### F-02 — §10 "no changes to IR, freeze, journal, leases, or replay" is false.
|
|
127
|
+
|
|
128
|
+
§10 asserts the §3.4 cascade and §3.6 flatten are "authoring-surface changes over the layer
|
|
129
|
+
resolution freeze already performs." Every one of the following requires an IR v3 shape change,
|
|
130
|
+
each of which trips `assertKeys` (`ir/schema.ts:417-433`) and therefore changes `plan_hash`
|
|
131
|
+
(`plan-hash.ts:22-34`) for every plan:
|
|
132
|
+
|
|
133
|
+
| §3.x feature | IR field needed | Blocking code |
|
|
134
|
+
|---|---|---|
|
|
135
|
+
| `agent:` persona (system prompt) | `IrUnitNode.systemPrompt` | `native-executor.ts:1026-1027` — "`systemPrompt`/`tools`/`cwd` come from the profile/asset, not the workflow unit" |
|
|
136
|
+
| `agent:` persona (tool policy) | new IR field + dispatch plumbing | no field on `UnitDispatchRequest` at all (`unit-dispatch.ts:9-31`) |
|
|
137
|
+
| `cwd:` as a value field | `IrUnitNode.cwd` | today `request.cwd` is populated only by worktree isolation |
|
|
138
|
+
| `shell:` | `IrUnitNode.shell` | no such concept |
|
|
139
|
+
| `params:` at step level | `IrUnitNode.params` | params are run-level only (`step-work.ts:326`) |
|
|
140
|
+
| `run:` target | a target discriminator on the node | `node.kind` is `"unit"\|"map"` only (`ir/schema.ts:392`) |
|
|
141
|
+
| `env:` literal mappings | `env` type widened | `validateStringArray(node.env, …)` (`ir/schema.ts:448`) |
|
|
142
|
+
|
|
143
|
+
`IrInvocation` today is exactly `{engine, model, timeoutMs, llm?}` (`ir/schema.ts:78-84`).
|
|
144
|
+
|
|
145
|
+
**Recommendation.** Replace §10's first bullet with an explicit IR-change budget: list the new
|
|
146
|
+
`IrUnitNode`/`IrInvocation` fields, state whether `WORKFLOW_IR_VERSION` bumps to 4 (it should — the
|
|
147
|
+
plan classifier already has an `unsupported-version` arm, `plan-classifier.ts:14`), and note that
|
|
148
|
+
every frozen-plan golden and the replay-fuzz suite re-baselines. Pre-release makes this cheap; the
|
|
149
|
+
spec pretending it is free makes it *unschedulable*.
|
|
150
|
+
|
|
151
|
+
### F-03 — A `run:` step cannot be frozen at all today.
|
|
152
|
+
|
|
153
|
+
§3.6 says a shell unit "journals like any unit (`workflow_run_units`): no tokens, but status,
|
|
154
|
+
timing, attempts, and `failure_reason` behave normally." Three hard blocks:
|
|
155
|
+
|
|
156
|
+
1. **Engine required.** `freezeInvocation()` (`freeze.ts:49-75`) throws `ConfigError("No workflow
|
|
157
|
+
engine is selected…")` when no layer and no `config.defaults.engine` names one. A workflow of
|
|
158
|
+
nothing but `run:` steps therefore **fails to freeze on a machine with no agent CLI installed** —
|
|
159
|
+
the single most obvious reason to want shell steps.
|
|
160
|
+
2. **Non-empty instructions required.** `ir/schema.ts:434-441` fails a unit whose `instructions` is
|
|
161
|
+
not a non-empty string. A `run:` step whose prose section is optional (§3.3/§4) produces `""`
|
|
162
|
+
(`compile.ts:174`).
|
|
163
|
+
3. **No shell runner.** `frozenUnitRunner`/`defaultUnitDispatcher` branch on `llm` / `sdk` / `agent`
|
|
164
|
+
(`native-executor.ts:1076,1104`). `FrozenEngineSnapshot` is `FrozenLlmEngine | FrozenAgentEngine`.
|
|
165
|
+
There is no fourth kind, and the two guards at `native-executor.ts:1050-1074` (env-unsupported,
|
|
166
|
+
isolation-unsupported) are written assuming a child process implies an agent.
|
|
167
|
+
|
|
168
|
+
**Recommendation.** §3.6 must specify a `kind: "shell"` frozen node with **no** `invocation`, make
|
|
169
|
+
`instructions` optional-when-shell (or synthesise the `run:` text as the instruction bytes), and
|
|
170
|
+
say explicitly that a shell-only workflow must freeze without any engine configured. Otherwise the
|
|
171
|
+
headline "`run:` is inline shell, no AI" is undeliverable.
|
|
172
|
+
|
|
173
|
+
### F-04 — The unit input-hash preimage is never mentioned; replay would be wrong.
|
|
174
|
+
|
|
175
|
+
`step-work.ts:376-392` computes the per-unit `inputHash` over a fixed preimage
|
|
176
|
+
(`hashVersion: 4`): `template.instructions`, `item`, `inputs`, `params`, `dispatch`, `invocation`,
|
|
177
|
+
`schema`, `env`, `isolation`, `gateFeedback`. Its own comment states the contract: *"Every field
|
|
178
|
+
here is a PLAN-FROZEN input that changes what the backend is actually asked to do, so a completed
|
|
179
|
+
unit is reused ONLY when all of them match."*
|
|
180
|
+
|
|
181
|
+
None of the new dispatch-significant surface is in that preimage:
|
|
182
|
+
|
|
183
|
+
- the `run:` shell text (for a shell unit `instructions` may be empty or unrelated prose — editing
|
|
184
|
+
`run: bun test` → `run: bun test --coverage` would **reuse the completed row**);
|
|
185
|
+
- `uses:` ref and the resolved target;
|
|
186
|
+
- `cwd`, `shell`, step-level `params`;
|
|
187
|
+
- the appended `uses:`-step prose (§3.3) if the concat happens at prompt assembly rather than at
|
|
188
|
+
freeze — `instructions` is what is hashed, not the assembled `prompt`.
|
|
189
|
+
|
|
190
|
+
That last one is subtle and important. §3.3 says the append is "a deterministic concat" at "one
|
|
191
|
+
seam". If that seam is `buildUnitPrompt` (`step-work.ts:331`), the hash preimage does not see it and
|
|
192
|
+
two materially different asks hash identically — the same class of bug the `gateFeedback` inclusion
|
|
193
|
+
(`step-work.ts:363-370`) was added to fix.
|
|
194
|
+
|
|
195
|
+
**Recommendation.** Add a §3.8 "Replay identity": every new field enters the preimage,
|
|
196
|
+
`hashVersion` becomes 5, and the `uses:` prose append happens **at freeze**, folded into
|
|
197
|
+
`instructions`, so the existing preimage covers it for free. Also note the one-time consequence:
|
|
198
|
+
bumping `hashVersion` invalidates reuse for every in-flight run at cutover.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 3. Major
|
|
203
|
+
|
|
204
|
+
### F-05 — Deleting the `unit:` bag silently deletes per-item output validation.
|
|
205
|
+
|
|
206
|
+
§3.6: *"`output:` is declared **both** on the step and inside the bag — a live wart … The duplicate
|
|
207
|
+
`output` declaration disappears with the bag."* They are not duplicates.
|
|
208
|
+
|
|
209
|
+
- `unit.output` → `WorkflowUnitDraft.schema` (`compile.ts:229`) → `IrUnitNode.schema` →
|
|
210
|
+
`UnitDispatchRequest.schema` (`native-executor.ts:663`) → constrains the harness's structured
|
|
211
|
+
output and drives `runStructured` / `parse_error` retries (`native-executor.ts:928-929,1038,1092`).
|
|
212
|
+
- `step.output` → `IrStepPlan.outputSchema` → validates the **promoted step artifact** after
|
|
213
|
+
reduction, with a distinct failure mode that feeds the gate loop
|
|
214
|
+
(`native-executor.ts:54-62`: "the promoted artifact is validated … flagged (`artifactSchemaFailure`)
|
|
215
|
+
so the engine's bounded gate loop can re-run the step").
|
|
216
|
+
|
|
217
|
+
For a `map` step these are necessarily different schemas: `map.unit.output` types *one item's*
|
|
218
|
+
result, `step.output` types the *collected* array. Collapsing them onto one step-level `output:`
|
|
219
|
+
key makes per-item structured output unexpressible on fan-out, and quietly disables constrained
|
|
220
|
+
generation for every mapped unit.
|
|
221
|
+
|
|
222
|
+
**Recommendation.** Keep two keys under distinct names after the flatten — e.g. `output:` (step
|
|
223
|
+
artifact, unchanged) and `result:`/`unit_output:` (per-unit/per-item schema). Correct the §3.6
|
|
224
|
+
"wart" claim and the §6 table row that repeats it.
|
|
225
|
+
|
|
226
|
+
### F-06 — `run:` shell text destroys akm-binary resolution for every shipped template.
|
|
227
|
+
|
|
228
|
+
Today `command:` is **pre-split argv** (`parser.ts:300-306`) executed without a shell
|
|
229
|
+
(`runner.ts:277`), and before spawning, `resolveNestedAkmCommand()` (`runner.ts:343-348`) rewrites a
|
|
230
|
+
bare `akm` in the executable position to the *current installation's* invocation via
|
|
231
|
+
`resolveAkmInvocation()` — including the `env VAR=… akm …` form (`command-executable.ts:10-22`).
|
|
232
|
+
|
|
233
|
+
All ten shipped templates are exactly this shape:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
# src/assets/tasks/core/improve.yml
|
|
237
|
+
command: akm improve
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Under `run: akm improve` executed by `sh -c`, that rewrite is impossible without shell-text
|
|
241
|
+
parsing — which the spec explicitly wants to avoid ("no ref-vs-inline sniffing exists anywhere in
|
|
242
|
+
the format"). The scheduled invocation captures `PATH` in its descriptor
|
|
243
|
+
(`scheduler-invocation.ts:86`), so a globally-installed binary survives; a `bun run src/index.ts`
|
|
244
|
+
dev install, a version-managed install, or a compiled binary not on the captured `PATH` does not.
|
|
245
|
+
`akm task doctor` already flags `path-selected` bindings as a distinct status (`tasks.ts:739`) —
|
|
246
|
+
this change makes *every* shell task path-selected.
|
|
247
|
+
|
|
248
|
+
Related: `runCommandTask` runs with `cwd: process.env.HOME ?? os.tmpdir()` (`runner.ts:279`) while
|
|
249
|
+
`runPromptTask` uses `cwd: stashDir` (`runner.ts:522`). §3.4 introduces `cwd:` as a value field but
|
|
250
|
+
never states the default, and the two existing paths disagree.
|
|
251
|
+
|
|
252
|
+
**Recommendation.** §3.6 must state: (a) how `akm` self-reference is resolved under shell
|
|
253
|
+
execution — the honest answer is probably to inject `AKM_BIN` into the env and document
|
|
254
|
+
`$AKM_BIN improve` in templates, or to prepend the resolved bin dir to `PATH`; (b) the default
|
|
255
|
+
`cwd` for `run:` in tasks vs steps, explicitly reconciling `runner.ts:279` and `:522`.
|
|
256
|
+
|
|
257
|
+
### F-07 — The hard error §3.4 argues against does not fire.
|
|
258
|
+
|
|
259
|
+
§3.4: *"`llm:` … was a grouping whose only job was to scope a kind-gated hard error, and that error
|
|
260
|
+
is incompatible with a cascade."* In `freeze.ts`:
|
|
261
|
+
|
|
262
|
+
```ts
|
|
263
|
+
67 const llm = engine.kind === "llm" ? mergedLlmOverrides(layers) : undefined;
|
|
264
|
+
68 if (engine.kind !== "llm" && llm !== undefined) {
|
|
265
|
+
69-73 throw new ConfigError(`Workflow engine "${name}" is an agent engine and cannot receive llm overrides.`, …);
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Line 68 is **unreachable**: `llm` is `undefined` in exactly the branch the guard tests. So today a
|
|
269
|
+
workflow that writes `defaults: { llm: { temperature: 0.2 } }` under an agent engine gets **silent
|
|
270
|
+
drop**, not an error. The real hard error lives on the *task* path
|
|
271
|
+
(`runner.ts:497-501`) and in `akm-task.json`'s `oneOf` (`:36-40`).
|
|
272
|
+
|
|
273
|
+
This matters two ways. First, the spec's premise is wrong about where the behavior is, which
|
|
274
|
+
weakens the case for dissolving `llm:` (the argument reduces to "the *task* error must relax",
|
|
275
|
+
which is true but much narrower). Second, the proposed capability notice is a strict
|
|
276
|
+
*improvement* over the current silent drop — the spec should claim that credit rather than
|
|
277
|
+
argue against a guard that never runs.
|
|
278
|
+
|
|
279
|
+
**Recommendation.** Fix `freeze.ts:67-73` independently of this proposal (compute
|
|
280
|
+
`mergedLlmOverrides(layers)` unconditionally, then branch). Amend §3.4 to describe the actual
|
|
281
|
+
state: workflow = silent drop (bug), task = hard error, target = uniform notice.
|
|
282
|
+
|
|
283
|
+
### F-08 — `agent:` as a selector needs persona plumbing that does not exist.
|
|
284
|
+
|
|
285
|
+
§3.4 defines `agent:` as picking "the persona node — *who* runs it (system prompt, tool policy,
|
|
286
|
+
model preference)". Today an agent asset yields three things (`renderers.ts:252-262`): `prompt`
|
|
287
|
+
(system prompt), `toolPolicy` (`tools` frontmatter), `modelHint` (`model`).
|
|
288
|
+
|
|
289
|
+
Only the third is in the spec's flat value vocabulary. The other two are the ones that make a
|
|
290
|
+
persona a persona, and neither can reach a workflow unit: `native-executor.ts:1026-1027` states
|
|
291
|
+
outright that `systemPrompt`/`tools`/`cwd` "come from the profile/asset, not the workflow unit".
|
|
292
|
+
`UnitDispatchRequest.systemPrompt` exists but is used only by the frozen gate judge
|
|
293
|
+
(`frozen-judge.ts:38`), and for agent-CLI dispatch it is passed through
|
|
294
|
+
`buildAgentDispatchRequest` (`native-executor.ts:1035`) with no tool-policy channel at all.
|
|
295
|
+
|
|
296
|
+
There is also a **security seam** the spec walks past: `renderers.ts:246-250` documents that the
|
|
297
|
+
self-declared `tools` policy is subject to a *provenance ceiling* applied at the show layer, which
|
|
298
|
+
knows whether the asset came from the operator's own writable stash or a read-only third-party
|
|
299
|
+
source. Making `agent:` a first-class cascade selector resolved at freeze moves tool-policy
|
|
300
|
+
selection to a layer that does **not** have that provenance context. A third-party bundle shipping
|
|
301
|
+
`agents/helper` with a permissive `tools:` block, referenced by `agent: agents/helper` in a
|
|
302
|
+
workflow step, would bypass the ceiling.
|
|
303
|
+
|
|
304
|
+
**Recommendation.** Either (a) scope `agent:` to model-preference-only in 0.9.0 and say so
|
|
305
|
+
explicitly, or (b) add a §3.4 sub-section covering system-prompt and tool-policy plumbing plus the
|
|
306
|
+
provenance ceiling, and move the IR cost into the §10 budget (F-02).
|
|
307
|
+
|
|
308
|
+
### F-09 — `params:` acquires three meanings; §5 sells that as simplification.
|
|
309
|
+
|
|
310
|
+
§5: *"`inputs:` declared / `with:` passed → `params:` both places — one word beats two."* After
|
|
311
|
+
this change `params:` means:
|
|
312
|
+
|
|
313
|
+
1. **Declarations** at workflow document level: name → JSON Schema (`ir/params.ts:34-56`,
|
|
314
|
+
`akm-workflow.json:26-36`). Not values.
|
|
315
|
+
2. **Workflow run arguments** on `uses: workflows/*` (§3.2) — coerced through those schemas.
|
|
316
|
+
3. **Template placeholder fills** on `uses: commands/*` (§3.2) — an entirely different mechanism
|
|
317
|
+
(see F-10).
|
|
318
|
+
4. And, per §3.4, a **cascading value field legal at every layer** — so `defaults: { params: … }`
|
|
319
|
+
would be values sitting one nesting level away from root `params:` which are schemas.
|
|
320
|
+
|
|
321
|
+
This is precisely the "three overloaded meanings" indictment the spec levels at `prompt:` in §3.1.
|
|
322
|
+
Worse, GHA's `inputs:`/`with:` split exists *because* the two are different things.
|
|
323
|
+
|
|
324
|
+
**Recommendation.** Keep two words. `params:` for declarations (existing), `with:` for passed
|
|
325
|
+
values at any call site. It is one extra word against four collapsed meanings, and it matches the
|
|
326
|
+
GHA muscle memory §5 is otherwise chasing.
|
|
327
|
+
|
|
328
|
+
### F-10 — Command-template filling is undefined against the real placeholder grammar.
|
|
329
|
+
|
|
330
|
+
§3.2: *"`uses: commands/<name>` … `params:` fill the placeholders … a placeholder with no matching
|
|
331
|
+
param is an error at fill time."*
|
|
332
|
+
|
|
333
|
+
The actual command placeholder grammar is **positional plus named**:
|
|
334
|
+
`$ARGUMENTS`, `$1`–`$9`, and `{{named}}` (`renderers.ts:164-176`, `indexer/passes/metadata.ts:438-444`,
|
|
335
|
+
`indexer/walk/matchers.ts:126` — `$ARGUMENTS|$[123]\b` is part of *recognizing* a file as a command
|
|
336
|
+
asset). A `params:` **mapping** has no defined projection onto `$ARGUMENTS` or `$1`.
|
|
337
|
+
|
|
338
|
+
Combined with the hard-error rule, this is actively breaking: `$ARGUMENTS` is the single most
|
|
339
|
+
common placeholder, and a scheduled task has no arguments, so
|
|
340
|
+
`uses: commands/<anything-with-$ARGUMENTS>` becomes an unconditional freeze/fill error.
|
|
341
|
+
|
|
342
|
+
**Recommendation.** §3.2 must state the mapping explicitly: `{{named}}` ← `params.<name>`;
|
|
343
|
+
`$1`–`$9` ← a positional `args:` list or `params: { "1": … }`; `$ARGUMENTS` ← the joined positional
|
|
344
|
+
list, defaulting to empty string rather than erroring. Also decide the converse case the spec omits:
|
|
345
|
+
a `params:` key with no matching placeholder (recommend: notice, consistent with §3.4's
|
|
346
|
+
capability-notice stance).
|
|
347
|
+
|
|
348
|
+
### F-11 — `env:` as a list of mappings breaks two existing contracts.
|
|
349
|
+
|
|
350
|
+
§3.7 claims the change "extends the existing schema additively — the workflow `unit.env` is already
|
|
351
|
+
a list of ref strings, so every currently-valid value stays valid." True of the *authoring* schema
|
|
352
|
+
(`akm-workflow.json:236-243`). False downstream:
|
|
353
|
+
|
|
354
|
+
- `ir/schema.ts:448`: `validateStringArray(node.env, …)` — a list containing a mapping fails plan
|
|
355
|
+
decode.
|
|
356
|
+
- `step-work.ts:353-357`: the input hash includes `env: template.env ?? null` with the documented
|
|
357
|
+
invariant *"`env` carries NAMES ONLY, never resolved values: hashing a resolved secret would leak
|
|
358
|
+
it into a durable hash oracle."* Literal mappings are values. Inline literals would land in both
|
|
359
|
+
`plan_json` and the durable hash.
|
|
360
|
+
- The spec also never says how `env` list concatenation interacts with **key collisions across
|
|
361
|
+
layers**: "later entries win" is stated for entries, but an `env/prod` group entry and a literal
|
|
362
|
+
entry can define the same key — is the winner determined by list position after concatenation
|
|
363
|
+
(yes, presumably) or by layer? Say it.
|
|
364
|
+
- `ProgramDefaults` (`program/schema.ts:204-211`) has **no** `env` field, so "legal at every layer"
|
|
365
|
+
is new surface at the document-defaults layer too.
|
|
366
|
+
|
|
367
|
+
**Recommendation.** State the IR representation for the new `env` shape (recommend: freeze
|
|
368
|
+
normalizes to an ordered list of `{ref}` / `{literals}` records, hash only refs + literal *keys*,
|
|
369
|
+
never literal values that resolve from `secrets/`), and add `env` to `ProgramDefaults`.
|
|
370
|
+
|
|
371
|
+
### F-12 — Optional prose on `uses:`/`run:` steps contradicts a hard parser + IR rule.
|
|
372
|
+
|
|
373
|
+
`workflows/parser.ts:281-296` errors when a unit/map step has no `## <id>` section, and errors again
|
|
374
|
+
when the section is empty. `ir/schema.ts:434-441` independently rejects empty `instructions`. §3.3
|
|
375
|
+
("Sections on `uses:` steps remain optional either way") and §3.6 (`run: bun test` with no section)
|
|
376
|
+
both require relaxing this.
|
|
377
|
+
|
|
378
|
+
That relaxation is not free: the "every unit step has prose" rule is what makes the prose rule
|
|
379
|
+
teachable and what the `instructions`-is-the-hash-preimage design leans on (`step-work.ts:378`).
|
|
380
|
+
|
|
381
|
+
**Recommendation.** Spell out the new body rule as a table: (no target → section **required**),
|
|
382
|
+
(`uses: commands/*` / `uses: tasks/<agent-task>` → optional, appended), (`run:` / `uses: scripts/*`
|
|
383
|
+
→ optional, documentation only). And say what fills `instructions` in the IR when the section is
|
|
384
|
+
absent.
|
|
385
|
+
|
|
386
|
+
### F-13 — The migrator depends on the live parser, and yml→md is a path change inside a journaled plan.
|
|
387
|
+
|
|
388
|
+
`scripts/akm-migrate/migrate/legacy/task-target-ref-migration.ts:27` imports `parseTaskDocument`
|
|
389
|
+
from `src/tasks/parser`, and its module doc says *"live task parsing remains strict 0.9 grammar."*
|
|
390
|
+
Replacing that parser with a markdown one breaks the migrator, which must read the **old** format.
|
|
391
|
+
|
|
392
|
+
Second problem: this migrator's plan is a list of `{filePath, before: Buffer, after: Buffer, mode}`
|
|
393
|
+
rewrites with `durabilityPaths` and a journaled, crash-resumable apply phase (`:44-58` and the
|
|
394
|
+
module doc). A format conversion **renames** `tasks/<id>.yml` → `tasks/<id>.md`. In-place byte
|
|
395
|
+
rewrite and rename-plus-write are different durability shapes; a crash between them leaves both
|
|
396
|
+
files present, which is exactly the "leftover files must never be silently invisible" lesson §8
|
|
397
|
+
invokes. Note also that `akmTasksSync` reads only `*.yml` today (`tasks.ts:414`) and
|
|
398
|
+
`akmTasksAdd` already has an *inverse* collision guard (`tasks.ts:154-163`, "a leftover `<id>.md`
|
|
399
|
+
still names the same task") that must be flipped.
|
|
400
|
+
|
|
401
|
+
**Recommendation.** §8 should require (a) a frozen copy of the v2 parser vendored into
|
|
402
|
+
`scripts/akm-migrate/`, with a note that `src/tasks/parser.ts` is free to change; (b) an explicit
|
|
403
|
+
ordering constraint (ref-rewrite phase completes before format-conversion phase, or they merge into
|
|
404
|
+
one phase); (c) the rename be journaled as delete+create with both paths in `durabilityPaths`.
|
|
405
|
+
|
|
406
|
+
### F-14 — Markdown tasks inherit the whole markdown lint / OKF / `improve` surface, including body rewrites.
|
|
407
|
+
|
|
408
|
+
`akm-adapter.ts:401-414` special-cases `type === "task"` to parse as **pure YAML with
|
|
409
|
+
`frontmatter: null`**, and the comment explains why: *"so the TaskLinter's field checks see real
|
|
410
|
+
data and `missing-updated` never fires."* Once tasks are markdown with real frontmatter, that
|
|
411
|
+
branch goes away and tasks join `runBaseValidateChecks` — `missing-updated`, `missing-description`,
|
|
412
|
+
staleness, OKF stamping, the lot. §6's "Envelope … future stamped keys inherited free" is true, and
|
|
413
|
+
also means the lint output for every existing task changes on day one.
|
|
414
|
+
|
|
415
|
+
The bigger issue is `improve`. A task body is now indexed prose *and*, for an agent task, the
|
|
416
|
+
literal executable prompt (§4, §3.1: "the prose *is* the work"). The improve pipeline semantically
|
|
417
|
+
rewrites markdown asset bodies. That means an automated pass can change what a scheduled agent job
|
|
418
|
+
does, with no scheduler-side signal — the file mtime changes but `akm task sync` only reconciles
|
|
419
|
+
`schedule`/`enabled` drift (`tasks.ts:388`), not body drift.
|
|
420
|
+
|
|
421
|
+
**Recommendation.** §4 must state whether task bodies are `improve`-eligible. Recommend: exclude
|
|
422
|
+
`tasks/` from semantic rewrite passes in 0.9.0, and add a §6 row acknowledging the lint-surface
|
|
423
|
+
change with an explicit list of newly-applicable base checks.
|
|
424
|
+
|
|
425
|
+
---
|
|
426
|
+
|
|
427
|
+
## 4. Minor
|
|
428
|
+
|
|
429
|
+
### F-15 — Model aliases are not as portable as §3.5 claims.
|
|
430
|
+
|
|
431
|
+
§3.5: *"`model: sonnet` resolves to the right string under a claude engine, an opencode engine, or
|
|
432
|
+
an LLM endpoint."* `BUILTIN_ALIASES` has exactly two platform columns, `claude` and `opencode`
|
|
433
|
+
(`model-aliases.ts:45-76`). `resolveModel` returns `entry?.platforms[platform] ?? model`
|
|
434
|
+
(`:103`) — so under any other harness id in `VALID_HARNESS_IDS` (codex, copilot, gemini, pi, …
|
|
435
|
+
referenced at `native-executor.ts:1016-1022`) `sonnet` passes through **verbatim** and the CLI gets
|
|
436
|
+
a bogus model string. For an LLM endpoint, `resolveLlmModel` looks up
|
|
437
|
+
`tier[engineName] ?? tier["llm"] ?? tier["*"]` (`:100,108`) — none of which the builtin table has —
|
|
438
|
+
so it also passes through verbatim unless the user has hand-written a global `modelAliases` entry.
|
|
439
|
+
|
|
440
|
+
Since §3.4's whole portability argument is "a persona node saying `model: opus` works under any
|
|
441
|
+
engine", this is load-bearing.
|
|
442
|
+
|
|
443
|
+
**Recommendation.** Soften §3.5 to "resolves under claude and opencode; other platforms and LLM
|
|
444
|
+
endpoints require a `modelAliases` entry", and add a §6 row for extending the builtin table (or
|
|
445
|
+
emitting an alias-unresolved notice, consistent with the capability-notice stance).
|
|
446
|
+
|
|
447
|
+
### F-16 — Gate judges sit outside the cascade.
|
|
448
|
+
|
|
449
|
+
`freezeGateJudge` (`freeze.ts:263-278`) resolves entirely from `config.workflow.judgeEngine` with
|
|
450
|
+
`layers = []`. §3.4 never mentions gate judges. Does a step's `model:`/`agent:` apply to its gate?
|
|
451
|
+
(Almost certainly it should not — but the "legal at every layer, nearest wins" sentence implies it
|
|
452
|
+
does.)
|
|
453
|
+
|
|
454
|
+
**Recommendation.** One sentence in §3.4: gate judges resolve from `workflow.judgeEngine` only and
|
|
455
|
+
are outside the cascade.
|
|
456
|
+
|
|
457
|
+
### F-17 — `on_error` is called steps-only but already lives at document defaults.
|
|
458
|
+
|
|
459
|
+
§3.4: *"**graph keys** (`map`, `route`, `inputs`, `output`, `gate`, `retry`, `on_error`,
|
|
460
|
+
`isolation`) are steps-only."* `ProgramDefaults.onError` exists (`program/schema.ts:210`), is
|
|
461
|
+
schema-declared (`akm-workflow.json:199-201`), and is consumed
|
|
462
|
+
(`compile.ts:231`: `unit?.onError ?? defaults?.onError ?? "fail"`). Removing it is an
|
|
463
|
+
unannounced breaking change; keeping it makes the tier rule false as stated.
|
|
464
|
+
|
|
465
|
+
**Recommendation.** Either exempt `on_error` (and note it), or list it in §8's conversion table as
|
|
466
|
+
removed.
|
|
467
|
+
|
|
468
|
+
### F-18 — Adapter recognition for `.md` tasks is underspecified and partly contradicts `okf-support.md`.
|
|
469
|
+
|
|
470
|
+
§6's last row: *"markdown task recognized by `type: task` / `tasks/` residence."*
|
|
471
|
+
|
|
472
|
+
- `okf-support.md:60-62` states the opposite rule for the `akm` adapter: *"The `akm` adapter still
|
|
473
|
+
derives native identity and capability from its directory, extension, filename, and content
|
|
474
|
+
rules; **frontmatter `type` does not override those rules**."* Residence-based recognition is
|
|
475
|
+
consistent; `type: task`-based recognition is not.
|
|
476
|
+
- The standalone `akm-task` adapter currently keys entirely on `.yml`
|
|
477
|
+
(`akm-task-adapter.ts:42,53,106,144`) and `directoryList()` returns `["."]` — tasks live *anywhere*
|
|
478
|
+
under the component root, so "tasks/ residence" does not describe it either.
|
|
479
|
+
- Ordering: `akmWorkflowAdapter` precedes `akmTaskAdapter` (`adapters/index.ts:81-83`), and its
|
|
480
|
+
`looksLikeRoot` fires on a top-level `.md` with `type: workflow` (`akm-workflow-adapter.ts:141-155`).
|
|
481
|
+
A markdown-task bundle root needs a symmetric probe (`type: task`), and the two probes must be
|
|
482
|
+
proven disjoint — the goldens under `tests/fixtures/format-family-goldens/akm-task/` all assume
|
|
483
|
+
`.yml`.
|
|
484
|
+
|
|
485
|
+
**Recommendation.** Add a §6 sub-item covering the `akm-task` adapter rewrite: `.md` extension,
|
|
486
|
+
`type: task` recognition *within* an akm-task bundle, an explicit `type: task` `looksLikeRoot`
|
|
487
|
+
probe, and a note that the four `akm-task` goldens re-baseline.
|
|
488
|
+
|
|
489
|
+
### F-19 — `status: draft` is a second, orthogonal installation gate.
|
|
490
|
+
|
|
491
|
+
§4: *"`status: draft` as author-now, arm-later (draft tasks are never installed by `sync`)."* There
|
|
492
|
+
is already `enabled:` (`tasks.ts:445+`, `runner.ts:169`) and a `disabled` run status
|
|
493
|
+
(`runner.ts:179`). Now there are two gates with different vocabularies, and the spec does not say
|
|
494
|
+
what `status: deprecated` does, what `enabled: true, status: draft` means, or how
|
|
495
|
+
`akm task list`/`doctor` report the distinction. Since OKF `status` is a lifecycle field that
|
|
496
|
+
tooling can rewrite, this couples scheduler state to a documentation field.
|
|
497
|
+
|
|
498
|
+
**Recommendation.** Pick one. Recommend: `status:` is documentation only and never gates
|
|
499
|
+
installation; `enabled:` remains the sole gate.
|
|
500
|
+
|
|
501
|
+
### F-20 — `task_history.target_kind` is a persisted enum the new vocabulary outgrows.
|
|
502
|
+
|
|
503
|
+
`appendHistory` writes `target_kind` ∈ {workflow, command, prompt} and `target_ref` only for
|
|
504
|
+
workflow (`runner.ts:823-824`); `taskHistoryRowToResult` decodes exactly those three
|
|
505
|
+
(`:875-888`), with a `metadataVersion` 1/2 split already in place. The new target space is
|
|
506
|
+
{prose, `uses:commands/*`, `uses:scripts/*`, `uses:workflows/*`, `run:`}. §8's "the `akm task run
|
|
507
|
+
<id>` ABI does not change" is about argv, but history rows are also an ABI (`akm task history` is
|
|
508
|
+
a documented surface).
|
|
509
|
+
|
|
510
|
+
**Recommendation.** Add a `metadataVersion: 3` row to §8 with the old→new `target_kind` mapping and
|
|
511
|
+
a statement that historical rows continue to decode.
|
|
512
|
+
|
|
513
|
+
### F-21 — Embedded-template enumeration fails silently on format change.
|
|
514
|
+
|
|
515
|
+
`listEmbeddedTasks()` swallows parse errors (`embedded.ts:91-96`: `catch { continue }`) and skips
|
|
516
|
+
non-command targets (`:97`). Converting the ten templates to markdown without updating this
|
|
517
|
+
function yields an **empty template list in `akm setup`** with no error — the wizard just offers
|
|
518
|
+
nothing. §8 says the templates "convert in this change"; it should also say `embedded.ts` converts
|
|
519
|
+
with them and that the silent `continue` becomes a loud failure.
|
|
520
|
+
|
|
521
|
+
### F-22 — Composition loses provenance and can exceed the instruction cap.
|
|
522
|
+
|
|
523
|
+
`IrUnitNode.source` is a single `SourceRef` (`ir/schema.ts:444-445`, `compile.ts:186`). A step
|
|
524
|
+
composed from `uses: tasks/<id>` has two source files (the task and the workflow). One of them will
|
|
525
|
+
be dropped from every error message and lint pointer. Separately, `instructions` is capped at
|
|
526
|
+
256 KiB (`ir/schema.ts:444`); task body + appended step section makes overflow reachable in a way
|
|
527
|
+
it was not before, and the error would name only one file.
|
|
528
|
+
|
|
529
|
+
**Recommendation.** Either make `source` an array, or state explicitly that a composed unit's
|
|
530
|
+
`source` points at the *step* and the referenced task's path is carried in a new sibling field.
|
|
531
|
+
|
|
532
|
+
### F-23 — Format whiplash and an inverted collision guard.
|
|
533
|
+
|
|
534
|
+
`tasks.ts:154-163` exists because *"Pre-0.8.0 tasks were markdown; the 0.8.0 cutover moved them to
|
|
535
|
+
pure YAML … A leftover `<id>.md` still names the same task, so creating `<id>.yml` beside it must
|
|
536
|
+
collide loudly."* §4 calls the new format "the 0.7.x markdown task restored". Users who ran the
|
|
537
|
+
documented `v0.7-to-v0.8` migration will run it back. That is defensible for a pre-1.0 project but
|
|
538
|
+
should be *stated* in §8 rather than framed as pure forward progress — and the guard must be
|
|
539
|
+
inverted (a leftover `<id>.yml` must now collide with `<id>.md`), which is exactly the failure mode
|
|
540
|
+
§8's "never silently invisible" bullet targets.
|
|
541
|
+
|
|
542
|
+
### F-24 — `prompt: agents/x` is worse than §3.5 says.
|
|
543
|
+
|
|
544
|
+
§3.5: *"the `.yml` task path **drops** an agent asset's model preference — `prompt: agents/x`
|
|
545
|
+
resolves the asset to prompt text only."* `resolvePromptText` does
|
|
546
|
+
`fs.readFileSync(assetPath, "utf8")` with **no frontmatter parse** (`runner.ts:592-593`). So the
|
|
547
|
+
agent's YAML frontmatter — `model:`, `tools:`, `description:` — is sent to the model **as part of
|
|
548
|
+
the prompt text**. Same for `prompt: commands/x`: the raw template with unfilled `$ARGUMENTS`
|
|
549
|
+
placeholders goes out verbatim.
|
|
550
|
+
|
|
551
|
+
This is a real bug in the current implementation and strengthens the case for the change; the spec
|
|
552
|
+
should cite it accurately as a §6 "Today" entry.
|
|
553
|
+
|
|
554
|
+
---
|
|
555
|
+
|
|
556
|
+
## 5. Cross-cutting: what this actually costs
|
|
557
|
+
|
|
558
|
+
The spec's §6 "shared plumbing" table reads as a code-*reduction* story. Counting the work the
|
|
559
|
+
findings above surface, the honest ledger is:
|
|
560
|
+
|
|
561
|
+
**Genuinely deleted:** `resolvePromptSource` sniffing, `rejectTargetFields`, `TASK_KEYS`,
|
|
562
|
+
`akm-task.json`'s standalone target `oneOf`, the ~12-flag `task add` surface, the `unit:` bag
|
|
563
|
+
nesting. Real, and worth having.
|
|
564
|
+
|
|
565
|
+
**Genuinely shared for the first time:** target resolution by ref subdir, command-template filling,
|
|
566
|
+
env assembly + redaction, the value-field cascade. Also real.
|
|
567
|
+
|
|
568
|
+
**Net-new, not in the table:** an IR v3 schema extension + version bump (F-02); a shell frozen node
|
|
569
|
+
kind and runner (F-03); an input-hash version bump and preimage extension (F-04); a new config
|
|
570
|
+
`defaults.*` schema surface (F-01); persona system-prompt/tool-policy plumbing with a provenance
|
|
571
|
+
ceiling (F-08); a placeholder-fill grammar (F-10); an env normalizer with a hash-safety rule
|
|
572
|
+
(F-11); a vendored legacy parser + a rename-safe migration phase (F-13); a rewritten `akm-task`
|
|
573
|
+
adapter + four goldens (F-18); `embedded.ts` (F-21).
|
|
574
|
+
|
|
575
|
+
**Test/golden churn:** 14 test files reference `unit:` (`tests/integration/workflows/*`,
|
|
576
|
+
`tests/workflows/*`, including `conformance/`, `driver-parity`, and `fuzz/replay-fuzz`);
|
|
577
|
+
`tests/fixtures/format-family-goldens/akm-task/{recognition,placement,lint,renderer}.json` all
|
|
578
|
+
assume `.yml`; every frozen-plan golden re-baselines on the IR bump; `docs/reference/workflows.md`
|
|
579
|
+
and `stash-conventions-code-spec.md` both document `unit:`.
|
|
580
|
+
|
|
581
|
+
None of that is a reason not to do it. It is a reason the spec should not say §10.
|
|
582
|
+
|
|
583
|
+
---
|
|
584
|
+
|
|
585
|
+
## 6. Answer to §9's remaining question
|
|
586
|
+
|
|
587
|
+
> Confirm the cascade model and the dissolution of `llm:`.
|
|
588
|
+
|
|
589
|
+
**Dissolving `llm:` — yes.** The grouping earns nothing: its workflow-side guard is dead code
|
|
590
|
+
(F-07), its task-side guard is a schema `oneOf` that a cascade cannot express anyway, and flat
|
|
591
|
+
`temperature`/`max_tokens`/`extra_params` with engine-capability notices is strictly better than
|
|
592
|
+
today's silent drop. Do fix `freeze.ts:67-73` first so the before/after comparison is honest.
|
|
593
|
+
|
|
594
|
+
**The cascade model — yes in shape, not as specified.** Nearest-wins layering is the right mental
|
|
595
|
+
model and matches what users know. But the spec currently sells it as *exposing an existing
|
|
596
|
+
mechanism* when three of its five layers do not exist (F-01), and buys that framing by asserting a
|
|
597
|
+
no-op change budget (F-02). Sign off on the *model*; require §3.4 and §10 to be rewritten with the
|
|
598
|
+
real layer inventory and the real IR cost before implementation starts. Specifically, before
|
|
599
|
+
sign-off I would want: the config-schema addition enumerated, `params:` de-overloaded (F-09), and
|
|
600
|
+
the merge semantics for mapping-valued fields (`params`, `extra_params`) stated — the spec says
|
|
601
|
+
"merged per-field, nearest wins" but `freeze.ts:211-216` deep-merges `llm` today, and those are
|
|
602
|
+
different answers.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# v8 Adversarial Review — new defects
|
|
2
|
+
|
|
3
|
+
critical | with: merge/replace semantics undefined for uses:tasks/x → uses:commands|workflows/y | §2.3 says step keys "override" the referenced task's keys and §2.2 says tasks/<n> inputs are "the task's own, overridable," but §2.2/§4 also declare with: is never cascaded and binds to "one referenced asset" — so when a step does `uses: tasks/x` and task x itself is `uses: commands/y with:{...}` (or `uses: workflows/y with:{...}`), the spec never states whether the step's with: mapping merges key-by-key with task x's own with:, wholly replaces it, or is simply illegal (since with: "isn't cascaded" yet §2.3 implies task/step are "adjacent cascade layers"); the ambiguity is sharper because commands' with: fills `{{name}}`/$ARGUMENTS while workflows' with: maps to declared param flags, so "override" means something different depending on what x ultimately targets (refs: §2.2, §2.3, §4, §5.1 "resolves recursively once").
|
|
4
|
+
|
|
5
|
+
critical | hashVersion 5 preimage omits the persona snapshot | §4 item 2 introduces a frozen persona snapshot (`{systemPrompt, toolPolicy, model, …valueFields}`) resolved through the agent: selector and consumed by dispatch, explicitly to fix runner.ts:592-593 shipping raw agent-file bytes — but the §5.3 hashVersion-5 preimage table only lists "item / inputs / dispatch / invocation / schema | as v4," with no row for the persona snapshot; changing the `agent:` selector or the referenced persona's systemPrompt/toolPolicy (a writable, frequently-edited bundle asset) would not change the unit hash, silently reusing a completed journal row dispatched under the old system prompt — the exact staleness bug hashVersion 5 was introduced to close for `run:`/prose (refs: §4.2, §5.3 table, step-work.ts:376-392 current v4 preimage which this table is supposed to supersede).
|
|
6
|
+
|
|
7
|
+
critical | .yml tombstone hard-error has no remedy for read-only/third-party bundles | §8 says sync/doctor/lint "each hard-error naming the file and the fix" for any `tasks/*.yml`, "never installed and never silently skipped," with no carve-out for bundle writability — but the repo's own existing migrator (`scripts/akm-migrate/migrate/legacy/task-target-ref-migration.ts:253-271`) treats read-only bundles specially precisely because "the migration must not write into a read-only bundle" and a user cannot fix content in a bundle they don't own; v8's tombstone rule regresses that precedent by hard-erroring `sync`/`doctor`/`lint` for the whole bundle (or task) with a "fix" the operator (non-maintainer) cannot apply, and never says whether the error is per-task (skip just that task) or fails the entire sync/install (refs: §8 tombstone rule; scripts/akm-migrate/migrate/legacy/task-target-ref-migration.ts:57-64,253-271).
|
|
8
|
+
|
|
9
|
+
major | mapping-type value fields (extra_params) merge rule contradicts current deep-merge behavior | §4 states cascade fields are "merged per-field, nearest wins" with only `env:` singled out as concatenating; this reads as whole-value replace for `extra_params` (a mapping), but the current implementation (`freeze.ts:211-216` `mergedLlmOverrides`) already deep-merges llm overrides across layers via `deepMergeConfig`. v8 doesn't say whether the new cascade module preserves deep-merge for mapping fields like `extra_params` or silently downgrades to whole-value replace — a real behavior change/regression risk left unstated (refs: §4 value-field table, src/workflows/ir/freeze.ts:211-216).
|
|
10
|
+
|
|
11
|
+
major | shell-kind IrInvocation union has no timeoutMs slot | §5.1/§5.2's discriminated union shows `{ kind: "agent", engine, … }` vs `{ kind: "shell", script, shell, cwd }` — the shell variant lists no timeout field, yet §4's value-field vocabulary explicitly includes `timeout` as legal on any step/task including `run:` shell work, and the current single-shape `IrInvocation` (schema.ts:82, 488-496) carries `timeoutMs` as a top-level required-ish field. The spec never states where a resolved shell-unit timeout is carried in IR v4, nor who enforces it (ShellUnitExecutor per §5.1, but with what deadline). (refs: §5.1, §5.2, §4 value fields, src/workflows/ir/schema.ts:82,488-496.)
|
|
12
|
+
|
|
13
|
+
major | orchestrator-owned shell units: no crash/restart semantics stated | §5.2 says shell units are "orchestrator-owned" and skip harness claiming ("a harness never claims shell work"), but the external driver protocol's claim/lease/reclaim machinery (native-executor.ts's claim-expiry/reclaim logic) exists specifically to recover from a crashed claimant; the spec never states what happens if the orchestrator process itself dies mid-`Bun.spawn()` for a shell unit — on restart, is the child process reattached, killed-and-retried (risking non-idempotent shell side effects), or left orphaned with a journal row stuck "dispatched"? This is unaddressed for the exact "races / blocked semantics / kill-abort paths" surface the spec claims to own (refs: §5.2, §5.1 ShellUnitExecutor, native-executor.ts claim/lease comments ~L87-103,645).
|
|
14
|
+
|
|
15
|
+
major | persona toolPolicy vs engine capability conflict has no resolution rule | §4 introduces both a persona snapshot with `toolPolicy` (item 2) and "capability notices" replacing kind-gates for engine-unconsumed fields (item 4), but never states what happens when a persona grants a tool (e.g. via `agents/<name>` toolPolicy) that the cascade-selected engine cannot support (e.g. an LLM engine with no tool-calling) — is that a lint/freeze notice like unconsumed value fields, a hard error, or silently inert? The two mechanisms (capability notices for value fields; provenance ceiling for persona tools) are never reconciled for this cross-cutting case explicitly called out as an attack surface.
|
|
16
|
+
|
|
17
|
+
major | improve-exclusion "by adapter policy" names no mechanism | §3 asserts "lint runs, improve is excluded by adapter policy" for task bodies, but no such exclusion mechanism (glob list, adapter capability flag, or improve-pipeline consult point) exists in the codebase today (`grep` for improve-exclusion hooks in src/core/adapter and src/improve returns nothing), and §9/§11 (M13) mark this "costed" without naming where in the improve pipeline the check lives — enforceability is asserted, not specified, leaving it plausible that a generic `akm improve` invocation over task-adapter-recognized files never consults "adapter policy" at all.
|
|
18
|
+
|
|
19
|
+
minor | H1-seeding collision when task body already has an H1 | §8's `name:` → body H1 migration doesn't say what happens when the source `.yml`'s `prompt: |` block or an already-inlined file (`prompt: ./file.md`) already begins with its own `#` heading — silently prepend a duplicate `name:` H1, skip seeding, or error? Left unspecified despite the review brief calling this out explicitly.
|
|
20
|
+
|
|
21
|
+
minor | argv shell-escaping portability unaddressed for the POSIX/`powershell` split introduced by §2.1 | §8 says `command: [argv…]` → `run:` "with each element shell-escaped," but §2.1 states `run:` executes via `sh` on POSIX and `powershell` on Windows by default — a single shell-escaping strategy applied at migration time (necessarily POSIX-flavored, since `[argv…]` is a Unix convention) will not portably re-quote for PowerShell's escaping rules, so a migrated array-form command may silently misbehave on the Windows default shell with no `shell:` override emitted by the migrator.
|
|
22
|
+
|
|
23
|
+
minor | with.arguments overflow beyond $9 is unspecified | §2.4 defines `with.arguments`'s whitespace-split words fill `$1`–`$9`; nothing states what happens to the 10th+ word (dropped silently vs concatenated into `$9` vs left for `$ARGUMENTS` only) — a minor but real gap in an otherwise precisely specified filling contract.
|
|
24
|
+
|
|
25
|
+
minor | `{{arguments}}` named-placeholder vs reserved `with.arguments` key collision unaddressed | §2.4's two filling rules ("`with:` mapping keys fill `{{name}}`" and "the reserved key `with.arguments` … fills `$ARGUMENTS`") both key off the literal string "arguments"; if a command template also contains a literal `{{arguments}}` placeholder, it's unstated whether `with: { arguments: "x" }` fills that placeholder too (double duty) or only ever feeds `$ARGUMENTS`/`$1`-`$9`, leaving `{{arguments}}` an "unused-key" or "unmatched-placeholder" lint case despite the value being supplied.
|
|
26
|
+
|
|
27
|
+
minor | draft/deprecated status transition doesn't say whether sync uninstalls a previously-enabled task | §3 pins `status: draft` → sync never installs and `status: deprecated` → installs with a warning, but doesn't address the state transition case: a task already installed (OS cron/launchd/schtasks entry present) whose `status:` later flips to `draft` — does the next `sync` remove/uninstall the existing entry, or just skip re-installing and leave a stale scheduled entry running the old (or edited) body indefinitely?
|