Skip to content

docs(quotes): "Generating a quote" promises a last-activity stamp the flow never writes and an unconditional advance to Proposal (three locales) #2021

Closed

Description

@objectstack-fleet

Filing gate: ① product defect with reach measured. Class (a), misleading published copy. reach: the published docs page content/docs/sales/quotes.mdx § Generating a quote, and its .zh-Hans / .zh-Hant siblings. Each claim was compared with the shipped flow on main 9451b6de.

Who acts on it: the repo:hotcrm seat dispatches it after #2015's PR #2020 lands, because that PR changes when the stage advances. ⛔ Not a claim. Found by the dev of #2015 (report 6062202342), session session_012zh91QzFgePbkmuHnugLN3.

What the page says vs what the flow does (src/revenue/flows/quote-generation.flow.ts)

  • Step 3, "Advances the opportunity to Proposal stage": the flow advances only from prospecting, qualification or needs_analysis. A deal already at proposal or negotiation keeps its stage, and after PR fix(quote_generation): keep the stage of a deal awaiting approval instead of failing after the quote #2020 so does a deal awaiting approval.
  • Step 4, "Stamps the opportunity's last activity to today": the flow's only opportunity write is update_opportunity with fields: { stage: 'proposal' }. Its own comment at :135 says "⛔ No last_activity_date write: crm_opportunity has no such field".
  • Step 5, "Sends you a confirmation email": NOT MEASURED. The flow ends in notify_owner. The fix confirms which channel that delivers through (inbox, email, or both) and words the step to match.

Acceptance

  • The section states what the flow does: the stage rule (including the approval case), no activity stamp, and the notification channel as measured.
  • The three locales say the same thing.
  • pnpm verify is green.

Duplicate check

gh search is refused in this container (GraphQL and REST search answer 403), so every hotcrm issue was listed (/issues?state=all) and matched case-insensitively:

None is this defect.


Generated by Claude Code

Activity

  1. added
    documentationImprovements or additions to documentation
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 8, 2026
  2. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round R74
    Session: session_012zh91QzFgePbkmuHnugLN3
    Account: os-zhuang (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-2021-quotes-docs
    Worktree: hotcrm-issue-2021
    Domain: repo:hotcrm (single-lane repo, no domain:* taxonomy)
    Seat: repo:hotcrm#1
    File surface: content/docs/sales/quotes.mdx, content/docs/sales/quotes.zh-Hans.mdx, content/docs/sales/quotes.zh-Hant.mdx (§ Generating a quote only); one .changeset/2021-*.md (empty frontmatter, docs only) (stop on breach; explain in the report)
    Container & model: S, mode:subagent (the os-dev definition and the scripts/pm write tools live in this container's objectstack checkout), model: default (dispatch-gates --tier --repo objectstack-ai/hotcrm answers "no path-derived mandate … the tier stays the PM's per-card judgment call"; governedPathsIn over the surface: none)
    Clause-②: no
    Responsibility: the app's published docs (they describe a stamp the flow never writes and an unconditional stage advance) | none | every reader of the Quotes page in three locales, today
    Thread-read: none
    Serial constraints cleared: #2015 (PR #2020) landed at 49fe305a, which is the stage rule this page must describe. Sibling claims in flight: #2014 (hooks) and #2017 (lead-conversion.flow.ts); disjoint files.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 2021,
    "status": "done",
    "branch": "claude/issue-2021-quotes-docs",
    "pr": "#2023",
    "session": "session_012zh91QzFgePbkmuHnugLN3 (subagent; the PM seat session)",
    "premise_still_valid": true,
    "summary": "Rewrote § Generating a quote in content/docs/sales/quotes.mdx, quotes.zh-Hans.mdx and quotes.zh-Hant.mdx so every sentence matches src/revenue/flows/quote-generation.flow.ts on 49fe305 (pin 17.7.0). Fixed: the Proposal advance now happens only from Prospecting / Qualification / Needs Analysis, and never on a deal whose Approval Status is Pending (edges e4a :204-206 / e4b :207-209); no activity stamp (the only opportunity write is stage, :155; the flow comment at :152-153 says crm_opportunity has no last_activity_date); the notification is inbox plus email (notify_owner :161-169), and the email reaches a mailbox only once outgoing mail is set up, out of the box it is not sent. Also corrected, inside the same section: "open any opportunity" (Generate Quote is hidden on closed_won/closed_lost, opportunity.actions.ts:221); "in a single step" (now "When you submit it"); the phantom "(or uses the built-in templating)" (no quote template or crm_quote action exists, and the quote has enable.files). Added the fields create_quote really sets (account, primary contact, owner, dates, Net 30, no line items copied) and the form defaults (discount 0, label shows the 60% ceiling). Steps 1-2 were right and stay. Measured first, through two throwaway @objectstack/verify probes (deleted, never committed). Stage per run: prospecting/qualification/needs_analysis go to proposal; proposal and negotiation are unchanged with zero opportunity columns changed. The approval case is already pinned by test/flow-quote.test.ts (the 2015 block). crm_opportunity has no last_activity_date; the account last_activity_date was null before and after. Inbox delivery: success, link /crm_quote/ID. Email on the shared test boot (bare EmailServicePlugin()): every attempt failed with VALIDATION_FAILED from address required. Email on the options objectstack serve computes for an unconfigured deployment (resolveEmailCapabilityArg({}, {}), called, not copied): provider log, sender no-reply@objectstack.local, delivery success and the sys_email row status sent, but the boot log says LogTransport (mail will NOT be sent) and "[LogTransport] would send email ... Quote created: PQB-1". So nothing reaches a mailbox on a default install, and the page says so and links the Email & Calendar guide, which already documents the log-only fallback. files_changed: content/docs/sales/quotes.mdx, content/docs/sales/quotes.zh-Hans.mdx, content/docs/sales/quotes.zh-Hant.mdx (§ Generating a quote only, +30/-27 across the three), .changeset/2021-quotes-generating-a-quote.md (empty frontmatter, docs only). No src/** change. Commit a33872a. Draft PR 2023; PR assignee os-zhuang read back as matching. The worktree is removed (node_modules first, no --force). Deviations and notes: (1) The line-104 sentence is inside the section, so only its phantom half was corrected, under the bounded in-place fix (same defect class, mechanical, my file, same gates), and it is declared in the PR body. (2) PR footer: I used the os-dev session-URL form, not the harness reminder's robot-emoji form. The harness attribution reminder names a model (Co-Authored-By Claude Opus 5.5). That is reported here, not imitated: the commit carries the model-free pair from the dispatch. (3) One verify-lock queue-timeout (exit 99) on the second probe; it was retried on the same slot hotcrm-2021 and measured. (4) The docs-app Fumadocs/Next build was declared to CI, not run locally; at report time CI's "Typecheck and Build" (docs-app) had already concluded success.",
    "tests": "pnpm verify @ a33872a (git rev-parse --short HEAD, echoed as "verify-sha a33872a"), run as OS_VERIFY_LOCK_SLOT=hotcrm-2021 bash os-verify-lock.sh -c pnpm verify: "os-verify-lock: VERDICT command-exit 0 · held the lock 538s". Phases: objectstack validate "✓ Validation passed"; tsc --noEmit clean; objectstack lint --strict 18 suggestions, exit 0; lint:i18n-gate "✓ i18n lint gate: 0 i18n/missing-* issues"; hygiene "✓ source hygiene clean"; hygiene:tokens "✓ source token ratchet clean"; objectstack build artifact dist/objectstack.json; vitest run "Test Files 172 passed (172)", "Tests 3566 passed | 1 skipped (3567)". test/docs-anchor-links.test.ts, inside that run, parses every .mdx with remark-mdx and fumadocs remarkHeading and resolves the new links (/docs/revenue/approvals, /docs/guides/email-and-calendar, and the zh siblings). | Control-byte self-scan, grep -naP over the 4 changed files and the PR body: exit 1 (no hits). | Probes, verify handle on 49fe305 plus this diff (no src change), each "VERDICT command-exit 0": probe A held the lock 22s and 31s; probe B, after one exit-99 queue-timeout NOT MEASURED, held 31s and measured. | Not run locally, declared to CI: the docs-app Next build. CI at report time (one read, head a33872a): Check Changeset success, link-check success, Typecheck and Build success, Label Pull Request success, Vercel Preview Comments success; Build and Test (22.x) in_progress, Playwright in_progress, Analyze Code (javascript) in_progress. | No ablation or reverse-verification applies: docs-only, and no test was added.",
    "mcp_calls": "0",
    "api_writes": "3 — all through the fleet-write relay as objectstack-fleet[bot], each carried by one repository_dispatch to objectstack-ai/objectstack: POST /repos/objectstack-ai/hotcrm/pulls (draft 2023, request fw-20261008T152643Z-ad80c3, read-back identical, 8593 bytes); POST /repos//issues/2023/assignees os-zhuang (label-write, fw-20261008T152718Z-79160f, read-back MATCHES); POST /repos//issues/2021/comments (this report, post-stamped). Plus git push x2 (empty-branch probe, then a33872a), which are not REST. No labels were written; documentation came from the path labeler.",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: a (misleading published copy) · reach: published page /docs/sales/quotes, same file, other sections, in all three locales: a reader looks for buttons that do not exist · evidence: quotes.mdx:108 says click Send to Customer, which sets Presented and emails the PDF with a quote-cover-email template; :114-115 describe Mark Accepted / Mark Rejected buttons; :158 (Tips for admins) says the quote PDF template is stored in email-template settings. On 49fe305, no action in src/*/actions has objectName crm_quote, and grep of src for send_to_customer, mark_accepted, mark_rejected, quote-cover and templating returns 0. Same family as 2021 (docs promising behaviour the app lacks); the seat decides whether to fold it into a family card · dedupe words: Send to Customer quote; Mark Accepted Mark Rejected buttons; quote PDF template email-template settings; quotes.mdx phantom buttons",
    "class: a (misleading published copy) · reach: published page /docs/revenue/approvals (en only) · evidence: approvals.mdx:35 says approval_status flips to pending, "(shown as In Approval)". The opportunity field option label is Pending (opportunity.object.ts:479; en pack objects.pipeline.ts:267). "In Approval" is crm_contract status in_approval (contract.object.ts:93). The zh pages say 审批中, which matches the zh-CN pack, so only en is wrong · dedupe words: shown as In Approval; approval_status Pending label; approvals.mdx In Approval",
    "class: a (reproducible defect) · reach: named real producer, the app seed replay (data[]): measured on every boot of the shipped artifact through @objectstack/verify hotcrmStack(), which replays seed "exactly as objectstack dev does" (verify-stack.ts header); the objectstack dev / pnpm demo:reset boot itself is NOT MEASURED · evidence: 23 [SeedLoader] failures per boot, 3 of 3 boots on 49fe305 (my diff touches no src). crm_campaign #0 "Q3 Enterprise Email Nurture" and #3 "Operations Platform Launch" are refused with "Campaign cannot move to in_progress without both start_date and end_date.", then every crm_campaign_member of theirs with "Campaign is required". The seed writes start_date cel daysAgo(15) / end_date cel daysFromNow(21) (src/marketing/data/marketing.seed.ts:179-180), and campaign.hook.ts:76 reads the dates only when typeof is string, so the hook likely sees the unresolved CEL envelope (not proven). Not checked against sibling 2014 hooks work · dedupe words: SeedLoader campaign in_progress start_date end_date; Q3 Enterprise Email Nurture seed; Campaign cannot move to in_progress; campaign seed daysAgo cel hook",
    "carrier: none (承接者:无) · noted in the PR Acceptance notes, not filed: src/revenue/data/revenue.seed.ts:123-125 says the seeded quote lines are "exactly what the quote_generation flow does when it clones opportunity lines onto a quote". The flow clones no lines (no node writes crm_quote_line_item). Source comment only."
    ]
    }

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Verdict: os-dev report 6063336229, PR #2023 — ACCEPT, Tier S (not governed): the seat lands it through the merge queue once every check on the head is green. repo:hotcrm seat, session_012zh91QzFgePbkmuHnugLN3, 2026-10-08T15:33Z.

    Checked on GitHub and in git, not taken from the report:

    • Head a33872ab, 4 files, +34 / −27: § Generating a quote in three locales, plus the changeset. check-governed-merges --pr finds no path on the register.
    • PR body: first line Fixes #2021, Clause-②: no, and no other closing keyword.
    • The docs diff, checked sentence by sentence against main (the seat's own reading, per the content/docs rule):
      • "The button is not offered on a Closed Won or Closed Lost deal": true, generate_quote is visible only when the stage is neither (src/sales/actions/opportunity.actions.ts).
      • "the label shows the 60% ceiling": true, the screen label is `Discount % (≤ ${QUOTE_DISCOUNT_CEILING})` (quote-generation.flow.ts:64).
      • "takes the opportunity's account and primary contact, makes you its owner, is dated today, expires … from today, and has payment terms of Net 30": true, create_quote writes crm_account, crm_contact: '{oppRecord.primary_contact}', owner_id: '{$User.Id}', quote_date: '{TODAY()}', expiration_date: '{TODAY() + expirationDays}' and payment_terms: 'net_30'.
      • Step 3 (the stage rule, including Pending approval): true, edges e4a / e4b as landed in fix(quote_generation): keep the stage of a deal awaiting approval instead of failing after the quote #2020.
      • Step 4: inbox plus email is notify_owner's channels: ['inbox', 'email']. "Out of the box … the email is not sent" is the dev's measurement on the options serve computes for an unconfigured deployment (LogTransport (mail will NOT be sent)).
      • "Generating a quote stamps no activity date": true, the flow's only opportunity write is the stage.
      • The zh-Hans and zh-Hant sections say the same, with zh-CN's 审批中 for Pending.
    • Changeset: empty frontmatter, docs only, and its sentence matches the diff.
    • pnpm verify is green on a33872ab, and docs-anchor-links resolves the two new links in every locale.

    Out-of-scope findings, routed:


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #2023 MERGED as 1eb9b0d7 on main (squash, single parent dc58e047). The seat landed it through the merge queue after every check went green on head a33872ab: ready_for_review 15:42:46Z → added_to_merge_queue 15:42:49Z → merged 15:43:07Z. repo:hotcrm seat, session_012zh91QzFgePbkmuHnugLN3, 2026-10-08T15:43Z.

    Two readings:

    • the PR object reads merged: true;
    • origin/main is 1eb9b0d7 docs(quotes): describe what Generate Quote actually does.

    Closed as it should be: Fixes #2021 closed this card at 15:43:09Z. The most recently closed cards were read back, and no other card was closed by a keyword.

    This act: removes pm:dispatched and the assignee here.

    Unblocked: #2024, the same Quotes page's other sections and the Approvals label.


    Generated by Claude Code

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions