Skip to content

fix(assign-to-workforce): keep truncate() within MAX_SUMMARY_LEN (#77)#78

Merged
OriNachum merged 1 commit into
mainfrom
fix/truncate-ellipsis-overshoot-77
Jul 15, 2026
Merged

fix(assign-to-workforce): keep truncate() within MAX_SUMMARY_LEN (#77)#78
OriNachum merged 1 commit into
mainfrom
fix/truncate-ellipsis-overshoot-77

Conversation

@OriNachum

Copy link
Copy Markdown
Contributor

What

Fixes #77truncate() in assign-to-workforce.sh's split-plan renderer
returned a string len(ELLIPSIS) (3) chars longer than MAX_SUMMARY_LEN
whenever it truncated:

return summary[:MAX_SUMMARY_LEN] + ELLIPSIS   # 72 + 3 = 75 chars

Because the table's column widths are computed from actual cell content
(max(len(...))), a truncated Task-summary cell widened the rendered table to
75 chars — overshooting the 72-char budget the constant is meant to enforce.
Presentation-only, but it made MAX_SUMMARY_LEN mean something other than what
it says.

Fix

Reserve room for the ellipsis so the rendered cell (ellipsis included) stays
within the cap:

return summary[:MAX_SUMMARY_LEN - len(ELLIPSIS)] + ELLIPSIS   # 69 + 3 = 72
  • tests/test_assign_to_workforce_script.py previously pinned the buggy
    75-char expectation
    — updated to the corrected slice, plus a module-level
    len(_EXPECTED_TRUNCATED) == 72 guard and an inline
    len(truncated_cell) <= MAX_SUMMARY_LEN assertion that locks the contract so
    a future regression fails loudly. Stale docstring wording ("past 72 chars")
    corrected to "to within 72 chars".
  • Patch version bump 0.19.0 → 0.19.1 + CHANGELOG entry.

Verification

  • uv run pytest -n auto — 616 passed.
  • flake8 / black --check / isort --check-only clean; markdownlint-cli2
    clean on CHANGELOG.md; agex pr lint — no violations.

Propagation note

assign-to-workforce is a devague origin skill (broadcast to the
AgentCulture mesh via guildmaster, cite-don't-import). Fixing at source means
downstream verbatim copies (rollout-cli, etc.) pick this up on their next
refresh rather than being patched per-copy — exactly as the reporter intended
by filing here. No sibling follow-up PR needed.

  • devague (Claude)

@OriNachum

Copy link
Copy Markdown
Contributor Author

/agentic_review

@qodo-code-review

qodo-code-review Bot commented Jul 15, 2026

Copy link
Copy Markdown

Code Review by Qodo

Grey Divider

New Review Started

This review has been superseded by a new analysis

Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Jul 15, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📎 Requirement gaps (0) 📜 Skill insights (0)

Context used
✅ Compliance rules (platform): 75 rules
✅ Skills: cicd, communicate

Grey Divider


Remediation recommended

1. Truncate invariant not enforced ✓ Resolved 🐞 Bug ≡ Correctness
Description
truncate() assumes MAX_SUMMARY_LEN > len(ELLIPSIS); if the cap is ever lowered or the ellipsis
changes, the negative slice index can produce unexpected output and break the “never exceed
MAX_SUMMARY_LEN” contract. This makes the width guarantee dependent on an undocumented configuration
invariant.
Code

.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh[R175-177]

+        # Reserve room for the ellipsis so the total stays within the cap
+        # (issue #77) — MAX_SUMMARY_LEN is the rendered width, ellipsis included.
+        return summary[:MAX_SUMMARY_LEN - len(ELLIPSIS)] + ELLIPSIS
Relevance

⭐⭐⭐ High

Team often accepts defensive validation/contract hardening (validation fixes accepted in PR #72;
robustness fixes in PR #31).

PR-#72
PR-#31

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script defines MAX_SUMMARY_LEN and ELLIPSIS immediately before truncate(), and the new
truncation logic directly subtracts len(ELLIPSIS) without validating the relationship between the
constants.

.claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh[159-178]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`truncate()` slices with `MAX_SUMMARY_LEN - len(ELLIPSIS)` but does not guard against `MAX_SUMMARY_LEN <= len(ELLIPSIS)`. In that case, Python’s negative slicing can return an unexpected substring and the function may no longer uphold the documented max-width contract.

## Issue Context
Current constants are safe (`MAX_SUMMARY_LEN=72`, `ELLIPSIS='...'`), but the function is brittle if either constant changes.

## Fix Focus Areas
- .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh[159-178]

## Suggested fix
- Compute `slice_len = max(0, MAX_SUMMARY_LEN - len(ELLIPSIS))`.
- If `MAX_SUMMARY_LEN <= len(ELLIPSIS)`, return `ELLIPSIS[:MAX_SUMMARY_LEN]` (or assert/raise) so the result length is always `<= MAX_SUMMARY_LEN`.
- Optionally add a small self-check (assert) documenting the invariant near the constants.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. Committed eidetic local state 🐞 Bug ⛨ Security
Description
The PR adds .eidetic/memory/default__public.jsonl, which appears to be runtime-generated memory
content (session note + author/timestamps) rather than source code. Keeping this in VCS risks
unintended disclosure and creates noisy diffs/merge conflicts as memory evolves.
Code

.eidetic/memory/default__public.jsonl[1]

+{"id": "plan-3layer-memory-evolution-2026-06-20", "hash": "db353fae964d96158a26d878e9a159ec5f6e8877cf3dba0a6c34e7e86b7535c3", "content": "3-layer memory evolution plan for eidetic-cli (requested 2026-06-20 by Ori). Layer 1 Migration: migrate the old ~/.claude memory skill data into eidetic across all stores \u2014 files (core.md, notes.md), Neo4j knowledge graph, MongoDB RAG. Eidetic becomes the drop-in replacement. Layer 2 Freshness/Temporal: every record carries a date signature and is temporal; signal strength degrades over time (a year-old fact is weaker than a fresh one); recalling and validating a fact reinforces its signal; remembering a new fact connected to an old one keeps them linked and the stronger validated one gains signal. Layer 3 No active deletion: memory is never actively deleted; a conflicting memory with a stronger signal shadows (supersedes but preserves) the older one; memory older than one year is archived. Open question to investigate: does the old memory solution already have a freshness mechanism. Skills to use: think (devague spec), remember, ask-colleague (explore/work/review).", "scope": {"name": "default", "visibility": "public"}, "metadata": {"type": "note", "record_metadata": {"source": "claude-code-session", "author": "Ori", "timestamp": "2026-06-20", "topic": "memory-architecture", "status": "proposed-spec", "relates_to": "eidetic-memory-surface"}, "created": "date-unknown", "last_recall": "2026-07-06T21:35:52.283202+00:00", "recall_count": 13, "links": [], "supersedes": null, "lifecycle": "active", "added_by": null}}
Relevance

⭐ Low

Similar “don’t commit/ignore mutable local state” suggestion explicitly rejected (kept tracked) in
PR #15.

PR-#15

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The added JSONL contains what looks like a personal/session memory record (author/timestamps). The
changelog describes eidetic’s memory surface as ~/.eidetic/memory, and the current .gitignore
does not ignore .eidetic/, making future accidental commits more likely.

.eidetic/memory/default__public.jsonl[1-1]
CHANGELOG.md[252-266]
.gitignore[97-126]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A new `.eidetic/memory/default__public.jsonl` file is being committed. This looks like generated local memory/tool state (including author and timestamps) rather than repo source, and can lead to accidental disclosure and ongoing churn.

## Issue Context
The project documentation describes eidetic memory as living under `~/.eidetic/memory` (user home), not a repo directory.

## Fix Focus Areas
- .eidetic/memory/default__public.jsonl[1-1]
- .gitignore[97-126]

## Suggested fix
- Remove `.eidetic/memory/default__public.jsonl` from the repo if it’s not intentional seed data.
- Add `.eidetic/` (or at least `.eidetic/memory/`) to `.gitignore` to prevent future accidental commits.
- If it *is* intentional seed data, move it under a clearly documented `fixtures/` or `docs/` area and document why it belongs in-repo.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread .claude/skills/assign-to-workforce/scripts/assign-to-workforce.sh Outdated
`truncate()` sliced MAX_SUMMARY_LEN chars and *then* appended the 3-char
ellipsis, so a truncated Task-summary cell rendered at 75 chars — 3 over
the cap the constant is meant to enforce. Since the split-plan table's
column widths are computed from actual cell content, this widened the
rendered table past its stated budget.

Reserve room for the ellipsis and clamp the result so the rendered cell
(ellipsis included) never exceeds MAX_SUMMARY_LEN — the trailing `[:MAX]`
clamp also upholds the contract in the degenerate MAX_SUMMARY_LEN <=
len(ELLIPSIS) config (Qodo, PR #78 review). Update the integration test,
which previously pinned the buggy 75-char expectation, and add a
`len(cell) <= MAX_SUMMARY_LEN` assertion to lock the contract.

Also gitignore `.eidetic/` (a repo-local eidetic memory store is stray
runtime state; the canonical store lives at ~/.eidetic).

Origin skill (broadcast to the mesh via guildmaster) — fixing at source so
downstream verbatim copies pick it up on next refresh rather than patching
per-copy.
@OriNachum OriNachum force-pushed the fix/truncate-ellipsis-overshoot-77 branch from f681693 to 2be54cd Compare July 15, 2026 12:46
@sonarqubecloud

Copy link
Copy Markdown

@OriNachum

Copy link
Copy Markdown
Contributor Author

Re: "Committed eidetic local state" — valid, and it was broader than the one file flagged. A stray git add -A swept in three untracked local files that predate this branch and are unrelated to the fix:

  • .eidetic/memory/default__public.jsonl (eidetic runtime memory)
  • .devague/proposed-steward-issue-3-skills.md
  • docs/steward/steward-suggestions.md

All three are removed from the PR (branch amended + force-pushed) — the diff now touches only the six fix-related files. I also added .eidetic/ to .gitignore, since the canonical eidetic store lives at ~/.eidetic and a repo-local copy is always stray runtime state. The files remain as untracked working state locally for separate handling. Thanks for catching it.

  • devague (Claude)

@OriNachum OriNachum merged commit 1a79e50 into main Jul 15, 2026
8 checks passed
@OriNachum OriNachum deleted the fix/truncate-ellipsis-overshoot-77 branch July 15, 2026 13:33
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.

assign-to-workforce: truncate() overshoots MAX_SUMMARY_LEN by the ellipsis length

1 participant