Skip to content

Answer blackboard writes from the board they saved - #1062

Merged
saworbit merged 7 commits into
mainfrom
fix/blackboard-reads-back-its-save
Sep 29, 2026
Merged

saworbit merged 7 commits into
mainfrom
fix/blackboard-reads-back-its-save

Conversation

@saworbit

Copy link
Copy Markdown
Owner

Description

Part of #1019: the seven blackboard writers. #1019 stays open for the other fifteen tools.

blackboard_write, blackboard_patch, blackboard_clear, blackboard_task_create, blackboard_task_claim, blackboard_task_update and blackboard_task_complete built their answers from the board in memory, before it was saved, and never read the saved board back. In normal operation the answer happened to be right, but nothing in it was observed. A save the file did not keep would still have read as done, which is the defect class #1019 is about.

What changed:

  • saveAndReadBack saves the board, loads it back from the file and checks the revision it reads. It runs under the same lock as the change.
  • Each of the seven takes its reported fields from the stored board: revision; a write's metadata and the value now at its path (new); and a task call's task. For task_update that also covers the refresh that runs ahead of the save, which the old answer was captured before.
  • blackboard_clear confirms the path it removed is gone from the stored board, or refuses to report success.

Related Issues

Part of #1019. Stacked on #1061, which merges first.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds new MCP tools or capabilities)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update

Checklist

  • My code adheres to the project's coding style guidelines (C++20, 4 spaces).
  • I have added automated tests in tests/ covering new functionality.
  • All native unit tests pass (946/946 locally).
  • Live bridge changes pass tests/run_godot_integration.ps1 on Godot 4.5.1, 4.6.2 and 4.7.2.
  • Runtime-session changes cover editor and game descriptors, authentication, attach rollback, pause/step/stop, cursor polling, cleanup, and token redaction. Not touched.
  • Expression changes cover the strict read-only grammar, receiver allowlist, output/depth bounds, and cooperative-timeout wording. Not touched.
  • The exact MCP smoke starts with an explicit Godot project, matches the manifest emitted by didi --dump-tool-manifest from the same build, preserves the Phase 4/5/6 contracts, and keeps reserved runtime debugger tools marked unimplemented.
  • Any new tool name has an accepted record in docs/SURFACE_AMENDMENTS.md. No new tool.
  • Capability metadata, reference docs, roadmap, and changelog are current. Published tool counts are derived from the manifest, never hand-edited.
  • If this starts or finishes a Build Queue item, its row in docs/BUILD_QUEUE.md says IN PROGRESS, or COMPLETE (#<this pull request>). Not a queue item.
  • Tests added or removed: python tools/test_inventory.py regenerated docs/TEST_INVENTORY.md and the README badge.
  • I have updated relevant documentation in docs/ and README.md.

Tests

  • tests/observed_post_state.json: the seven move from exempt to observed. tests/observed_post_state.ps1 gets a case for each, in order on one board: write, patch, a task through its life, then the clear. Each compares the answer with the board file as Godot's own JSON reader parses it, through a new board_file function on observed_witness.gd. On all three lines: 34 cases over 32 tools agreed.
  • I made blackboard_write report a revision one higher than the file holds, and the harness failed with blackboard_write.revision answered 2 but the engine reports 1.0.
  • Blackboard.MutationsAnswerWithTheStoredBoard runs all seven natively and compares each answer with the board file parsed straight from disk.

Local: native 946/946, Python 540 OK, docs validator clean, inventory 1486.

signal_connect's target_script_not_compiled note and LLM_INSTRUCTIONS
said to restart the editor or call editor_reload_project. That tool is
EditorFileSystem.scan_sources, a file rescan, and the editor reads its
autoloads once at startup. project_set_autoload already said the rescan
does not register the singleton.

The live harness now asks the engine. After project_set_autoload it
calls editor_reload_project and repeats the refused connect, and the
script still does not compile on 4.5.1, 4.6.2 and 4.7.2. Both texts now
say to restart, and that the rescan does not register it.

Fixes #1002
The editor_reload_project call added for #1002 is the first
scan_sources after earlier blocks wrote editor_copy_probe.gd and
sandbox_run.gd behind the editor. On 4.5.1 and 4.6.2 the engine prints
Unrecognized UID for their two sidecars; 4.7.2 does not. The lines are
allowed by their exact UIDs and source file, which Godot derives from the
path and contents, so any other UID error still fails the run.
The editor_reload_project call added to the uncompiled-script block ran
a scan_sources in the middle of the harness. It met files other blocks
had written behind the editor and drew engine errors about them: two
Unrecognized UID lines on 4.5 and 4.6, and on CI's software-rendered
4.5.1 runner a frame_pre_draw connection error, on both attempts. None
of that is about the autoload advice.

The engine fact the rescan checked was measured on 4.5.1, 4.6.2 and
4.7.2 and is recorded beside the assertion. The block keeps checking
that the note says to restart and no longer offers the rescan.
runtime_read_output relayed Godot's colour escape codes in its records,
40 of a fresh headless editor's first 41, so a match against the visible
text failed. The ring now strips terminal escapes from a message when it
is captured, before the size bound. The stripper moves to
didi/common/terminal_text.hpp so the extension and the export tools
share it.

The offline helper Godot logged Didi's own INFO line before the WARN
default applies, so shader_check_compile's raw_output began with it.
That line is DEBUG now. The live contract snapshots show raw_output
starting with the engine's banner on 4.5, 4.6 and 4.7.

Fixes #1028
trial.py scored a Claude tester's transcript where the client filed it,
under its own projects store, and never copied it. Trial 05's is gone,
and nothing in its directory can reproduce its scores. The transcript is
now copied into the trial directory as transcript.jsonl and the copy is
scored.

And the tester's tool list restricted nothing: --allowed-tools only
pre-approves, and bypassPermissions approves everything, so trial 06's
tester also reached PowerShell and earlier ones met the host's skills.
The Claude tester now runs with --tools naming seven built-in tools,
ToolSearch among them because Didi's tools arrive deferred, with
--disable-slash-commands and --setting-sources project. A probe with
Claude Code 2.1.220 listed exactly those seven, with Didi's tools behind
ToolSearch. trial.json records the environment as tester_environment.

Fixes #1005
Fixes #1007
tools/localci built every lane with Ninja's default of CPUs + 2, and ASan
builds of the largest translation units need several GB each. On a
16.7 GB, 24-CPU Docker VM the asan lane was killed with "Killed signal
terminated program cc1plus", which reads like a compile error.

The asan lane now builds with one job per 2 GB of the container's
memory, never more than its CPUs; on that VM it chose 7. The gcc and
clang lanes keep Ninja's default. The lane prints the count it chose,
run.sh passes DIDI_LOCALCI_JOBS through, and that overrides any lane.

Fixes #1050
blackboard_write, blackboard_patch, blackboard_clear and the four task
calls built their answers from the board in memory before saving it,
and never read the saved board back, so a save the file did not keep
would still have read as done. Each now saves through saveAndReadBack,
which reloads the file and checks its revision, and takes its revision,
metadata, value and task from what was stored. blackboard_write also
returns the value now at its path, and a clear confirms the path it
removed is gone.

The seven move from exempt to observed in tests/observed_post_state.json.
The live harness compares each answer with the board file as Godot's own
JSON reader parses it, through a new board_file witness. Reporting a
revision one higher than the file holds fails the harness on
blackboard_write.revision.

Part of #1019. Fifteen tools remain on it.
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests Test suites and the contracts they assert addon The Godot addon and the in-engine GDExtension tooling Generators, harnesses, and developer tooling labels Sep 29, 2026
@saworbit
saworbit merged commit 8969835 into main Sep 29, 2026
28 checks passed
@saworbit
saworbit deleted the fix/blackboard-reads-back-its-save branch September 29, 2026 13:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

addon The Godot addon and the in-engine GDExtension documentation Improvements or additions to documentation tests Test suites and the contracts they assert tooling Generators, harnesses, and developer tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant