Skip to content

#866 stage 0: key the plan fingerprint and step cache only by what changes the output #905

Closed

Description

@dkackman

Stage 0 of #866. See the plan's section "Stage 0", and "The design → Cache keys": #866 (comment). The plan comment (now v4) is authoritative, and this body restates it.

claude-opus-5-5 / anthropic, lead. Reshaped for plan v3/v4: the step-cache acceptance is narrowed to an in-place edit, integral floats are canonicalized in the fingerprint, seed stays out of the fingerprint, and the step cache keeps subfolder / file_base_name.

Builds

The plan fingerprint and the step cache are keyed only by what can change the generated output (Don's ruling, 2026-10-14).

  • Audit every key that reaches the plan fingerprint (dw/plan.py:209-242, DOCUMENTATION_KEYS at :38) and the step-cache keys (dw/step_cache.py: pipeline_definition_key, pipeline_cache_key, _closure_keys).
  • Move each key that can't change the output into DOCUMENTATION_KEYS, or into the step cache's equivalent exclusion. That covers at least cost_drivers and vram_estimate. It also covers any of descriptions, notes and roles that reach a key.
  • Keep every key that can change the output: attention backend, cache config, dtype, LoRA and the rest.
  • cost_drivers must not reach either key. Make sure of that; checking it is not enough.
  • Integral floats are canonicalized in the fingerprint digest, so 12.0 and 12 digest alike. This is the fingerprint only. It is already built on feat/866-0-output-keys @ b63cfaf.
  • Seed stays out of the plan fingerprint (the Assess: acknowledged_cost gate should bind to a budget/fingerprint, not just a boolean #85 contract). The step cache keys on seed.
  • The step cache keeps subfolder and file_base_name. A hit replays files to their recorded paths, so a moved destination must miss. The fingerprint excludes both.
  • The step cache's scope is unchanged. It is per card and per workflow identity, and it is cleared on an identity switch. Caching across identities is idea: step cache across workflow identities (renamed and inline copies hit) #912.

Owes

  • A test that 12.0 and 12 give the same fingerprint.
  • A test that pins the exclusion list exactly.
  • A test that workflows differing only in cost_drivers give the same plan fingerprint and the same step-cache keys, and likewise for workflows differing only in vram_estimate.
  • A test that a change in attention_backend, a cache config, a dtype or a LoRA still changes the key.
  • The existing step-cache and fingerprint tests keep passing.
  • The ARCHITECTURE fingerprint / step-cache row states the rule and names the pinning test.
  • The hand-off lists each key moved or kept, with a one-line reason.

Deploy

Server restart. Fingerprints change once, so the first run of each affected workflow after the deploy misses the step cache.

Passes when

The repro must work:

  • validate_workflow gives the same plan.fingerprint for a catalog H3 workflow and for a copy that differs only in cost_drivers.
  • A copy that differs in attention_backend gives a different fingerprint.
  • Inline and by-name validation of the same H3 template give the same fingerprint.
  • Seeds 42 and 43 give the same fingerprint.
  • A stored workflow edited in place with only metadata changes still reports its steps as cached_steps. An in-place edit to attention_backend, dtype, seed, subfolder or file_base_name gives cached_steps: 0.

A copy under another name, or an inline copy, is not expected to hit the cache. The stage also needs every pending: #905 case the tester writes to pass.

Activity

  1. added
    featureWork bigger than a fix: designed with Don, built in stages (harnest R11)
    owner:leadFeature lead's turn (harnest R11)
    stageA child issue: one stage of a feature
    on Oct 14, 2026
  2. added and removed
    owner:leadFeature lead's turn (harnest R11)
    on Oct 14, 2026
  3. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Shipped f68b4b82 (merged into develop as ec68fec2). Deploy: [deploy 23:28:55] deployed develop @ ec68fec2, healthy, mcp=true.

    Plan items covered

    • Audit and exclusion: dw/plan.py DOCUMENTATION_KEYS, CONSTRAINT_DOCUMENTATION_KEYS, PLACEMENT_RESULT_KEYS, applied by output_only. dw/step_cache.py NON_OUTPUT_RESULT_KEYS, applied by output_identity (in workflow_run.cache_lookup).
    • cost_drivers reaches neither key: the fingerprint drops it, including from a composed child (the child digest is now child_work_digest, the child with output_only applied, not its raw bytes). The step cache never saw top-level keys.
    • Tests:
      • tests/test_plan.py::TestFingerprintKeys pins the lists exactly and checks that every top-level schema key and every result schema key is either excluded or explicitly kept, so a new schema key fails until someone sorts it.
      • TestFingerprintIgnoresWhatCannotChangeTheOutput covers cost_drivers, vram_estimate, shape/traits, a constraint's reason, role/subfolder/file name, and a child's cost/docs.
      • TestFingerprintStillChangesWithWhatChangesTheOutput covers attention backend, cache type/threshold, dtype, LoRA name/scale/absence, and result format.
      • TestTheCatalogH3Template runs on the real minimax/reference-to-video.
      • tests/test_workflow_step_cache.py::TestOutputKeys runs a real rerun of an edited copy:
        • cost_drivers, vram_estimate, description, shape/traits and role each still hit;
        • attention backend, cache, dtype, LoRA and LoRA scale each miss;
        • a subfolder change misses.
    • Existing step-cache and fingerprint tests pass. The full suite has the same 17 failures as develop without this change (local Kandinsky-6/diffusers environment), so there are no new failures. ruff is clean.
    • The ARCHITECTURE rows "Bound acknowledgement" and "Step cache" state the rule and name the pinning tests. The SERVER.md fingerprint sentence is updated to match.

    Each key moved or kept

    Key Fingerprint Step cache Why
    cost_drivers moved out never reached pricing metadata
    vram_estimate moved out never reached a ceiling estimate; it raises a warning, it doesn't change the work
    shape, traits moved out never reached catalog classification
    variable_constraints.*.reason moved out never reached prose; the rule itself is kept
    result.role moved out moved out a label; the run reads roles from its own definition when it opens
    result.subfolder, result.file_base_name moved out kept see deviation
    cost, description, summary, configures, seed already out never reached unchanged
    id kept kept (key) it names every saved file
    variables, steps, variable_constraints rules, argument_template kept steps kept the work itself; a rule rounds or refuses a value
    attention backend, cache config, dtype, LoRA (and all pipeline config) kept kept they change the pixels
    result.format, embed_metadata, compression_level, fps, rates, save, content_type kept kept they change the bytes, or whether anything is written

    Deviations

    • The step cache keeps subfolder and file_base_name, although the plan lists subfolder and file naming among the keys to exclude. A cache hit writes nothing and republishes the cached entry's file paths verbatim. A rerun that only moved the subfolder would therefore be handed files in the old place, which is wrong output, not the same output. The fingerprint does drop them, because there the work is identical.
    • One-time change: every plan fingerprint changes once with this deploy, so a bound acknowledgement quoted before it gets one 409. A step-cache entry for a step whose result had a role misses once.
    • Not breaking-change: no MCP shape changed, only fingerprint values.

    Ran as claude-opus-5-5 via anthropic.

  4. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Architecture review queued by the loop driver: this hand-off changed dw/ or dw_mcp/ on develop (f73088a58c..ec68fec2bd: dw/plan.py dw/step_cache.py dw/workflow_run.py). The reviewer checks it against docs/ARCHITECTURE.md before the tester verifies.

  5. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Architecture review: pass (no findings). claude-opus-5-5 / anthropic, reviewer

    Read: git diff f73088a5..ec68fec2 under dw/ (dw/plan.py, dw/step_cache.py, dw/workflow_run.py), plus its docs/ARCHITECTURE.md change. I checked it against docs/ARCHITECTURE.md and item 3 of docs/stabilization/harness/stage-c-guardrails.md.

    • Second owner: none.
      • child_work_digest reads the child through dw/realize.py read_sub_workflow, the owner of reading sub-workflow files, and doesn't resolve or open the path itself.
      • The raw-bytes manifest digest stays with realize._digest (the provenance record, "Realized workflow" row). The new digest belongs to the fingerprint, the "Bound acknowledgement" row, owned by dw/plan.py fingerprint.
      • The step cache's exclusion output_identity/NON_OUTPUT_RESULT_KEYS sits in dw/step_cache.py, which the "Step cache" row makes the owner. cache_lookup calls it and doesn't filter on its own.
    • Build vs. buy: none. The canonical JSON and SHA-256 come from the standard library (json, hashlib), as the fingerprint already did. No dependency in pyproject.toml does this.
    • Map: updated in the same change.
      • The "Bound acknowledgement" and "Step cache" rows state the output-only rule and the exclusions, and name the pinning tests (TestFingerprintKeys::test_the_exclusion_lists_are_pinned, TestOutputKeys::test_the_exclusion_list_is_pinned).
      • The change adds no module and moves no rule between modules.
    • Context: in the right place. The rationale is in the dw/step_cache.py module docstring and in comments beside the constants. No CLAUDE.md changed.

    Note for the tester, not a finding: two lists now each say that a result's role isn't output, plan.PLACEMENT_RESULT_KEYS and step_cache.NON_OUTPUT_RESULT_KEYS. They differ on purpose, since the cache keeps subfolder and file_base_name, and each is pinned under its own map row.

    No arch-approved waiver was needed or used. Back to the tester for MCP verification.

  6. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Verify: FAIL. Bouncing to owner:lead. Tester: claude-opus-5-5 via anthropic. lem is on develop @ 581bfff. All calls were made over MCP in workspace regression-complete.

    I ran the three pending: #905 cases (C-F473, C-F474, C-F475) as written. The metadata exclusion in the fingerprint works. Three things fail.

    C-F473: fingerprint of templates/text-to-image

    • Base: inline W (the template with variables.seed=42) gives F0 = sha256:70cf5bf2…7ab36. A repeat gives the same value, and so does by-name validation.
    • (a)–(g) all give F0, valid:true: cost_drivers removed or reordered, cost[0].minutes, description, result.subfolder, file_base_name, and an added vram_estimate. Pass.
    • (i) prompt, (j) steps 26 and (k) float16 give 5df8986d…, b01dabc1… and 6ee2be26…. They are distinct from F0 and from each other. Pass.
    • (h) seed 43: FAIL. It returned sha256:70cf5bf2…7ab36, which is F0. A different seed produces a different image, yet it binds to the same acknowledgement fingerprint. The hand-off table lists top-level seed as "already out", so this behaviour isn't new, but the plan's rule is to key by what changes the output, and seed does. The lead should decide whether seed belongs in the fingerprint or the case should drop (h).

    C-F474: fingerprint of templates/minimax/reference-to-video

    • By name with seed 42 gives F0 = sha256:cc322422…acbb6. A repeat gives the same value. Seed 43 also gives cc322422, the same seed gap as above.
    • Calls 2–5 give distinct values, each different from F0. Pass.
      • attention_backend sage_hub: 849c2e60…
      • cache {"type":"first_block","threshold":0.05}: 14923e40…
      • weights_dtype {int8}: 8dc28a21…
      • lora null: 8a4a18f3…
    • Call 6: FAIL as written. I validated the inline get_workflow JSON with seed 42 and with cost_drivers and vram_estimate removed. It returned sha256:3c07adc7…f9b0a6, not F0.
      • The same inline JSON with the metadata kept also returns 3c07adc7…. So the metadata is excluded, and the gap is between inline and by-name for this template.
      • For SD1.5, inline and by-name agree. I can't see the cause from the consumer side.

    C-F475: step cache (GPU)

    • Setup: saved W as c-f475-t2i.
    • Call 1: run_workflow(name="c-f475-t2i", acknowledged_cost=true, wait_seconds=55, note="C-F475 seed run") gave J1 0da8c845007f. It succeeded on cuda:0 with 26 passes.
      • After J1, validate_workflow(name="c-f475-t2i") reports cached_steps: 1, so the cache does work for the same name.
    • Call 2: FAIL. I validated the inline variant: description "meta copy", cost_drivers removed, cost[0].minutes 5, result.subfolder "other", file_base_name "renamed". It returned cached_steps: 0 (fingerprint 70cf5bf2…).
      • This is not only the subfolder/file_base_name deviation the hand-off described. I also validated inline W with only description, cost and cost_drivers changed, keeping subfolder: final and file_base_name: test_image. That also returned cached_steps: 0.
      • So an inline workflow that is identical in output never hits the cache entry the named run wrote. Only the same stored name does.
    • Call 3: inline W with seed 43 returned cached_steps: 0. Pass, though it can't discriminate given call 2.
    • Call 4: FAIL. I saved the call-2 variant as c-f475-t2i-meta, and validate_workflow(name=…) returned cached_steps: 0. run_workflow(name="c-f475-t2i-meta", acknowledged_cost=true, wait_seconds=55) gave J2 a957e2b0e9c8.
      • J2 recomputed: the manifest has no reused marker, timing shows 26 passes and denoise_s 3.3, and the wall time is about 11 s against J1's about 14 s.
      • J2 ran on cuda:1 and J1 on cuda:0. If the step cache is per-GPU, that is a second reason it would miss. I can't tell which from here.
    • Cleanup is done: delete_output on both job_ids, and delete_workflow on both names.

    Notes for the lead

    • C-F475 call 2 changes subfolder and file_base_name, which the implementation deliberately keeps in the step-cache key. Even setting that deviation aside, the cache misses across workflow names and inline definitions, which the plan's "key the step cache only by what changes the output" does not allow.
    • The case text for C-F475 call 1 says run_workflow(workflow="c-f475-t2i", …). On this server workflow is the inline spelling, and it is refused as invalid JSON. I used name=. If that wording should change, I'll raise it through the suite route once the lead rules on the substance.
    • The pending: #905 lines are left in place.
  7. 4 remaining items

  8. dkackman commented on Oct 14, 2026

    @dkackman
    OwnerAuthor

    Build: the bounce shows that plan v2's stage 0 doesn't hold. Re-planning. #866 goes back to Don as plan v3. claude-opus-5-5 / anthropic, lead

    I went through each failure in the bounce. One is a bug, now fixed on the branch. One is the existing contract. One is a plan assumption that the code doesn't support.

    C-F474 call 6 (inline vs. by-name fingerprint): a bug, fixed on feat/866-0-output-keys @ b63cfaf. Not merged or deployed yet.

    • reference-to-video holds integral floats: video_shift: 12.0, audio_shift: 3.0 and lora_scale: 1.0.
    • An inline round trip through an MCP client respells them as 12, 3 and 1. json.dumps writes 12.0 and 12 differently, so the digest changes.
    • I reproduced it in the test client: the by-name form and the unmodified inline JSON both give sha256:cc322422…acbb6. Respelling just those floats as ints gives exactly sha256:3c07adc7186ba44b09a1f46402594dca7cb0d58c8c08d3fe18a8ab53a6f9b0a6, which is the tester's value.
    • text-to-image has no integral floats, which is why SD1.5 agreed.
    • The fix: _canonical_digest spells every integral float as an int (bools are left alone) before hashing. It is pinned by test_an_integral_float_spelled_as_an_int. The step cache already treated them as equal, since Python 12.0 == 12.

    C-F473 (h) / C-F474 seed: not a bug. The fingerprint leaves seed out on purpose.

    C-F475 (inline or other-name copy never hits the cache): a plan assumption that doesn't hold.
    v2's acceptance said "a re-run of a copy differing only in metadata gets step-cache hits". The step cache can't meet that for a copy, and the reason has nothing to do with which keys it hashes:

    • The cache is scoped to a workflow identity.
      • Identity is ("path", file) by name, or ("inline", id) (dw/worker_protocol.py workflow_identity).
      • A worker clears its whole step cache when the identity changes (dw/worker.py _prepare_workflow → _cleanup_all → step_cache.clear()).
      • c-f475-t2i-meta and an inline copy are different identities from c-f475-t2i, so running one empties the cache before it could hit.
    • The cache is per card. Each --devices card has its own worker process and its own cache. A job is routed by identity (pool.choose_slot prefers the card whose warm identity matches), so a different identity may not even reach the card that holds the entries.
    • A related, existing issue: the validate probe asks the routed card's cache without checking identity. It could report hits that the run's identity switch would then clear. Plan v3 lists it as a follow-up.

    So the step-cache half of stage 0 holds only for the same stored workflow edited in place, metadata only, then re-run. That edit keeps the identity, so the hits stand. That is also the case stage B needs: adding cost_drivers to H3 templates must not bust their caches. Caching across identities and cards is a different feature, because it changes what a worker keeps in memory and for how long. It is not a key audit.

    What's on the branch is kept: the key exclusions as merged at ec68fec, plus the float fix. #905 stays on owner:lead until Don rules on v3.

  9. added 2 commits that reference this issue on Oct 15, 2026
  10. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Shipped again after the bounce. Branch feat/866-0-output-keys, develop @ 9dfb9e6c. Deploy: [deploy 00:50:41] deployed develop @ 9dfb9e6c, healthy, mcp=true. claude-opus-5-5 / anthropic, lead

    Built to plan v4 (approved). Here is what each bounced item became:

    • C-F474 call 6 (inline vs. by-name on reference-to-video): fixed. dw/plan.py _canonical_digest now spells every integral float as an int before hashing (_same_number). An MCP round trip turns video_shift 12.0, audio_shift 3.0 and lora_scale 1.0 into 12, 3 and 1, and those now digest the same. This applies to the fingerprint only; the step cache already compared by value. Tests:
      • tests/test_plan.py::TestFingerprintIgnoresWhatCannotChangeTheOutput::test_an_integral_float_spelled_as_an_int (12.0 vs 12);
      • TestTheCatalogH3Template::test_a_client_round_trip_keeps_it, which runs on the real template.
    • Seed (C-F473 (h), C-F474 seed): unchanged, by the plan. Seed stays out of the fingerprint (the Assess: acknowledged_cost gate should bind to a budget/fingerprint, not just a boolean #85 contract), pinned by TestTheCatalogH3Template::test_the_seed_stays_out. The step cache does key on seed: tests/test_workflow_step_cache.py::TestOutputKeys::test_a_seed_is_a_miss.
    • C-F475 (a copy or inline copy misses the cache): expected, by plan v4. The cache is scoped per card and per identity (idea: step cache across workflow identities (renamed and inline copies hit) #912 covers caching across identities). The acceptance is now an in-place edit of one saved workflow:
      • a metadata-only edit hits (TestOutputKeys::test_metadata_alone_is_a_hit: cost_drivers, vram_estimate, description, catalog, role);
      • attention backend, cache, dtype, LoRA, seed, subfolder and file_base_name each miss. test_a_file_base_name_is_a_miss and test_a_seed_is_a_miss are new.
      • The validate probe's identity gap (bug: validate's cached_steps probe ignores the card's warm workflow identity #911) was already fixed on develop (021dcb62). So after an in-place edit, validate_workflow(name=…) reports the hits that the run will actually use.

    Plan items covered. The key audit and exclusions, cost_drivers reaching neither key, the integral-float rule, seed out of the fingerprint and in the cache, and the cache keeping subfolder/file_base_name. The key-by-key table in my earlier hand-off still holds. The ARCHITECTURE "Bound acknowledgement" row now also states the number and seed rules and names the round-trip test.

    Checks. The full pytest run has the same 17 failures as develop without this change: the local Kandinsky-6/diffusers environment (component-type, examples and plugin-skill tests). Nothing new fails, and ruff is clean.

    Deviations. None from plan v4. Fingerprints change once more for workflows that hold integral floats, such as the H3 templates, so an acknowledgement bound before this deploy has to be re-quoted. No MCP shape changed.

  11. added and removed
    owner:leadFeature lead's turn (harnest R11)
    on Oct 15, 2026
  12. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Architecture review queued by the loop driver: this hand-off changed dw/ or dw_mcp/ on develop (f65d5d8ce0..9dfb9e6c28: dw/plan.py). The reviewer checks it against docs/ARCHITECTURE.md before the tester verifies.

  13. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Architecture review: pass (no findings). claude-opus-5-5 / anthropic, reviewer

    Read: git diff f65d5d8c..9dfb9e6c under dw/ and dw_mcp/ (only dw/plan.py changed: _same_number, called from _canonical_digest), plus its docs/ARCHITECTURE.md change. I checked it against docs/ARCHITECTURE.md and item 3 of docs/stabilization/harness/stage-c-guardrails.md.

    • Second owner: none. The number normalization sits inside _canonical_digest in dw/plan.py, which the "Bound acknowledgement" row names as the fingerprint's owner. The step cache's keys are untouched. The repo's other is_integer() uses (dw/variables.py, dw/variable_constraints.py, dw/task_domains.py, dw/media_frames.py, dw/server/deps.py) validate or format values. None of them digests anything, so they aren't owners this change bypasses.
    • Build vs. buy: none. It is a small recursive walk before json.dumps and hashlib, from the standard library. No dependency in pyproject.toml canonicalizes JSON numbers.
    • Map: updated in the same change. The "Bound acknowledgement" row now states the number rule (12.0 as 12) and the seed rule (Assess: acknowledged_cost gate should bind to a budget/fingerprint, not just a boolean #85), and names tests/test_plan.py::TestTheCatalogH3Template::test_a_client_round_trip_keeps_it, which exists at tests/test_plan.py:439. The change adds no module and moves no rule.
    • Context: in the right place. The rationale, including why a bool is left alone, is in _same_number's docstring. No CLAUDE.md changed.

    No arch-approved waiver was needed or used. Back to the tester for MCP verification.

  14. dkackman commented on Oct 15, 2026

    @dkackman
    OwnerAuthor

    Verified: tester, claude-opus-5-5 via anthropic, against lem on develop @ 9dfb9e6. All three pending: #905 cases pass, and their pending: lines are removed, so they are now ordinary cases in regression-suite-complete.md.

    C-F497 (text-to-image fingerprint): pass. F0 = sha256:70cf5bf2…7ab36. A repeat gave the same value.

    • These variants all returned F0:
      • (a) cost_drivers removed
      • (b)+(c) together
      • (d)–(h) together in one call: description, cost minutes, vram_estimate added, plus the case's other metadata edits
      • (i) seed 43
    • (j), the 25.0 spelling, was not run separately. C-F498 call 3 covers integral floats.
    • Controls all moved, each to a distinct value:
      • (k) prompt → 5df8986d…
      • (l) 26 steps → b01dabc1…
      • (m) fp16 → 6ee2be26…
      • (n) 2 images → 0eb59102…

    C-F498 (H3 ref2va): pass. F0 = sha256:3c07adc7…f9b0a6.

    • Calls 1–5 all returned F0:
      • by name with seed 42, and with seed 43
      • inline with integral floats spelled as ints (call 3)
      • inline without cost_drivers and vram_estimate (call 4)
      • saved as c-f498-ref2v with cost_drivers: ["num_frames"], validated by name (call 5)
    • Controls all moved, each distinct from F0 and from each other:
      • sage_hub → 5fbc267b…
      • native → af01396c…
      • first_block cache 0.05 → ceef4523…
      • {int8} → 10d09db1…
      • LoRA null → 593e0d99…

    C-F499 (step cache, in-place edit): pass.

    • Step 1: J1 533cfffa7da6 succeeded in 12.4 s. Validate by name then reported cached_steps: 1.
    • Step 2: saved W1 over it, with description changed, cost_drivers dropped, minutes set to 5 and vram_estimate added. Validate reported cached_steps: 1 with the fingerprint unchanged.
    • Step 3: J2 665e01e405b7 succeeded in 0.42 s, against J1's 12.4 s. Its manifest has main with reused: true, pointing at J1's own file c-f499-t2i/20261015-005748-26bb3d22/final/test_image-0.0.jpg, so the image is J1's. Its events show phase: cached. Both jobs ran on cuda:0.
    • Step 4: each edit reported cached_steps: 0, and each restore of W1 reported 1 again:
      • (a) seed 43: fingerprint unchanged, as it should be
      • (b) fp16: 6ee2be26…
      • (c) subfolder other
      • (d) file_base_name renamed
      • (e) configuration.components.unet.attention_backend: "native": validate accepted it on SD1.5, fingerprint ce0711c6…
    • Cleanup: both runs deleted with delete_output(job_id=…), and c-f499-t2i and c-f498-ref2v deleted.

    Deviations from the cases as written:

    • W0's description was shortened to "c-f499 base". Description is metadata, and the fingerprint still matched C-F497's F0.
    • Edits were applied with save_workflow patches. steps is replaced whole in a patch, so the full step was sent each time.
    • Two save_workflow + validate_workflow pairs were issued in parallel. The returned fingerprint and cached_steps match the state that was supposed to be saved in each case.
    • C-F499 writes the calls as run_workflow(workflow="c-f499-t2i", …) and validate_workflow(workflow="c-f499-t2i"). On this server that form fails with "workflow is not valid JSON", because workflow takes a definition. I used name= instead. This is a small wording fix for the case, not a #866 stage 0: key the plan fingerprint and step cache only by what changes the output #905 defect. I'll leave it to the curator rather than editing the case.
  15. added
    status:verifiedTester confirmed the fix via a real MCP call
    and removed on Oct 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureWork bigger than a fix: designed with Don, built in stages (harnest R11)owner:testerTester's turn to actstageA child issue: one stage of a featurestatus:verifiedTester confirmed the fix via a real MCP calltarget:lem

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions