Skip to content

feat: configurable max_objective_chars option for objective/evidence/blocker limits - #38

Open
ErcinDedeoglu wants to merge 2 commits into
prevalentWare:mainfrom
ErcinDedeoglu:feat/max-objective-chars
Open

feat: configurable max_objective_chars option for objective/evidence/blocker limits#38
ErcinDedeoglu wants to merge 2 commits into
prevalentWare:mainfrom
ErcinDedeoglu:feat/max-objective-chars

Conversation

@ErcinDedeoglu

Copy link
Copy Markdown

Summary

Fixes #37.

The 4000-character limit on goal objectives, completion evidence, and blockers is hardcoded in validateObjective/validateEvidence and in the create_goal / set_goal / update_goal_objective / update_goal tool schemas (zod max() and maxLength). The schema-side limit also causes clients to silently truncate long objectives before the tool is even called.

Changes

  • New max_objective_chars plugin option; default raised from 4000 to 100000
  • Limit is threaded through runtime validation and both V1 (zod) and V2 (JSON schema) tool registrations, so runtime validation and advertised schema limits always match
  • /goal command template updated to ask for a complete, faithful objective — no compressing/truncating and no substitution with references or pointers to external files, while restructuring/rephrasing for clarity stays allowed (addresses the over-summarization failure mode from Long objectives get lost: 4000-char hard limit + model summarizes instead of passing verbatim #37 without forcing raw verbatim dumps)
  • Boundary test updated to exercise the configured limit; module-global limit is reset between tests

Example

{
  "plugin": [
    ["@prevalentware/opencode-goal-plugin", { "max_objective_chars": 100000 }]
  ]
}

Validation

  • bun run lint
  • bun run typecheck
  • bun run test — 213/213 pass ✅
  • bun run build + bun run pack:dry-run

…blocker limits

The 4000-character limit on goal objectives, completion evidence, and blockers
was hardcoded in validateObjective/validateEvidence and in the create_goal /
set_goal / update_goal_objective / update_goal tool schemas (zod max() and
maxLength). The schema-side limit also causes clients to silently truncate
long objectives before the tool is even called.

- Add a max_objective_chars plugin option (default 100000, up from 4000).
- Thread it through runtime validation and both V1 (zod) and V2 (JSON schema)
  tool registrations so runtime and advertised limits always match.
- Update the /goal command template to ask for a complete, faithful objective
  (no compressing/truncating, no substitution with references to external
  files) instead of the weaker "use the full arguments" wording.
- Update the boundary test to exercise the configured limit and reset the
  module-global limit between tests.

Fixes prevalentWare#37

@danyel117 danyel117 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution. The issue is valid, and the updated /goal wording is a good direction. Before merging, please address these correctness and coverage issues:

  1. Scope max_objective_chars per plugin instance. The current objectiveCharLimit in src/state.ts is module-global, and every V1/V2 setup overwrites it (src/server.ts). This makes active instances affect each other and can make an already-registered schema disagree with runtime validation. I reproduced this by creating instance A with a limit of 100, then instance B with a limit of 10: A's schema still accepted an 11-character objective, but A's executor rejected it with goal objective must be at most 10 characters. Please capture the limit in each server/setup instance and pass it explicitly to runtime validation/state operations and to V2 tool schema construction.

  2. Use consistent normalization and character-counting semantics in schemas and runtime. Runtime currently trims first and counts Unicode code points with [...value].length, while the V1 Zod schemas validate the untrimmed string and count UTF-16 code units. For example, with a limit of 1, 😀 passes runtime validation but fails the V1 schema; surrounding whitespace can create another mismatch. Since matching advertised and runtime limits is central to #37, please define one behavior and apply it consistently in V1, V2, and runtime validation.

  3. Add regression coverage for the new option. The current test change only configures the old 4000 boundary, so it does not exercise the new behavior. Please cover custom and default limits in both V1 and V2, advertised schema limits, objective/evidence/blocker runtime boundaries, simultaneous instances with different limits, and Unicode/whitespace behavior. An assertion for the new command fidelity wording would also protect that part of the fix.

Please also confirm that changing the default from 4000 to 100000 is an intentional product decision, since the issue suggested preserving 4000 for backward compatibility or using a more moderate increase.

For reference, the existing local gate passes (lint, typecheck, 213 tests, build, and pack), but these cases are currently uncovered. Once the changes are pushed, we can approve and run the GitHub Actions workflow.

Address review on prevalentWare#38:

- Capture the limit per V1/V2 setup instead of a process-wide setter so
  concurrent instances keep matching schemas and runtime validation.
- Count trimmed Unicode code points in V1 Zod, V2 JSON Schema, and
  runtime validation (emoji and surrounding whitespace now agree).
- Cover custom/default limits, advertised schema max, evidence/blocker,
  simultaneous instances, Unicode/whitespace, and command wording.
- Keep the 100000 default as an intentional replacement for the 4000
  defect; document that large objectives are echoed into later prompts.
@ErcinDedeoglu

Copy link
Copy Markdown
Author

Thanks for the review — the requested correctness and coverage issues are addressed in 996188a.

  1. Per-instance limit. objectiveCharLimit is no longer module-global. Each V1/V2 setup captures maxObjectiveChars on GoalServices and passes that value into runtime validation (validateObjective / validateEvidence / create-update-close) and into V1/V2 schema construction. Two live instances with different limits no longer clobber each other.

  2. One counting rule. Runtime, V1 Zod, and V2 maxLength now use the same definition: trim, then Unicode code points ([...value].length). V1 no longer uses z.string().max() (UTF-16, no trim). The advertised JSON Schema maxLength is that same code-point limit.

  3. Regression coverage. Added V1 and V2 tests for advertised schema max, custom vs default limits, objective/evidence/blocker execute boundaries, simultaneous instances, emoji/whitespace, and the faithful-objective command wording.

  4. Default 100000 is intentional. The old 4000 cap was the defect that caused silent truncation (Long objectives get lost: 4000-char hard limit + model summarizes instead of passing verbatim #37). README now states that explicitly, and notes that large objectives are echoed into continuation/compaction prompts.

Local gate: lint, typecheck, 216 tests, build, pack:dry-run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Long objectives get lost: 4000-char hard limit + model summarizes instead of passing verbatim

2 participants