From 1c6e4a158c979fe5308a2a5a8c5cd492bf9eb24d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 04:52:31 +0000 Subject: [PATCH 1/4] fix(objects): write field help for the person reading the form Field descriptions render as help text under every form field, and many cited hook files, card numbers, DESIGN.md sections, flow codes and API field names. Each now says what the field means to the user; the implementation notes that were not already in the object headers move into code comments beside the field. Three help texts were also wrong, not just technical, and are corrected while rewritten: the contract type's review SLA promised a per-type reminder that fires at a fixed 30 days; the obligation and payment-plan status texts (both locales) omitted transitions the state machine allows (in_progress -> overdue; partial -> paid / overdue). The en bundle mirrors every changed inline string; zh-CN help that carried the same notes (design-doc citations, write-layer mechanics) is rewritten in step. No key added or removed, no behaviour change. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1 --- src/objects/clause.object.ts | 2 +- src/objects/contract-type.object.ts | 15 ++-- src/objects/contract-version.object.ts | 5 +- src/objects/contract.object.ts | 77 ++++++++++++++------- src/objects/deviation.object.ts | 4 +- src/objects/obligation.object.ts | 10 +-- src/objects/party.object.ts | 6 +- src/objects/payment-plan.object.ts | 15 ++-- src/objects/review.object.ts | 2 +- src/objects/signature.object.ts | 11 +-- src/translations/en/objects.catalog.ts | 14 ++-- src/translations/en/objects.contract.ts | 56 +++++++-------- src/translations/en/objects.lifecycle.ts | 34 ++++----- src/translations/zh-CN/objects.catalog.ts | 6 +- src/translations/zh-CN/objects.contract.ts | 14 ++-- src/translations/zh-CN/objects.lifecycle.ts | 4 +- 16 files changed, 159 insertions(+), 116 deletions(-) diff --git a/src/objects/clause.object.ts b/src/objects/clause.object.ts index 067117e..f0e25e1 100644 --- a/src/objects/clause.object.ts +++ b/src/objects/clause.object.ts @@ -102,7 +102,7 @@ export const Clause = ObjectSchema.create({ label: 'Deviation Needs Head of Legal', group: 'scope', defaultValue: false, - description: 'An accepted deviation from this clause routes the contract through the head-of-legal rung (F6).', + description: 'An accepted deviation from this clause routes the contract through the head-of-legal rung.', }), is_active: Field.boolean({ label: 'Active', diff --git a/src/objects/contract-type.object.ts b/src/objects/contract-type.object.ts index 67f5c1b..ff19496 100644 --- a/src/objects/contract-type.object.ts +++ b/src/objects/contract-type.object.ts @@ -110,7 +110,8 @@ export const ContractType = ObjectSchema.create({ label: 'Requires Legal Review', group: 'workflow', defaultValue: true, - description: 'When off, a submitted contract of this type goes straight to approval (DESIGN.md §03 状态机).', + // The submitted → in_approval edge of the DESIGN.md §03 state machine. + description: 'When off, a submitted contract of this type skips legal review and goes straight to approval.', }), execution_formalities: Field.select({ label: 'Execution Formalities', @@ -141,7 +142,11 @@ export const ContractType = ObjectSchema.create({ min: 0, max: 90, defaultValue: 5, - description: 'Calendar days legal has to finish review before the overdue reminder fires (F3).', + // DESIGN.md §06 F3 reads this per type, but the reminder fires at a fixed + // 30 days until the platform can compare dates (decision #31, 1C + 2B — see + // legal-review-sla.flow.ts), so the help text must not promise a per-type + // reminder. + description: 'Calendar days legal has to finish reviewing a contract of this type. The overdue reminder does not use this value: it currently fires at a fixed 30 days.', }), template_file: Field.file({ @@ -149,12 +154,14 @@ export const ContractType = ObjectSchema.create({ group: 'template', accept: ['application/pdf', '.docx'], maxSize: 20 * 1024 * 1024, - description: 'The document a first version is drafted from. No rendering engine exists on the platform yet — the launch form hands the template and its placeholder list to the drafter (DESIGN.md §12).', + // No rendering engine exists on the platform yet (DESIGN.md §12). + description: 'The document a first version is drafted from. The launch form hands the template and its placeholder list to the drafter; it does not fill the template in.', }), template_placeholders: Field.json({ label: 'Template Placeholders', group: 'template', - description: 'Array of { key, label, type, required } — the same shape as DocumentTemplate.placeholders in @objectstack/spec.', + // The same shape as DocumentTemplate.placeholders in @objectstack/spec. + description: 'A JSON list of the template\'s placeholders, one { key, label, type, required } entry per placeholder.', }), default_term_months: Field.number({ diff --git a/src/objects/contract-version.object.ts b/src/objects/contract-version.object.ts index 675810b..b570b5f 100644 --- a/src/objects/contract-version.object.ts +++ b/src/objects/contract-version.object.ts @@ -38,7 +38,7 @@ export const ContractVersion = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 80, - description: 'Stored mirror "v · ", stamped by mirror.hook.ts.', + description: 'Filled in automatically from the version number and kind, e.g. "v2 · Clean".', }), contract: Field.masterDetail('clm_contract', { label: 'Contract', @@ -84,7 +84,8 @@ export const ContractVersion = ObjectSchema.create({ label: 'Current', group: 'version', defaultValue: false, - description: 'The version negotiation is currently on. The clean-version guard before signing reads this flag.', + // The approved → signing guard in contract.hook.ts reads this flag. + description: 'The version negotiation is currently on. A contract can go to signing only once its current version is a clean copy.', }), file: Field.file({ diff --git a/src/objects/contract.object.ts b/src/objects/contract.object.ts index 2ad7a50..d51e013 100644 --- a/src/objects/contract.object.ts +++ b/src/objects/contract.object.ts @@ -62,7 +62,7 @@ export const Contract = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 32, - description: 'Generated on insert by contract.hook.ts as --<4-digit sequence>, one sequence per type per year (DESIGN.md §13 Q5). Regenerated only if the type changes while the contract is still a draft.', + description: 'Generated when the contract is created: the type code, the year and a four-digit sequence (e.g. NDA-2026-0001), one sequence per type per year. Regenerated only if the type changes while the contract is still a draft.', }), title: Field.text({ label: 'Title', @@ -80,7 +80,8 @@ export const Contract = ObjectSchema.create({ // Inactive types are hidden from the picker; existing contracts keep // them (clm_contract_type.is_active). lookupFilters: [{ field: 'is_active', operator: 'eq', value: true }], - description: 'The workflow this contract runs: intake fields, review, execution method and formalities (DESIGN.md §02).', + // The type IS the workflow definition (DESIGN.md §02). + description: 'The workflow this contract runs: intake fields, review, execution method and formalities.', }), category: Field.select({ label: 'Category', @@ -116,7 +117,9 @@ export const Contract = ObjectSchema.create({ group: 'identity', required: true, storage: { notNull: true }, - description: 'Lifecycle state. Transitions and their guards are enforced by contract.hook.ts (DESIGN.md §03 状态机); expired, terminated and cancelled are terminal.', + // Transitions and their guards: the state machine in contract.hook.ts + // (DESIGN.md §03 状态机), on every write path. + description: 'Where the contract is in its lifecycle. Status changes follow fixed rules; Expired, Terminated and Cancelled are final.', options: [ { label: 'Draft', value: 'draft', color: '#94A3B8', default: true }, { label: 'Submitted', value: 'submitted', color: '#3B82F6' }, @@ -146,14 +149,16 @@ export const Contract = ObjectSchema.create({ group: 'identity', readonly: true, defaultValue: false, - description: 'An already-executed contract entered after the fact through the F16 executed_upload action (DESIGN.md §13 Q8) — the only writer. Such a contract starts active and skipped review and approval.', + // Only writer: the F16 executed_upload action (DESIGN.md §13 Q8). + description: 'An already-signed contract recorded after the fact with Backfill Executed Contract. It starts active, without review or approval.', }), archive_no: Field.text({ label: 'Archive Number', group: 'identity', searchable: true, maxLength: 40, - description: 'Physical or records-management archive reference, assigned at archive time (F14).', + // Assigned by the archive step (DESIGN.md §06 F14). + description: 'Physical or records-management archive reference, assigned at archive time.', }), // ─── Parties & owners ─────────────────────────────────────────────── @@ -169,7 +174,8 @@ export const Contract = ObjectSchema.create({ our_entity: Field.select({ label: 'Our Signing Entity', group: 'parties', - description: 'Which of our legal entities signs. The shipped list is a single placeholder — a group with several legal entities replaces it with its own (DESIGN.md §01: signing entities are configuration, not schema).', + // DESIGN.md §01: signing entities are configuration, not schema. + description: 'Which of our legal entities signs. The shipped list is a single placeholder — a group with several legal entities replaces it with its own.', options: [ { label: 'Head office', value: 'head_office', default: true }, ], @@ -177,7 +183,9 @@ export const Contract = ObjectSchema.create({ department: Field.select({ label: 'Requesting Department', group: 'parties', - description: 'The business unit that launched the contract. A redundant scalar on the contract because RLS cannot cross objects (DESIGN.md §04); department-level sharing is a customer overlay (§13 Q2).', + // A redundant scalar on the contract because RLS cannot cross objects + // (DESIGN.md §04); department-level sharing is a customer overlay (§13 Q2). + description: 'The business unit that launched the contract. Sharing contracts by department is a customer-specific extension, not part of the standard product.', options: [ { label: 'Sales', value: 'sales' }, { label: 'Procurement', value: 'procurement' }, @@ -227,12 +235,14 @@ export const Contract = ObjectSchema.create({ label: 'Contract Amount', group: 'commercial', min: 0, - description: 'Total contract value in currency_code. The approval matrix bands on it (clm_approval_rule).', + // In currency_code; the clm_approval_rule amount bands read it. + description: 'Total contract value, in the contract currency. The approval matrix bands on it.', }), currency_code: Field.select({ label: 'Currency', group: 'commercial', - description: 'ISO 4217 code. The organization-level default is a setting, not schema; the factory default is USD (DESIGN.md §01).', + // DESIGN.md §01: the organization-level default is a setting, not schema. + description: 'ISO 4217 code. The organization\'s default currency is a setting; out of the box it is USD.', options: [ { label: 'USD — US Dollar', value: 'usd', default: true }, { label: 'EUR — Euro', value: 'eur' }, @@ -250,7 +260,9 @@ export const Contract = ObjectSchema.create({ payment_terms: Field.select({ label: 'Payment Terms', group: 'commercial', - description: 'Same value set as HotCRM crm_contract.payment_terms so the F15 hand-off maps 1:1.', + // Same value set as HotCRM crm_contract.payment_terms so the F15 hand-off + // maps 1:1. + description: 'The same values HotCRM uses for payment terms, so the two match one to one when a contract is handed over.', options: [ { label: 'Net 15', value: 'net_15' }, { label: 'Net 30', value: 'net_30' }, @@ -263,7 +275,7 @@ export const Contract = ObjectSchema.create({ label: 'Liability Cap', group: 'commercial', min: 0, - description: 'Maximum aggregate liability in currency_code. Empty means uncapped or not negotiated.', + description: 'Maximum aggregate liability, in the contract currency. Empty means uncapped or not negotiated.', }), // ─── Term & renewal ───────────────────────────────────────────────── @@ -274,7 +286,9 @@ export const Contract = ObjectSchema.create({ end_date: Field.date({ label: 'End Date', group: 'term', - description: 'The expiry job (F13) flags is_expiring renewal_notice_days before this date.', + // F12 renewal_notice (renewal-notice.flow.ts) flags is_expiring + // renewal_notice_days before this date. + description: 'The contract is flagged Expiring Soon once this date is within its renewal notice period.', }), term_months: Field.number({ label: 'Term (months)', @@ -294,12 +308,14 @@ export const Contract = ObjectSchema.create({ scale: 0, min: 0, max: 365, - description: 'Days before end_date by which a non-renewal notice must be given.', + description: 'Days before the end date by which a non-renewal notice must be given.', }), renewed_from: Field.lookup('clm_contract', { label: 'Renewed From', group: 'term', - description: 'Set by the "start renewal" action on the new draft; renewal is a new contract, not a transition (DESIGN.md §03).', + // Written by the start_renewal flow; DESIGN.md §03: renewal is a new + // contract, not a transition. + description: 'Set by Start Renewal on the new draft. A renewal is a new contract, not a status change.', }), parent_contract: Field.lookup('clm_contract', { label: 'Parent Contract', @@ -311,7 +327,8 @@ export const Contract = ObjectSchema.create({ group: 'term', readonly: true, defaultValue: false, - description: 'Stamped daily by the expiry job (F13) when end_date is within the renewal notice window.', + // Stamped by F12 renewal_notice — see end_date above. + description: 'Set by the daily check once the end date is within the renewal notice period.', }), // ─── Legal ────────────────────────────────────────────────────────── @@ -353,7 +370,7 @@ export const Contract = ObjectSchema.create({ group: 'legal', multiple: true, readonly: true, - description: 'Stamped from the contract type. Activation waits for a completed signature whose formalities_done covers every value here.', + description: 'Stamped from the contract type. Activation waits for a completed signing round whose Formalities Done covers every value here.', options: [ { label: 'Countersigned copy returned', value: 'countersigned_copy' }, { label: 'Company seal', value: 'company_seal' }, @@ -364,7 +381,7 @@ export const Contract = ObjectSchema.create({ summary: Field.richtext({ label: 'Summary', group: 'legal', - description: 'Human-written summary of the deal. The AI summary lives in ai_summary and is adopted separately.', + description: 'Human-written summary of the deal. The AI summary is kept in its own field and adopted separately.', }), // ─── Routing & approval — stamped by F2 (route) and F5 (ladder) ──── @@ -376,7 +393,8 @@ export const Contract = ObjectSchema.create({ label: 'Approval Status', group: 'routing', readonly: true, - description: 'Mirror of the approval ladder (F5) decision node; written by the flow, never by hand.', + // Mirror of the F5 approval ladder's decision node (contract-approval.flow.ts). + description: 'The outcome of the approval process. Set by the approval flow; do not edit it by hand.', options: [ { label: 'Not Required', value: 'not_required', color: '#94A3B8', default: true }, { label: 'Pending', value: 'pending', color: '#F59E0B' }, @@ -433,7 +451,7 @@ export const Contract = ObjectSchema.create({ group: 'lifecycle', requiredWhen: P`record.status == "terminated"`, maxLength: 2000, - description: 'Why the contract was ended before its term ran out. Required to terminate (DESIGN.md §03 active → terminated); asked once, by the Terminate action, and never on the intake form.', + description: 'Why the contract was ended before its term ran out. Required to terminate; asked once, by the Terminate action, and never on the intake form.', }), archived_at: Field.datetime({ label: 'Archived At', group: 'lifecycle', readonly: true }), @@ -442,7 +460,9 @@ export const Contract = ObjectSchema.create({ label: 'AI Summary', group: 'ai', readonly: true, - description: 'Adopted from an S2/S6 suggestion (DESIGN.md §07). Empty when nothing has been adopted, or when the ai capability is off.', + // Adopted from an S2/S6 suggestion (DESIGN.md §07); empty while the ai + // capability is off. + description: 'Adopted from an AI suggestion. Empty when nothing has been adopted, or when AI is turned off.', }), ai_risk_score: Field.number({ label: 'AI Risk Score', @@ -451,7 +471,8 @@ export const Contract = ObjectSchema.create({ scale: 0, min: 0, max: 100, - description: '0 (no concern) to 100 (do not sign). Adopted from the S6 approver memo after legal review; never written directly by the model.', + // Adopted from the S6 approver memo (DESIGN.md §07). + description: '0 (no concern) to 100 (do not sign). Adopted from the AI approver memo after legal review; never written directly by the AI.', }), ai_risk_rationale: Field.textarea({ label: 'AI Risk Rationale', @@ -484,7 +505,7 @@ export const Contract = ObjectSchema.create({ readonly: true, scale: 0, min: 0, - description: 'Count of clm_contract_version rows on this contract.', + description: 'How many document versions this contract has.', summaryOperations: { object: 'clm_contract_version', relationshipField: 'contract', @@ -498,7 +519,9 @@ export const Contract = ObjectSchema.create({ readonly: true, scale: 0, min: 0, - description: 'Count of clm_deviation rows still open. The in_review → in_approval guard reads the children directly (a guard must not trust a cached aggregate); this is the number people list and sort on.', + // The in_review → in_approval guard in contract.hook.ts reads the children + // directly: a guard must not trust a cached aggregate. + description: 'How many clause deviations are still open. Used for listing and sorting; sending for approval checks the deviations themselves, not this number.', summaryOperations: { object: 'clm_deviation', relationshipField: 'contract', @@ -513,7 +536,9 @@ export const Contract = ObjectSchema.create({ readonly: true, scale: 0, min: 0, - description: 'Count of clm_obligation rows in arrears. Moves only when the daily job (card 09) flips a child to overdue — the roll-up is recomputed by that write like any other.', + // Only the daily job (card 09, obligation-due.flow.ts) writes overdue; the + // roll-up is recomputed by that write like any other. + description: 'How many obligations are overdue. Only the daily check marks an obligation overdue.', summaryOperations: { object: 'clm_obligation', relationshipField: 'contract', @@ -528,7 +553,7 @@ export const Contract = ObjectSchema.create({ readonly: true, scale: 2, min: 0, - description: 'Sum of clm_payment_plan.planned_amount, in the contract currency. Compare with `amount`: that is the negotiated total, this is what the schedule actually adds up to.', + description: 'Total planned amount of the payment schedule, in the contract currency. Compare it with Contract Amount: that is the negotiated total, this is what the schedule actually adds up to.', summaryOperations: { object: 'clm_payment_plan', relationshipField: 'contract', @@ -542,7 +567,7 @@ export const Contract = ObjectSchema.create({ readonly: true, scale: 2, min: 0, - description: 'Sum of clm_payment_plan.actual_amount, in the contract currency — what has actually arrived against the schedule.', + description: 'Total actual amount of the payment schedule, in the contract currency — what has actually arrived against the schedule.', summaryOperations: { object: 'clm_payment_plan', relationshipField: 'contract', diff --git a/src/objects/deviation.object.ts b/src/objects/deviation.object.ts index f4a2c8c..be7f491 100644 --- a/src/objects/deviation.object.ts +++ b/src/objects/deviation.object.ts @@ -36,7 +36,7 @@ export const Deviation = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 200, - description: 'Stored mirror " · ", stamped by mirror.hook.ts.', + description: 'Filled in automatically as "clause title · status".', }), contract: Field.masterDetail('clm_contract', { label: 'Contract', @@ -82,7 +82,7 @@ export const Deviation = ObjectSchema.create({ group: 'decision', required: true, storage: { notNull: true }, - description: 'open → accepted / rejected / withdrawn; the decided states are terminal (contract.hook.ts).', + description: 'Moves from Open to Accepted, Rejected or Withdrawn; those three are final.', options: [ { label: 'Open', value: 'open', color: '#F59E0B', default: true }, { label: 'Accepted', value: 'accepted', color: '#2F7D5B' }, diff --git a/src/objects/obligation.object.ts b/src/objects/obligation.object.ts index 684bb94..aa4f3a5 100644 --- a/src/objects/obligation.object.ts +++ b/src/objects/obligation.object.ts @@ -47,7 +47,7 @@ export const Obligation = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 200, - description: 'Stored mirror of title, stamped by mirror.hook.ts.', + description: 'Filled in automatically from the title.', }), contract: Field.masterDetail('clm_contract', { label: 'Contract', @@ -70,7 +70,7 @@ export const Obligation = ObjectSchema.create({ kind: Field.select({ label: 'Kind', group: 'obligation', - description: 'What class of commitment this is; the reminder job and the dashboards band on it.', + description: 'What class of commitment this is; reminders and dashboards group by it.', options: [ { label: 'Deliverable', value: 'deliverable', color: '#3B82F6', default: true }, { label: 'Payment', value: 'payment', color: '#0B6E63' }, @@ -85,7 +85,7 @@ export const Obligation = ObjectSchema.create({ group: 'obligation', required: true, storage: { notNull: true }, - description: 'The date the daily job (card 09) measures arrears against.', + description: 'The date the daily check measures arrears against.', }), owner: Field.user({ label: 'Owner', @@ -98,7 +98,9 @@ export const Obligation = ObjectSchema.create({ group: 'progress', required: true, storage: { notNull: true }, - description: 'pending → in_progress / done / waived / overdue; in_progress → done / waived; overdue → done / waived. Enforced by contract.hook.ts; overdue is written only by the daily job (card 09).', + // The full table, including in_progress → overdue (decision #10, 1A), is the + // state machine in contract.hook.ts. + description: 'Pending moves to In Progress, Done, Waived or Overdue; In Progress to Done, Waived or Overdue; Overdue to Done or Waived. Done and Waived are final. Only the daily check sets Overdue.', options: [ { label: 'Pending', value: 'pending', color: '#94A3B8', default: true }, { label: 'In Progress', value: 'in_progress', color: '#3B82F6' }, diff --git a/src/objects/party.object.ts b/src/objects/party.object.ts index 3d92e30..3b47175 100644 --- a/src/objects/party.object.ts +++ b/src/objects/party.object.ts @@ -110,7 +110,8 @@ export const Party = ObjectSchema.create({ { label: 'Watch', value: 'watch', color: '#F59E0B' }, { label: 'Blocked', value: 'blocked', color: '#EF4444' }, ], - description: 'Blocked parties cannot be chosen on a new contract (intake guard, F1).', + // Enforced by the intake guard (F1) and the contract state machine. + description: 'Blocked parties cannot be chosen on a new contract.', }), risk_note: Field.textarea({ label: 'Risk Note', @@ -121,7 +122,8 @@ export const Party = ObjectSchema.create({ group: 'risk', required: true, storage: { notNull: true }, - description: 'Result of the last sanctions / registry screening. Written by the screening connector when one is configured (DESIGN.md §08), otherwise by legal.', + // The screening connector is DESIGN.md §08. + description: 'Result of the last sanctions / registry screening. Written by the screening connector when one is configured, otherwise by legal.', options: [ { label: 'Not screened', value: 'not_screened', color: '#94A3B8', default: true }, { label: 'Clear', value: 'clear', color: '#2F7D5B' }, diff --git a/src/objects/payment-plan.object.ts b/src/objects/payment-plan.object.ts index 06c023f..35e4d83 100644 --- a/src/objects/payment-plan.object.ts +++ b/src/objects/payment-plan.object.ts @@ -49,7 +49,7 @@ export const PaymentPlan = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 80, - description: 'Stored mirror "# · ", stamped by mirror.hook.ts. ASCII by design; the localized form belongs to the zh-CN bundle.', + description: 'Filled in automatically as "#instalment number · planned date".', }), contract: Field.masterDetail('clm_contract', { label: 'Contract', @@ -68,14 +68,14 @@ export const PaymentPlan = ObjectSchema.create({ scale: 0, min: 1, max: 999, - description: 'Position in the schedule, 1-based. Unique within the contract.', + description: 'Position in the schedule, starting at 1. Unique within the contract.', }), planned_date: Field.date({ label: 'Planned Date', group: 'schedule', required: true, storage: { notNull: true }, - description: 'The date the daily job (card 09) measures arrears against.', + description: 'The date the daily check measures arrears against.', }), planned_amount: Field.currency({ label: 'Planned Amount', @@ -83,7 +83,8 @@ export const PaymentPlan = ObjectSchema.create({ required: true, storage: { notNull: true }, min: 0, - description: 'In the contract currency (clm_contract.currency_code); the instalment amounts are not separately denominated.', + // Denominated in clm_contract.currency_code. + description: 'In the contract currency; the instalment amounts are not separately denominated.', }), condition: Field.textarea({ label: 'Condition', @@ -96,7 +97,9 @@ export const PaymentPlan = ObjectSchema.create({ group: 'actual', required: true, storage: { notNull: true }, - description: 'planned → due; due → partial / paid / overdue; overdue → partial / paid. Enforced by contract.hook.ts; overdue is written only by the daily job (card 09).', + // The full table, including the partial edges (decision #10, 2A), is the + // state machine in contract.hook.ts. + description: 'Planned moves to Due; Due to Partial, Paid or Overdue; Partial to Paid or Overdue; Overdue to Partial or Paid. Paid is final. Only the daily check sets Overdue.', options: [ { label: 'Planned', value: 'planned', color: '#94A3B8', default: true }, { label: 'Due', value: 'due', color: '#F59E0B' }, @@ -114,7 +117,7 @@ export const PaymentPlan = ObjectSchema.create({ label: 'Actual Amount', group: 'actual', min: 0, - description: 'What actually arrived, in the contract currency. Below planned_amount on a partial instalment.', + description: 'What actually arrived, in the contract currency. Below the planned amount on a partial instalment.', }), invoice_no: Field.text({ label: 'Invoice Number', diff --git a/src/objects/review.object.ts b/src/objects/review.object.ts index 2ccbe25..561ad23 100644 --- a/src/objects/review.object.ts +++ b/src/objects/review.object.ts @@ -34,7 +34,7 @@ export const Review = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 160, - description: 'Stored mirror " · ", stamped by mirror.hook.ts.', + description: 'Filled in automatically as "stage · reviewer".', }), contract: Field.masterDetail('clm_contract', { label: 'Contract', diff --git a/src/objects/signature.object.ts b/src/objects/signature.object.ts index b4ae057..beefde3 100644 --- a/src/objects/signature.object.ts +++ b/src/objects/signature.object.ts @@ -39,7 +39,7 @@ export const Signature = ObjectSchema.create({ readonly: true, searchable: true, maxLength: 80, - description: 'Stored mirror " · ", stamped by mirror.hook.ts.', + description: 'Filled in automatically as "method · status".', }), contract: Field.masterDetail('clm_contract', { label: 'Contract', @@ -63,7 +63,8 @@ export const Signature = ObjectSchema.create({ provider: Field.select({ label: 'Provider', group: 'round', - description: 'E-signature provider the envelope was sent through. Regional packs append their own (DESIGN.md §13 Q7).', + // Regional packs append their own options (DESIGN.md §13 Q7). + description: 'E-signature provider the envelope was sent through. Regional add-ons can add their own providers.', options: [ { label: 'DocuSign', value: 'docusign' }, { label: 'Adobe Acrobat Sign', value: 'adobe_sign' }, @@ -75,7 +76,8 @@ export const Signature = ObjectSchema.create({ group: 'round', searchable: true, maxLength: 120, - description: 'The provider\'s envelope or agreement id, for status polling and audit (F8).', + // Written and read by the e-signature dispatch and callback (DESIGN.md §06 F8). + description: 'The provider\'s envelope or agreement id, for status checks and audit.', }), signers: Field.json({ label: 'Signers', @@ -100,7 +102,8 @@ export const Signature = ObjectSchema.create({ label: 'Formalities Done', group: 'execution', multiple: true, - description: 'Same value set as clm_contract_type.execution_formalities. Activation waits until every formality the type requires is ticked here on a completed round.', + // Same value set as clm_contract_type.execution_formalities. + description: 'Same values as the contract type\'s execution formalities. Activation waits until every formality the type requires is ticked here on a completed round.', options: [ { label: 'Countersigned copy returned', value: 'countersigned_copy' }, { label: 'Company seal', value: 'company_seal' }, diff --git a/src/translations/en/objects.catalog.ts b/src/translations/en/objects.catalog.ts index bd2d3e3..d315811 100644 --- a/src/translations/en/objects.catalog.ts +++ b/src/translations/en/objects.catalog.ts @@ -64,7 +64,7 @@ export const catalog: Record = { }, requires_legal_review: { label: 'Requires Legal Review', - help: 'When off, a submitted contract of this type goes straight to approval (DESIGN.md §03 状态机).', + help: 'When off, a submitted contract of this type skips legal review and goes straight to approval.', }, execution_formalities: { label: 'Execution Formalities', @@ -87,15 +87,15 @@ export const catalog: Record = { }, review_sla_days: { label: 'Review SLA (days)', - help: 'Calendar days legal has to finish review before the overdue reminder fires (F3).', + help: 'Calendar days legal has to finish reviewing a contract of this type. The overdue reminder does not use this value: it currently fires at a fixed 30 days.', }, template_file: { label: 'Template', - help: 'The document a first version is drafted from. No rendering engine exists on the platform yet — the launch form hands the template and its placeholder list to the drafter (DESIGN.md §12).', + help: 'The document a first version is drafted from. The launch form hands the template and its placeholder list to the drafter; it does not fill the template in.', }, template_placeholders: { label: 'Template Placeholders', - help: 'Array of { key, label, type, required } — the same shape as DocumentTemplate.placeholders in @objectstack/spec.', + help: 'A JSON list of the template\'s placeholders, one { key, label, type, required } entry per placeholder.', }, default_term_months: { label: 'Default Term (months)', @@ -189,7 +189,7 @@ export const catalog: Record = { }, requires_legal_head: { label: 'Deviation Needs Head of Legal', - help: 'An accepted deviation from this clause routes the contract through the head-of-legal rung (F6).', + help: 'An accepted deviation from this clause routes the contract through the head-of-legal rung.', }, is_active: { label: 'Active', @@ -346,7 +346,7 @@ export const catalog: Record = { }, risk_flag: { label: 'Risk Flag', - help: 'Blocked parties cannot be chosen on a new contract (intake guard, F1).', + help: 'Blocked parties cannot be chosen on a new contract.', options: { none: 'None', watch: 'Watch', @@ -358,7 +358,7 @@ export const catalog: Record = { }, screening_status: { label: 'Screening', - help: 'Result of the last sanctions / registry screening. Written by the screening connector when one is configured (DESIGN.md §08), otherwise by legal.', + help: 'Result of the last sanctions / registry screening. Written by the screening connector when one is configured, otherwise by legal.', options: { not_screened: 'Not screened', clear: 'Clear', diff --git a/src/translations/en/objects.contract.ts b/src/translations/en/objects.contract.ts index 091d387..9441a7d 100644 --- a/src/translations/en/objects.contract.ts +++ b/src/translations/en/objects.contract.ts @@ -19,14 +19,14 @@ export const contract: Record = { fields: { contract_number: { label: 'Contract Number', - help: 'Generated on insert by contract.hook.ts as --<4-digit sequence>, one sequence per type per year (DESIGN.md §13 Q5). Regenerated only if the type changes while the contract is still a draft.', + help: 'Generated when the contract is created: the type code, the year and a four-digit sequence (e.g. NDA-2026-0001), one sequence per type per year. Regenerated only if the type changes while the contract is still a draft.', }, title: { label: 'Title', }, contract_type: { label: 'Contract Type', - help: 'The workflow this contract runs: intake fields, review, execution method and formalities (DESIGN.md §02).', + help: 'The workflow this contract runs: intake fields, review, execution method and formalities.', }, category: { label: 'Category', @@ -55,7 +55,7 @@ export const contract: Record = { }, status: { label: 'Status', - help: 'Lifecycle state. Transitions and their guards are enforced by contract.hook.ts (DESIGN.md §03 状态机); expired, terminated and cancelled are terminal.', + help: 'Where the contract is in its lifecycle. Status changes follow fixed rules; Expired, Terminated and Cancelled are final.', options: { draft: 'Draft', submitted: 'Submitted', @@ -81,25 +81,25 @@ export const contract: Record = { }, is_backfilled: { label: 'Backfilled', - help: 'An already-executed contract entered after the fact through the F16 executed_upload action (DESIGN.md §13 Q8) — the only writer. Such a contract starts active and skipped review and approval.', + help: 'An already-signed contract recorded after the fact with Backfill Executed Contract. It starts active, without review or approval.', }, archive_no: { label: 'Archive Number', - help: 'Physical or records-management archive reference, assigned at archive time (F14).', + help: 'Physical or records-management archive reference, assigned at archive time.', }, party: { label: 'Counterparty', }, our_entity: { label: 'Our Signing Entity', - help: 'Which of our legal entities signs. The shipped list is a single placeholder — a group with several legal entities replaces it with its own (DESIGN.md §01: signing entities are configuration, not schema).', + help: 'Which of our legal entities signs. The shipped list is a single placeholder — a group with several legal entities replaces it with its own.', options: { head_office: 'Head office', }, }, department: { label: 'Requesting Department', - help: 'The business unit that launched the contract. A redundant scalar on the contract because RLS cannot cross objects (DESIGN.md §04); department-level sharing is a customer overlay (§13 Q2).', + help: 'The business unit that launched the contract. Sharing contracts by department is a customer-specific extension, not part of the standard product.', options: { sales: 'Sales', procurement: 'Procurement', @@ -133,11 +133,11 @@ export const contract: Record = { }, amount: { label: 'Contract Amount', - help: 'Total contract value in currency_code. The approval matrix bands on it (clm_approval_rule).', + help: 'Total contract value, in the contract currency. The approval matrix bands on it.', }, currency_code: { label: 'Currency', - help: 'ISO 4217 code. The organization-level default is a setting, not schema; the factory default is USD (DESIGN.md §01).', + help: 'ISO 4217 code. The organization\'s default currency is a setting; out of the box it is USD.', options: { usd: 'USD — US Dollar', eur: 'EUR — Euro', @@ -152,7 +152,7 @@ export const contract: Record = { }, payment_terms: { label: 'Payment Terms', - help: 'Same value set as HotCRM crm_contract.payment_terms so the F15 hand-off maps 1:1.', + help: 'The same values HotCRM uses for payment terms, so the two match one to one when a contract is handed over.', options: { net_15: 'Net 15', net_30: 'Net 30', @@ -163,14 +163,14 @@ export const contract: Record = { }, liability_cap: { label: 'Liability Cap', - help: 'Maximum aggregate liability in currency_code. Empty means uncapped or not negotiated.', + help: 'Maximum aggregate liability, in the contract currency. Empty means uncapped or not negotiated.', }, start_date: { label: 'Start Date', }, end_date: { label: 'End Date', - help: 'The expiry job (F13) flags is_expiring renewal_notice_days before this date.', + help: 'The contract is flagged Expiring Soon once this date is within its renewal notice period.', }, term_months: { label: 'Term (months)', @@ -180,11 +180,11 @@ export const contract: Record = { }, renewal_notice_days: { label: 'Renewal Notice (days)', - help: 'Days before end_date by which a non-renewal notice must be given.', + help: 'Days before the end date by which a non-renewal notice must be given.', }, renewed_from: { label: 'Renewed From', - help: 'Set by the "start renewal" action on the new draft; renewal is a new contract, not a transition (DESIGN.md §03).', + help: 'Set by Start Renewal on the new draft. A renewal is a new contract, not a status change.', }, parent_contract: { label: 'Parent Contract', @@ -192,7 +192,7 @@ export const contract: Record = { }, is_expiring: { label: 'Expiring Soon', - help: 'Stamped daily by the expiry job (F13) when end_date is within the renewal notice window.', + help: 'Set by the daily check once the end date is within the renewal notice period.', }, governing_law: { label: 'Governing Law', @@ -220,7 +220,7 @@ export const contract: Record = { }, execution_formalities: { label: 'Execution Formalities', - help: 'Stamped from the contract type. Activation waits for a completed signature whose formalities_done covers every value here.', + help: 'Stamped from the contract type. Activation waits for a completed signing round whose Formalities Done covers every value here.', options: { countersigned_copy: 'Countersigned copy returned', company_seal: 'Company seal', @@ -230,7 +230,7 @@ export const contract: Record = { }, summary: { label: 'Summary', - help: 'Human-written summary of the deal. The AI summary lives in ai_summary and is adopted separately.', + help: 'Human-written summary of the deal. The AI summary is kept in its own field and adopted separately.', }, route_legal_head: { label: 'Routes: Head of Legal', @@ -246,7 +246,7 @@ export const contract: Record = { }, approval_status: { label: 'Approval Status', - help: 'Mirror of the approval ladder (F5) decision node; written by the flow, never by hand.', + help: 'The outcome of the approval process. Set by the approval flow; do not edit it by hand.', options: { not_required: 'Not Required', pending: 'Pending', @@ -279,18 +279,18 @@ export const contract: Record = { }, termination_reason: { label: 'Termination Reason', - help: 'Why the contract was ended before its term ran out. Required to terminate (DESIGN.md §03 active → terminated); asked once, by the Terminate action, and never on the intake form.', + help: 'Why the contract was ended before its term ran out. Required to terminate; asked once, by the Terminate action, and never on the intake form.', }, archived_at: { label: 'Archived At', }, ai_summary: { label: 'AI Summary', - help: 'Adopted from an S2/S6 suggestion (DESIGN.md §07). Empty when nothing has been adopted, or when the ai capability is off.', + help: 'Adopted from an AI suggestion. Empty when nothing has been adopted, or when AI is turned off.', }, ai_risk_score: { label: 'AI Risk Score', - help: '0 (no concern) to 100 (do not sign). Adopted from the S6 approver memo after legal review; never written directly by the model.', + help: '0 (no concern) to 100 (do not sign). Adopted from the AI approver memo after legal review; never written directly by the AI.', }, ai_risk_rationale: { label: 'AI Risk Rationale', @@ -300,23 +300,23 @@ export const contract: Record = { }, version_count: { label: 'Versions', - help: 'Count of clm_contract_version rows on this contract.', + help: 'How many document versions this contract has.', }, open_deviation_count: { label: 'Open Deviations', - help: 'Count of clm_deviation rows still open. The in_review → in_approval guard reads the children directly (a guard must not trust a cached aggregate); this is the number people list and sort on.', + help: 'How many clause deviations are still open. Used for listing and sorting; sending for approval checks the deviations themselves, not this number.', }, overdue_obligation_count: { label: 'Overdue Obligations', - help: 'Count of clm_obligation rows in arrears. Moves only when the daily job (card 09) flips a child to overdue — the roll-up is recomputed by that write like any other.', + help: 'How many obligations are overdue. Only the daily check marks an obligation overdue.', }, planned_amount: { label: 'Planned Amount', - help: 'Sum of clm_payment_plan.planned_amount, in the contract currency. Compare with `amount`: that is the negotiated total, this is what the schedule actually adds up to.', + help: 'Total planned amount of the payment schedule, in the contract currency. Compare it with Contract Amount: that is the negotiated total, this is what the schedule actually adds up to.', }, actual_amount: { label: 'Actual Amount', - help: 'Sum of clm_payment_plan.actual_amount, in the contract currency — what has actually arrived against the schedule.', + help: 'Total actual amount of the payment schedule, in the contract currency — what has actually arrived against the schedule.', }, }, _actions: { @@ -548,7 +548,7 @@ export const contract: Record = { fields: { display_name: { label: 'Version', - help: 'Stored mirror "v · ", stamped by mirror.hook.ts.', + help: 'Filled in automatically from the version number and kind, e.g. "v2 · Clean".', }, contract: { label: 'Contract', @@ -576,7 +576,7 @@ export const contract: Record = { }, is_current: { label: 'Current', - help: 'The version negotiation is currently on. The clean-version guard before signing reads this flag.', + help: 'The version negotiation is currently on. A contract can go to signing only once its current version is a clean copy.', }, file: { label: 'File', diff --git a/src/translations/en/objects.lifecycle.ts b/src/translations/en/objects.lifecycle.ts index 17f0302..a17484f 100644 --- a/src/translations/en/objects.lifecycle.ts +++ b/src/translations/en/objects.lifecycle.ts @@ -17,7 +17,7 @@ export const lifecycle: Record = { fields: { display_name: { label: 'Review', - help: 'Stored mirror " · ", stamped by mirror.hook.ts.', + help: 'Filled in automatically as "stage · reviewer".', }, contract: { label: 'Contract', @@ -83,7 +83,7 @@ export const lifecycle: Record = { fields: { display_name: { label: 'Deviation', - help: 'Stored mirror " · ", stamped by mirror.hook.ts.', + help: 'Filled in automatically as "clause title · status".', }, contract: { label: 'Contract', @@ -110,7 +110,7 @@ export const lifecycle: Record = { }, status: { label: 'Status', - help: 'open → accepted / rejected / withdrawn; the decided states are terminal (contract.hook.ts).', + help: 'Moves from Open to Accepted, Rejected or Withdrawn; those three are final.', options: { open: 'Open', accepted: 'Accepted', @@ -144,7 +144,7 @@ export const lifecycle: Record = { fields: { display_name: { label: 'Signature', - help: 'Stored mirror " · ", stamped by mirror.hook.ts.', + help: 'Filled in automatically as "method · status".', }, contract: { label: 'Contract', @@ -158,7 +158,7 @@ export const lifecycle: Record = { }, provider: { label: 'Provider', - help: 'E-signature provider the envelope was sent through. Regional packs append their own (DESIGN.md §13 Q7).', + help: 'E-signature provider the envelope was sent through. Regional add-ons can add their own providers.', options: { docusign: 'DocuSign', adobe_sign: 'Adobe Acrobat Sign', @@ -167,7 +167,7 @@ export const lifecycle: Record = { }, envelope_id: { label: 'Envelope ID', - help: 'The provider\'s envelope or agreement id, for status polling and audit (F8).', + help: 'The provider\'s envelope or agreement id, for status checks and audit.', }, signers: { label: 'Signers', @@ -185,7 +185,7 @@ export const lifecycle: Record = { }, formalities_done: { label: 'Formalities Done', - help: 'Same value set as clm_contract_type.execution_formalities. Activation waits until every formality the type requires is ticked here on a completed round.', + help: 'Same values as the contract type\'s execution formalities. Activation waits until every formality the type requires is ticked here on a completed round.', options: { countersigned_copy: 'Countersigned copy returned', company_seal: 'Company seal', @@ -222,7 +222,7 @@ export const lifecycle: Record = { fields: { display_name: { label: 'Obligation', - help: 'Stored mirror of title, stamped by mirror.hook.ts.', + help: 'Filled in automatically from the title.', }, contract: { label: 'Contract', @@ -233,7 +233,7 @@ export const lifecycle: Record = { }, kind: { label: 'Kind', - help: 'What class of commitment this is; the reminder job and the dashboards band on it.', + help: 'What class of commitment this is; reminders and dashboards group by it.', options: { deliverable: 'Deliverable', payment: 'Payment', @@ -245,7 +245,7 @@ export const lifecycle: Record = { }, due_date: { label: 'Due Date', - help: 'The date the daily job (card 09) measures arrears against.', + help: 'The date the daily check measures arrears against.', }, owner: { label: 'Owner', @@ -253,7 +253,7 @@ export const lifecycle: Record = { }, status: { label: 'Status', - help: 'pending → in_progress / done / waived / overdue; in_progress → done / waived; overdue → done / waived. Enforced by contract.hook.ts; overdue is written only by the daily job (card 09).', + help: 'Pending moves to In Progress, Done, Waived or Overdue; In Progress to Done, Waived or Overdue; Overdue to Done or Waived. Done and Waived are final. Only the daily check sets Overdue.', options: { pending: 'Pending', in_progress: 'In Progress', @@ -300,22 +300,22 @@ export const lifecycle: Record = { fields: { display_name: { label: 'Instalment', - help: 'Stored mirror "# · ", stamped by mirror.hook.ts. ASCII by design; the localized form belongs to the zh-CN bundle.', + help: 'Filled in automatically as "#instalment number · planned date".', }, contract: { label: 'Contract', }, seq: { label: 'Instalment No.', - help: 'Position in the schedule, 1-based. Unique within the contract.', + help: 'Position in the schedule, starting at 1. Unique within the contract.', }, planned_date: { label: 'Planned Date', - help: 'The date the daily job (card 09) measures arrears against.', + help: 'The date the daily check measures arrears against.', }, planned_amount: { label: 'Planned Amount', - help: 'In the contract currency (clm_contract.currency_code); the instalment amounts are not separately denominated.', + help: 'In the contract currency; the instalment amounts are not separately denominated.', }, condition: { label: 'Condition', @@ -323,7 +323,7 @@ export const lifecycle: Record = { }, status: { label: 'Status', - help: 'planned → due; due → partial / paid / overdue; overdue → partial / paid. Enforced by contract.hook.ts; overdue is written only by the daily job (card 09).', + help: 'Planned moves to Due; Due to Partial, Paid or Overdue; Partial to Paid or Overdue; Overdue to Partial or Paid. Paid is final. Only the daily check sets Overdue.', options: { planned: 'Planned', due: 'Due', @@ -338,7 +338,7 @@ export const lifecycle: Record = { }, actual_amount: { label: 'Actual Amount', - help: 'What actually arrived, in the contract currency. Below planned_amount on a partial instalment.', + help: 'What actually arrived, in the contract currency. Below the planned amount on a partial instalment.', }, invoice_no: { label: 'Invoice Number', diff --git a/src/translations/zh-CN/objects.catalog.ts b/src/translations/zh-CN/objects.catalog.ts index 1d9565c..aaa4ff3 100644 --- a/src/translations/zh-CN/objects.catalog.ts +++ b/src/translations/zh-CN/objects.catalog.ts @@ -87,15 +87,15 @@ export const catalog: Record = { }, review_sla_days: { label: '审查时限(天)', - help: '法务完成审查的自然日天数,超时会触发催办提醒。', + help: '法务完成这种类型合同审查的自然日天数。催办提醒目前不按这个值,而是固定在 30 天时触发。', }, template_file: { label: '模板', - help: '起草首版所依据的文档。平台目前没有文档渲染引擎,发起表单会把模板和占位符清单交给起草人。', + help: '起草首版所依据的文档。发起表单会把模板和占位符清单交给起草人,不会自动填好模板。', }, template_placeholders: { label: '模板占位符', - help: '由 { key, label, type, required } 组成的数组,形状与平台文档模板的占位符一致。', + help: '模板占位符的 JSON 列表,每个占位符一项,形如 { key, label, type, required }。', }, default_term_months: { label: '默认期限(月)', diff --git a/src/translations/zh-CN/objects.contract.ts b/src/translations/zh-CN/objects.contract.ts index 259fddb..937e415 100644 --- a/src/translations/zh-CN/objects.contract.ts +++ b/src/translations/zh-CN/objects.contract.ts @@ -55,7 +55,7 @@ export const contract: Record = { }, status: { label: '状态', - help: '合同所处的生命周期环节。状态之间怎么流转由写入层强制,界面隐藏不算数;已到期、已终止、已作废是终态。', + help: '合同所处的生命周期环节。状态只能按规定的路径流转;已到期、已终止、已作废是终态。', options: { draft: '草稿', submitted: '已提交', @@ -137,7 +137,7 @@ export const contract: Record = { }, currency_code: { label: '币种', - help: 'ISO 4217 代码。组织级默认币种是一项设置,不写死在模型里;出厂默认为美元。', + help: 'ISO 4217 代码。组织级默认币种是一项设置;出厂默认为美元。', options: { usd: 'USD — 美元', eur: 'EUR — 欧元', @@ -246,7 +246,7 @@ export const contract: Record = { }, approval_status: { label: '审批状态', - help: '审批流的结果镜像,由流程写入,不要手工修改。', + help: '审批的结果,由审批流程写入,不要手工修改。', options: { not_required: '无需审批', pending: '审批中', @@ -279,7 +279,7 @@ export const contract: Record = { }, termination_reason: { label: '终止原因', - help: '为什么在期限届满前结束这份合同。终止时必填(设计方案第 3 章「生效 → 已终止」守卫);只在按下「终止」时问一次,发起表单上不出现。', + help: '为什么在期限届满前结束这份合同。终止时必填;只在按下「终止」时问一次,发起表单上不出现。', }, archived_at: { label: '归档时间', @@ -304,11 +304,11 @@ export const contract: Record = { }, open_deviation_count: { label: '未决偏离数', - help: '仍未处理的条款偏离条数。用于列表展示和排序;送审时的拦截会直接查子记录,不依赖这个汇总值。', + help: '仍未处理的条款偏离条数,用于列表展示和排序;送审时检查的是偏离本身,而不是这个数字。', }, overdue_obligation_count: { label: '逾期义务数', - help: '已经逾期的履约义务条数。只有每日检查把某条义务改为逾期时,这个数字才会变化。', + help: '已经逾期的履约义务条数。只有每日检查会把义务标记为逾期。', }, planned_amount: { label: '计划金额', @@ -576,7 +576,7 @@ export const contract: Record = { }, is_current: { label: '当前版本', - help: '谈判当前所在的版本。签署前的清稿检查读的就是这个标记。', + help: '谈判当前所在的版本。只有当前版本是清稿时,合同才能进入签署。', }, file: { label: '文件', diff --git a/src/translations/zh-CN/objects.lifecycle.ts b/src/translations/zh-CN/objects.lifecycle.ts index 32bde6e..e81af30 100644 --- a/src/translations/zh-CN/objects.lifecycle.ts +++ b/src/translations/zh-CN/objects.lifecycle.ts @@ -253,7 +253,7 @@ export const lifecycle: Record = { }, status: { label: '状态', - help: '待办可转为进行中、已完成或已豁免;进行中可转为已完成或已豁免;逾期可转为已完成或已豁免。逾期只由每日检查写入。', + help: '待办可转为进行中、已完成、已豁免或已逾期;进行中可转为已完成、已豁免或已逾期;已逾期可转为已完成或已豁免。已完成和已豁免是终态。已逾期只由每日检查标记。', options: { pending: '待办', in_progress: '进行中', @@ -323,7 +323,7 @@ export const lifecycle: Record = { }, status: { label: '状态', - help: '计划中可转为待收付;待收付可转为部分收付、已结清或逾期;逾期可转为部分收付或已结清。逾期只由每日检查写入。', + help: '计划中可转为待收付;待收付可转为部分收付、已结清或已逾期;部分收付可转为已结清或已逾期;已逾期可转为部分收付或已结清。已结清是终态。已逾期只由每日检查标记。', options: { planned: '计划中', due: '待收付', From 39341a7938667148598d83561c6a7d78692e45bc Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 04:52:31 +0000 Subject: [PATCH 2/4] fix(dashboards): drop seed, flow-code and PR references from widget help Four widget descriptions on the legal and finance boards told the reader about seeded SLAs, the F4 flow, "the PR" and a daily job's stamping. They now state what the tile counts; the reasoning already lives in each widget's code comment. en and zh-CN bundles in step. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1 --- src/dashboards/finance.dashboard.ts | 2 +- src/dashboards/legal.dashboard.ts | 6 +++--- src/translations/en/app.ts | 8 ++++---- src/translations/zh-CN/app.ts | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/dashboards/finance.dashboard.ts b/src/dashboards/finance.dashboard.ts index 9666136..ccc45c6 100644 --- a/src/dashboards/finance.dashboard.ts +++ b/src/dashboards/finance.dashboard.ts @@ -110,7 +110,7 @@ export const FinanceDashboard: Dashboard = { { id: 'overdue_amount', title: 'Overdue Amount', - description: 'Scheduled value of instalments the daily job has stamped overdue', + description: 'Scheduled value of instalments the daily check has marked overdue', type: 'metric', dataset: 'payment_metrics', values: ['overdue_amount'], diff --git a/src/dashboards/legal.dashboard.ts b/src/dashboards/legal.dashboard.ts index d3620bd..24567d5 100644 --- a/src/dashboards/legal.dashboard.ts +++ b/src/dashboards/legal.dashboard.ts @@ -177,7 +177,7 @@ export const LegalDashboard: Dashboard = { */ id: 'review_ageing', title: 'In Review Over 30 Days', - description: 'Older than every seeded type SLA (longest is 10 days) — a fixed threshold, not the per-type breach', + description: 'Contracts in legal review for more than 30 days. A fixed threshold, not each contract type\'s own review SLA.', type: 'metric', dataset: 'contract_metrics', values: ['contract_count'], @@ -188,7 +188,7 @@ export const LegalDashboard: Dashboard = { { id: 'negotiation_stalled', title: 'Waiting on Counterparty', - description: 'The ball is in their court — the queue F4 chases', + description: 'The ball is in their court — the queue to chase', type: 'metric', dataset: 'contract_metrics', values: ['contract_count'], @@ -230,7 +230,7 @@ export const LegalDashboard: Dashboard = { */ id: 'approval_throughput', title: 'Approved This Month', - description: 'Contracts reaching approved this month, against the previous period. Not an average duration — see the PR.', + description: 'Contracts approved this month, compared with last month. A count, not an average turnaround time.', type: 'metric', dataset: 'contract_metrics', values: ['contract_count'], diff --git a/src/translations/en/app.ts b/src/translations/en/app.ts index 4b9d1be..bc8d79f 100644 --- a/src/translations/en/app.ts +++ b/src/translations/en/app.ts @@ -158,7 +158,7 @@ export const appSurface: Pick Date: Sat, 10 Oct 2026 04:52:31 +0000 Subject: [PATCH 3/4] fix(flows): describe each automation in user terms Flow descriptions named a decision number, an upstream issue, API field names and "insert-time twin"; they now say what the automation does, with the mechanics moved into code comments. The two held flows (contract-intake, contract-approval) are untouched. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1 --- src/flows/executed-upload.flow.ts | 4 +++- src/flows/legal-review-sla.flow.ts | 5 ++++- src/flows/obligation-due.flow.ts | 2 +- src/flows/renewal-notice.flow.ts | 3 ++- src/flows/signature-record.flow.ts | 5 +++-- 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/flows/executed-upload.flow.ts b/src/flows/executed-upload.flow.ts index 7982975..d5cc529 100644 --- a/src/flows/executed-upload.flow.ts +++ b/src/flows/executed-upload.flow.ts @@ -128,7 +128,9 @@ const PARTY_BAD = '!has(vars.partyRecord) || vars.partyRecord == null || !has(va export const ExecutedUploadFlow: Flow = { name: 'executed_upload', label: 'Backfill An Executed Contract', - description: 'Record a contract that was signed outside this system: create it directly in active with is_backfilled set, and file the executed copy as its final signed version.', + // Creates the contract in `active` with `is_backfilled` set and files the + // executed copy as a `final_signed` version. + description: 'Record a contract that was signed outside this system: create it directly as active, marked as backfilled, and file the executed copy as its final signed version.', type: 'autolaunched', status: 'active', // See the header: the ONE thing elevation buys is the right to insert a diff --git a/src/flows/legal-review-sla.flow.ts b/src/flows/legal-review-sla.flow.ts index 1d42959..7e1f0f8 100644 --- a/src/flows/legal-review-sla.flow.ts +++ b/src/flows/legal-review-sla.flow.ts @@ -52,7 +52,10 @@ import { holdersPrelude, rowBody, sweepFlow } from './_daily-sweep.js'; export const LegalReviewSlaFlow: Flow = sweepFlow({ name: 'legal_review_sla', label: 'Legal Review Running Long', - description: 'Daily: remind the legal owner of a contract that has been in review over 30 days, and copy the head of legal once it passes 60. A fixed threshold, stated in the message — decision #31 ruled 2B, the per-type SLA needs platform date support (objectstack#16737).', + // A fixed threshold, stated in the message — decision #31 ruled 2B: the + // per-type SLA needs platform date support (objectstack#16737). See the + // header above. + description: 'Daily: remind the legal owner of a contract that has been in review over 30 days, and copy the head of legal once it passes 60. A fixed threshold, not each contract type\'s own review SLA.', prelude: holdersPrelude('clm_legal_head', 'legalHeads'), stages: [ { diff --git a/src/flows/obligation-due.flow.ts b/src/flows/obligation-due.flow.ts index a92c99a..b65f709 100644 --- a/src/flows/obligation-due.flow.ts +++ b/src/flows/obligation-due.flow.ts @@ -59,7 +59,7 @@ const flagOverdue: FlowNode = { export const ObligationDueFlow: Flow = sweepFlow({ name: 'obligation_due', label: 'Obligations Due And Overdue', - description: 'Daily: remind an obligation owner seven days out and on the due date, and move an unfinished obligation past its due date into overdue (which moves the contract roll-up with it).', + description: 'Daily: remind an obligation owner seven days out and on the due date, and move an unfinished obligation past its due date into overdue (which also updates the contract\'s overdue count).', stages: [ { id: 'week', diff --git a/src/flows/renewal-notice.flow.ts b/src/flows/renewal-notice.flow.ts index 23b516a..27777ef 100644 --- a/src/flows/renewal-notice.flow.ts +++ b/src/flows/renewal-notice.flow.ts @@ -228,7 +228,8 @@ export const RenewalNoticeFlow: Flow = sweepFlow({ export const RenewalStartFlow: Flow = { name: 'renewal_start', label: 'Start Renewal', - description: 'Create a renewal draft of this contract, pre-filled from it and linked back through renewed_from.', + // "Linked back" = `renewed_from` on the new draft. + description: 'Create a renewal draft of this contract, pre-filled from it and linked back to it.', type: 'autolaunched', status: 'active', runAs: 'user', diff --git a/src/flows/signature-record.flow.ts b/src/flows/signature-record.flow.ts index 78be98e..a246abd 100644 --- a/src/flows/signature-record.flow.ts +++ b/src/flows/signature-record.flow.ts @@ -205,7 +205,8 @@ const when = (...clauses: string[]) => expression(clauses.join(' && ')); export const SignatureRecordFlow: Flow = { name: 'signature_record', label: 'Signature Completed — Execution Check', - description: 'When a signing round completes, compare the formalities done against the ones the contract requires: stamp executed_at and file the final signed version when covered, or tell the legal owner which formality is missing.', + // "Record the execution date" = stamp `executed_at`. + description: 'When a signing round completes, compare the formalities done against the ones the contract requires: record the execution date and file the final signed version when covered, or tell the legal owner which formality is missing.', type: 'record_change', status: 'active', // See the header: the stamp lands on a readonly, field-secured column, and @@ -440,7 +441,7 @@ export const SignatureRecordOnCreateFlow: Flow = { ...SignatureRecordFlow, name: 'signature_record_on_create', label: 'Signature Completed — Execution Check (on create)', - description: 'Execution-formalities check for a signing round created already completed (insert-time twin of signature_record).', + description: 'The same execution check, for a signing round that is recorded as already completed.', nodes: SignatureRecordFlow.nodes.map((node) => node.id === 'start' ? { ...node, config: { ...node.config, triggerType: 'record-after-create' } } From 779486057d01b04ed5383d6c73960c66be1f8138 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 10 Oct 2026 04:54:57 +0000 Subject: [PATCH 4/4] fix(objects,dashboards): tighten three help texts read in the browser The review-ageing tile truncated its help after two lines, hiding the point; it now leads with the fixed 30-day threshold the title does not state. Contract Language is a picker of language names, so "ISO 639-1 code" told the user to type something they never type; the code note moves to a comment. Parent Contract drops a field:value aside. Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01HihZ11bQSqjCgjzHbpv4M1 --- src/dashboards/legal.dashboard.ts | 2 +- src/objects/contract.object.ts | 5 +++-- src/translations/en/app.ts | 2 +- src/translations/en/objects.contract.ts | 4 ++-- src/translations/zh-CN/app.ts | 2 +- src/translations/zh-CN/objects.contract.ts | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/dashboards/legal.dashboard.ts b/src/dashboards/legal.dashboard.ts index 24567d5..3d28ec0 100644 --- a/src/dashboards/legal.dashboard.ts +++ b/src/dashboards/legal.dashboard.ts @@ -177,7 +177,7 @@ export const LegalDashboard: Dashboard = { */ id: 'review_ageing', title: 'In Review Over 30 Days', - description: 'Contracts in legal review for more than 30 days. A fixed threshold, not each contract type\'s own review SLA.', + description: 'A fixed 30-day threshold, not each contract type\'s own review SLA.', type: 'metric', dataset: 'contract_metrics', values: ['contract_count'], diff --git a/src/objects/contract.object.ts b/src/objects/contract.object.ts index d51e013..51648bb 100644 --- a/src/objects/contract.object.ts +++ b/src/objects/contract.object.ts @@ -320,7 +320,7 @@ export const Contract = ObjectSchema.create({ parent_contract: Field.lookup('clm_contract', { label: 'Parent Contract', group: 'term', - description: 'The framework agreement this order sits under, or the main contract an amendment (category: amendment) modifies.', + description: 'The framework agreement this order sits under, or the main contract an amendment modifies.', }), is_expiring: Field.boolean({ label: 'Expiring Soon', @@ -347,7 +347,8 @@ export const Contract = ObjectSchema.create({ contract_language: Field.select({ label: 'Contract Language', group: 'legal', - description: 'ISO 639-1 code of the governing text.', + // Option values are ISO 639-1 codes. + description: 'The language whose text governs the contract.', options: [ { label: 'English', value: 'en', default: true }, { label: 'Chinese', value: 'zh' }, diff --git a/src/translations/en/app.ts b/src/translations/en/app.ts index bc8d79f..9b0fee5 100644 --- a/src/translations/en/app.ts +++ b/src/translations/en/app.ts @@ -188,7 +188,7 @@ export const appSurface: Pick = { }, parent_contract: { label: 'Parent Contract', - help: 'The framework agreement this order sits under, or the main contract an amendment (category: amendment) modifies.', + help: 'The framework agreement this order sits under, or the main contract an amendment modifies.', }, is_expiring: { label: 'Expiring Soon', @@ -204,7 +204,7 @@ export const contract: Record = { }, contract_language: { label: 'Contract Language', - help: 'ISO 639-1 code of the governing text.', + help: 'The language whose text governs the contract.', options: { en: 'English', zh: 'Chinese', diff --git a/src/translations/zh-CN/app.ts b/src/translations/zh-CN/app.ts index 924858f..ed4d91c 100644 --- a/src/translations/zh-CN/app.ts +++ b/src/translations/zh-CN/app.ts @@ -188,7 +188,7 @@ export const appSurface: Pick = { }, contract_language: { label: '合同文本语言', - help: '以哪种语言的文本为准,填 ISO 639-1 代码。', + help: '以哪种语言的文本为准。', options: { en: '英语', zh: '中文',